S: USA
N: William (Bill) Metzenthen
-E: billm@jacobi.maths.monash.edu.au
+E: billm@suburbia.net
D: Author of the FPU emulator.
D: Minor kernel hacker for other lost causes (Hercules mono, etc).
S: 22 Parker Street
S: 79539 Loerrach
S: Germany
+N: Joerg Reuter
+E: jreuter@lykos.oche.de
+E: dl1bke@db0pra.ampr.org
+D: Generic Z8530 driver, AX.25 DAMA slave implementation
+D: Several AX.25 hacks
+
N: William E. Roadcap
E: roadcapw@cfw.com
W: http://www.cfw.com/~roadcapw
this option in their lilo.config file. Comment it out and re-run lilo
if you need ramdisks.
+Module load errors
+==================
+
+ The 386 Linux kernel versions 2.1.0 and above have moved to address
+0xc0000000. This means that syscalls that return an address in the
+kernel area will return a value that is a negative 32 bit number.
+Versions of libc prior to libc-5.4.8 will interpret the negative value
+as an error. In particular, this prevents modules from loading. You
+need at least libc-5.4.10 to load modules successfully again.
+
+
The Linux C Library
===================
- The latest stable Linux C Library release is 5.2.18. If you upgrade
-to this from 5.0.9 or earlier, be sure to read the
-`release.libc-5.2.18' file, since GNU make and a few other fairly
-important utils can be broken by the upgrade.
-
- The current (beta) Linux C Library release is 5.3.12. In this
-release there are some important changes that may cause troubles to
-buggy programs (programs that call free() on a pointer not returned by
-malloc() work with previous libc, but not with this release) so read the
-`release.libc-5.3.12' file carefully! In the latest libc releases a
-dirent bug, which erroneously defined d->reclen to d->namlen if USE_GNU
-was defined, has been fixed. Unfortunately, some GNU packages depend
-on this bug. GNU make 3.xx is one of them. To fix that you need to
-patch and recompile those programs (a patch for make is included in the
-file `release.libc-.5.3.9', and the address to obtain a precompiled
-binary is at the end of this file).
-
- Also, the libc-5.3.x line has a known security hole relating to
-rlogin. Libc-5.3.12 fixes this, so if you're going to run an
-experimental libc, be sure to upgrade to 5.3.12.
-
- If you're getting an error message that is something to the effect of
+ Before upgrading your C library, be sure to carefully read the
+`release.libc-x.y.z' file. (x.y.z is the version number eg. 5.4.7)
+
+- GNU make, perl, and a few other important utils can be broken by the
+ upgrade. A dirent bug, which erroneously defined d->reclen to
+ d->namlen if USE_GNU was defined, has been fixed. Unfortunately,
+ some GNU packages depend on this bug. GNU make 3.xx is one of them.
+ To fix that you need to patch and recompile those programs (a patch
+ for make is included in the file `release.libc-x.y.z', and the
+ address to obtain a precompiled binary is at the end of this file).
+
+- Upgrading libc can also break xterm support. If it does, you need
+ to recompile xterm.
+
+- There have been some important changes to libc that may cause
+ trouble with buggy programs. Programs that call free() on a pointer
+ not returned by malloc() work with older versions of libc, but not
+ with newer versions of libc.
+
+
+There are good reasons to upgrade your libc though!
+
+- If you use modules, you'll need libc-5.4.10 or later with version
+ 2.1.x i386 kernels
+
+- The libc-5.3.x line before libc-5.3.12 have a known security hole
+ relating to rlogin. Another security fix was done in libc-5.4.7.
+
+- If you're getting an error message that is something like
`fcntl_setlk() called by process 123 with broken flock() emulation'
- then you need to upgrade to at least libc-5.2.18 as well. A proper
-(in other words, BSD-style ;-) flock system call was added to 2.0.x,
-and older libc's will now give this error. It doesn't *really* matter,
-so you can just ignore it. If it really annoys you, upgrade libc (and
-recompile any static binaries you might have that are linked against
-the old libc). If you're feeling lazy, just comment out
+ then you need to upgrade to at least libc-5.2.18. A proper (in
+ other words, BSD-style ;-) flock system call was added to 2.0.x, and
+ older libc's will now give this error. It doesn't *really* matter,
+ so you can just ignore it. If it really annoys you, upgrade libc
+ (and recompile any static binaries you might have that are linked
+ against the old libc). If you're feeling lazy, just comment out
+
+ `printk(KERN_WARNING
+ "fcntl_setlk() called by process %d with broken flock() emulation\n",
+ current->pid);'
- ` printk(KERN_WARNING
-"fcntl_setlk() called by process %d with broken flock()
- emulation\n", current->pid);'
+ in linux/fs/locks.c and recompile. If you're still running a.out,
+ there's an unofficial libc-4.7.6 to which you can upgrade to fix
+ this problem.
- in linux/fs/locks.c and recompile. If you're still running a.out,
-there's an unofficial libc-4.7.6 release out to which you can upgrade
-to fix this problem. Libc is available from
-ftp://sunsite.unc.edu/pub/Linux/GCC/.
GCC Signal 11 error
===================
If make no longer works, you need to read the release notes for the
libc you upgraded to. The latest libc and release notes can be found at
ftp://tsx-11.mit.edu/pub/linux/packages/GCC. This is NOT an error due
-to the kernel, though many people have mistakenly thought it is. When
-you upgrade to libc-5.3.9, you have to patch make to get it to work.
-All of this is documented in the release notes with libc. Upgrading
-libc can also break xterm support. If it does, you need to recompile
-xterm.
+to the kernel, though many people have mistakenly thought it was. When
+you upgrade to libc-5.3.9 or later, from previous versions, you have
+to patch make to get it to work.
Loop device
===========
Linux C Library
===============
-The stable 5.2.18 release:
-ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.2.18.bin.tar.gz
-Installation notes for 5.2.18:
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.2.18
+The stable 5.4.7 release:
+ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.7.bin.tar.gz
+Installation notes for 5.4.7:
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.7
-The latest 5.3.12 release:
-ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.3.12.bin.tar.gz
-Installation notes for 5.3.12:
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.3.12
+The latest release:
+ftp://sunsite.unc.edu/pub/Linux/GCC/private/tofu/libc-x.y.z.bin.tar.gz
+Installation notes for x.y.z:
+ftp://sunsite.unc.edu/pub/Linux/GCC/private/tofu/release.libc-x.y.z
Patched make sources:
ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74.patched.tar.gz
Linux C++ Library
=================
+ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.2.1.bin.tar.gz
ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.1.4.bin.tar.gz
ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.1.3.bin.tar.gz
Installation notes:
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.2.1
ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.1.4
ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.1.3
-Use 2.7.13 with libc 5.2.18 and 2.7.14 with libc 5.3.12.
+Use libg++-2.7.2.1 with libc-5.4.4 and above,
+ libg++-2.7.1.4 with libc-5.3.5 to libc-5.4.3,
+ libg++-2.7.1.3 with libc 5.2.14 to libc-5.3.4
Dynamic Linker
==============
modified texinfo setup, so you don't need to bother generating a diff
against the current version before you send the additional information
to me.
-
code which can be inserted in and removed from the running kernel
whenever you want), say M here and read Documentation/modules.txt.
-Z8530 SCC kiss emulation driver for AX.25
+Z8530 SCC driver for AX.25
CONFIG_SCC
These cards are used to connect your Linux box to an amateur radio
in order to communicate with other computers. If you want to use
- this, read Documentation/networking/z8530drv.txt and the HAM-HOWTO,
+ this, read Documentation/networking/z8530drv.txt and the AX.25-HOWTO,
available via ftp (user: anonymous) at
sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you want to compile this
as a module ( = code which can be inserted in and removed from the
Internet:
=========
-ftp.ucsd.edu:/hamradio/packet/tcpip/incoming/z8530drv-2.0.dl1bke.real.tar.gz
+1. db0bm.automation.fh-aachen.de/incoming/dl1bke/z8530drv-utils-3.0.tar.gz
-[
- if you can't find it there, try:
- .../tcpip/linux/z8530drv-2.0.dl1bke.tar.gz
-
-]
+2. ftp.ucsd.edu:/hamradio/packet/tcpip/incoming/z8530drv-utils-3.0.tar.gz
+ If you can't find it there, try .../tcpip/linux/z8530drv-utils-3.0.tar.gz
and various mirrors (i.e. nic.switch.ch)
----------------------------------------------------------------------------
+Please note that the information in this document may be hopelessly outdated.
+-----------------------------------------------------------------------------
SCC.C - Linux driver for Z8530 based HDLC cards for AX.25
********************************************************************
- (c) 1993,1995 by Joerg Reuter DL1BKE
+ (c) 1993,1996 by Joerg Reuter DL1BKE <jreuter@lykos.oche.de>
portions (c) 1993 Guido ten Dolle PE1NNZ
1. if compiled as module: loading the module
2. Setup of hardware, MODEM and KISS parameters with sccinit
- 3. Attachment of each channel in the packet software
+ 3. Attach each channel to the Linux kernel AX.25 with "ifconfig"
+
+Unlike the versions below 2.4 this driver is a real network device
+driver. If you want to run xNOS instead of our fine kernel AX.25
+use a 2.x version (available from above sites) or read the
+AX.25-HOWTO on how to emulate a KISS TNC on network device drivers.
1.1 Loading the module
You should include the insmod in one of the /etc/rc.d/rc.* files,
and don't forget to insert a call of sccinit after that. It
-will read your
+will read your /etc/z8530drv.conf.
-
-1.2. /etc/z8530drv.rc
-=====================
+1.2. /etc/z8530drv.conf
+=======================
To setup all parameters you must run /sbin/sccinit from one
-of your rc.*-files. This has to be done BEFORE the start of
-NET or axattach. Sccinit reads the file /etc/z8530drv.rc
+of your rc.*-files. This has to be done BEFORE you can
+"ifconfig" an interface. Sccinit reads the file /etc/z8530drv.conf
and sets the hardware, MODEM and KISS parameters. A sample file is
delivered with this package. Change it to your needs.
gencfg 2 0x150 4 2 0 1 0x168 9 4915200
-will print a skeleton z8530drv.rc for the OptoSCC to stdout.
+will print a skeleton z8530drv.conf for the OptoSCC to stdout.
gencfg 2 0x300 2 4 5 -4 0 7 4915200 0x10
The channel definition is divided into three sub sections for each
channel:
-An example for /dev/scc0:
+An example for scc0:
# DEVICE
-device /dev/scc0 # the device for the following params
+device scc0 # the device for the following params
# MODEM / BUFFERS
# nrzi = 1k2 MODEM, G3RUH 9k6 MODEM
# nrz = DF9IC 9k6 MODEM
#
-rxbuffers 8 # number of rx buffers allocated
- # (option, default is 4)
-txbuffers 16 # number of tx buffers allocated
- # (option, default is 16)
bufsize 384 # size of buffers. Note that this must include
# the AX.25 header, not only the data field!
# (optional, defaults to 384)
sections IS important. The MODEM parameters are set with the first
recognized KISS parameter...
-Please note that you can initialize the board only once after boot.
-You can change all parameters but "mode" and "clock" later with the
-Sccparam program or through KISS. Just to avoid security holes...
+Please note that you can initialize the board only once after boot
+(or insmod). You can change all parameters but "mode" and "clock"
+later with the Sccparam program or through KISS. Just to avoid
+security holes...
(1) this divider is usually mounted on the SCC-PBC (PA0HZP) or not
present at all (BayCom). It feeds back the output of the DPLL
installed will normally result in keying the transceiver until
maxkey expires --- of course without sending anything (useful).
-
2. Attachment of a channel by your AX.25 software
=================================================
-2.1 KA9Q NOS derivates
-======================
+2.1 Kernel AX.25
+================
-When the linux has startup, the SCC driver has been initialized,
-you can attach the channels in your packet software. This is done
-by open the scc devices by using the attach asy command.
-The SCC-drivers emulates the scc devices as serial asy ports,
-this means e.g. that the baudrate can be set in the attach command.
+To set up an AX.25 device you can simply type:
+ ifconfig scc0 44.128.1.1 hw ax25 dl0tha-7
-Example Wampes:
+This will create a network interface with the IP number 44.128.20.107
+and the callsign "dl0tha". If you do not have any IP number (yet) you
+can use any of the 44.128.0.0 network. Note that you do not need
+axattach. The purpose of axattach (like slattach) is to create a KISS
+network device linked to a TTY. Please read the documentation of the
+ax25-utils and the AX.25-HOWTO to learn how to set the parameters of
+the kernel AX.25.
-#############################################################################################
-# Wampes device attach
-# NOTE: Interfacename and the device must be the same!!
-# Usage: attach asy 0 0 slip|vjslip|ax25ui|ax25i|nrs|kissui <label> 0 <mtu> <speed> [ip_addr]
-#
-attach asy 0 0 kissi scc0 256 256 1200 # Attach SCC channel 1 in 1200 baud
-attach asy 0 0 kissi scc1 256 256 1200 # Attach SCC channel 2 in 1200 baud
-attach asy 0 0 kissui scc2 256 256 38400 # Attach SCC channel 3 in 38400 baud
-attach asy 0 0 kissui scc3 256 256 9600 # Attach SCC channel 4 in 9600 baud
-# ^^^^
-# for WAMPES 921229 use here: ax25
-#
+2.2 NOS, NET and TFKISS
+=======================
-Example JNOS:
+Since the TTY driver (aka KISS TNC emulation) is gone you need
+to emulate the old behaviour. The cost using these programs is
+that you probably need to compile the kernel AX.25, regardless
+if you actually use it or not. First setup your /etc/ax25/axports,
+for example:
-############################################
-# JNOS device attach
-#
-attach asy scc0 0 ax25 scc0 256 256 1200
-attach asy scc1 0 ax25 scc1 256 256 1200
-attach asy scc2 0 ax25 scc2 256 256 300
-attach asy scc3 0 ax25 scc3 256 256 4800
-#
-#
+ 9k6 dl0tha-9 9600 255 4 9600 baud port (scc3)
+ axlink dl0tha-15 38400 255 4 Link to NOS
+Now "ifconfig" the scc device:
-It allows AX.25 communication without a TNC. Only a MODEM is
-needed. The parameters have the same meaning as in KISS mode.
-In fact, the AX.25 mode is emulating an extended KISS TNC, so
-the same commands can be used to set the parameters of the
-interface (see below).
+ ifconfig scc3 44.128.1.1 hw ax25 dl0tha-9
-To be able to run fullduplex using an SCC in AX.25 mode, an
-external divider must be available, that divides the baudrate
-generator clock available on the TRxC pin by 32, and puts the
-resulting signal on the RTxC pint of the same channel of the SCC.
-Such a divider is not necessary for normal CSMA packet radio
-operation, but interrupt overhead is slightly reduced if you
-still install it.
+You can now axattach a pseudo-TTY:
-2.2 Kernel AX.25
-================
+ axattach /dev/ptys0 axlink
-Well, as said before: The driver emulates a KISS TNC, so you
-can simply run
+and start your NOS and attach /dev/ptys0 there. The problem is that
+NOS is reachable only via digipeating through the kernel AX.25
+(disasterous on a DAMA controlled channel). To solve this problem,
+configure "rxecho" to echo the incoming frames from "9k6" to "axlink"
+and outgoing frames from "axlink" to "9k6" and start:
- axattach -s 1200 /dev/scc0 DL1BKE
+ rxecho
-to establish the link between kernel AX.25 and z8530drv.
+Or simply use "kissbridge" coming with z8530drv-utils:
+
+ ifconfig scc3 hw ax25 dl0tha-9
+ kissbridge scc3 /dev/ptys0
3. Adjustment and Display of parameters
Once a SCC channel has been attached, the parameter settings and
some statistic information can be shown using the param program:
-dl1bke-u:~$ sccstat /dev/scc0
+dl1bke-u:~$ sccstat scc0
Parameters:
Status:
-HDLC Z8530 Interrupts Queues
+HDLC Z8530 Interrupts Buffers
-----------------------------------------------------------------------
-Sent : 273 RxOver : 0 RxInts : 125074 RxQueue : 0
-Received : 1095 TxUnder: 0 TxInts : 4684 TxQueue : 0
-RxErrors : 1591 ExInts : 11776 NoSpace : 0
-KissErrors : 0 SpInts : 1503
+Sent : 273 RxOver : 0 RxInts : 125074 Size : 384
+Received : 1095 TxUnder: 0 TxInts : 4684 NoSpace : 0
+RxErrors : 1591 ExInts : 11776
+TxErrors : 0 SpInts : 1503
Tx State : idle
-Memory allocated:
-
-Buffer size: 384
-rx buffers : 4
-tx buffers : 8
-
The status info shown is:
Sent - number of frames transmitted
Received - number of frames received
RxErrors - number of receive errors (CRC, ABORT)
-KissErrors - number of KISS errors (should be zero...)
+TxErrors - number of discarded Tx frames (due to various reasons)
Tx State - status of the Tx interrupt handler: idle/busy/active/tail (2)
RxOver - number of receiver overruns
-TxUnder - number of transmitter underruns
+TxUnder - number of transmitter underruns
RxInts - number of receiver interrupts
TxInts - number of transmitter interrupts
EpInts - number of receiver special condition interrupts
SpInts - number of external/status interrupts
-RxQueue - number of received packets enqueued for this channel
-TxQueue - number of packets enqueued for Tx
-NoSpace - number of times the receiver buffer pool was found empty
-
+Size - maximum size of an AX.25 frame (*with* AX.25 headers!)
+NoSpace - number of times a buffer could not get allocated
An overrun is abnormal. If lots of these occur, the product of
baudrate and number of interfaces is too high for the processing
-power of you computer. If "Space" errors occur, specify a higher
-number of buffers in the "scc.h" file.
+power of you computer. NoSpace errors are unlikely caused by the
+driver or the kernel AX.25.
3.2 Setting Parameters
The setting of parameters of the emulated KISS TNC is done in the
same way in the SCC driver. You can change parameters by using
-the command param in NET or NOS
-
- param <iface> <paramname> <value>
-
-or use the program "sccparam":
+the kissparms program from the ax25-utils package or use the program
+"sccparam":
sccparam <device> <paramname> <decimal-|hexadecimal value>
Example: sccparam /dev/scc0 soft on
-slip:
- use slip encoding instead of kiss
-
- Example: sccparam /dev/scc1 slip on
-
-
-
4. Problems
===========
If you have tx-problems with your BayCom USCC card please check
the manufacturer of the 8530. SGS chips have a slightly
-different timing. Try Zilog... I have no information if this
-driver works with baudrates higher than 1200 baud. A solution is
-to write to register 8 instead to the data port, but this won't
-work with the ESCC chips *SIGH!*
+different timing. Try Zilog... A solution is to write to register 8
+instead to the data port, but this won't work with the ESCC chips.
+*SIGH!*
+
+A very common problem is that the PTT locks until the maxkeyup timer
+expires, although interrupts and clock source are correct. In most
+cases #define SCC_DELAY solves the problems. For more hints read
+the (pseudo) FAQ and the documentation coming with z8530drv-utils.
I got reports that the driver has problems on some 386-based systems.
(i.e. Amstrad) Those systems have a bogus AT bus timing which will
lead to delayed answers on interrupts. You can recognize these
problems by looking at the output of Sccstat for the suspected
port. See if it shows under- and overruns you own such a system.
-Perhaps it will help if you simplify the scc_isr() function a bit.
-You'll find a slightly faster version in the files scc_isr_intack
-or scc_isr_novec.
-
Delayed processing of received data: This depends on
- kernel profiling compiled or not
-- the rather slow receiver in tty_io.c
-
- a high interrupt load
- a high load of the machine --- running X, Xmorph, XV and Povray,
while compiling the kernel... hmm ... even with 32 MB RAM ... ;-)
+ Or running a named for the whole .ampr.org. domain on an 8 MB
+ box...
-- NET's speed itself.
-
+- using information from rxecho or kissbridge.
Kernel panics: please read to /linux/README and find out if it
really occurred within the scc driver.
-If you can't solve a problem, send me
+If you cannot solve a problem, send me
- a description of the problem,
- information on your hardware (computer system, scc board, modem)
- your kernel version
-- the output of sccstat /dev/scc# ("#" is the No. of the channel)
-- the settings of "speed", "clock" and "mode" for that channel
- in /etc/z8530drv.rc
-- your scc_config.h
-
-
-And always remember:
-The 1.1.* kernel series is for alpha tests -- use at your own risk ;-)
-The 1.2.* series should run reliable. This driver perhaps NOT!
-The 1.3.* kernel series is for alpha tests again... you get the idea!
-
-
-3. DRSI Boards
-==============
-
-I still can't test the DRSI board, but this configuration derived from
-the PE1CHL SCC driver configuration should work:
-
-An example of scc_config.h for
-
-One DRSI board installed:
-=========================
-
-/* gencfg 1 0x300 0x10 2 0 1 0 7 4915200 */
-
-/* file generated by $Id: gencfg.c,v 1.2 1994/11/29 21:42:24 JReuter Exp JReuter $ */
-
-#include <linux/scc.h>
-
-int Nchips = 1;
-io_port Vector_Latch = 0x0;
-int Ivec = 7;
-long Clock = 4915200;
-char Board = PA0HZP;
-int Option = 0;
-io_port Special_Port = 0x0;
-
-io_port SCC_ctrl[MAXSCC * 2] =
-{0x302, 0x300, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
-
-io_port SCC_data[MAXSCC * 2] =
-{0x303, 0x301, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
-
-/* set to '1' if you have and want ESCC chip (8580/85180/85280) support */
-
-/* Chip */
-/* ======== */
-int SCC_Enhanced[MAXSCC] = {0, /* ...one... */
- 0, /* ...two... */
- 0, /* ...three... */
- 0}; /* ...four... */
-
-#define VERBOSE_BOOTMSG 1
-#undef SCC_DELAY /* perhaps a 486DX2 is a *bit* too fast */
-#undef SCC_LDELAY /* slow it even a bit more down */
-#undef DONT_CHECK /* don't look if the SCCs you specified are available */
-
-
-
-Two boards installed:
-=====================
-
-/* file generated by $Id: gencfg.c,v 1.2 1994/11/29 21:42:24 JReuter Exp JReuter $ */
-
-#include <linux/scc.h>
-
-int Nchips = 2;
-io_port Vector_Latch = 0x0;
-int Ivec = 7;
-long Clock = 4915200;
-char Board = PA0HZP;
-int Option = 0;
-io_port Special_Port = 0x0;
-
-io_port SCC_ctrl[MAXSCC * 2] =
-{0x302, 0x300, 0x312, 0x310, 0x0, 0x0, 0x0, 0x0};
-
-io_port SCC_data[MAXSCC * 2] =
-{0x303, 0x301, 0x313, 0x311, 0x0, 0x0, 0x0, 0x0};
-
-/* set to '1' if you have and want ESCC chip (8580/85180/85280) support */
-
-/* Chip */
-/* ======== */
-int SCC_Enhanced[MAXSCC] = {0, /* ...one... */
- 0, /* ...two... */
- 0, /* ...three... */
- 0}; /* ...four... */
-
-#define VERBOSE_BOOTMSG 1
-#undef SCC_DELAY /* perhaps a 486DX2 is a *bit* too fast */
-#undef SCC_LDELAY /* slow it even a bit more down */
-#undef DONT_CHECK /* don't look if the SCCs you specified are available */
-
-
-*****************
-
-You m u s t use "clock dpll" in /etc/z8530drv.rc for operation,
-the on-board baudrate generator is not supported.
-
-*****************
-(mni tnx to Mike Bilow)
-
+- the output of cat /proc/net/z8530
4. Thor RLC100
==============
Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org
AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU
- Internet: jreuter@lykos.tng.oche.de
+ Internet: jreuter@lykos.oche.de
L: linux-hams@vger.rutgers.edu
S: Maintained
+DAMA SLAVE for AX.25
+P: Joerg Reuter
+M: jreuter@lykos.oche.de
+L: linux-hams@vger.rutgers.edu
+S: Maintained
+
+Z8530 DRIVER FOR AX.25
+P: Joerg Reuter
+M: jreuter@lykos.oche.de
+L: linux-hams@vger.rutgers.edu
+S: Maintained
+
BUSLOGIC SCSI DRIVER
P: Leonard N. Zubkoff
M: Leonard N. Zubkoff <lnz@dandelion.com>
L: linux-kernel@vger.rutgers.edu
S: Maintained
+FPU EMULATOR
+P: Bill Metzenthen
+M: billm@suburbia.net
+W: http://suburbia.net/~billm/floating-point/emulator/
+S: Maintained
+
CREDITS FILE
P: John A. Martin
M: jam@acm.org
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 5
+SUBLEVEL = 6
ARCH = i386
#include <asm/fpu.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
#include <linux/elfcore.h>
#include <asm/reg.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#include <linux/user.h>
#include <linux/debugreg.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <linux/delay.h>
#include <linux/config.h> /* CONFIG_ALPHA_LCA etc */
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/hwrpb.h>
#include <linux/mm.h>
#include <asm/bitops.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define _S(nr) (1<<((nr)-1))
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
#include <linux/string.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/hwrpb.h>
#include <linux/tty.h>
#include <asm/gentrap.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/unaligned.h>
void die_if_kernel(char * str, struct pt_regs * regs, long err)
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "ieee-math.h"
#include <linux/mm.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/mmu_context.h>
#include <linux/swap.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/hwrpb.h>
#include <asm/dma.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
extern void dump_thread(struct pt_regs *, struct user *);
#include <linux/mm.h>
#include <linux/vmalloc.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/ldt.h>
#include <linux/delay.h>
#include <linux/smp.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/io.h>
#include <linux/user.h>
#include <linux/debugreg.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#ifdef CONFIG_BLK_DEV_RAM
#include <linux/blk.h>
#endif
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/smp.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define _S(nr) (1<<((nr)-1))
/* set up the "normal" stack seen by the signal handler (iBCS2) */
#define __CODE ((unsigned long)(frame+24))
#define CODE(x) ((unsigned long *) ((x)+__CODE))
- put_user(__CODE,frame);
+ if (put_user(__CODE,frame))
+ do_exit(SIGSEGV);
if (current->exec_domain && current->exec_domain->signal_invmap)
put_user(current->exec_domain->signal_invmap[signr], frame+1);
else
{
unsigned int tmp = 0;
#define PUT_SEG(seg, mem) \
-__asm__("mov %%" #seg",%w0":"=r" (tmp):"0" (tmp)); *(mem) = tmp;
+__asm__("mov %%" #seg",%w0":"=r" (tmp):"0" (tmp)); put_user(tmp,mem);
PUT_SEG(gs, frame+2);
PUT_SEG(fs, frame+3);
}
#include <linux/mman.h>
#include <linux/file.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/ipc.h>
/*
#include <linux/mm.h>
#include <linux/interrupt.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/mm.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
asmlinkage int system_call(void);
#include <linux/ptrace.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
+---------------------------------------------------------------------------+
| wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. |
| |
- | Copyright (C) 1992,1993,1994,1995 |
+ | Copyright (C) 1992,1993,1994,1995,1996 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | Australia. E-mail billm@suburbia.net |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License version 2 as |
some differences.
Please report bugs, etc to me at:
- billm@jacobi.maths.monash.edu.au
+ billm@suburbia.net
--Bill Metzenthen
- October 1995
+ October 1996
----------------------- Internals of wm-FPU-emu -----------------------
#include <linux/signal.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "fpu_system.h"
#include "exception.h"
#include <linux/signal.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "fpu_system.h"
#include "fpu_emu.h"
#include <linux/stddef.h>
#include <linux/head.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "fpu_system.h"
#include "exception.h"
| other processes using the emulator while swapping is in progress. |
+---------------------------------------------------------------------------*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "fpu_system.h"
#include "exception.h"
| other processes using the emulator while swapping is in progress. |
+---------------------------------------------------------------------------*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "fpu_system.h"
#include "exception.h"
#include <linux/mm.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
extern void die_if_kernel(const char *,struct pt_regs *,long);
#endif
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
static int use_virtual_dma=0; /* virtual DMA for Intel */
static unsigned short virtual_dma_port=0x3f0;
#define REALLY_SLOW_IO
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define MAJOR_NR HD_MAJOR
#include <linux/blk.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/byteorder.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/unaligned.h>
#include "ide.h"
#include <asm/byteorder.h>
#include <asm/irq.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
/*
#include <asm/byteorder.h>
#include <asm/irq.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
#ifdef CONFIG_PCI
unsigned long capacity, check;
id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_KERNEL);
- ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */
+ ide_input_data(drive, id, SECTOR_WORDS);/* read 512 bytes of id info */
sti();
+#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO)
/*
- * EATA SCSI controllers do a hardware ATA emulation: ignore them
+ * EATA SCSI controllers do a hardware ATA emulation:
+ * Ignore them if there is a driver for them available.
*/
if ((id->model[0] == 'P' && id->model[1] == 'M')
|| (id->model[0] == 'S' && id->model[1] == 'K')) {
drive->present = 0;
return;
}
+#endif
/*
* WIN_IDENTIFY returns little-endian info,
#include <linux/errno.h>
#include <linux/major.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#ifdef CONFIG_BLK_DEV_LOOP_DES
#include <linux/des.h>
#include <linux/module.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
extern void wait_for_keypress(void);
* Germany
*
* To enable UMC8672 support there must a lilo line like
- * append="hd=umc8672"...
+ * append="ide0=umc8672"...
* To set the speed according to the abilities of the hardware there must be a
* line like
* #define UMC_DRIVE0 11
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/dma.h>
#define MAJOR_NR XT_DISK_MAJOR
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define MAJOR_NR AZTECH_CDROM_MAJOR
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/dma.h>
#include <linux/cdrom.h>
int num_tracks;
- num_tracks = sony_toc.last_track_num - sony_toc.first_track_num + 1;
+ num_tracks = ( bcd_to_int(sony_toc.last_track_num)
+ - bcd_to_int(sony_toc.first_track_num)
+ + 1);
for (i = 0; i < num_tracks; i++)
{
if (sony_toc.tracks[i].track == track)
i=verify_area(VERIFY_WRITE, hdr, sizeof(*hdr));
if(i<0)
return i;
- loc_hdr.cdth_trk0 = sony_toc.first_track_num;
- loc_hdr.cdth_trk1 = sony_toc.last_track_num;
+ loc_hdr.cdth_trk0 = bcd_to_int(sony_toc.first_track_num);
+ loc_hdr.cdth_trk1 = bcd_to_int(sony_toc.last_track_num);
copy_to_user(hdr, &loc_hdr, sizeof(*hdr));
}
return 0;
return i;
copy_from_user(&ti, (char *) arg, sizeof(ti));
- if ( (ti.cdti_trk0 < sony_toc.first_track_num)
- || (ti.cdti_trk0 > sony_toc.last_track_num)
+ if ( (ti.cdti_trk0 < bcd_to_int(sony_toc.first_track_num))
+ || (ti.cdti_trk0 > bcd_to_int(sony_toc.last_track_num))
|| (ti.cdti_trk1 < ti.cdti_trk0))
{
return -EINVAL;
* If we want to stop after the last track, use the lead-out
* MSF to do that.
*/
- if (ti.cdti_trk1 >= sony_toc.last_track_num)
+ if (ti.cdti_trk1 >= bcd_to_int(sony_toc.last_track_num))
{
log_to_msf(msf_to_log(sony_toc.lead_out_start_msf)-1,
&(params[4]));
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define MAJOR_NR GOLDSTAR_CDROM_MAJOR
#include <linux/blk.h>
/* #define REALLY_SLOW_IO */
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define MAJOR_NR MITSUMI_CDROM_MAJOR
#include <linux/blk.h>
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <stdarg.h>
#include <linux/sbpcd.h>
#include <linux/config.h>
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define MAJOR_NR SANYO_CDROM_MAJOR
#include <linux/blk.h>
#define REALLY_SLOW_IO
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/cdrom.h>
endif
endif
-ifeq ($(CONFIG_SCC),y)
-L_OBJS += scc.o
-else
- ifeq ($(CONFIG_SCC),m)
- M_OBJS += scc.o
- endif
-endif
-
ifeq ($(CONFIG_BAYCOM),y)
L_OBJS += baycom.o
else
+The z8530drv is now a network device driver, you can find it in
+ ../net/scc.c
-You will find subset of the documentation in
-
- linux/Documentation/networking/z8530drv.txt
-
-
-To use this driver you MUST have the full package from
-
-ftp.ucsd.edu:/hamradio/packet/tcpip/incoming/z8530drv-2.01.dl1bke.real.tar.gz
-
-[
- if you can't find it there, try:
- .../tcpip/linux/z8530drv-2.01.dl1bke.tar.gz
-
-]
-
-and various mirrors (i.e. nic.switch.ch)
-
-The package includes the utilities necessary to initialize and
-control the driver.
-
-Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org
- AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU
- Internet: jreuter@lykos.tng.oche.de
+A subset of the documentation is in
+ ../../Documentation/networking/z8530drv.txt
#include <linux/random.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/amigamouse.h>
#include <asm/amigahw.h>
#include <linux/module.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/types.h>
#include <linux/stddef.h>
#include <asm/atarikb.h>
#include <asm/atari_mouse.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bootinfo.h>
static struct mouse_status mouse;
#include <linux/random.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/major.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
#include "kbd_kern.h"
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/malloc.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "consolemap.h"
static unsigned short translations[][256] = {
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/config.h>
#include <linux/mman.h>
#include <linux/tty.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bootinfo.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <linux/delay.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
/* the BIOS manuals say there can be up to 4 lpt devices
#include <linux/malloc.h>
#include <linux/interrupt.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/mm.h>
#include <linux/random.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <linux/random.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <linux/string.h>
#include <linux/malloc.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
#define VERSION "1.5.7"
#include <linux/random.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/config.h>
#include <linux/major.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <linux/malloc.h>
#include <linux/random.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/mc146818rtc.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
/*
static struct timer_list rtc_irq_timer;
-static int rtc_lseek(struct inode *inode, struct file *file, off_t offset,
- int origin);
+static long long rtc_llseek(struct inode *inode, struct file *file,
+ loff_t offset, int origin);
-static int rtc_read(struct inode *inode, struct file *file,
- char *buf, int count);
+static long rtc_read(struct inode *inode, struct file *file,
+ char *buf, unsigned long count);
static int rtc_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
* Now all the various file operations that we export.
*/
-static int rtc_lseek(struct inode *inode, struct file *file, off_t offset,
- int origin)
+static long long rtc_llseek(struct inode *inode, struct file *file,
+ loff_t offset, int origin)
{
return -ESPIPE;
}
-static int rtc_read(struct inode *inode, struct file *file, char *buf, int count)
+static long rtc_read(struct inode *inode, struct file *file, char *buf,
+ unsigned long count)
{
struct wait_queue wait = { current, NULL };
int retval;
*/
static struct file_operations rtc_fops = {
- rtc_lseek,
+ rtc_llseek,
rtc_read,
NULL, /* No write */
NULL, /* No readdir */
+++ /dev/null
-#define RCS_ID "$Id: scc.c,v 1.41 1995/12/17 22:36:40 jreuter Exp jreuter $"
-
-#define BANNER "Z8530 SCC driver version 2.01.dl1bke (alpha) by DL1BKE\n"
-
-/*
-
- ********************************************************************
- * SCC.C - Linux driver for Z8530 based HDLC cards for AX.25 *
- ********************************************************************
-
-
- ********************************************************************
-
- Copyright (c) 1993, 1995 Joerg Reuter DL1BKE
-
- portions (c) 1993 Guido ten Dolle PE1NNZ
-
- ********************************************************************
-
- The driver and the programs in the archive are UNDER CONSTRUCTION.
- The code is likely to fail, and so your kernel could --- even
- a whole network.
-
- This driver is intended for Amateur Radio use. If you are running it
- for commercial purposes, please drop me a note. I am nosy...
-
- ...BUT:
-
- ! You m u s t recognize the appropriate legislations of your country !
- ! before you connect a radio to the SCC board and start to transmit or !
- ! receive. The GPL allows you to use the d r i v e r, NOT the RADIO! !
-
- For non-Amateur-Radio use please note that you might need a special
- allowance/licence from the designer of the SCC Board and/or the
- MODEM.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the (modified) GNU General Public License
- delivered with the Linux kernel source.
-
- 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 find a copy of the GNU General Public License in
- /usr/src/linux/COPYING;
-
- ********************************************************************
-
-
- ...If you find any portions of the code that are copyrighted to you,
- and you don't want to see in here, please send me a private (!)
- message to my internet site. I will change it as soon as possible.
- Please don't flame to the tcp-group or anywhere else. Thanks!
-
- Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org
- AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU
- Internet: jreuter@lykos.tng.oche.de
-
-
- Incomplete history of z8530drv:
- -------------------------------
-
- 940913 - started to write the driver, rescued most of my own
- code (and Hans Alblas' memory buffer pool concept) from
- an earlier project "sccdrv" which was initiated by
- Guido ten Dolle. Not much of the old driver survived,
- though. The first version I put my hands on was sccdrv1.3
- from August 1993. The memory buffer pool concept
- appeared in an unauthorized sccdrv version (1.5) from
- August 1994.
-
- 950131 - changed copyright notice to GPL without limitations.
-
- .
- .
- .
-
- 950922 - using kernel timer chain
-
- 951002 - splitting timer routine, adding support for throttle/
- unthrottle calls, removed typo in kiss decoder,
- corrected termios settings.
-
- 951011 - at last found one (the?) problem which caused the
- driver to mess up buffers on heavy load pe1ayx was
- complaining about. Quite simple to reproduce:
- set a 9k6 port into audio loopback, add a route
- to 44.99.99.99 on that route and do a
- ping -f 44.99.99.99
-
- 951013 - it still does not survive a flood ping...
-
- 951107 - axattach w/o "-s" option (or setting an invalid
- baudrate) does not produce "division by zero" faults
- anymore.
-
- 951114 - rewrote memory management, took first steps to allow
- compilation as a module. Well, it looks like a whole
- new driver now. BTW: It d o e s survive the flood
- ping at last...
-
- 951116 - scc_config.h is gone -- the driver will be initialized
- through ioctl-commands. Use sccinit.c for this purpose.
-
- 951117 - Well --- what should I say: You can compile it as a
- module now. And I solved the problem with slip.c...
-
- 951120 - most ioctl() routines may be called w/o suser()
- permissions, check if you've set the permissions of
- /dev/scc* right! NOT 0666, you know it's evil ;-)
-
- 951217 - found silly bug in init_channel(), some bugfixes
- for the "standalone" module
-
-
- Thanks to:
- ----------
-
- PE1CHL Rob - for a lot of good ideas from his SCC driver for DOS
- PE1NNZ Guido - for his port of the original driver to Linux
- KA9Q Phil - from whom we stole the mbuf-structure
- PA3AYX Hans - for some useful changes
- DL8MBT Flori - for support
- DG0FT Rene - for the BayCom USCC support
- PA3AOU Harry - for ESCC testing, information supply and support
-
- PE1KOX Rob, DG1RTF Thomas, ON5QK Roland, G4XYW Andy, Linus,
- EI9GL Paul,
-
- and all who sent me bug reports and ideas...
-
-
- NB -- if you find errors, change something, please let me know
- first before you distribute it... And please don't touch
- the version number. Just replace my callsign in
- "v2.01.dl1bke" with your own. Just to avoid confusion...
-
- If you want to add your modification to the linux distribution
- please (!) contact me first.
-
- Jörg Reuter DL1BKE
-
-*/
-
-/* ----------------------------------------------------------------------- */
-
-#define DEBUG_BUFFERS /* keep defined unless it is really stable... */
-
-#undef SCC_DELAY /* perhaps a 486DX2 is a *bit* too fast */
-#undef SCC_LDELAY 5 /* slow it even a bit more down */
-#undef DONT_CHECK /* don't look if the SCCs you specified are available */
-
-#define MAXSCC 4 /* number of max. supported chips */
-#define RXBUFFERS 8 /* default number of RX buffers */
-#define TXBUFFERS 8 /* default number of TX buffers */
-#define BUFSIZE 384 /* must not exceed 4096-sizeof(mbuf) */
-#define TPS 25 /* scc_tx_timer(): Ticks Per Second */
-
-#define DEFAULT_CLOCK 4915200 /* default pclock if nothing is specified */
-
-/* ----------------------------------------------------------------------- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/tqueue.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/termios.h>
-#include <linux/serial.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/scc.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/segment.h>
-#include <asm/bitops.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <time.h>
-#include <linux/kernel.h>
-
-#ifdef MODULE
-int init_module(void);
-void cleanup_module(void);
-#endif
-
-#ifndef Z8530_MAJOR
-#define Z8530_MAJOR 34
-#endif
-
-int scc_init(void);
-
-static struct mbuf * scc_enqueue_buffer(struct mbuf **queue, struct mbuf * buffer);
-static struct mbuf * scc_dequeue_buffer(struct mbuf **queue);
-static void alloc_buffer_pool(struct scc_channel *scc);
-static void free_buffer_pool(struct scc_channel *scc);
-static struct mbuf * scc_get_buffer(struct scc_channel *scc, char type);
-
-int scc_open(struct tty_struct *tty, struct file *filp);
-static void scc_close(struct tty_struct *tty, struct file *filp);
-int scc_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
-static void scc_put_char(struct tty_struct *tty, unsigned char ch);
-static void scc_flush_chars(struct tty_struct *tty);
-static int scc_write_room(struct tty_struct *tty);
-static int scc_chars_in_buffer(struct tty_struct *tty);
-static void scc_flush_buffer(struct tty_struct *tty);
-static int scc_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
-static void scc_set_termios(struct tty_struct *tty, struct termios *old_termios);
-static void scc_set_ldisc(struct tty_struct *tty);
-static void scc_throttle(struct tty_struct *tty);
-static void scc_unthrottle(struct tty_struct *tty);
-static void scc_start(struct tty_struct *tty);
-static void scc_stop(struct tty_struct *tty);
-
-static void z8530_init(void);
-
-static void scc_change_speed(struct scc_channel *scc);
-static void kiss_encode(struct scc_channel *scc);
-
-static void init_channel(struct scc_channel *scc);
-static void scc_key_trx (struct scc_channel *scc, char tx);
-static void scc_txint(register struct scc_channel *scc);
-static void scc_exint(register struct scc_channel *scc);
-static void scc_rxint(register struct scc_channel *scc);
-static void scc_spint(register struct scc_channel *scc);
-static void scc_isr(int irq, void *dev_id, struct pt_regs *regs);
-static void scc_tx_timer(unsigned long);
-static void scc_rx_timer(unsigned long);
-static void scc_init_timer(struct scc_channel *scc);
-
-/* from serial.c */
-
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 0 };
-
-
-struct tty_driver scc_driver;
-static int scc_refcount;
-static struct tty_struct *scc_table[2*MAXSCC];
-static struct termios scc_termios[2 * MAXSCC];
-static struct termios scc_termios_locked[2 * MAXSCC];
-
-struct irqflags { unsigned char used : 1; } Ivec[16];
-
-struct scc_channel SCC_Info[2 * MAXSCC]; /* information per channel */
-io_port SCC_ctrl[2 * MAXSCC]; /* Control ports */
-
-unsigned char Random = 0; /* random number for p-persist */
-unsigned char Driver_Initialized = 0;
-int Nchips = 0;
-io_port Vector_Latch = 0;
-
-struct semaphore scc_sem = MUTEX;
-unsigned char scc_wbuf[BUFSIZE];
-
-static struct termios scc_std_termios;
-
-/* ******************************************************************** */
-/* * Port Access Functions * */
-/* ******************************************************************** */
-
-static inline unsigned char
-InReg(register io_port port, register unsigned char reg)
-{
-#ifdef SCC_LDELAY
- register unsigned char r;
- Outb(port, reg);
- udelay(SCC_LDELAY);
- r=Inb(port);
- udelay(SCC_LDELAY);
- return r;
-#else
- Outb(port, reg);
- return Inb(port);
-#endif
-}
-
-static inline void
-OutReg(register io_port port, register unsigned char reg, register unsigned char val)
-{
-#ifdef SCC_LDELAY
- Outb(port, reg); udelay(SCC_LDELAY);
- Outb(port, val); udelay(SCC_LDELAY);
-#else
- Outb(port, reg);
- Outb(port, val);
-#endif
-}
-
-static inline void
-wr(register struct scc_channel *scc, register unsigned char reg, register unsigned char val)
-{
- OutReg(scc->ctrl, reg, (scc->wreg[reg] = val));
-}
-
-static inline void
-or(register struct scc_channel *scc, register unsigned char reg, register unsigned char val)
-{
- OutReg(scc->ctrl, reg, (scc->wreg[reg] |= val));
-}
-
-static inline void
-cl(register struct scc_channel *scc, register unsigned char reg, register unsigned char val)
-{
- OutReg(scc->ctrl, reg, (scc->wreg[reg] &= ~val));
-}
-
-/* ******************************************************************** */
-/* * Memory Buffer Management */
-/* ******************************************************************** */
-
-/*
- * The new buffer scheme uses a ring chain of buffers. This has the
- * advantage to access both, first and last element of the list, very
- * fast. It has the disadvantage to mess things up double if something
- * is wrong.
- *
- * Every scc channel has its own buffer pool now with an adjustable
- * number of buffers for transmit and receive buffers. The buffer
- * size remains the same for each AX.25 frame, but is (as a semi-
- * undocumented feature) adjustable within a range of 512 and 4096
- * to benefit experiments with higher frame lengths. If you need
- * larger frames... Well, you'd better choose a whole new concept
- * for that, like a DMA capable I/O card and a block device driver...
- *
- */
-
-/* ------ Management of buffer queues ------ */
-
-
-/* Insert a buffer at the "end" of the chain */
-
-static struct mbuf *
-scc_enqueue_buffer(struct mbuf **queue, struct mbuf * buffer)
-{
- unsigned long flags;
- struct mbuf * anchor;
-
- save_flags(flags); cli(); /* do not disturb! */
-
-#ifdef DEBUG_BUFFERS
- if (queue == NULLBUFP) /* called with illegal parameters, notify the user */
-
- {
- printk("z8530drv: Pointer to queue anchor is NULL pointer [enq]\n");
- restore_flags(flags);
- return NULLBUF;
- }
-
- if (buffer == NULLBUF)
- {
- printk("z8530drv: can't enqueue a NULL pointer\n");
- restore_flags(flags);
- return NULLBUF;
- }
-#endif
-
- anchor = *queue; /* the anchor is the "start" of the chain */
-
- if (anchor == NULLBUF) /* found an empty list */
- {
- *queue = buffer; /* new anchor */
- buffer->next = buffer->prev = NULLBUF;
- } else
- if (anchor->prev == NULLBUF) /* list has one member only */
- {
-#ifdef DEBUG_BUFFERS
- if (anchor->prev != NULLBUF) /* oops?! */
- printk("weird --- anchor->prev is NULL but not anchor->next [enq]\n");
-#endif
- anchor->next = anchor->prev = buffer;
- buffer->next = buffer->prev = anchor;
- } else
-#ifdef DEBUG_BUFFERS
- if (anchor->next == NULLBUF) /* this has to be an error. Okay, make the best out of it */
- {
- printk("z8530drv: weird --- anchor->next is NULL but not anchor->prev [enq]\n");
- anchor->next = anchor->prev = buffer;
- buffer->next = buffer->prev = anchor;
- } else
-#endif
- { /* every other case */
- buffer->prev = anchor->prev; /* self explaining, isn't it? */
- buffer->next = anchor;
- anchor->prev->next = buffer;
- anchor->prev = buffer;
- }
-
- restore_flags(flags);
- return *queue; /* return "start" of chain */
-}
-
-
-
-/* Remove a buffer from the "start" of the chain an return it */
-
-static struct mbuf *
-scc_dequeue_buffer(struct mbuf **queue)
-{
- unsigned long flags;
- struct mbuf *buffer;
-
- save_flags(flags); cli();
-
-#ifdef DEBUG_BUFFERS
- if (queue == NULLBUFP) /* called with illegal parameter */
-
- {
- printk("z8530drv: Pointer to queue anchor is NULL pointer [deq]\n");
- restore_flags(flags);
- return NULLBUF;
- }
-#endif
-
- buffer = *queue; /* head of the chain */
-
- if (buffer != NULLBUF) /* not an empty list? */
- {
- if (buffer->prev != NULLBUF) /* not last buffer? */
- {
-#ifdef DEBUG_BUFFERS
- if (buffer->next == NULLBUF)
- { /* what?! */
- printk("z8530drv: weird --- buffer->next is NULL but not buffer->prev [deq]\n");
- } else
-#endif
- if (buffer->prev->next == buffer->prev->prev)
- { /* only one buffer remaining... */
- buffer->next->prev = NULLBUF;
- buffer->next->next = NULLBUF;
- } else { /* the one remaining situation... */
- buffer->next->prev = buffer->prev;
- buffer->prev->next = buffer->next;
- }
- }
-#ifdef DEBUG_BUFFERS
- else if (buffer->next != NULLBUF)
- printk("z8530drv: weird --- buffer->prev is NULL but not buffer->next [deq]\n");
-#endif
- *queue = buffer->next; /* new head of chain */
-
- buffer->next = NULLBUF; /* for security only... */
- buffer->prev = NULLBUF;
- buffer->rw_ptr = buffer->data;
- }
-
- restore_flags(flags);
- return buffer; /* give it away... */
-}
-
-/* ------ buffer pool management ------ */
-
-
-/* allocate buffer pool for a channel */
-
-static void
-alloc_buffer_pool(struct scc_channel *scc)
-{
- int k;
- struct mbuf * bptr;
- int buflen;
-
- buflen = sizeof(struct mbuf) + scc->stat.bufsize;
-
- if (scc->stat.bufsize < 336) scc->stat.bufsize = 336;
- if (buflen > 4096)
- {
- scc->stat.bufsize = 4096-sizeof(struct mbuf);
- buflen = 4096;
- }
-
- if (scc->stat.rxbuffers < 4) scc->stat.rxbuffers = 4;
- if (scc->stat.txbuffers < 4) scc->stat.txbuffers = 4;
-
-
-
- /* allocate receive buffers for this channel */
-
- for (k = 0; k < scc->stat.rxbuffers ; k++)
- {
- /* allocate memory for the struct and the buffer */
-
- bptr = (struct mbuf *) kmalloc(buflen, GFP_ATOMIC);
-
- /* should not happen, but who knows? */
-
- if (bptr == NULLBUF)
- {
- printk("z8530drv: %s: can't allocate memory for rx buffer pool", kdevname(scc->tty->device));
- break;
- }
-
- /* clear memory */
-
- memset(bptr, 0, buflen);
-
- /* initialize structure */
-
- bptr->rw_ptr = bptr->data;
-
- /* and append the buffer to the pool */
-
- scc_enqueue_buffer(&scc->rx_buffer_pool, bptr);
- }
-
- /* now do the same for the transmit buffers */
-
- for (k = 0; k < scc->stat.txbuffers ; k++)
- {
- bptr = (struct mbuf *) kmalloc(buflen, GFP_ATOMIC);
-
- if (bptr == NULLBUF)
- {
- printk("z8530drv: %s: can't allocate memory for tx buffer pool", kdevname(scc->tty->device));
- break;
- }
-
- memset(bptr, 0, buflen);
-
- bptr->rw_ptr = bptr->data;
-
- scc_enqueue_buffer(&scc->tx_buffer_pool, bptr);
- }
-}
-
-
-/* remove buffer pool */
-
-static void
-free_buffer_pool(struct scc_channel *scc)
-{
- struct mbuf * bptr;
- unsigned long flags;
- int cnt;
-
- /* this one is a bit tricky and probably dangerous. */
-
- save_flags(flags); cli();
-
- /* esp. to free the buffers currently in use by ISR */
-
- bptr = scc->rx_bp;
- if (bptr != NULLBUF)
- {
- scc->rx_bp = NULLBUF;
- scc_enqueue_buffer(&scc->rx_buffer_pool, bptr);
- }
-
- bptr = scc->tx_bp;
- if (bptr != NULLBUF)
- {
- scc->tx_bp = NULLBUF;
- scc_enqueue_buffer(&scc->tx_buffer_pool, bptr);
- }
-
- bptr = scc->kiss_decode_bp;
- if (bptr != NULLBUF)
- {
- scc->kiss_decode_bp = NULLBUF;
- scc_enqueue_buffer(&scc->tx_buffer_pool, bptr);
- }
-
- bptr = scc->kiss_encode_bp;
- if (bptr != NULLBUF)
- {
- scc->kiss_encode_bp = NULLBUF;
- scc_enqueue_buffer(&scc->rx_buffer_pool, bptr);
- }
-
- restore_flags(flags);
-
-
- while (scc->rx_queue != NULLBUF)
- {
- bptr = scc_dequeue_buffer(&scc->rx_queue);
- scc_enqueue_buffer(&scc->rx_buffer_pool, bptr);
- }
-
- while (scc->tx_queue != NULLBUF)
- {
- bptr = scc_dequeue_buffer(&scc->tx_queue);
- scc_enqueue_buffer(&scc->tx_buffer_pool, bptr);
- }
-
- /* you want to know why we move every buffer back to the
- buffer pool? Well, good question... ;-)
- */
-
- cnt = 0;
-
- /* Probably because we just want a central position in the
- code were we actually call free()?
- */
-
- while (scc->rx_buffer_pool != NULLBUF)
- {
- bptr = scc_dequeue_buffer(&scc->rx_buffer_pool);
-
- if (bptr != NULLBUF)
- {
- cnt++;
- kfree(bptr);
- }
- }
-
- if (cnt < scc->stat.rxbuffers) /* hmm... hmm... :-( */
- printk("z8530drv: oops, deallocated only %d of %d rx buffers\n", cnt, scc->stat.rxbuffers);
- if (cnt > scc->stat.rxbuffers) /* WHAT?!! */
- printk("z8530drv: oops, deallocated %d instead of %d rx buffers. Very strange.\n", cnt, scc->stat.rxbuffers);
-
- cnt = 0;
-
- while (scc->tx_buffer_pool != NULLBUF)
- {
- bptr = scc_dequeue_buffer(&scc->tx_buffer_pool);
-
- if (bptr != NULLBUF)
- {
- cnt++;
- kfree(bptr);
- }
- }
-
- if (cnt < scc->stat.txbuffers)
- printk("z8530drv: oops, deallocated only %d of %d tx buffers\n", cnt, scc->stat.txbuffers);
- if (cnt > scc->stat.txbuffers)
- printk("z8530drv: oops, deallocated %d instead of %d tx buffers. Very strange.\n", cnt, scc->stat.txbuffers);
-}
-
-
-/* ------ rx/tx buffer management ------ */
-
-/*
- get a fresh buffer from the pool if possible; if not: get one from
- the queue. We will remove the oldest frame from the queue and hope
- it was a good idea... ;-)
-
- */
-
-static struct mbuf *
-scc_get_buffer(struct scc_channel *scc, char type)
-{
- struct mbuf * bptr;
-
- if (type == BT_TRANSMIT)
- {
- bptr = scc_dequeue_buffer(&scc->tx_buffer_pool);
-
- /* no free buffers in the pool anymore? */
-
- if (bptr == NULLBUF)
- {
- printk("z8530drv: scc_get_buffer(%s): tx buffer pool empty\n", kdevname(scc->tty->device));
-
- /* use the oldest from the queue instead */
-
- bptr = scc_dequeue_buffer(&scc->tx_queue);
-
- /* this should never, ever happen... */
-
- if (bptr == NULLBUF)
- printk("z8530drv: scc_get_buffer(): panic - even no buffer found in tx queue\n");
- }
- } else {
- bptr = scc_dequeue_buffer(&scc->rx_buffer_pool);
-
- if (bptr == NULLBUF)
- {
- printk("z8530drv: scc_get_buffer(%s): rx buffer pool empty\n", kdevname(scc->tty->device));
-
- bptr = scc_dequeue_buffer(&scc->rx_queue);
-
- if (bptr == NULLBUF)
- printk("z8530drv: scc_get_buffer(): panic - even no buffer found in rx queue\n");
- }
- }
-
- if (bptr != NULLBUF)
- {
- bptr->rw_ptr = bptr->data;
- bptr->cnt = 0;
- }
-
- return bptr;
-}
-
-
-/* ******************************************************************** */
-/* * Interrupt Service Routines * */
-/* ******************************************************************** */
-
-/* ----> interrupt service routine for the 8530 <---- */
-
-/* it's recommended to keep this function "inline" ;-) */
-
-static inline void
-scc_isr_dispatch(register struct scc_channel *scc, register int vector)
-{
- switch (vector & VECTOR_MASK)
- {
- case TXINT: scc_txint(scc); break;
- case EXINT: scc_exint(scc); break;
- case RXINT: scc_rxint(scc); break;
- case SPINT: scc_spint(scc); break;
- default : printk("scc_isr(): unknown interrupt status (addr %4.4x, state %2.2x)\n",scc->ctrl,vector);
- }
-}
-
-
-
-
-
-/* If the card has a latch for the interrupt vector (like the PA0HZP card)
- use it to get the number of the chip that generated the int.
- If not: poll all defined chips.
- */
-
-static void
-scc_isr(int irq, void *dev_id, struct pt_regs *regs)
-{
- register unsigned char vector;
- register struct scc_channel *scc;
- register io_port q;
- register io_port *p;
- register int k;
-
-
- cli();
-
- if (Vector_Latch)
- {
- while(1) /* forever...? */
- {
- Outb(Vector_Latch, 0); /* Generate INTACK */
-
- /* Read the vector */
- if((vector=Inb(Vector_Latch)) >= 16 * Nchips) break;
- /* ...not forever! */
-
- /* Extract channel number and status from vector. */
- /* Isolate channel number */
- /* Call handler */
-
- if (vector & 0x01) break;
-
- scc=&SCC_Info[(((vector>>1)&0x7c)^0x04) >> 2];
-
- if (!scc->tty) break;
-
- scc_isr_dispatch(scc, vector);
-
- Outb(scc->ctrl,0x38); /* Reset Highest IUS" opcode to WR0 */
- }
-
- sti();
- return;
- }
-
-
- /* Find the SCC generating the interrupt by polling all attached SCCs
- * reading RR3A (the interrupt pending register)
- */
-
- k = 0;
- p = SCC_ctrl;
-
- while (k++ < Nchips)
- {
- if (!(q=*p++)) break;
-
- Outb(q,3);
-
- if (Inb(q))
- {
- if (!(q=*p++)) break;
-
- Outb(q,2);
- vector=Inb(q); /* Read the vector */
-
- /* Extract channel number and status from vector. */
- /* Isolate channel number */
- /* Call handler */
-
-
- if (vector & 1) break;
-
- scc = &SCC_Info[(((vector >> 1) & 0x7c) ^ 0x04) >> 2];
-
- if (!scc->tty) break;
-
- /* Isolate status info from vector, call handler */
-
- scc_isr_dispatch(scc, vector);
-
- k = 0;
- p = SCC_ctrl;
-
- } else p++;
- }
-
- sti();
-}
-
-
-
-/* ----> four different interrupt handlers for Tx, Rx, changing of */
-/* DCD/CTS and Rx/Tx errors */
-
-
-/* Transmitter interrupt handler */
-static void
-scc_txint(register struct scc_channel *scc)
-{
- register struct mbuf *bp;
-
- scc->stat.txints++;
-
- bp = scc->tx_bp;
-
- if (bp == NULLBUF)
- {
- do
- {
- if (bp != NULLBUF)
- scc_enqueue_buffer(&scc->tx_buffer_pool, bp);
-
- bp = scc_dequeue_buffer(&scc->tx_queue);
-
- if (bp == NULLBUF)
- {
- scc->stat.tx_state = TXS_BUSY;
- scc->t_tail = scc->kiss.tailtime;
-
- Outb(scc->ctrl, RES_Tx_P); /* clear int */
- return;
- }
-
- if ( scc->kiss.not_slip && (bp->cnt > 0) )
- {
- bp->rw_ptr++;
- bp->cnt--;
- }
-
- } while (bp->cnt < 1);
-
-
- Outb(scc->ctrl, RES_Tx_CRC); /* reset CRC generator */
- or(scc,R10,ABUNDER); /* re-install underrun protection */
- Outb(scc->data,*bp->rw_ptr); /* send byte */
- if (!scc->enhanced) /* reset EOM latch */
- Outb(scc->ctrl, RES_EOM_L);
-
- scc->tx_bp = bp;
- scc->stat.tx_state = TXS_ACTIVE; /* next byte... */
- } else
- if (bp->cnt <= 0)
- {
- if (--scc->stat.tx_queued < 0) scc->stat.tx_queued = 0;
-
- Outb(scc->ctrl, RES_Tx_P); /* reset pending int */
- cl(scc, R10, ABUNDER); /* send CRC */
- scc_enqueue_buffer(&scc->tx_buffer_pool, bp);
- scc->tx_bp = NULLBUF;
- scc->stat.tx_state = TXS_NEWFRAME; /* next frame... */
- return;
- } else {
- Outb(scc->data,*bp->rw_ptr);
- }
-
- bp->rw_ptr++; /* increment pointer */
- bp->cnt--; /* decrease byte count */
-}
-
-static inline void
-flush_FIFO(register struct scc_channel *scc)
-{
- register int k;
-
- for (k=0; k<3; k++)
- Inb(scc->data);
-
- if(scc->rx_bp != NULLBUF) /* did we receive something? */
- {
- scc->stat.rxerrs++; /* then count it as an error */
- scc_enqueue_buffer(&scc->rx_buffer_pool, scc->rx_bp);
-
- scc->rx_bp = NULLBUF;
- }
-}
-
-
-/* External/Status interrupt handler */
-static void
-scc_exint(register struct scc_channel *scc)
-{
- register unsigned char status,changes,chg_and_stat;
-
- scc->stat.exints++;
-
- status = InReg(scc->ctrl,R0);
- changes = status ^ scc->status;
- chg_and_stat = changes & status;
-
- /* ABORT: generated whenever DCD drops while receiving */
-
- if (chg_and_stat & BRK_ABRT) /* Received an ABORT */
- flush_FIFO(scc);
-
-
- /* DCD: on = start to receive packet, off = ABORT condition */
- /* (a successfully received packet generates a special condition int) */
-
- if(changes & DCD) /* DCD input changed state */
- {
- if(status & DCD) /* DCD is now ON */
- {
- if (scc->modem.clocksrc != CLK_EXTERNAL)
- OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
-
- or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */
- } else { /* DCD is now OFF */
- cl(scc,R3,ENT_HM|RxENABLE); /* disable the receiver */
- flush_FIFO(scc);
- }
- }
-
-#ifdef notdef
- /* CTS: use external TxDelay (what's that good for?!) */
-
- if (chg_and_stat & CTS) /* CTS is now ON */
- {
- if (!Running(t_txdel) && scc->kiss.txdelay == 0) /* zero TXDELAY = wait for CTS */
- scc->t_txdel = 0; /* kick it! */
-
- }
-#endif
-
- if ( (status & TxEOM) && (scc->stat.tx_state == TXS_ACTIVE) )
- {
- scc->stat.tx_under++; /* oops, an underrun! count 'em */
- Outb(scc->ctrl, RES_Tx_P);
- Outb(scc->ctrl, RES_EXT_INT); /* reset ext/status interrupts */
- scc->t_maxk = 1;
-
- if (scc->tx_bp != NULLBUF)
- {
- scc_enqueue_buffer(&scc->tx_buffer_pool, scc->tx_bp);
- scc->tx_bp = NULLBUF;
- }
-
- if (--scc->stat.tx_queued < 0) scc->stat.tx_queued = 0;
- or(scc,R10,ABUNDER);
- }
-
- if (status & ZCOUNT) /* Oops? */
- {
- scc->stat.tx_under = 9999; /* errr... yes. */
- Outb(scc->ctrl, RES_Tx_P); /* just to be sure */
- scc->t_maxk = 1;
-
- if (scc->tx_bp != NULLBUF)
- {
- scc_enqueue_buffer(&scc->tx_buffer_pool, scc->tx_bp);
- scc->tx_bp = NULLBUF;
- }
-
- if (--scc->stat.tx_queued < 0) scc->stat.tx_queued = 0;
- scc->kiss.tx_inhibit = 1; /* don't try it again! */
- }
-
-
- scc->status = status;
- Outb(scc->ctrl,RES_EXT_INT);
-}
-
-
-/* Receiver interrupt handler */
-static void
-scc_rxint(register struct scc_channel *scc)
-{
- register struct mbuf *bp;
-
- scc->stat.rxints++;
-
- if( Running(t_maxk) && !(scc->kiss.fulldup))
- {
- Inb(scc->data); /* discard char */
- or(scc,R3,ENT_HM); /* enter hunt mode for next flag */
- return;
- }
-
- bp = scc->rx_bp;
-
- if (bp == NULLBUF)
- {
- bp = scc_get_buffer(scc, BT_RECEIVE);
- if (bp == NULLBUF)
- {
- printk("scc_rxint(): panic --- cannot get a buffer\n");
- Inb(scc->data);
- or(scc, R3, ENT_HM);
- scc->stat.nospace++;
- return;
- }
-
- scc->rx_bp = bp;
- }
-
- if (bp->cnt > scc->stat.bufsize)
- {
-#ifdef notdef
- printk("scc_rxint(): oops, received huge frame...\n");
-#endif
- scc_enqueue_buffer(&scc->rx_buffer_pool, bp);
- scc->rx_bp = NULLBUF;
- Inb(scc->data);
- or(scc, R3, ENT_HM);
- return;
- }
-
- /* now, we have a buffer. read character and store it */
- *bp->rw_ptr = Inb(scc->data);
- bp->rw_ptr++;
- bp->cnt++;
-}
-
-/* kick rx_timer (try to send received frame or part of it ASAP) */
-
-/* of course we could define a "bottom half" routine to do the job,
- but since its structures are saved in an array instead of a linked
- list we would get in trouble if it clashes with another driver or
- when we try to modularize the driver. IMHO we are fast enough
- with a timer routine called on the next timer-INT... Your opinions?
- */
-
-static inline void
-kick_rx_timer(register struct scc_channel *scc)
-{
- if (scc->rx_t.next)
- del_timer(&(scc->rx_t));
-
- scc->rx_t.expires = jiffies + 1;
- scc->rx_t.function = scc_rx_timer;
- scc->rx_t.data = (unsigned long) scc;
- add_timer(&scc->rx_t);
-}
-
-/* Receive Special Condition interrupt handler */
-static void
-scc_spint(register struct scc_channel *scc)
-{
- register unsigned char status;
- register struct mbuf *bp;
-
- scc->stat.spints++;
-
- status = InReg(scc->ctrl,R1); /* read receiver status */
-
- Inb(scc->data); /* throw away Rx byte */
- bp = scc->rx_bp;
-
- if(status & Rx_OVR) /* receiver overrun */
- {
- scc->stat.rx_over++; /* count them */
- or(scc,R3,ENT_HM); /* enter hunt mode for next flag */
-
- if (bp) scc_enqueue_buffer(&scc->rx_buffer_pool, bp);
- scc->rx_bp = NULLBUF;
- }
-
- if(status & END_FR && bp != NULLBUF) /* end of frame */
- {
- /* CRC okay, frame ends on 8 bit boundary and received something ? */
-
- if (!(status & CRC_ERR) && (status & 0xe) == RES8 && bp->cnt)
- {
- /* ignore last received byte (first of the CRC bytes) */
- bp->cnt--;
-
- scc_enqueue_buffer(&scc->rx_queue, bp);
- scc->rx_bp = NULLBUF;
- scc->stat.rxframes++;
- scc->stat.rx_queued++;
- kick_rx_timer(scc);
- } else { /* a bad frame */
- scc_enqueue_buffer(&scc->rx_buffer_pool, bp);
- scc->rx_bp = NULLBUF;
- scc->stat.rxerrs++;
- }
- }
-
- Outb(scc->ctrl,ERR_RES);
-}
-
-
-/* ******************************************************************** */
-/* * Init Channel */
-/* ******************************************************************** */
-
-
-/* ----> set SCC channel speed <---- */
-
-static inline void set_brg(register struct scc_channel *scc, unsigned int tc)
-{
- unsigned long flags;
-
- save_flags(flags); cli(); /* 2-step register accesses... */
-
- cl(scc,R14,BRENABL); /* disable baudrate generator */
- wr(scc,R12,tc & 255); /* brg rate LOW */
- wr(scc,R13,tc >> 8); /* brg rate HIGH */
- or(scc,R14,BRENABL); /* enable baudrate generator */
-
- restore_flags(flags);
-}
-
-static inline void set_speed(register struct scc_channel *scc)
-{
- if (scc->modem.speed > 0) /* paranoia... */
- set_brg(scc, (unsigned) (scc->clock / (scc->modem.speed * 64)) - 2);
-}
-
-
-/* ----> initialize a SCC channel <---- */
-
-static inline void init_brg(register struct scc_channel *scc)
-{
- wr(scc, R14, BRSRC); /* BRG source = PCLK */
- OutReg(scc->ctrl, R14, SSBR|scc->wreg[R14]); /* DPLL source = BRG */
- OutReg(scc->ctrl, R14, SNRZI|scc->wreg[R14]); /* DPLL NRZI mode */
-}
-
-/*
- * Initialization according to the Z8530 manual (SGS-Thomson's version):
- *
- * 1. Modes and constants
- *
- * WR9 11000000 chip reset
- * WR4 XXXXXXXX Tx/Rx control, async or sync mode
- * WR1 0XX00X00 select W/REQ (optional)
- * WR2 XXXXXXXX program interrupt vector
- * WR3 XXXXXXX0 select Rx control
- * WR5 XXXX0XXX select Tx control
- * WR6 XXXXXXXX sync character
- * WR7 XXXXXXXX sync character
- * WR9 000X0XXX select interrupt control
- * WR10 XXXXXXXX miscellaneous control (optional)
- * WR11 XXXXXXXX clock control
- * WR12 XXXXXXXX time constant lower byte (optional)
- * WR13 XXXXXXXX time constant upper byte (optional)
- * WR14 XXXXXXX0 miscellaneous control
- * WR14 XXXSSSSS commands (optional)
- *
- * 2. Enables
- *
- * WR14 000SSSS1 baud rate enable
- * WR3 SSSSSSS1 Rx enable
- * WR5 SSSS1SSS Tx enable
- * WR0 10000000 reset Tx CRG (optional)
- * WR1 XSS00S00 DMA enable (optional)
- *
- * 3. Interrupt status
- *
- * WR15 XXXXXXXX enable external/status
- * WR0 00010000 reset external status
- * WR0 00010000 reset external status twice
- * WR1 SSSXXSXX enable Rx, Tx and Ext/status
- * WR9 000SXSSS enable master interrupt enable
- *
- * 1 = set to one, 0 = reset to zero
- * X = user defined, S = same as previous init
- *
- *
- * Note that the implementation differs in some points from above scheme.
- *
- */
-
-static void
-init_channel(register struct scc_channel *scc)
-{
- unsigned long flags;
-
- if (scc->rx_t.next) del_timer(&(scc->rx_t));
- if (scc->tx_t.next) del_timer(&(scc->tx_t));
-
- save_flags(flags); cli();
-
- wr(scc,R4,X1CLK|SDLC); /* *1 clock, SDLC mode */
- wr(scc,R1,0); /* no W/REQ operation */
- wr(scc,R3,Rx8|RxCRC_ENAB); /* RX 8 bits/char, CRC, disabled */
- wr(scc,R5,Tx8|DTR|TxCRC_ENAB); /* TX 8 bits/char, disabled, DTR */
- wr(scc,R6,0); /* SDLC address zero (not used) */
- wr(scc,R7,FLAG); /* SDLC flag value */
- wr(scc,R9,VIS); /* vector includes status */
- wr(scc,R10,(scc->modem.nrz? NRZ : NRZI)|CRCPS|ABUNDER); /* abort on underrun, preset CRC generator, NRZ(I) */
- wr(scc,R14, 0);
-
-
-/* set clock sources:
-
- CLK_DPLL: normal halfduplex operation
-
- RxClk: use DPLL
- TxClk: use DPLL
- TRxC mode DPLL output
-
- CLK_EXTERNAL: external clocking (G3RUH or DF9IC modem)
-
- BayCom: others:
-
- TxClk = pin RTxC TxClk = pin TRxC
- RxClk = pin TRxC RxClk = pin RTxC
-
-
- CLK_DIVIDER:
- RxClk = use DPLL
- TxClk = pin RTxC
-
- BayCom: others:
- pin TRxC = DPLL pin TRxC = BRG
- (RxClk * 1) (RxClk * 32)
-*/
-
-
- switch(scc->modem.clocksrc)
- {
- case CLK_DPLL:
- wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP);
- init_brg(scc);
- break;
-
- case CLK_DIVIDER:
- wr(scc, R11, ((scc->brand & BAYCOM)? TRxCDP : TRxCBR) | RCDPLL|TCRTxCP|TRxCOI);
- init_brg(scc);
- break;
-
- case CLK_EXTERNAL:
- wr(scc, R11, (scc->brand & BAYCOM)? RCTRxCP|TCRTxCP : RCRTxCP|TCTRxCP);
- OutReg(scc->ctrl, R14, DISDPLL);
- break;
-
- }
-
- set_speed(scc); /* set baudrate */
-
- if(scc->enhanced)
- {
- or(scc,R15,SHDLCE|FIFOE); /* enable FIFO, SDLC/HDLC Enhancements (From now R7 is R7') */
- wr(scc,R7,AUTOEOM);
- }
-
- if((InReg(scc->ctrl,R0)) & DCD) /* DCD is now ON */
- {
- if (scc->modem.clocksrc != CLK_EXTERNAL)
- or(scc,R14, SEARCH);
-
- or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */
- }
-
- /* enable CTS (not for Baycom), ABORT & DCD interrupts */
- wr(scc,R15,((scc->brand & BAYCOM) ? 0 : CTSIE)|BRKIE|DCDIE|TxUIE);
-
- Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */
- Outb(scc->ctrl,RES_EXT_INT); /* must be done twice */
-
- or(scc,R1,INT_ALL_Rx|TxINT_ENAB|EXT_INT_ENAB); /* enable interrupts */
-
- scc->status = InReg(scc->ctrl,R0); /* read initial status */
-
- or(scc,R9,MIE); /* master interrupt enable */
-
- scc_init_timer(scc);
-
- restore_flags(flags);
-}
-
-
-
-
-/* ******************************************************************** */
-/* * SCC timer functions * */
-/* ******************************************************************** */
-
-
-/* ----> scc_key_trx sets the time constant for the baudrate
- generator and keys the transmitter <---- */
-
-static void
-scc_key_trx(struct scc_channel *scc, char tx)
-{
- unsigned int time_const;
-
- if (scc->modem.speed < baud_table[1])
- scc->modem.speed = 1200;
-
- if (scc->brand & PRIMUS)
- Outb(scc->ctrl + 4, scc->option | (tx? 0x80 : 0));
-
- time_const = (unsigned) (scc->clock / (scc->modem.speed * (tx? 2:64))) - 2;
-
- if (scc->modem.clocksrc == CLK_DPLL)
- { /* simplex operation */
- if (tx)
- {
- cl(scc,R3,RxENABLE|ENT_HM); /* then switch off receiver */
-
- set_brg(scc, time_const); /* reprogram baudrate generator */
-
- /* DPLL -> Rx clk, BRG -> Tx CLK, TRxC mode output, TRxC = BRG */
- wr(scc, R11, RCDPLL|TCBR|TRxCOI|TRxCBR);
-
- or(scc,R5,RTS|TxENAB); /* set the RTS line and enable TX */
- } else {
- cl(scc,R5,RTS|TxENAB);
-
- set_brg(scc, time_const); /* reprogram baudrate generator */
-
- /* DPLL -> Rx clk, DPLL -> Tx CLK, TRxC mode output, TRxC = DPLL */
- wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP);
-
- or(scc,R3,RxENABLE|ENT_HM);
- }
- } else {
- if (tx)
- or(scc,R5,RTS|TxENAB); /* enable tx */
- else
- cl(scc,R5,RTS|TxENAB); /* disable tx */
- }
-}
-
-
-/* ----> SCC timer interrupt handler and friends. Will be called every 1/TPS s <---- */
-
-static unsigned char Rand = 17;
-
-static inline int is_grouped(register struct scc_channel *scc)
-{
- int k;
- struct scc_channel *scc2;
- unsigned char grp1, grp2;
-
- grp1 = scc->kiss.group;
-
- for (k = 0; k < (Nchips * 2); k++)
- {
- scc2 = &SCC_Info[k];
- grp2 = scc2->kiss.group;
-
- if (scc2 == scc || !(scc2->tty && grp2))
- return 0;
-
- if ((grp1 & 0x3f) == (grp2 & 0x3f))
- {
- if ( (grp1 & TXGROUP) && (scc2->wreg[R5] & RTS) )
- return 1;
-
- if ( (grp1 & RXGROUP) && (scc2->status & DCD) )
- return 1;
- }
- }
- return 0;
-}
-
-
-static inline void dw_slot_timeout(register struct scc_channel *scc)
-{
- scc->t_dwait = TIMER_STOPPED;
- scc->t_slot = TIMER_STOPPED;
-
- if (!scc->kiss.fulldup)
- {
- Rand = Rand * 17 + 31;
-
- if ( (scc->kiss.softdcd? !(scc->status & SYNC_HUNT):(scc->status & DCD)) || (scc->kiss.persist) < Rand || (scc->kiss.group && is_grouped(scc)) )
- {
- if (scc->t_mbusy == TIMER_STOPPED)
- scc->t_mbusy = TPS * scc->kiss.maxdefer;
-
- scc->t_slot = scc->kiss.slottime;
- return ;
-
- }
- }
-
- if ( !(scc->wreg[R5] & RTS) )
- {
- scc->t_txdel = scc->kiss.txdelay;
- scc_key_trx(scc, TX_ON);
- } else {
- scc->t_txdel = 0;
- }
-}
-
-
-
-
-static inline void txdel_timeout(register struct scc_channel *scc)
-{
- scc->t_txdel = TIMER_STOPPED;
-
- scc->t_maxk = TPS * scc->kiss.maxkeyup;
-
- if (scc->tx_bp == NULLBUF)
- scc_txint(scc);
-}
-
-
-
-static inline void tail_timeout(register struct scc_channel *scc)
-{
- scc->t_tail = TIMER_STOPPED;
-
- /* when fulldup is 0 or 1, switch off the transmitter.
- * when frames are still queued (because of transmit time limit),
- * restart the procedure to get the channel after MINTIME.
- * when fulldup is 2, the transmitter remains keyed and we
- * continue sending after waiting for waittime. IDLETIME is an
- * idle timeout in this case.
- */
-
- if (scc->kiss.fulldup < 2)
- {
- if (scc->tx_bp) /* we had a timeout? */
- {
- scc->stat.tx_state = TXS_BUSY;
- scc->t_dwait = TPS * scc->kiss.mintime; /* try again */
- }
-
- scc->stat.tx_state = TXS_IDLE;
- scc->t_maxk = TIMER_STOPPED;
- scc_key_trx(scc, TX_OFF);
- return;
- }
-
- if (scc->tx_bp) /* maxkeyup expired */ /* ?! */
- {
- scc->stat.tx_state = TXS_BUSY;
- scc->t_txdel = TPS * scc->kiss.waittime;
- }
- else
-
- scc->t_idle = TPS * scc->kiss.idletime;
-}
-
-
-static inline void busy_timeout(register struct scc_channel *scc)
-{
-#ifdef THROW_AWAY_AFTER_BUSY_TIMEOUT
- register struct mbuf *bp; /* not tested */
-
- while (bp = scc_dequeue_buffer(&scc->tx_queue))
- scc_enqueue_buffer(&scc->tx_buffer_pool, bp);
-
- scc->tx_queue = NULLBUF;
- scc->stat.tx_state = TXS_IDLE;
-
-#else
- scc->t_txdel = scc->kiss.txdelay; /* brute force ... */
-#endif
- scc->t_mbusy = TIMER_STOPPED;
-
-}
-
-
-static inline void maxk_idle_timeout(register struct scc_channel *scc)
-{
- scc->t_maxk = TIMER_STOPPED;
- scc->t_idle = TIMER_STOPPED;
-
- scc->stat.tx_state = TXS_BUSY;
- scc->t_tail = scc->kiss.tailtime;
-}
-
-static void
-scc_tx_timer(unsigned long channel)
-{
- register struct scc_channel *scc;
- unsigned long flags;
-
-
- scc = (struct scc_channel *) channel;
-
- if (scc->tty && scc->init)
- {
- save_flags(flags); cli();
-
- /* KISS-TNC emulation */
-
- if (Expired(t_dwait)) dw_slot_timeout(scc) ; else
- if (Expired(t_slot)) dw_slot_timeout(scc) ; else
- if (Expired(t_txdel)) txdel_timeout(scc) ; else
- if (Expired(t_tail)) tail_timeout(scc) ;
-
- /* watchdogs */
-
- if (Expired(t_mbusy)) busy_timeout(scc);
- if (Expired(t_maxk)) maxk_idle_timeout(scc);
- if (Expired(t_idle)) maxk_idle_timeout(scc);
-
- restore_flags(flags);
- }
-
- scc->tx_t.expires = jiffies + HZ/TPS;
- add_timer(&scc->tx_t);
-}
-
-
-static void
-scc_rx_timer(unsigned long channel)
-{
- register struct scc_channel *scc;
-
- scc = (struct scc_channel *) channel;
-
- if (scc->rx_queue && scc->throttled)
- {
- scc->rx_t.expires = jiffies + HZ/TPS;
- add_timer(&scc->rx_t);
- return;
- }
-
- kiss_encode(scc);
-
- if (scc->rx_queue && !scc->throttled)
- {
-
- printk("z8530drv: warning: %s should be throttled\n",
- kdevname(scc->tty->device));
-
- scc->rx_t.expires = jiffies + HZ/TPS;
- add_timer(&scc->rx_t);
- }
-}
-
-static void
-scc_init_timer(struct scc_channel *scc)
-{
- unsigned long flags;
-
- save_flags(flags); cli();
-
- Stop_Timer(t_dwait);
- Stop_Timer(t_slot);
- Stop_Timer(t_txdel);
- Stop_Timer(t_tail);
- Stop_Timer(t_mbusy);
- Stop_Timer(t_maxk);
- Stop_Timer(t_idle);
-
- scc->stat.tx_state = TXS_IDLE;
-
- if (scc->tx_t.next)
- del_timer(&scc->tx_t);
-
- scc->tx_t.data = (unsigned long) scc;
- scc->tx_t.function = scc_tx_timer;
- scc->tx_t.expires = jiffies + HZ/TPS;
- add_timer(&scc->tx_t);
-
- scc->rx_t.data = (unsigned long) scc;
- scc->rx_t.function = scc_rx_timer;
-
- restore_flags(flags);
-}
-
-
-/* ******************************************************************** */
-/* * KISS interpreter * */
-/* ******************************************************************** */
-
-
-/*
- * this will set the "kiss" parameters through kiss itself
- */
-
-static void
-kiss_set_param(struct scc_channel *scc,char cmd, unsigned int val)
-{
-
-#define VAL val=val*TPS/100
-#define SVAL val? val:TIMER_STOPPED
-
- switch(cmd){
- case PARAM_TXDELAY:
- scc->kiss.txdelay = VAL; break;
- case PARAM_PERSIST:
- scc->kiss.persist = val; break;
- case PARAM_SLOTTIME:
- scc->kiss.slottime = VAL; break;
- case PARAM_TXTAIL:
- scc->kiss.tailtime = VAL; break;
- case PARAM_FULLDUP:
- scc->kiss.fulldup = val; break;
- case PARAM_WAIT:
- scc->kiss.waittime = VAL; break;
- case PARAM_MAXKEY:
- scc->kiss.maxkeyup = SVAL; break;
- case PARAM_MIN:
- scc->kiss.mintime = SVAL; break;
- case PARAM_IDLE:
- scc->kiss.idletime = val; break;
- case PARAM_MAXDEFER:
- scc->kiss.maxdefer = SVAL; break;
- case PARAM_GROUP:
- scc->kiss.group = val; break;
- case PARAM_TX:
- scc->kiss.tx_inhibit = val;
- case PARAM_SOFTDCD:
- scc->kiss.softdcd = val;
- }
- return;
-
-#undef VAL
-#undef SVAL
-}
-
-
-/* interpret frame: strip CRC and decode KISS */
-
-static void kiss_interpret_frame(struct scc_channel * scc)
-{
- unsigned char kisscmd;
- unsigned long flags;
- struct mbuf *bp;
-
- bp = scc->kiss_decode_bp;
- bp->rw_ptr = bp->data;
-
-#ifdef DEBUG_BUFFERS
- if (bp == NULLBUF)
- {
- printk("kiss_interpret_frame(): weird --- nothing to do.\n");
- return;
- }
-#endif
-
- if (bp->cnt < 2)
- {
- scc_enqueue_buffer(&scc->tx_buffer_pool, bp);
- scc->kiss_decode_bp = NULLBUF;
- return;
- }
-
-
-
- if (scc->kiss.not_slip)
- {
- kisscmd = *bp->rw_ptr;
- bp->rw_ptr++;
- } else {
- kisscmd = 0;
- }
-
- if (kisscmd & 0xa0)
- {
- if (bp->cnt > 3)
- bp->cnt -= 2;
- else
- {
- scc_enqueue_buffer(&scc->tx_buffer_pool, bp);
- scc->kiss_decode_bp = NULLBUF;
- return;
- }
- }
-
-
- kisscmd &= 0x1f;
-
-
- if (kisscmd)
- {
- kiss_set_param(scc, kisscmd, *bp->rw_ptr);
- scc_enqueue_buffer(&scc->tx_buffer_pool, bp);
- scc->kiss_decode_bp = NULLBUF;
- return;
- }
-
- scc_enqueue_buffer(&scc->tx_queue, bp); /* enqueue frame */
-
- scc->stat.txframes++;
- scc->stat.tx_queued++;
- scc->kiss_decode_bp = NULLBUF;
-
- save_flags(flags); cli();
-
- if(scc->stat.tx_state == TXS_IDLE)
- { /* when transmitter is idle */
- scc->stat.tx_state = TXS_BUSY;
- scc->t_dwait = (scc->kiss.fulldup? 0:scc->kiss.waittime);
- }
-
- restore_flags(flags);
-}
-
-static inline void kiss_store_byte(struct scc_channel *scc, unsigned char ch)
-{
- register struct mbuf *bp = scc->kiss_decode_bp;
-
- if (bp != NULLBUF)
- {
- if (bp->cnt > scc->stat.bufsize)
- printk("kiss_decode(): frame too long\n");
- else
- {
- *bp->rw_ptr = ch;
- bp->rw_ptr++;
- bp->cnt++;
- }
- }
-}
-
-static inline int kiss_decode(struct scc_channel *scc, unsigned char ch)
-{
- switch (scc->stat.tx_kiss_state)
- {
- case KISS_IDLE:
- if (ch == FEND)
- {
- scc->kiss_decode_bp = scc_get_buffer(scc, BT_TRANSMIT);
- if (scc->kiss_decode_bp == NULLBUF)
- return 1;
-
- scc->stat.tx_kiss_state = KISS_DATA;
- } else scc->stat.txerrs++;
- break;
-
- case KISS_DATA:
- if (ch == FESC)
- scc->stat.tx_kiss_state = KISS_ESCAPE;
- else if (ch == FEND)
- {
- kiss_interpret_frame(scc);
- scc->stat.tx_kiss_state = KISS_IDLE;
- }
- else kiss_store_byte(scc, ch);
- break;
-
- case KISS_ESCAPE:
- if (ch == TFEND)
- {
- kiss_store_byte(scc, FEND);
- scc->stat.tx_kiss_state = KISS_DATA;
- }
- else if (ch == TFESC)
- {
- kiss_store_byte(scc, FESC);
- scc->stat.tx_kiss_state = KISS_DATA;
- }
- else
- {
- scc_enqueue_buffer(&scc->tx_buffer_pool, scc->kiss_decode_bp);
- scc->kiss_decode_bp = NULLBUF;
- scc->stat.txerrs++;
- scc->stat.tx_kiss_state = KISS_IDLE;
- }
- break;
- } /* switch */
-
- return 0;
-
-}
-
-/* ----> Encode received data and write it to the flip-buffer <---- */
-
-static void
-kiss_encode(register struct scc_channel *scc)
-{
- struct mbuf *bp;
- struct tty_struct * tty = scc->tty;
- unsigned char ch;
-
- bp = scc->kiss_encode_bp;
-
- /* worst case: FEND 0 FESC TFEND -> 4 bytes */
-
- while(tty->flip.count < TTY_FLIPBUF_SIZE-4)
- {
- if (bp == NULLBUF)
- {
- bp = scc_dequeue_buffer(&scc->rx_queue);
- scc->kiss_encode_bp = bp;
-
- if (bp == NULLBUF)
- {
- scc->stat.rx_kiss_state = KISS_IDLE;
- break;
- }
- }
-
-
- if (bp->cnt <= 0)
- {
- if (--scc->stat.rx_queued < 0)
- scc->stat.rx_queued = 0;
-
- if (scc->stat.rx_kiss_state == KISS_RXFRAME) /* new packet? */
- {
- tty_insert_flip_char(tty, FEND, 0); /* send FEND for old frame */
- scc->stat.rx_kiss_state = KISS_IDLE; /* generate FEND for new frame */
- }
-
- scc_enqueue_buffer(&scc->rx_buffer_pool, bp);
-
- bp = scc->kiss_encode_bp = NULLBUF;
- continue;
- }
-
-
- if (scc->stat.rx_kiss_state == KISS_IDLE)
- {
- tty_insert_flip_char(tty, FEND, 0);
-
- if (scc->kiss.not_slip)
- tty_insert_flip_char(tty, 0, 0);
-
- scc->stat.rx_kiss_state = KISS_RXFRAME;
- }
-
- switch(ch = *bp->rw_ptr)
- {
- case FEND:
- tty_insert_flip_char(tty, FESC, 0);
- tty_insert_flip_char(tty, TFEND, 0);
- break;
- case FESC:
- tty_insert_flip_char(tty, FESC, 0);
- tty_insert_flip_char(tty, TFESC, 0);
- break;
- default:
- tty_insert_flip_char(tty, ch, 0);
- }
-
- bp->rw_ptr++;
- bp->cnt--;
- }
-
- queue_task(&tty->flip.tqueue, &tq_timer); /* kick it... */
-}
-
-
-/* ******************************************************************* */
-/* * Init channel structures, special HW, etc... * */
-/* ******************************************************************* */
-
-
-static void
-z8530_init(void)
-{
- struct scc_channel *scc;
- int chip, k;
- unsigned long flags;
- char *flag;
-
-
- printk("Init Z8530 driver: %u channels, IRQ", Nchips*2);
-
- flag=" ";
- for (k = 0; k < 16; k++)
- if (Ivec[k].used)
- {
- printk("%s%d", flag, k);
- flag=",";
- }
- printk("\n");
-
-
- /* reset and pre-init all chips in the system */
- for (chip = 0; chip < Nchips; chip++)
- {
- scc=&SCC_Info[2*chip];
- if (!scc->ctrl) continue;
-
- save_flags(flags); cli(); /* because of 2-step accesses */
-
- /* Special SCC cards */
-
- if(scc->brand & EAGLE) /* this is an EAGLE card */
- Outb(scc->special,0x08); /* enable interrupt on the board */
-
- if(scc->brand & (PC100 | PRIMUS)) /* this is a PC100/EAGLE card */
- Outb(scc->special,scc->option); /* set the MODEM mode (0x22) */
-
-
- /* Init SCC */
-
- /* some general init we can do now */
-
- Outb(scc->ctrl, 0);
- OutReg(scc->ctrl,R9,FHWRES); /* force hardware reset */
- udelay(100); /* give it 'a bit' more time than required */
- wr(scc, R2, chip*16); /* interrupt vector */
- wr(scc, R9, VIS); /* vector includes status */
-
- restore_flags(flags);
- }
-
-
- Driver_Initialized = 1;
-}
-
-
-/* ******************************************************************** */
-/* * Filesystem Routines: open, close, ioctl, settermios, etc * */
-/* ******************************************************************** */
-
-
-
-/* scc_paranoia_check(): warn user if something went wrong */
-
-static inline int scc_paranoia_check(struct scc_channel *scc, kdev_t device,
- const char *routine)
-{
-#ifdef SCC_PARANOIA_CHECK
-
-static const char *badmagic =
- "Warning: bad magic number for Z8530 SCC struct (%s) in %s\n";
-static const char *badinfo =
- "Warning: Z8530 not found for (%s) in %s\n";
-
- if (!scc->init)
- {
- printk(badinfo, kdevname(device), routine);
- return 1;
- }
-
- if (scc->magic != SCC_MAGIC)
- {
- printk(badmagic, kdevname(device), routine);
- return 1;
- }
-#endif
-
- return 0;
-}
-
-
-/* ----> this one is called whenever you open the device <---- */
-
-int scc_open(struct tty_struct *tty, struct file * filp)
-{
- struct scc_channel *scc;
- int chan;
-
- chan = MINOR(tty->device) - tty->driver.minor_start;
-
- if (Driver_Initialized)
- {
- if ( (chan < 0) || (chan >= (Nchips * 2)) )
- return -ENODEV;
- } else {
- tty->driver_data = &SCC_Info[0];
- MOD_INC_USE_COUNT;
- return 0;
- }
-
- scc = &SCC_Info[chan];
-
- tty->driver_data = scc;
- tty->termios->c_cflag &= ~CBAUD;
-
- if (scc->magic != SCC_MAGIC)
- {
- printk("ERROR: scc_open(): bad magic number for device (%s)",
- kdevname(tty->device));
- return -ENODEV;
- }
-
- MOD_INC_USE_COUNT;
-
- if(scc->tty != NULL)
- {
- scc->tty_opened++;
- return 0;
- }
-
- scc->tty = tty;
- alloc_buffer_pool(scc);
-
- if(!scc->init) return 0;
-
- scc->throttled = 0;
-
- scc->stat.tx_kiss_state = KISS_IDLE; /* don't change this... */
- scc->stat.rx_kiss_state = KISS_IDLE; /* ...or this */
-
- init_channel(scc);
- return 0;
-}
-
-
-/* ----> and this whenever you close the device <---- */
-
-static void
-scc_close(struct tty_struct *tty, struct file * filp)
-{
- struct scc_channel *scc = tty->driver_data;
- unsigned long flags;
-
- if (!scc || (scc->magic != SCC_MAGIC))
- return;
-
- MOD_DEC_USE_COUNT;
-
- if(scc->tty_opened)
- {
- scc->tty_opened--;
- return;
- }
-
- tty->driver_data = NULLBUF;
-
- if (!Driver_Initialized)
- return;
-
- save_flags(flags); cli();
-
- Outb(scc->ctrl,0); /* Make sure pointer is written */
- wr(scc,R1,0); /* disable interrupts */
- wr(scc,R3,0);
-
- scc->tty = NULL;
-
- del_timer(&scc->tx_t);
- del_timer(&scc->rx_t);
-
- free_buffer_pool(scc);
-
- restore_flags(flags);
-
- scc->throttled = 0;
- tty->stopped = 0;
-}
-
-
-/*
- * change scc_speed
- */
-
-static void
-scc_change_speed(struct scc_channel * scc)
-{
- long speed;
-
- if (scc->tty == NULL)
- return;
-
-
- speed = baud_table[scc->tty->termios->c_cflag & CBAUD];
-
- if (speed > 0) scc->modem.speed = speed;
-
- if (scc->stat.tx_state == 0) /* only switch baudrate on rx... ;-) */
- set_speed(scc);
-}
-
-
-/* ----> ioctl-routine of the driver <---- */
-
-/* perform ioctl on SCC (sdlc) channel
- * this is used for AX.25 mode, and will set the "kiss" parameters
- */
-
-/* TIOCMGET - get modem status arg: (unsigned long *) arg
- * TIOCMBIS - set PTT arg: ---
- * TIOCMBIC - reset PTT arg: ---
- * TIOCMBIC - set PTT arg: ---
- * TIOCSCCINI - initialize driver arg: ---
- * TIOCCHANINI - initialize channel arg: (struct scc_modem *) arg
- * TIOCGKISS - get level 1 parameter arg: (struct ioctl_command *) arg
- * TIOCSKISS - set level 1 parameter arg: (struct ioctl_command *) arg
- * TIOCSCCSTAT - get driver status arg: (struct scc_stat *) arg
- */
-
-
-static int
-scc_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
-{
- struct scc_channel * scc = tty->driver_data;
- unsigned long flags, r;
- unsigned int result;
- unsigned int value;
- struct ioctl_command kiss_cmd;
- struct scc_mem_config memcfg;
- struct scc_hw_config hwcfg;
- int error, chan;
-
- if (scc->magic != SCC_MAGIC)
- {
- printk("ERROR: scc_ioctl(): bad magic number for device %s",
- kdevname(tty->device));
-
- return -ENODEV;
- }
-
- r = NO_SUCH_PARAM;
-
- if (!Driver_Initialized)
- {
- if (cmd == TIOCSCCCFG)
- {
- int found = 1;
-
- if (!suser()) return -EPERM;
- if (!arg) return -EFAULT;
-
- if (Nchips >= MAXSCC)
- return -EINVAL;
-
- copy_from_user(&hwcfg, (void *) arg, sizeof(hwcfg));
-
- if (hwcfg.irq == 2) hwcfg.irq = 9;
-
- if (!Ivec[hwcfg.irq].used && hwcfg.irq)
- {
- if (request_irq(hwcfg.irq, scc_isr, SA_INTERRUPT, "AX.25 SCC", NULL))
- printk("z8530drv: Warning --- could not get IRQ %d\n", hwcfg.irq);
- else
- Ivec[hwcfg.irq].used = 1;
- }
-
- if (hwcfg.vector_latch)
- Vector_Latch = hwcfg.vector_latch;
-
- if (hwcfg.clock == 0)
- hwcfg.clock = DEFAULT_CLOCK;
-
-#ifndef DONT_CHECK
- save_flags(flags); cli();
-
- check_region(scc->ctrl, 1);
- Outb(hwcfg.ctrl_a, 0);
- udelay(5);
- OutReg(hwcfg.ctrl_a,R13,0x55); /* is this chip really there? */
- udelay(5);
-
- if (InReg(hwcfg.ctrl_a,R13) != 0x55 )
- found = 0;
-
- restore_flags(flags);
-#endif
-
- if (found)
- {
- SCC_Info[2*Nchips ].ctrl = hwcfg.ctrl_a;
- SCC_Info[2*Nchips ].data = hwcfg.data_a;
- SCC_Info[2*Nchips+1].ctrl = hwcfg.ctrl_b;
- SCC_Info[2*Nchips+1].data = hwcfg.data_b;
-
- SCC_ctrl[2*Nchips ] = hwcfg.ctrl_a;
- SCC_ctrl[2*Nchips+1] = hwcfg.ctrl_b;
- }
-
- for (chan = 0; chan < 2; chan++)
- {
- SCC_Info[2*Nchips+chan].special = hwcfg.special;
- SCC_Info[2*Nchips+chan].clock = hwcfg.clock;
- SCC_Info[2*Nchips+chan].brand = hwcfg.brand;
- SCC_Info[2*Nchips+chan].option = hwcfg.option;
- SCC_Info[2*Nchips+chan].enhanced = hwcfg.escc;
-
-#ifdef DONT_CHECK
- printk("%s%i: data port = 0x%3.3x control port = 0x%3.3x\n",
- scc_driver.name, 2*Nchips+chan,
- SCC_Info[2*Nchips+chan].data,
- SCC_Info[2*Nchips+chan].ctrl);
-
-#else
- printk("%s%i: data port = 0x%3.3x control port = 0x%3.3x -- %s\n",
- scc_driver.name, 2*Nchips+chan,
- chan? hwcfg.data_b : hwcfg.data_a,
- chan? hwcfg.ctrl_b : hwcfg.ctrl_a,
- found? "found" : "missing");
-#endif
-
- if (found)
- {
- request_region(SCC_Info[2*Nchips+chan].ctrl, 1, "scc ctrl");
- request_region(SCC_Info[2*Nchips+chan].data, 1, "scc data");
- }
- }
-
- if (found) Nchips++;
-
- return 0;
- }
-
- if (cmd == TIOCSCCINI)
- {
- if (!suser())
- return -EPERM;
-
- if (Nchips == 0)
- return -EINVAL;
-
- z8530_init();
-
- scc->tty=tty;
- alloc_buffer_pool(scc);
- return 0;
- }
-
- return -EINVAL; /* confuse the user */
- }
-
- if (!scc->init)
- {
- if (cmd == TIOCCHANINI)
- {
- if (!arg)
- return -EFAULT;
-
- if (!suser())
- return -EPERM;
-
- copy_from_user(&scc->modem, (void *) arg, sizeof(struct scc_modem));
-
- /* default KISS Params */
-
- if (scc->modem.speed < 4800)
- {
- scc->kiss.txdelay = 36*TPS/100; /* 360 ms */
- scc->kiss.persist = 42; /* 25% persistence */ /* was 25 */
- scc->kiss.slottime = 16*TPS/100; /* 160 ms */
- scc->kiss.tailtime = 4; /* minimal reasonable value */
- scc->kiss.fulldup = 0; /* CSMA */
- scc->kiss.waittime = 50*TPS/100; /* 500 ms */
- scc->kiss.maxkeyup = 10; /* 10 s */
- scc->kiss.mintime = 3; /* 3 s */
- scc->kiss.idletime = 30; /* 30 s */
- scc->kiss.maxdefer = 120; /* 2 min */
- scc->kiss.not_slip = 1; /* KISS mode */
- scc->kiss.softdcd = 0; /* hardware dcd */
- } else {
- scc->kiss.txdelay = 10*TPS/100; /* 100 ms */
- scc->kiss.persist = 64; /* 25% persistence */ /* was 25 */
- scc->kiss.slottime = 8*TPS/100; /* 160 ms */
- scc->kiss.tailtime = 1; /* minimal reasonable value */
- scc->kiss.fulldup = 0; /* CSMA */
- scc->kiss.waittime = 50*TPS/100; /* 500 ms */
- scc->kiss.maxkeyup = 7; /* 7 s */
- scc->kiss.mintime = 3; /* 3 s */
- scc->kiss.idletime = 30; /* 30 s */
- scc->kiss.maxdefer = 120; /* 2 min */
- scc->kiss.not_slip = 1; /* KISS mode */
- scc->kiss.softdcd = 0; /* hardware dcd */
- }
-
- scc->init = 1;
-
- return 0;
- }
-
- return -EINVAL;
- }
-
- switch(cmd){
- case TCSBRK:
- return 0;
- case TIOCMGET:
- error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(unsigned int *));
- if (error)
- return error;
-
- save_flags(flags); cli();
-
- result = ((scc->wreg[R5] & RTS) ? TIOCM_RTS : 0)
- | ((scc->wreg[R5] & DTR) ? TIOCM_DTR : 0)
- | ((InReg(scc->ctrl,R0) & DCD) ? TIOCM_CAR : 0)
- | ((InReg(scc->ctrl,R0) & CTS) ? TIOCM_CTS : 0);
-
- restore_flags(flags);
-
- put_user(result,(unsigned int *) arg);
- return 0;
- case TIOCMBIS:
- case TIOCMBIC:
- case TIOCMSET:
- switch (cmd) {
- case TIOCMBIS:
- scc->wreg[R5] |= DTR;
- scc->wreg[R5] |= RTS;
- break;
- case TIOCMBIC:
- scc->wreg[R5] &= ~DTR;
- scc->wreg[R5] &= ~RTS;
- break;
- case TIOCMSET:
- value = get_user((unsigned int *) arg);
-
- if(value & TIOCM_DTR)
- scc->wreg[R5] |= DTR;
- else
- scc->wreg[R5] &= ~DTR;
- if(value & TIOCM_RTS)
- scc->wreg[R5] |= RTS;
- else
- scc->wreg[R5] &= ~RTS;
- break;
- }
-
- save_flags(flags); cli();
-
- if(scc->stat.tx_state == TXS_IDLE && !Running(t_idle))
- maxk_idle_timeout(scc);
-
- restore_flags(flags);
-
- return 0;
-
- case TCGETS:
- error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct termios));
- if (error)
- return error;
- if (!arg)
- return -EFAULT;
-
- copy_to_user((void *) arg, scc->tty->termios, sizeof(struct termios));
- return 0;
-
- case TCSETS:
- case TCSETSF: /* should flush first, but... */
- case TCSETSW: /* should wait 'till flush, but... */
- if (!arg)
- return -EFAULT;
-
- copy_from_user(scc->tty->termios, (void *) arg, sizeof(struct termios));
- scc_change_speed(scc);
- return 0;
-
- case TIOCCHANMEM:
- if (!arg)
- return -EFAULT;
-
- copy_from_user(&memcfg, (void *) arg, sizeof(struct scc_mem_config));
-
- save_flags(flags); cli();
-
- free_buffer_pool(scc);
- scc->stat.rxbuffers = memcfg.rxbuffers;
- scc->stat.txbuffers = memcfg.txbuffers;
- scc->stat.bufsize = memcfg.bufsize;
- alloc_buffer_pool(scc);
-
- restore_flags(flags);
- return 0;
-
-
- case TIOCSCCSTAT:
- error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(struct scc_stat));
- if (error)
- return error;
-
- if (!arg)
- return -EFAULT;
-
- copy_to_user((void *) arg, &scc->stat, sizeof(struct scc_stat));
- return 0;
-
-#define TICKS (100/TPS)
-#define CAST(x) (unsigned long)(x)
-#define Val kiss_cmd.param
-#define VAL kiss_cmd.param*TPS/100
-#define SVAL kiss_cmd.param? kiss_cmd.param:TIMER_STOPPED
-
- case TIOCGKISS:
- error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(struct ioctl_command));
- if (error)
- return error;
-
- if (!arg)
- return -EFAULT;
-
- copy_from_user(&kiss_cmd, (void *) arg, sizeof(struct ioctl_command));
-
- switch (kiss_cmd.command)
- {
- case PARAM_TXDELAY: r = CAST(scc->kiss.txdelay*TICKS); break;
- case PARAM_PERSIST: r = CAST(scc->kiss.persist); break;
- case PARAM_SLOTTIME: r = CAST(scc->kiss.slottime*TICKS); break;
- case PARAM_TXTAIL: r = CAST(scc->kiss.tailtime*TICKS); break;
- case PARAM_FULLDUP: r = CAST(scc->kiss.fulldup); break;
- case PARAM_SOFTDCD: r = CAST(scc->kiss.softdcd); break;
- case PARAM_DTR: r = CAST((scc->wreg[R5] & DTR)? 1:0); break;
- case PARAM_RTS: r = CAST((scc->wreg[R5] & RTS)? 1:0); break;
- case PARAM_SPEED: r = CAST(scc->modem.speed); break;
- case PARAM_GROUP: r = CAST(scc->kiss.group); break;
- case PARAM_IDLE: r = CAST(scc->kiss.idletime); break;
- case PARAM_MIN: r = CAST(scc->kiss.mintime); break;
- case PARAM_MAXKEY: r = CAST(scc->kiss.maxkeyup); break;
- case PARAM_WAIT: r = CAST(scc->kiss.waittime); break;
- case PARAM_MAXDEFER: r = CAST(scc->kiss.maxdefer); break;
- case PARAM_TX: r = CAST(scc->kiss.tx_inhibit); break;
- case PARAM_SLIP: r = CAST(!scc->kiss.not_slip); break;
- default: r = NO_SUCH_PARAM;
- }
-
- kiss_cmd.param = r;
-
- copy_to_user((void *) arg, &kiss_cmd, sizeof(struct ioctl_command));
- return 0;
- break;
-
- case TIOCSKISS:
- if (!arg)
- return -EFAULT;
-
- copy_from_user(&kiss_cmd, (void *) arg, sizeof(struct ioctl_command));
-
- switch (kiss_cmd.command)
- {
- case PARAM_TXDELAY: scc->kiss.txdelay=VAL; break;
- case PARAM_PERSIST: scc->kiss.persist=Val; break;
- case PARAM_SLOTTIME: scc->kiss.slottime=VAL; break;
- case PARAM_TXTAIL: scc->kiss.tailtime=VAL; break;
- case PARAM_FULLDUP: scc->kiss.fulldup=Val; break;
- case PARAM_SOFTDCD: scc->kiss.softdcd=Val; break;
- case PARAM_DTR: break; /* does someone need this? */
- case PARAM_RTS: break; /* or this? */
- case PARAM_SPEED: scc->modem.speed=Val; break;
- case PARAM_GROUP: scc->kiss.group=Val; break;
- case PARAM_IDLE: scc->kiss.idletime=Val; break;
- case PARAM_MIN: scc->kiss.mintime=SVAL; break;
- case PARAM_MAXKEY: scc->kiss.maxkeyup=SVAL; break;
- case PARAM_WAIT: scc->kiss.waittime=Val; break;
- case PARAM_MAXDEFER: scc->kiss.maxdefer=SVAL; break;
- case PARAM_TX: scc->kiss.tx_inhibit=Val; break;
- case PARAM_SLIP: scc->kiss.not_slip=!Val; break;
- default: return -ENOIOCTLCMD;
- }
-
- return 0;
- break;
-#undef TICKS
-#undef CAST
-#undef VAL
-#undef SVAL
-#undef Val
-
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-
-/* ----> tx routine: decode KISS data and scc_enqueue it <---- */
-
-/* send raw frame to SCC. used for AX.25 */
-int scc_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
-{
- struct scc_channel * scc = tty->driver_data;
- unsigned char *p;
- unsigned long flags;
- int cnt, cnt2;
-
- if (!tty) return count;
-
- if (scc_paranoia_check(scc, tty->device, "scc_write"))
- return 0;
-
- if (scc->kiss.tx_inhibit) return count;
-
- save_flags(flags); cli();
-
- cnt2 = count;
-
- while (cnt2)
- {
- cnt = cnt2 > BUFSIZE? BUFSIZE:cnt2;
- cnt2 -= cnt;
-
- if (from_user)
- {
- down(&scc_sem);
- copy_from_user(scc_wbuf, buf, cnt);
- up(&scc_sem);
- }
- else
- memcpy(scc_wbuf, buf, cnt);
-
- /* Strange thing. The timeout of the slip driver is */
- /* very small, thus we'll wake him up now. */
-
- if (cnt2 == 0)
- {
- wake_up_interruptible(&tty->write_wait);
-
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
- } else
- buf += cnt;
-
- p=scc_wbuf;
-
- while(cnt--)
- if (kiss_decode(scc, *p++))
- {
- scc->stat.nospace++;
- restore_flags(flags);
- return 0;
- }
- } /* while cnt2 */
-
- restore_flags(flags);
-
- return count;
-}
-
-
-/* put a single char into the buffer */
-
-static void scc_put_char(struct tty_struct * tty, unsigned char ch)
-{
- struct scc_channel *scc = tty->driver_data;
- unsigned char ch2;
-
- if (scc_paranoia_check(scc, tty->device, "scc_put_char"))
- return;
-
- ch2 = ch;
- scc_write(tty, 0, &ch2, 1); /* that's all */
-}
-
-static void scc_flush_chars(struct tty_struct * tty)
-{
- struct scc_channel *scc = tty->driver_data;
-
- scc_paranoia_check(scc, tty->device, "scc_flush_chars"); /* just to annoy the user... */
-
- return; /* no flush needed */
-}
-
-
-static int scc_write_room(struct tty_struct *tty)
-{
- struct scc_channel *scc = tty->driver_data;
-
- if (scc_paranoia_check(scc, tty->device, "scc_write_room"))
- return 0;
-
- return BUFSIZE;
-}
-
-static int scc_chars_in_buffer(struct tty_struct *tty)
-{
- struct scc_channel *scc = tty->driver_data;
-
- if (scc && scc->kiss_decode_bp)
- return scc->kiss_decode_bp->cnt;
- else
- return 0;
-}
-
-static void scc_flush_buffer(struct tty_struct *tty)
-{
- struct scc_channel *scc = tty->driver_data;
-
- if (scc_paranoia_check(scc, tty->device, "scc_flush_buffer"))
- return;
- wake_up_interruptible(&tty->write_wait);
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
-}
-
-static void scc_throttle(struct tty_struct *tty)
-{
- struct scc_channel *scc = tty->driver_data;
-
- if (scc_paranoia_check(scc, tty->device, "scc_throttle"))
- return;
-
-#ifdef DEBUG
- printk("scc: scc_throttle() called for device %d\n", MINOR(tty->device));
-#endif
- scc->throttled = 1;
-
- del_timer(&(scc->rx_t));
- scc->rx_t.expires = jiffies + HZ/TPS;
- add_timer(&scc->rx_t);
-}
-
-static void scc_unthrottle(struct tty_struct *tty)
-{
- struct scc_channel *scc = tty->driver_data;
-
- if (scc_paranoia_check(scc, tty->device, "scc_unthrottle"))
- return;
-
-#ifdef DEBUG
- printk("scc: scc_unthrottle() called for device %d\n", MINOR(tty->device));
-#endif
- scc->throttled = 0;
- del_timer(&(scc->rx_t));
- scc_tx_timer(scc->rx_t.data);
-}
-
-/* experimental, the easiest way to stop output is a fake scc_throttle */
-
-static void scc_start(struct tty_struct *tty)
-{
- struct scc_channel *scc = tty->driver_data;
-
- if (scc_paranoia_check(scc, tty->device, "scc_start"))
- return;
-
- scc_unthrottle(tty);
-}
-
-static void scc_stop(struct tty_struct *tty)
-{
- struct scc_channel *scc = tty->driver_data;
-
- if (scc_paranoia_check(scc, tty->device, "scc_stop"))
- return;
-
- scc_throttle(tty);
-}
-
-static void
-scc_set_termios(struct tty_struct * tty, struct termios * old_termios)
-{
- struct scc_channel *scc = tty->driver_data;
-
- if (scc_paranoia_check(scc, tty->device, "scc_set_termios"))
- return;
-
- if (old_termios && (tty->termios->c_cflag == old_termios->c_cflag))
- return;
-
- scc_change_speed(scc);
-}
-
-static void
-scc_set_ldisc(struct tty_struct * tty)
-{
- struct scc_channel *scc = tty->driver_data;
-
- if (scc_paranoia_check(scc, tty->device, "scc_set_ldisc"))
- return;
-
- scc_change_speed(scc);
-}
-
-
-/* ******************************************************************** */
-/* * Init SCC driver * */
-/* ******************************************************************** */
-
-int scc_init (void)
-{
- int chip, chan, k;
-
- memset(&scc_std_termios, 0, sizeof(struct termios));
- memset(&scc_driver, 0, sizeof(struct tty_driver));
- scc_driver.magic = TTY_DRIVER_MAGIC;
- scc_driver.name = "scc";
- scc_driver.major = Z8530_MAJOR;
- scc_driver.minor_start = 0;
- scc_driver.num = MAXSCC*2;
- scc_driver.type = TTY_DRIVER_TYPE_SERIAL;
- scc_driver.subtype = 1; /* not needed */
- scc_driver.init_termios = scc_std_termios;
- scc_driver.init_termios.c_cflag = B9600 | CREAD | CS8 | HUPCL | CLOCAL;
- scc_driver.init_termios.c_iflag = IGNBRK | IGNPAR;
- scc_driver.flags = TTY_DRIVER_REAL_RAW;
- scc_driver.refcount = &scc_refcount;
- scc_driver.table = scc_table;
- scc_driver.termios = (struct termios **) scc_termios;
- scc_driver.termios_locked = (struct termios **) scc_termios_locked;
- scc_driver.open = scc_open;
- scc_driver.close = scc_close;
- scc_driver.write = scc_write;
- scc_driver.start = scc_start;
- scc_driver.stop = scc_stop;
-
- scc_driver.put_char = scc_put_char;
- scc_driver.flush_chars = scc_flush_chars;
- scc_driver.write_room = scc_write_room;
- scc_driver.chars_in_buffer = scc_chars_in_buffer;
- scc_driver.flush_buffer = scc_flush_buffer;
-
- scc_driver.throttle = scc_throttle;
- scc_driver.unthrottle = scc_unthrottle;
-
- scc_driver.ioctl = scc_ioctl;
- scc_driver.set_termios = scc_set_termios;
- scc_driver.set_ldisc = scc_set_ldisc;
-
- printk(BANNER);
-
- if (tty_register_driver(&scc_driver))
- {
- printk("Failed to register Z8530 SCC driver\n");
- return -EIO;
- }
-
- /* pre-init channel information */
-
- for (chip = 0; chip < MAXSCC; chip++)
- {
- memset((char *) &SCC_Info[2*chip ], 0, sizeof(struct scc_channel));
- memset((char *) &SCC_Info[2*chip+1], 0, sizeof(struct scc_channel));
-
- for (chan = 0; chan < 2; chan++)
- {
- SCC_Info[2*chip+chan].magic = SCC_MAGIC;
- SCC_Info[2*chip+chan].stat.rxbuffers = RXBUFFERS;
- SCC_Info[2*chip+chan].stat.txbuffers = TXBUFFERS;
- SCC_Info[2*chip+chan].stat.bufsize = BUFSIZE;
- }
- }
-
- for (k = 0; k < 16; k++) Ivec[k].used = 0;
-
- return 0;
-}
-
-/* ******************************************************************** */
-/* * Module support * */
-/* ******************************************************************** */
-
-
-#ifdef MODULE
-int init_module(void)
-{
- int result = 0;
-
- result = scc_init();
-
- if (result == 0)
- printk("Copyright 1993,1995 Joerg Reuter DL1BKE (jreuter@lykos.tng.oche.de)\n");
-
- return result;
-}
-
-void cleanup_module(void)
-{
- long flags;
- io_port ctrl;
- int k, errno;
- struct scc_channel *scc;
-
- save_flags(flags); cli();
- if ( (errno = tty_unregister_driver(&scc_driver)) )
- {
- printk("Failed to unregister Z8530 SCC driver (%d)", -errno);
- restore_flags(flags);
- return;
- }
-
- for (k = 0; k < Nchips; k++)
- if ( (ctrl = SCC_ctrl[k*2]) )
- {
- Outb(ctrl, 0);
- OutReg(ctrl,R9,FHWRES); /* force hardware reset */
- udelay(50);
- }
-
- for (k = 0; k < Nchips*2; k++)
- {
- scc = &SCC_Info[k];
- if (scc)
- {
- release_region(scc->ctrl, 1);
- release_region(scc->data, 1);
- }
- }
-
- for (k=0; k < 16 ; k++)
- if (Ivec[k].used) free_irq(k, NULL);
-
- restore_flags(flags);
-}
-#endif
#include <linux/malloc.h>
#include <linux/types.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "vt_kern.h"
#include "consolemap.h"
if (!bp || !c)
return 0;
do_unblank_screen();
- current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&vt->paste_wait, &wait);
- while (c) {
+ do {
+ current->state = TASK_INTERRUPTIBLE;
if (test_bit(TTY_THROTTLED, &tty->flags)) {
schedule();
continue;
tty->ldisc.receive_buf(tty, bp, 0, l);
c -= l;
bp += l;
- }
+ } while (c);
+ remove_wait_queue(&vt->paste_wait, &wait);
current->state = TASK_RUNNING;
return 0;
}
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
static char *serial_name = "Serial driver";
#include <linux/config.h> /* for CONFIG_PCI */
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#ifdef CONFIG_PCI
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
#include "kbd_kern.h"
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
/* We really shouldn't be using this define.. */
#define IOCCMD_MASK 0x0000ffff
#include <linux/string.h>
#include <linux/malloc.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/bitops.h>
-#include <linux/scc.h>
-
#include "kbd_kern.h"
#include "vt_kern.h"
#include "selection.h"
if (((*p)->tty == tty) ||
((session > 0) && ((*p)->session == session)))
send_sig(SIGKILL, *p, 1);
- else {
+ else if ((*p)->files) {
for (i=0; i < NR_OPEN; i++) {
filp = (*p)->files->fd[i];
if (filp && (filp->f_op == &tty_fops) &&
#ifdef CONFIG_SERIAL
rs_init();
#endif
-#ifdef CONFIG_SCC
- scc_init();
-#endif
#ifdef CONFIG_CYCLADES
cy_init();
#endif
#include <asm/io.h>
#include <asm/bitops.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#undef TTY_DEBUG_WAIT_UNTIL_SENT
#include <linux/tty.h>
#include <linux/sched.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "vt_kern.h"
#include "selection.h"
#include <asm/io.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/mm.h>
extern unsigned short video_port_reg, video_port_val;
#include <asm/io.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
#include "kbd_kern.h"
#include <linux/fs.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "kbd_kern.h"
#include "vt_kern.h"
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
static int wdt_is_open=0;
/*
* isdn_readbchan() tries to get data from the read-queue.
* It MUST be called with interrupts off.
+ *
+ * I hope I got the EFAULT error path right -AK.
*/
int isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user)
{
int dflag;
struct sk_buff *skb;
u_char *cp;
+ int ret = 0;
if (!dev->drv[di])
return 0;
cp = buf;
count = 0;
while (left) {
+ ret = 0;
if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
break;
if (skb->lock)
count_pull = count_put = 0;
while ((count_pull < skb->len) && (left-- > 0)) {
if (dev->drv[di]->DLEflag & DLEmask) {
- if (user)
- put_fs_byte(DLE,cp++);
- else
+ if (user) {
+ ret = put_user(DLE,cp);
+ cp++;
+ if (ret) break;
+ } else
*cp++ = DLE;
dev->drv[di]->DLEflag &= ~DLEmask;
} else {
- if (user)
- put_fs_byte(*p,cp++);
- else
+ if (user) {
+ ret = put_user(*p,cp);
+ if (ret) break;
+ cp++;
+ } else
*cp++ = *p;
if (*p == DLE) {
dev->drv[di]->DLEflag |= DLEmask;
dflag = 0;
}
count_put = count_pull;
+ ret = 0;
if (user)
- copy_to_user(cp, skb->data, count_put);
+ ret = copy_to_user(cp, skb->data, count_put);
else
memcpy(cp, skb->data, count_put);
+ count_put -= ret;
cp += count_put;
left -= count_put;
}
* but we pull off the data we got until now.
*/
skb_pull(skb,count_pull);
- skb->lock = 0;
+ skb->lock = 0;
}
dev->drv[di]->rcvcount[channel] -= count_put;
}
- return count;
+ return ret ? -EFAULT : count;
}
static __inline int isdn_minor2drv(int minor)
p = isdn_statstr();
file->private_data = 0;
if ((len = strlen(p)) <= count) {
- copy_to_user(buf, p, len);
+ if (copy_to_user(buf, p, len))
+ return -EFAULT;
file->f_pos += len;
- return len;
+ return len;
}
return 0;
}
return ret;
save_flags(flags);
cli();
- if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(int)))) {
- restore_flags(flags);
- return ret;
- }
- copy_from_user((char *) &i, src, sizeof(int));
- src += sizeof(int);
+ ret = get_user(i, src);
+ if (ret)
+ goto out;
+ src += sizeof(int);
while (i) {
char *c;
char *c2;
- if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(cfg)))) {
- restore_flags(flags);
- return ret;
- }
- copy_from_user((char *) &cfg, src, sizeof(cfg));
+ if(copy_from_user((char *) &cfg, src, sizeof(cfg)))
+ goto fault;
src += sizeof(cfg);
if (!isdn_net_new(cfg.name, NULL)) {
restore_flags(flags);
return -EIO;
}
- if ((ret = isdn_net_setcfg(&cfg))) {
- restore_flags(flags);
- return ret;
- }
- if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(buf)))) {
- restore_flags(flags);
- return ret;
- }
- copy_from_user(buf, src, sizeof(buf));
+ if ((ret = isdn_net_setcfg(&cfg)))
+ goto out;
+ if(copy_from_user(buf, src, sizeof(buf)))
+ goto fault;
src += sizeof(buf);
c = buf;
while (*c) {
strcpy(phone.phone, c);
strcpy(phone.name, cfg.name);
phone.outgoing = 0;
- if ((ret = isdn_net_addphone(&phone))) {
- restore_flags(flags);
- return ret;
- }
+ if ((ret = isdn_net_addphone(&phone)))
+ goto fault;
if (c2)
c = c2;
else
c += strlen(c);
}
- if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(buf)))) {
- restore_flags(flags);
- return ret;
- }
- copy_from_user(buf, src, sizeof(buf));
+ if(copy_from_user(buf, src, sizeof(buf)))
+ goto fault;
src += sizeof(buf);
c = buf;
while (*c) {
strcpy(phone.phone, c);
strcpy(phone.name, cfg.name);
phone.outgoing = 1;
- if ((ret = isdn_net_addphone(&phone))) {
- restore_flags(flags);
- return ret;
- }
+ if ((ret = isdn_net_addphone(&phone)))
+ goto out;
if (c2)
c = c2;
else
}
i--;
}
+out:
restore_flags(flags);
- return 0;
+ return ret;
+fault:
+ restore_flags(flags);
+ return -EFAULT;
}
static int isdn_get_allcfg(char *dest)
isdn_net_ioctl_phone phone;
isdn_net_dev *p;
ulong flags;
- int ret;
+ int ret = 0;
/* Walk through netdev-chain */
save_flags(flags);
cli();
p = dev->netdev;
while (p) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 10))) {
- restore_flags(flags);
- return ret;
- }
strcpy(cfg.eaz, p->local.msn);
cfg.exclusive = p->local.exclusive;
if (p->local.pre_device >= 0) {
cfg.callback = (p->local.flags & ISDN_NET_CALLBACK) ? 1 : 0;
cfg.chargehup = (p->local.hupflags & 4) ? 1 : 0;
cfg.ihup = (p->local.hupflags & 8) ? 1 : 0;
- copy_to_user(dest, p->local.name, 10);
+ ret = 0;
+ ret += copy_to_user(dest, p->local.name, 10);
dest += 10;
- copy_to_user(dest, (char *) &cfg, sizeof(cfg));
+ ret += copy_to_user(dest, (char *) &cfg, sizeof(cfg));
dest += sizeof(cfg);
strcpy(phone.name, p->local.name);
phone.outgoing = 0;
- if ((ret = isdn_net_getphones(&phone, dest)) < 0) {
- restore_flags(flags);
- return ret;
- } else
+ if (ret)
+ break;
+ if ((ret = isdn_net_getphones(&phone, dest)) < 0)
+ break;
+ else
dest += ret;
strcpy(phone.name, p->local.name);
phone.outgoing = 1;
- if ((ret = isdn_net_getphones(&phone, dest)) < 0) {
- restore_flags(flags);
- return ret;
- } else
+ if ((ret = isdn_net_getphones(&phone, dest)) < 0)
+ break;
+ else
dest += ret;
p = p->next;
}
restore_flags(flags);
- return 0;
+ return ret;
}
static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
isdn_ctrl c;
int drvidx;
int chidx;
- int ret;
+ int ret = 0;
char *s;
char name[10];
char bname[21];
if (arg) {
ulong *p = (ulong *)arg;
int i;
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(ulong)*ISDN_MAX_CHANNELS*2)))
- return ret;
for (i = 0;i<ISDN_MAX_CHANNELS;i++) {
- put_fs_long(dev->ibytes[i],p++);
- put_fs_long(dev->obytes[i],p++);
+ ret = put_user(dev->ibytes[i],p);
+ if (ret) break;
+ p++;
+ ret = put_user(dev->obytes[i],p);
+ p++;
+ if (ret) break;
}
- return 0;
+ return ret;
} else
return -EINVAL;
break;
case IIOCNETAIF:
/* Add a network-interface */
if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
- return ret;
- copy_from_user(name, (char *) arg, sizeof(name));
+ if(copy_from_user(name, (char *) arg, sizeof(name)))
+ return -EFAULT;
s = name;
} else
s = NULL;
if ((s = isdn_net_new(s, NULL))) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg, strlen(s) + 1)))
- return ret;
- copy_to_user((char *) arg, s, strlen(s) + 1);
- return 0;
+ return copy_to_user((char *) arg, s, strlen(s) + 1) ? -EFAULT : ret;
} else
return -ENODEV;
case IIOCNETASL:
/* Add a slave to a network-interface */
if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(bname))))
- return ret;
- copy_from_user(bname, (char *) arg, sizeof(bname));
+ if(copy_from_user(bname, (char *) arg, sizeof(bname)))
+ return -EFAULT;
} else
return -EINVAL;
if ((s = isdn_net_newslave(bname))) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg, strlen(s) + 1)))
- return ret;
- copy_to_user((char *) arg, s, strlen(s) + 1);
- return 0;
+ return copy_to_user((char *) arg, s, strlen(s) + 1) ? -EFAULT : 0;
} else
return -ENODEV;
case IIOCNETDIF:
/* Delete a network-interface */
if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
- return ret;
- copy_from_user(name, (char *) arg, sizeof(name));
- return isdn_net_rm(name);
+ ret = copy_from_user(name, (char *) arg, sizeof(name));
+ return ret ? -EFAULT : isdn_net_rm(name);
} else
return -EINVAL;
case IIOCNETSCF:
/* Set configurable parameters of a network-interface */
if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(cfg))))
- return ret;
- copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg));
- return isdn_net_setcfg(&cfg);
+ ret = copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg));
+ return ret ? -EFAULT : isdn_net_setcfg(&cfg);
} else
return -EINVAL;
case IIOCNETGCF:
/* Get configurable parameters of a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(cfg))))
- return ret;
- copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg));
+ if (arg) {
+ if(copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
+ return -EFAULT;
if (!(ret = isdn_net_getcfg(&cfg))) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(cfg))))
- return ret;
- copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg));
+ if(copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
+ return -EFAULT;
}
return ret;
} else
case IIOCNETANM:
/* Add a phone-number to a network-interface */
if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
- return ret;
- copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
- return isdn_net_addphone(&phone);
+ ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
+ return ret ? -EFAULT : isdn_net_addphone(&phone);
} else
return -EINVAL;
case IIOCNETGNM:
/* Get list of phone-numbers of a network-interface */
if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
- return ret;
- copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
- return isdn_net_getphones(&phone, (char *) arg);
+ ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
+ return ret ? -EFAULT : isdn_net_getphones(&phone, (char *) arg);
} else
return -EINVAL;
case IIOCNETDNM:
/* Delete a phone-number of a network-interface */
if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
- return ret;
- copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
- return isdn_net_delphone(&phone);
+ ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
+ return ret ? -EFAULT : isdn_net_delphone(&phone);
} else
return -EINVAL;
case IIOCNETDIL:
/* Force dialing of a network-interface */
if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
- return ret;
- copy_from_user(name, (char *) arg, sizeof(name));
- return isdn_net_force_dial(name);
+ ret = copy_from_user(name, (char *) arg, sizeof(name));
+ return ret ? -EFAULT : isdn_net_force_dial(name);
} else
return -EINVAL;
#ifdef CONFIG_ISDN_PPP
case IIOCNETALN:
- if(arg) {
- if ((ret = verify_area(VERIFY_READ,
- (void*)arg,
- sizeof(name))))
- return ret;
- } else
- return -EINVAL;
- copy_from_user(name,(char*)arg,sizeof(name));
- return isdn_ppp_dial_slave(name);
+ if (arg)
+ ret = copy_from_user(name,(char*)arg,sizeof(name));
+ else
+ return -EINVAL;
+ return ret ? -EFAULT : isdn_ppp_dial_slave(name);
case IIOCNETDLN:
+
if(arg) {
- if ((ret = verify_area(VERIFY_READ,
- (void*)arg,
- sizeof(name))))
- return ret;
+ ret = copy_from_user(name,(char*)arg,sizeof(name));
} else
return -EINVAL;
- copy_from_user(name,(char*)arg,sizeof(name));
- return isdn_ppp_hangup_slave(name);
+ return ret ? -EFAULT : isdn_ppp_hangup_slave(name);
#endif
case IIOCNETHUP:
/* Force hangup of a network-interface */
if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
- return ret;
- copy_from_user(name, (char *) arg, sizeof(name));
- return isdn_net_force_hangup(name);
+ ret = copy_from_user(name, (char *) arg, sizeof(name));
+ return ret ? -EFAULT : isdn_net_force_hangup(name);
} else
return -EINVAL;
break;
if (arg) {
int i;
char *p;
- if ((ret = verify_area(VERIFY_READ, (void *) arg,
- sizeof(isdn_ioctl_struct))))
- return ret;
- copy_from_user((char *) &iocts, (char *) arg,
- sizeof(isdn_ioctl_struct));
- if (strlen(iocts.drvid)) {
+ if(copy_from_user((char *) &iocts, (char *) arg,
+ sizeof(isdn_ioctl_struct)))
+ return -EFAULT;
+ if (strlen(iocts.drvid)) {
if ((p = strchr(iocts.drvid, ',')))
*p = 0;
drvidx = -1;
if (arg) {
char *p = (char *) arg;
int i;
-
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
- (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
- * ISDN_MAX_CHANNELS)))
- return ret;
-
+
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- copy_to_user(p, dev->mdm.info[i].emu.profile,
- ISDN_MODEM_ANZREG);
+ if(copy_to_user(p, dev->mdm.info[i].emu.profile,
+ ISDN_MODEM_ANZREG))
+ return -EFAULT;
p += ISDN_MODEM_ANZREG;
- copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN);
+ if(copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
+ return -EFAULT;
p += ISDN_MSNLEN;
}
return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS;
char *p = (char *) arg;
int i;
- if ((ret = verify_area(VERIFY_READ, (void *) arg,
- (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
- * ISDN_MAX_CHANNELS)))
- return ret;
-
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- copy_from_user(dev->mdm.info[i].emu.profile, p,
- ISDN_MODEM_ANZREG);
- p += ISDN_MODEM_ANZREG;
- copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN);
- p += ISDN_MSNLEN;
+ if(copy_from_user(dev->mdm.info[i].emu.profile, p,
+ ISDN_MODEM_ANZREG))
+ return -EFAULT;
+ p += ISDN_MODEM_ANZREG;
+ if(copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
+ return -EFAULT;
+ p += ISDN_MSNLEN;
}
return 0;
} else
char *p;
char nstring[255];
- if ((ret = verify_area(VERIFY_READ, (void *) arg,
- sizeof(isdn_ioctl_struct))))
- return ret;
- copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
- if (strlen(iocts.drvid)) {
+ ret = copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
+
+ if (ret) return -EFAULT;
+ if (strlen(iocts.drvid)) {
drvidx = -1;
for (i = 0; i < ISDN_MAX_DRIVERS; i++)
if (!(strcmp(dev->drvid[i], iocts.drvid))) {
if (drvidx == -1)
return -ENODEV;
if (cmd == IIOCSETMAP) {
- if ((ret = verify_area(VERIFY_READ, (void *) iocts.arg, 255)))
- return ret;
- copy_from_user(nstring, (char *) iocts.arg, 255);
+ ret = copy_from_user(nstring, (char *) iocts.arg, 255);
+ if (ret) return -EFAULT;
memset(dev->drv[drvidx]->msn2eaz, 0,
sizeof(dev->drv[drvidx]->msn2eaz));
p = strtok(nstring, ",");
strlen(dev->drv[drvidx]->msn2eaz[i]) ?
dev->drv[drvidx]->msn2eaz[i] : "-",
(i < 9) ? "," : "\0");
- if ((ret = verify_area(VERIFY_WRITE, (void *) iocts.arg,
- strlen(nstring) + 1)))
- return ret;
- copy_to_user((char *) iocts.arg, nstring, strlen(nstring) + 1);
- }
+ if(copy_to_user((char *) iocts.arg, nstring, strlen(nstring) + 1))
+ return -EFAULT;
+ }
return 0;
} else
return -EINVAL;
case IIOCDBGVAR:
if (arg) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(ulong))))
- return ret;
- copy_to_user((char *) arg, (char *) &dev, sizeof(ulong));
- return 0;
- } else
+ return copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)) ? -EFAULT : 0;
+ } else
return -EINVAL;
break;
default:
if (arg) {
int i;
char *p;
- if ((ret = verify_area(VERIFY_READ, (void *) arg,
- sizeof(isdn_ioctl_struct))))
- return ret;
- copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
+
+ ret = copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
+ if (ret)
+ return -EFAULT;
if (strlen(iocts.drvid)) {
if ((p = strchr(iocts.drvid, ',')))
*p = 0;
drvidx = 0;
if (drvidx == -1)
return -ENODEV;
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(isdn_ioctl_struct))))
- return ret;
c.driver = drvidx;
c.command = ISDN_CMD_IOCTL;
c.arg = cmd;
memcpy(c.num, (char *) &iocts.arg, sizeof(ulong));
ret = dev->drv[drvidx]->interface->command(&c);
memcpy((char *) &iocts.arg, c.num, sizeof(ulong));
- copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct));
- return ret;
+ return copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)) ? -EFAULT : 0;
} else
return -EINVAL;
}
skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen);
skb->free = 1;
- if (user)
- copy_from_user(skb_put(skb, len), buf, len);
- else
+ if (user) {
+ if(copy_from_user(skb_put(skb, len), buf, len)) {
+ kfree_skb(skb,FREE_WRITE);
+ return -EFAULT;
+ }
+ } else
memcpy(skb_put(skb, len), buf, len);
ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx,
p->start = 1;
p = (((isdn_net_local *) p->priv)->slave);
}
- }
+ }
- isdn_MOD_INC_USE_COUNT();
- return 0;
-}
+ isdn_MOD_INC_USE_COUNT();
+ return 0;
+}
-/*
- * Assign an ISDN-channel to a net-interface
+/*
+ Assign an ISDN-channel to a net-interface
*/
static void
isdn_net_bind_channel(isdn_net_local * lp, int idx)
int count = 0;
isdn_net_phone *n;
int flags;
- int ret;
+ int ret = 0;
if (!p)
return -ENODEV;
inout &= 1;
for (n = p->local.phone[inout]; n; n = n->next) {
if (more) {
- put_fs_byte(' ', phones++);
+ ret = put_user(((char)' '), phones);
+ phones++;
count++;
}
- if ((ret = verify_area(VERIFY_WRITE, (void *) phones, strlen(n->num) + 1))) {
+ if (ret || copy_to_user(phones, n->num, strlen(n->num) + 1)) {
restore_flags(flags);
- return ret;
+ return -EFAULT;
}
- copy_to_user(phones, n->num, strlen(n->num) + 1);
phones += strlen(n->num);
count += strlen(n->num);
more = 1;
}
- put_fs_byte(0,phones);
- count++;
+ ret = put_user(((char)0),phones);
+ count++;
restore_flags(flags);
- return count;
+ return ret ? -EFAULT : count;
}
/*
is->state = 0;
}
+#if 0 /* get_user() / put_user() in 2.1 replace them 1:1 */
/*
* get_arg .. ioctl helper
*/
static int get_arg(void *b, unsigned long *val)
{
int r;
- if ((r = verify_area(VERIFY_READ, (void *) b, sizeof(unsigned long))))
- return r;
- copy_from_user((void *) val, b, sizeof(unsigned long));
+ if (copy_from_user((void *) val, b, sizeof(unsigned long)))
+ return -EFAULT;
return 0;
}
copy_to_user(b, (void *) &val, sizeof(unsigned long));
return 0;
}
+#endif
/*
* ippp device ioctl
unsigned long val;
int r;
struct ippp_struct *is;
+ unsigned long *argp = (unsigned long*)arg;
is = file->private_data;
switch (cmd) {
case PPPIOCBUNDLE:
#ifdef CONFIG_ISDN_MPP
- if ((r = get_arg((void *) arg, &val)))
+ if ((r = get_user(val, arg)))
return r;
printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
(int) min, (int) is->unit, (int) val);
#endif
break;
case PPPIOCGUNIT: /* get ppp/isdn unit number */
- if ((r = set_arg((void *) arg, is->unit)))
+ if ((r = put_user(is->unit, argp)))
return r;
break;
case PPPIOCGMPFLAGS: /* get configuration flags */
- if ((r = set_arg((void *) arg, is->mpppcfg)))
+ if ((r = put_user(is->mpppcfg, argp)))
return r;
break;
case PPPIOCSMPFLAGS: /* set configuration flags */
- if ((r = get_arg((void *) arg, &val)))
+ if ((r = get_user(val, argp)))
return r;
is->mpppcfg = val;
break;
case PPPIOCGFLAGS: /* get configuration flags */
- if ((r = set_arg((void *) arg, is->pppcfg)))
+ if ((r = put_user(is->pppcfg ,argp)))
return r;
break;
case PPPIOCSFLAGS: /* set configuration flags */
- if ((r = get_arg((void *) arg, &val))) {
+ if ((r = get_user(val, argp))) {
return r;
}
if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP)) {
break;
#endif
case PPPIOCSMRU: /* set receive unit size for PPP */
- if ((r = get_arg((void *) arg, &val)))
+ if ((r = get_user(val, argp)))
return r;
is->mru = val;
break;
case PPPIOCSMPMTU:
break;
case PPPIOCSMAXCID: /* set the maximum compression slot id */
- if ((r = get_arg((void *) arg, &val)))
+ if ((r = get_user(val, argp)))
return r;
val++;
if(is->maxcid != val) {
}
break;
case PPPIOCGDEBUG:
- if ((r = set_arg((void *) arg, is->debug)))
+ if ((r = put_user(is->debug, argp)))
return r;
break;
case PPPIOCSDEBUG:
- if ((r = get_arg((void *) arg, &val)))
+ if ((r = get_user(val, argp)))
return r;
is->debug = val;
break;
if (!(is->state & IPPP_OPEN))
return 0;
- if ((r = verify_area(VERIFY_WRITE, (void *) buf, count)))
- return r;
-
save_flags(flags);
cli();
}
if (b->len < count)
count = b->len;
- copy_to_user(buf, b->buf, count);
+ if (copy_to_user(buf, b->buf, count))
+ count = -EFAULT; /* ugly */
kfree(b->buf);
b->buf = NULL;
is->first = b;
isdn_net_local *lp = (isdn_net_local *) dev->priv;
int err;
- res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
- err = verify_area (VERIFY_WRITE, res,sizeof(struct ppp_stats));
-
- if(err)
- return err;
+ res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
/* build a temporary stat struct and copy it to user space */
}
#endif
}
- copy_to_user (res, &t, sizeof (struct ppp_stats));
- return 0;
-
+ return copy_to_user (res, &t, sizeof (struct ppp_stats)) ? -EFAULT : 0;
}
int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
case SIOCGPPPVER:
r = (char *) ifr->ifr_ifru.ifru_data;
len = strlen(PPP_VERSION) + 1;
- error = verify_area(VERIFY_WRITE, r, len);
- if (!error)
- copy_to_user(r, PPP_VERSION, len);
+ if (copy_to_user(r, PPP_VERSION, len))
+ error = -EFAULT;
break;
case SIOCGPPPSTATS:
error = isdn_ppp_dev_ioctl_stats (lp->ppp_slot, ifr, dev);
status = info->lsr;
restore_flags(flags);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- put_user(result, (ulong *) value);
- return 0;
+ return put_user(result, (ulong *) value);
}
| ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
| ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
| ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
- put_user(result, (ulong *) value);
- return 0;
+ return put_user(result, (ulong *) value);
}
static int isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
{
- uint arg = get_user((uint *) value);
- int pre_dtr;
+ uint arg;
+ int pre_dtr;
+ int error;
+
+ error = get_user(arg, ((uint *) value));
+ if (error)
+ return error;
switch (cmd) {
case TIOCMBIS:
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
#endif
- error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
- if (error)
- return error;
- put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
+ error = put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
+ if (error)
+ return error;
return 0;
case TIOCSSOFTCAR:
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
#endif
- error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
- if (error)
- return error;
- arg = get_user((ulong *) arg);
+ error = get_user(arg ,((ulong *) arg));
+ if (error)
+ return error;
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
#endif
- error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
- if (error)
- return error;
return isdn_tty_get_modem_info(info, (uint *) arg);
case TIOCMBIS:
case TIOCMBIC:
case TIOCMSET:
- error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint));
- if (error)
- return error;
return isdn_tty_set_modem_info(info, cmd, (uint *) arg);
case TIOCSERGETLSR: /* Get line status register */
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
#endif
- error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
- if (error)
- return error;
- else
- return isdn_tty_get_lsr_info(info, (uint *) arg);
+ return isdn_tty_get_lsr_info(info, (uint *) arg);
default:
#ifdef ISDN_DEBUG_MODEM_IOCTL
for (cnt = count; cnt > 0; p++, cnt--) {
if (user)
- c = get_user(p);
+ get_user(c, p);
else
c = *p;
total++;
ptr += i;
- if (user)
- memcpy_fromfs(ptr, buf, count);
- else
+ if (user) {
+ if (copy_from_user(ptr, buf, count))
+ return -EFAULT;
+ } else
memcpy(ptr, buf, count);
ibh->datasize = count + i;
#include <linux/tqueue.h>
#include <linux/interrupt.h>
+#include <asm/io.h>
+
#undef DCHAN_VERBOSE
extern void tei_handler(struct PStack *st, byte pr,
#define bytein(addr) inb_p(addr)
static inline byte
-readisac_0(byte * cardm, byte offset)
+readisac_0(unsigned int cardm, byte offset)
{
- return *(byte *) (cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
+ return readb(cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
}
static inline byte
((mbase)?readisac_0(mbase,ofs):readisac_3(ibase,ofs))
static inline void
-writeisac_0(byte * cardm, byte offset, byte value)
+writeisac_0(unsigned int cardm, byte offset, byte value)
{
- *(byte *) (cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset) = value;
+ writeb(value, cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
}
static inline void
}
static inline byte
-readhscx_0(byte * base, byte hscx, byte offset)
+readhscx_0(unsigned int base, byte hscx, byte offset)
{
- return *(byte *) (base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
+ return readb(base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
((hscx & 1) ? 0x40 : 0) + offset);
}
((mbase)?readhscx_0(mbase,hscx,ofs):readhscx_3(ibase,hscx,ofs))
static inline void
-writehscx_0(byte * base, byte hscx, byte offset, byte data)
+writehscx_0(unsigned int base, byte hscx, byte offset, byte data)
{
- *(byte *) (base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
- ((hscx & 1) ? 0x40 : 0) + offset) = data;
+ writeb(data, base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
+ ((hscx & 1) ? 0x40 : 0) + offset);
}
static inline void
#define HSCX_MASK 0x20
static inline void
-waitforCEC_0(byte * base, byte hscx)
+waitforCEC_0(unsigned int base, byte hscx)
{
long to = 10;
}
static inline void
-waitforXFW_0(byte * base, byte hscx)
+waitforXFW_0(unsigned int base, byte hscx)
{
long to = 20;
}
static inline void
-writehscxCMDR_0(byte * base, byte hscx, byte data)
+writehscxCMDR_0(unsigned int base, byte hscx, byte data)
{
long flags;
}
static void
-initisac(byte * cardmem, int iobase)
+initisac(unsigned int cardmem, int iobase)
{
if (cardmem) {
writeisac_0(cardmem, ISAC_MASK, 0xff);
struct IsdnCard *card = cards + cardnr;
if (card->membase)
- if ((unsigned long)card->membase < 0x10000) {
- (unsigned long)card->membase <<= 4;
+ if (card->membase < 0x10000) {
+ card->membase <<= 4;
printk(KERN_INFO
- "Teles membase configured DOSish, assuming 0x%lx\n",
- (unsigned long)card->membase);
+ "Teles membase configured DOSish, assuming 0x%x\n",
+ card->membase);
}
if (!card->iobase) {
if (card->membase) {
printk(KERN_NOTICE
- "Teles 8 assumed, mem: %lx irq: %d proto: %s\n",
- (long) card->membase, card->interrupt,
+ "Teles 8 assumed, mem: %x irq: %d proto: %s\n",
+ card->membase, card->interrupt,
(card->protocol == ISDN_PTYPE_1TR6) ?
"1TR6" : "EDSS1");
printk(KERN_INFO "HSCX version A:%x B:%x\n",
break;
}
if (card->membase) {
- cfval |= (((unsigned int) card->membase >> 9) & 0xF0);
+ cfval |= (card->membase >> 9) & 0xF0;
}
if (bytein(card->iobase + 0) != 0x51) {
printk(KERN_INFO "XXX Byte at %x is %x\n",
if (card->membase)
printk(KERN_NOTICE
- "Teles 16.0 found, io: %x mem: %lx irq: %d proto: %s\n",
- card->iobase, (long) card->membase,
+ "Teles 16.0 found, io: %x mem: %x irq: %d proto: %s\n",
+ card->iobase, card->membase,
card->interrupt,
(card->protocol == ISDN_PTYPE_1TR6) ?
"1TR6" : "EDSS1");
if (card->membase) {
cli();
timout = jiffies + (HZ / 5) + 1;
- *(byte *) (card->membase + 0x80) = 0;
+ writeb(0, card->membase + 0x80);
sti();
while (jiffies <= timout);
cli();
- *(byte *) (card->membase + 0x80) = 1;
+ writeb(1, card->membase + 0x80);
timout = jiffies + (HZ / 5) + 1;
sti();
while (jiffies <= timout);
struct IsdnCard cards[] =
{
- {(byte *) 0xd0000, 15, 0xd80, ISDN_PTYPE_EURO, NULL}, /* example */
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
+ {0xd0000, 15, 0xd80, ISDN_PTYPE_EURO, NULL}, /* example */
+ {0, 0, 0, 0, NULL},
+ {0, 0, 0, 0, NULL},
+ {0, 0, 0, 0, NULL},
+ {0, 0, 0, 0, NULL},
+ {0, 0, 0, 0, NULL},
+ {0, 0, 0, 0, NULL},
+ {0, 0, 0, 0, NULL},
+ {0, 0, 0, 0, NULL},
+ {0, 0, 0, 0, NULL},
+ {0, 0, 0, 0, NULL},
+ {0, 0, 0, 0, NULL},
+ {0, 0, 0, 0, NULL},
+ {0, 0, 0, 0, NULL},
+ {0, 0, 0, 0, NULL},
+ {0, 0, 0, 0, NULL},
};
byte *p;
for (p = buf, count = 0; count < len; p++, count++) {
- if (user)
- put_fs_byte(*teles_status_read++, p);
- else
+ if (user) {
+ put_user(*teles_status_read, p);
+ teles_status_read++;
+ } else
*p++ = *teles_status_read++;
if (teles_status_read > teles_status_end)
teles_status_read = teles_status_buf;
int nrcards;
typedef struct {
- byte *membase;
+ unsigned int membase;
int interrupt;
unsigned int iobase;
unsigned int protocol;
j++; argc--;
}
if (argc) {
- io[i].membase = (byte *)ints[j];
+ io[i].membase = ints[j];
j++; argc--;
}
if (argc) {
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/major.h>
-#include <asm/segment.h>
-#include <asm/io.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/isdnif.h>
#include <linux/tty.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
#define PH_ACTIVATE 1
#define PH_DATA 2
#define PH_DEACTIVATE 3
};
struct HscxState {
- byte *membase;
+ unsigned int membase;
int iobase;
int inuse, init, active;
struct BufPool sbufpool, rbufpool, smallpool;
#ifdef DEBUG_MAGIC
int magic;
#endif
- byte *membase;
+ unsigned int membase;
int iobase;
struct BufPool sbufpool, rbufpool, smallpool;
struct PStack *stlist;
};
struct IsdnCard {
- byte *membase;
+ unsigned int membase;
int interrupt;
unsigned int iobase;
int protocol; /* EDSS1 or 1TR6 */
root_vortex_dev = NULL;
cards_found = vortex_scan(0);
- return cards_found < 0 ? cards_found : 0;
+ return cards_found ? 0 : -ENODEV;
}
#else
#include <linux/ptrace.h>
#include <linux/string.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <linux/errno.h>
endif
endif
+ifeq ($(CONFIG_SCC),y)
+L_OBJS += scc.o
+else
+ ifeq ($(CONFIG_SCC),m)
+ M_OBJS += scc.o
+ endif
+endif
+
ifeq ($(CONFIG_PI),y)
L_OBJS += pi2.o
endif
--- /dev/null
+
+You will find subset of the documentation in
+
+ linux/Documentation/networking/z8530drv.txt
+
+To use this driver you MUST have the full package from:
+
+Internet:
+=========
+
+1. db0bm.automation.fh-aachen.de/incoming/dl1bke/z8530drv-utils-3.0.tar.gz
+
+2. ftp.ucsd.edu:/hamradio/packet/tcpip/incoming/z8530drv-utils-3.0.tar.gz
+ If you can't find it there, try .../tcpip/linux/z8530drv-utils-3.0.tar.gz
+
+and various mirrors (i.e. nic.switch.ch)
+
+The package includes the utilities necessary to initialize and
+control the driver.
+
+Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org
+ AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU
+ Internet: jreuter@lykos.oche.de
**********************
+ v2.56 (96/10/18)
+ - Turned arc0e/arc0s startup messages back on by default, as most
+ people will probably not notice the additional devices
+ otherwise, and experience more protocol confusion than
+ necessary.
+ - Fixed a tiny but noticeable bug in the packet debugging routines
+ (thanks Tomasz)
+
v2.55 (96/08/05)
- A couple more messages moved to D_EXTRA.
- SLOW_XMIT_COPY off by default.
*/
static const char *version =
- "arcnet.c: v2.55 96/08/05 Avery Pennarun <apenwarr@foxnet.net>\n";
+ "arcnet.c: v2.56 96/10/18 Avery Pennarun <apenwarr@foxnet.net>\n";
{
if (i%16==0)
printk("\n" KERN_DEBUG "[%04X] ",i);
- else
- printk("%02X ",((u_char *)skb->data)[i]);
+ printk("%02X ",((u_char *)skb->data)[i]);
}
printk("\n");
restore_flags(flags);
{
if (i%16==0)
printk("\n" KERN_DEBUG "[%04X] ",i);
- else
- printk("%02X ",buffer[i]);
+ printk("%02X ",buffer[i]);
}
printk("\n");
restore_flags(flags);
* NOTE: the list of possible ports/shmems is static, so it is retained
* across calls to arcnet_probe. So, if more than one ARCnet probe is made,
* values that were discarded once will not even be tried again.
+ *
+ * FIXME: grab all devices in one shot and eliminate the big static array.
*/
int arcnet_probe(struct device *dev)
{
ports[(count-0x200)/16] = count;
for (count=0xA0000; count<=0xFF800; count+=2048)
shmems[(count-0xA0000)/2048] = count;
- }
- else
init_once=1;
+ }
BUGLVL(D_NORMAL) printk(version);
/* The RFC1201 driver is the default - just store */
lp->adev=dev;
- BUGMSG(D_EXTRA,"ARCnet RFC1201 protocol initialized.\n");
+ BUGMSG(D_NORMAL,"ARCnet RFC1201 protocol initialized.\n");
#ifdef CONFIG_ARCNET_ETH
/* Initialize the ethernet-encap protocol driver */
lp->edev->init=arcnetE_init;
register_netdev(lp->edev);
#else
- BUGMSG(D_EXTRA,"Ethernet-Encap protocol not available (disabled).\n");
+ BUGMSG(D_NORMAL,"Ethernet-Encap protocol not available (disabled).\n");
#endif
#ifdef CONFIG_ARCNET_1051
lp->sdev->init=arcnetS_init;
register_netdev(lp->sdev);
#else
- BUGMSG(D_EXTRA,"RFC1051 protocol not available (disabled).\n");
+ BUGMSG(D_NORMAL,"RFC1051 protocol not available (disabled).\n");
#endif
/* we're started */
dev->stop=arcnetE_open_close;
dev->hard_start_xmit=arcnetE_send_packet;
- BUGMSG(D_EXTRA,"ARCnet Ethernet-Encap protocol initialized.\n");
+ BUGMSG(D_NORMAL,"ARCnet Ethernet-Encap protocol initialized.\n");
return 0;
}
dev->hard_start_xmit=arcnetS_send_packet;
dev->hard_header=arcnetS_header;
dev->rebuild_header=arcnetS_rebuild_header;
- BUGMSG(D_EXTRA,"ARCnet RFC1051 (NetBSD, AmiTCP) protocol initialized.\n");
+ BUGMSG(D_NORMAL,"ARCnet RFC1051 (NetBSD, AmiTCP) protocol initialized.\n");
return 0;
}
static int io=0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
-static int irqnum=0; /* or use the insmod io= irqnum= shmem= options */
+static int irqnum=0; /* or use the insmod io= irq= shmem= options */
static int irq=0;
static int shmem=0;
-static char *device = NULL;
+static char *device = NULL; /* use eg. device="arc1" to change name */
int
init_module(void)
}
#endif /* MODULE */
-
-
-\f
-/*
- * Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c arcnet.c"
- * version-control: t
- * kept-new-versions: 5
- * tab-width: 8
- * End:
- */
-
#include <asm/system.h>
#include <asm/bitops.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include <linux/if.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/in.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/inet.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/signal.h> /* used in new tty drivers */
#include <asm/system.h>
#include <asm/bitops.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
--- /dev/null
+#define RCS_ID "$Id: scc.c,v 1.63 1996/10/09 16:45:47 jreuter Exp jreuter $"
+
+#define VERSION "3.0"
+#define BANNER "Z8530 SCC driver version "VERSION".dl1bke (experimental) by DL1BKE\n"
+
+/*
+ * Please use z8530drv-utils-3.0 with this version.
+ * ------------------
+ */
+
+/*
+ ********************************************************************
+ * SCC.C - Linux driver for Z8530 based HDLC cards for AX.25 *
+ ********************************************************************
+
+
+ ********************************************************************
+
+ Copyright (c) 1993, 1996 Joerg Reuter DL1BKE
+
+ portions (c) 1993 Guido ten Dolle PE1NNZ
+
+ ********************************************************************
+
+ The driver and the programs in the archive are UNDER CONSTRUCTION.
+ The code is likely to fail, and so your kernel could --- even
+ a whole network.
+
+ This driver is intended for Amateur Radio use. If you are running it
+ for commercial purposes, please drop me a note. I am nosy...
+
+ ...BUT:
+
+ ! You m u s t recognize the appropriate legislations of your country !
+ ! before you connect a radio to the SCC board and start to transmit or !
+ ! receive. The GPL allows you to use the d r i v e r, NOT the RADIO! !
+
+ For non-Amateur-Radio use please note that you might need a special
+ allowance/licence from the designer of the SCC Board and/or the
+ MODEM.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the (modified) GNU General Public License
+ delivered with the Linux kernel source.
+
+ 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 find a copy of the GNU General Public License in
+ /usr/src/linux/COPYING;
+
+ ********************************************************************
+
+
+ Incomplete history of z8530drv:
+ -------------------------------
+
+ 940913 - started to write the driver, rescued most of my own
+ code (and Hans Alblas' memory buffer pool concept) from
+ an earlier project "sccdrv" which was initiated by
+ Guido ten Dolle. Not much of the old driver survived,
+ though. The first version I put my hands on was sccdrv1.3
+ from August 1993. The memory buffer pool concept
+ appeared in an unauthorized sccdrv version (1.5) from
+ August 1994.
+
+ 950131 - changed copyright notice to GPL without limitations.
+
+ .
+ . <SNIP>
+ .
+
+ 961005 - New semester, new driver...
+
+ * KISS TNC emulator removed (TTY driver)
+ * Source moved to drivers/net/
+ * Includes Z8530 defines from drivers/net/z8530.h
+ * Uses sk_buffer memory management
+ * Doesn't have own queues anymore
+ * Reduced overhead of /proc/net/z8530drv output
+ * Streamlined quite a lot things
+ * Invents brand new bugs... ;-)
+
+ The move to version number 3.0 reflects theses changes.
+ You can use version 2.4 if you need a KISS TNC emulator.
+
+ Thanks to all who contributed to this driver with ideas and bug
+ reports!
+
+ NB -- if you find errors, change something, please let me know
+ first before you distribute it... And please don't touch
+ the version number. Just replace my callsign in
+ "v3.0.dl1bke" with your own. Just to avoid confusion...
+
+ If you want to add your modification to the linux distribution
+ please (!) contact me first.
+
+ New versions of the driver will be announced on the linux-hams
+ mailing list on vger.rutgers.edu. To subscribe send an e-mail
+ to majordomo@vger.rutgers.edu with the following line in
+ the body of the mail:
+
+ subscribe linux-hams
+
+ The content of the "Subject" field will be ignored.
+
+ vy 73,
+ Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org
+ AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU
+ Internet: jreuter@lykos.oche.de
+*/
+
+/* ----------------------------------------------------------------------- */
+
+#undef SCC_DELAY /* perhaps your ISA bus is a *bit* too fast? */
+#undef SCC_LDELAY 1 /* slow it even a bit more down */
+#undef DONT_CHECK /* don't look if the SCCs you specified are available */
+
+#define MAXSCC 4 /* number of max. supported chips */
+#define BUFSIZE 384 /* must not exceed 4096 */
+#undef DISABLE_ALL_INTS /* use cli()/sti() in ISR instead of */
+ /* enable_irq()/disable_irq() */
+#undef SCC_DEBUG
+
+#define DEFAULT_CLOCK 4915200 /* default pclock if nothing is specified */
+
+/* ----------------------------------------------------------------------- */
+
+#include <linux/module.h>
+#include <linux/config.h>
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
+#include <linux/socket.h>
+
+#include <linux/scc.h>
+#include "z8530.h"
+
+#include <net/ax25.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+#endif
+
+int scc_init(void);
+
+static void t_dwait(unsigned long);
+static void t_txdelay(unsigned long);
+static void t_tail(unsigned long);
+static void t_busy(unsigned long);
+static void t_maxkeyup(unsigned long);
+static void t_idle(unsigned long);
+static void scc_tx_done(struct scc_channel *);
+static void scc_start_tx_timer(struct scc_channel *, void (*)(unsigned long), unsigned long);
+static void scc_start_maxkeyup(struct scc_channel *);
+static void scc_start_defer(struct scc_channel *);
+
+static void z8530_init(void);
+
+static void init_channel(struct scc_channel *scc);
+static void scc_key_trx (struct scc_channel *scc, char tx);
+static void scc_isr(int irq, void *dev_id, struct pt_regs *regs);
+static void scc_init_timer(struct scc_channel *scc);
+
+static int scc_net_setup(struct scc_channel *scc, unsigned char *name);
+static int scc_net_init(struct device *dev);
+static int scc_net_open(struct device *dev);
+static int scc_net_close(struct device *dev);
+static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb);
+static int scc_net_tx(struct sk_buff *skb, struct device *dev);
+static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
+static int scc_net_set_mac_address(struct device *dev, void *addr);
+static int scc_net_rebuild_header(void *buff, struct device *dev, unsigned long raddr, struct sk_buff *skb);
+static int scc_net_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len);
+static struct enet_statistics * scc_net_get_stats(struct device *dev);
+
+static unsigned char *SCC_DriverName = "scc";
+
+static struct irqflags { unsigned char used : 1; } Ivec[16];
+
+static struct scc_channel SCC_Info[2 * MAXSCC]; /* information per channel */
+
+static struct scc_ctrl {
+ io_port chan_A;
+ io_port chan_B;
+ int irq;
+} SCC_ctrl[MAXSCC+1];
+
+static unsigned char Driver_Initialized = 0;
+static int Nchips = 0;
+static io_port Vector_Latch = 0;
+
+
+/* ******************************************************************** */
+/* * Port Access Functions * */
+/* ******************************************************************** */
+
+/* These provide interrupt save 2-step access to the Z8530 registers */
+
+static __inline__ unsigned char
+InReg(io_port port, unsigned char reg)
+{
+ unsigned long flags;
+ unsigned char r;
+
+ save_flags(flags);
+ cli();
+#ifdef SCC_LDELAY
+ Outb(port, reg);
+ udelay(SCC_LDELAY);
+ r=Inb(port);
+ udelay(SCC_LDELAY);
+#else
+ Outb(port, reg);
+ r=Inb(port);
+#endif
+ restore_flags(flags);
+ return r;
+}
+
+static __inline__ void
+OutReg(io_port port, unsigned char reg, unsigned char val)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+#ifdef SCC_LDELAY
+ Outb(port, reg); udelay(SCC_LDELAY);
+ Outb(port, val); udelay(SCC_LDELAY);
+#else
+ Outb(port, reg);
+ Outb(port, val);
+#endif
+ restore_flags(flags);
+}
+
+static __inline__ void
+wr(struct scc_channel *scc, unsigned char reg, unsigned char val)
+{
+ OutReg(scc->ctrl, reg, (scc->wreg[reg] = val));
+}
+
+static __inline__ void
+or(struct scc_channel *scc, unsigned char reg, unsigned char val)
+{
+ OutReg(scc->ctrl, reg, (scc->wreg[reg] |= val));
+}
+
+static __inline__ void
+cl(struct scc_channel *scc, unsigned char reg, unsigned char val)
+{
+ OutReg(scc->ctrl, reg, (scc->wreg[reg] &= ~val));
+}
+
+#ifdef DISABLE_ALL_INTS
+static __inline__ void scc_cli(int irq)
+{ cli(); }
+static __inline__ void scc_sti(int irq)
+{ sti(); }
+#else
+static __inline__ void scc_cli(int irq)
+{ disable_irq(irq); }
+static __inline__ void scc_sti(int irq)
+{ enable_irq(irq); }
+#endif
+
+/* ******************************************************************** */
+/* * Some useful macros * */
+/* ******************************************************************** */
+
+
+static __inline__ void
+scc_lock_dev(struct scc_channel *scc)
+{
+ scc->dev->tbusy = 1;
+}
+
+static __inline__ void
+scc_unlock_dev(struct scc_channel *scc)
+{
+ scc->tx_next_buff = NULL;
+ scc->dev->tbusy = 0;
+}
+
+static __inline__ void
+scc_discard_buffers(struct scc_channel *scc)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ if (scc->tx_buff != NULL)
+ {
+ dev_kfree_skb(scc->tx_buff, FREE_WRITE);
+ scc->tx_buff = NULL;
+ }
+
+ if (scc->tx_next_buff != NULL)
+ {
+ dev_kfree_skb(scc->tx_next_buff, FREE_WRITE);
+ scc->tx_next_buff = NULL;
+ }
+
+ restore_flags(flags);
+}
+
+
+
+/* ******************************************************************** */
+/* * Interrupt Service Routines * */
+/* ******************************************************************** */
+
+
+/* ----> subroutines for the interrupt handlers <---- */
+
+static __inline__ void
+scc_notify(struct scc_channel *scc, int event)
+{
+ struct sk_buff *skb;
+ char *bp;
+
+ if (scc->kiss.fulldup != KISS_DUPLEX_OPTIMA)
+ return;
+
+ skb = dev_alloc_skb(2);
+ if (skb != NULL)
+ {
+ skb->free = 1;
+ bp = skb_put(skb, 2);
+ *bp++ = PARAM_HWEVENT;
+ *bp++ = event;
+ scc_net_rx(scc, skb);
+ } else
+ scc->stat.nospace++;
+}
+
+static __inline__ void
+flush_rx_FIFO(struct scc_channel *scc)
+{
+ int k;
+
+ for (k=0; k<3; k++)
+ Inb(scc->data);
+
+ if(scc->rx_buff != NULL) /* did we receive something? */
+ {
+ scc->stat.rxerrs++; /* then count it as an error */
+ kfree_skb(scc->rx_buff, FREE_READ);
+ scc->rx_buff = NULL;
+ }
+}
+
+
+/* ----> four different interrupt handlers for Tx, Rx, changing of */
+/* DCD/CTS and Rx/Tx errors */
+
+/* Transmitter interrupt handler */
+static __inline__ void
+scc_txint(struct scc_channel *scc)
+{
+ struct sk_buff *skb;
+
+ scc->stat.txints++;
+ skb = scc->tx_buff;
+
+ /* send first octet */
+
+ if (skb == NULL)
+ {
+ skb = scc->tx_next_buff;
+ scc->tx_buff = skb;
+
+ if (skb == NULL)
+ {
+ scc_tx_done(scc);
+ Outb(scc->ctrl, RES_Tx_P);
+ return;
+ }
+
+ if (skb->len == 0) /* Paranoia... */
+ {
+ dev_kfree_skb(skb, FREE_WRITE);
+ scc->tx_buff = NULL;
+ scc_tx_done(scc);
+ Outb(scc->ctrl, RES_Tx_P);
+ return;
+ }
+
+ scc_unlock_dev(scc);
+
+ scc->stat.tx_state = TXS_ACTIVE;
+
+ OutReg(scc->ctrl, R0, RES_Tx_CRC);
+ /* reset CRC generator */
+ or(scc,R10,ABUNDER); /* re-install underrun protection */
+ Outb(scc->data,*skb->data); /* send byte */
+ skb_pull(skb, 1);
+
+ if (!scc->enhanced) /* reset EOM latch */
+ Outb(scc->ctrl,RES_EOM_L);
+ return;
+ }
+
+ /* End Of Frame... */
+
+ if (skb->len == 0)
+ {
+ Outb(scc->ctrl, RES_Tx_P); /* reset pending int */
+ cl(scc, R10, ABUNDER); /* send CRC */
+ dev_kfree_skb(skb, FREE_WRITE);
+ scc->tx_buff = NULL;
+ scc->stat.tx_state = TXS_NEWFRAME; /* next frame... */
+ return;
+ }
+
+ /* send octet */
+
+ Outb(scc->data,*skb->data);
+ skb_pull(skb, 1);
+}
+
+
+/* External/Status interrupt handler */
+static __inline__ void
+scc_exint(struct scc_channel *scc)
+{
+ unsigned char status,changes,chg_and_stat;
+
+ scc->stat.exints++;
+
+ status = InReg(scc->ctrl,R0);
+ changes = status ^ scc->status;
+ chg_and_stat = changes & status;
+
+ /* ABORT: generated whenever DCD drops while receiving */
+
+ if (chg_and_stat & BRK_ABRT) /* Received an ABORT */
+ flush_rx_FIFO(scc);
+
+
+ /* DCD: on = start to receive packet, off = ABORT condition */
+ /* (a successfully received packet generates a special condition int) */
+
+ if(changes & DCD) /* DCD input changed state */
+ {
+ if(status & DCD) /* DCD is now ON */
+ {
+ if (scc->modem.clocksrc != CLK_EXTERNAL)
+ OutReg(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
+
+ or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */
+ } else { /* DCD is now OFF */
+ cl(scc,R3,ENT_HM|RxENABLE); /* disable the receiver */
+ flush_rx_FIFO(scc);
+ }
+
+ if (!scc->kiss.softdcd)
+ scc_notify(scc, (status & DCD)? HWEV_DCD_ON:HWEV_DCD_OFF);
+ }
+
+ /* HUNT: software DCD; on = waiting for SYNC, off = receiving frame */
+
+ if (changes & SYNC_HUNT)
+ {
+ if (scc->kiss.softdcd)
+ scc_notify(scc, (status & SYNC_HUNT)? HWEV_DCD_OFF:HWEV_DCD_ON);
+ else
+ cl(scc,R15,SYNCIE); /* oops, we were too lazy to disable this? */
+ }
+
+#ifdef notdef
+ /* CTS: use external TxDelay (what's that good for?!)
+ * Anyway: If we _could_ use it (BayCom USCC uses CTS for
+ * own purposes) we _should_ use the "autoenable" feature
+ * of the Z8530 and not this interrupt...
+ */
+
+ if (chg_and_stat & CTS) /* CTS is now ON */
+ {
+ if (scc->kiss.txdelay == 0) /* zero TXDELAY = wait for CTS */
+ scc_start_tx_timer(scc, t_txdelay, 0);
+ }
+#endif
+
+ if (scc->stat.tx_state == TXS_ACTIVE && (status & TxEOM))
+ {
+ scc->stat.tx_under++; /* oops, an underrun! count 'em */
+ Outb(scc->ctrl, RES_EXT_INT); /* reset ext/status interrupts */
+
+ if (scc->tx_buff != NULL)
+ {
+ dev_kfree_skb(scc->tx_buff, FREE_WRITE);
+ scc->tx_buff = NULL;
+ }
+
+ or(scc,R10,ABUNDER);
+ scc_start_tx_timer(scc, t_txdelay, 1); /* restart transmission */
+ }
+
+ scc->status = status;
+ Outb(scc->ctrl,RES_EXT_INT);
+}
+
+
+/* Receiver interrupt handler */
+static __inline__ void
+scc_rxint(struct scc_channel *scc)
+{
+ struct sk_buff *skb;
+
+ scc->stat.rxints++;
+
+ if((scc->wreg[5] & RTS) && scc->kiss.fulldup == KISS_DUPLEX_HALF)
+ {
+ Inb(scc->data); /* discard char */
+ or(scc,R3,ENT_HM); /* enter hunt mode for next flag */
+ return;
+ }
+
+ skb = scc->rx_buff;
+
+ if (skb == NULL)
+ {
+ skb = dev_alloc_skb(scc->stat.bufsize);
+ if (skb == NULL)
+ {
+ scc->dev_stat.rx_dropped++;
+ scc->stat.nospace++;
+ Inb(scc->data);
+ or(scc, R3, ENT_HM);
+ return;
+ }
+
+ skb->free = 1;
+ scc->rx_buff = skb;
+
+ *(skb_put(skb, 1)) = 0; /* KISS data */
+ }
+
+ if (skb->len >= scc->stat.bufsize)
+ {
+#ifdef notdef
+ printk(KERN_DEBUG "z8530drv: oops, scc_rxint() received huge frame...\n");
+#endif
+ kfree_skb(skb, FREE_READ);
+ scc->rx_buff = NULL;
+ Inb(scc->data);
+ or(scc, R3, ENT_HM);
+ return;
+ }
+
+ *(skb_put(skb, 1)) = Inb(scc->data);
+}
+
+
+/* Receive Special Condition interrupt handler */
+static __inline__ void
+scc_spint(struct scc_channel *scc)
+{
+ unsigned char status;
+ struct sk_buff *skb;
+
+ scc->stat.spints++;
+
+ status = InReg(scc->ctrl,R1); /* read receiver status */
+
+ Inb(scc->data); /* throw away Rx byte */
+ skb = scc->rx_buff;
+
+ if(status & Rx_OVR) /* receiver overrun */
+ {
+ scc->stat.rx_over++; /* count them */
+ or(scc,R3,ENT_HM); /* enter hunt mode for next flag */
+
+ if (skb != NULL)
+ kfree_skb(skb, FREE_READ);
+ scc->rx_buff = NULL;
+ }
+
+ if(status & END_FR && skb != NULL) /* end of frame */
+ {
+ /* CRC okay, frame ends on 8 bit boundary and received something ? */
+
+ if (!(status & CRC_ERR) && (status & 0xe) == RES8 && skb->len > 0)
+ {
+ /* ignore last received byte (first of the CRC bytes) */
+ skb_trim(skb, skb->len-1);
+ scc_net_rx(scc, skb);
+ scc->rx_buff = NULL;
+ scc->stat.rxframes++;
+ } else { /* a bad frame */
+ kfree_skb(skb, FREE_READ);
+ scc->rx_buff = NULL;
+ scc->stat.rxerrs++;
+ }
+ }
+
+ Outb(scc->ctrl,ERR_RES);
+}
+
+
+/* ----> interrupt service routine for the Z8530 <---- */
+
+static void
+scc_isr_dispatch(struct scc_channel *scc, int vector)
+{
+ switch (vector & VECTOR_MASK)
+ {
+ case TXINT: scc_txint(scc); break;
+ case EXINT: scc_exint(scc); break;
+ case RXINT: scc_rxint(scc); break;
+ case SPINT: scc_spint(scc); break;
+ }
+}
+
+/* If the card has a latch for the interrupt vector (like the PA0HZP card)
+ use it to get the number of the chip that generated the int.
+ If not: poll all defined chips.
+ */
+
+#define SCC_IRQTIMEOUT 30000
+
+static void
+scc_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned char vector;
+ struct scc_channel *scc;
+ struct scc_ctrl *ctrl;
+ int k;
+
+ scc_cli(irq);
+
+ if (Vector_Latch)
+ {
+ for(k=0; k < SCC_IRQTIMEOUT; k++)
+ {
+ Outb(Vector_Latch, 0); /* Generate INTACK */
+
+ /* Read the vector */
+ if((vector=Inb(Vector_Latch)) >= 16 * Nchips) break;
+ if (vector & 0x01) break;
+
+ scc=&SCC_Info[vector >> 3 ^ 0x01];
+ if (!scc->dev) break;
+
+ scc_isr_dispatch(scc, vector);
+
+ OutReg(scc->ctrl,R0,RES_H_IUS); /* Reset Highest IUS */
+ }
+ scc_sti(irq);
+
+ if (k == SCC_IRQTIMEOUT)
+ printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?\n");
+
+ return;
+ }
+
+ /* Find the SCC generating the interrupt by polling all attached SCCs
+ * reading RR3A (the interrupt pending register)
+ */
+
+ ctrl = SCC_ctrl;
+ while (ctrl->chan_A)
+ {
+ if (ctrl->irq != irq)
+ {
+ ctrl++;
+ continue;
+ }
+
+ scc = NULL;
+ for (k = 0; InReg(ctrl->chan_A,R3) && k < SCC_IRQTIMEOUT; k++)
+ {
+ vector=InReg(ctrl->chan_B,R2); /* Read the vector */
+ if (vector & 0x01) break;
+
+ scc = &SCC_Info[vector >> 3 ^ 0x01];
+ if (!scc->dev) break;
+
+ scc_isr_dispatch(scc, vector);
+ }
+
+ if (k == SCC_IRQTIMEOUT)
+ {
+ printk(KERN_WARNING "z8530drv: endless loop in scc_isr()?!\n");
+ break;
+ }
+
+ /* This looks wierd and it is. At least the BayCom USCC doesn't
+ * use the Interrupt Daisy Chain, thus we'll have to start
+ * all over again to be sure not to miss an interrupt from
+ * (any of) the other chip(s)...
+ * Honestly, the situation *is* braindamaged...
+ */
+
+ if (scc != NULL)
+ {
+ OutReg(scc->ctrl,R0,RES_H_IUS);
+ ctrl = SCC_ctrl;
+ } else
+ ctrl++;
+ }
+
+ scc_sti(irq);
+}
+
+
+
+/* ******************************************************************** */
+/* * Init Channel */
+/* ******************************************************************** */
+
+
+/* ----> set SCC channel speed <---- */
+
+static __inline__ void
+set_brg(struct scc_channel *scc, unsigned int tc)
+{
+ cl(scc,R14,BRENABL); /* disable baudrate generator */
+ wr(scc,R12,tc & 255); /* brg rate LOW */
+ wr(scc,R13,tc >> 8); /* brg rate HIGH */
+ or(scc,R14,BRENABL); /* enable baudrate generator */
+}
+
+static __inline__ void
+set_speed(struct scc_channel *scc)
+{
+ disable_irq(scc->irq);
+
+ if (scc->modem.speed > 0) /* paranoia... */
+ set_brg(scc, (unsigned) (scc->clock / (scc->modem.speed * 64)) - 2);
+
+ enable_irq(scc->irq);
+}
+
+
+/* ----> initialize a SCC channel <---- */
+
+static __inline__ void
+init_brg(struct scc_channel *scc)
+{
+ wr(scc, R14, BRSRC); /* BRG source = PCLK */
+ OutReg(scc->ctrl, R14, SSBR|scc->wreg[R14]); /* DPLL source = BRG */
+ OutReg(scc->ctrl, R14, SNRZI|scc->wreg[R14]); /* DPLL NRZI mode */
+}
+
+/*
+ * Initialization according to the Z8530 manual (SGS-Thomson's version):
+ *
+ * 1. Modes and constants
+ *
+ * WR9 11000000 chip reset
+ * WR4 XXXXXXXX Tx/Rx control, async or sync mode
+ * WR1 0XX00X00 select W/REQ (optional)
+ * WR2 XXXXXXXX program interrupt vector
+ * WR3 XXXXXXX0 select Rx control
+ * WR5 XXXX0XXX select Tx control
+ * WR6 XXXXXXXX sync character
+ * WR7 XXXXXXXX sync character
+ * WR9 000X0XXX select interrupt control
+ * WR10 XXXXXXXX miscellaneous control (optional)
+ * WR11 XXXXXXXX clock control
+ * WR12 XXXXXXXX time constant lower byte (optional)
+ * WR13 XXXXXXXX time constant upper byte (optional)
+ * WR14 XXXXXXX0 miscellaneous control
+ * WR14 XXXSSSSS commands (optional)
+ *
+ * 2. Enables
+ *
+ * WR14 000SSSS1 baud rate enable
+ * WR3 SSSSSSS1 Rx enable
+ * WR5 SSSS1SSS Tx enable
+ * WR0 10000000 reset Tx CRG (optional)
+ * WR1 XSS00S00 DMA enable (optional)
+ *
+ * 3. Interrupt status
+ *
+ * WR15 XXXXXXXX enable external/status
+ * WR0 00010000 reset external status
+ * WR0 00010000 reset external status twice
+ * WR1 SSSXXSXX enable Rx, Tx and Ext/status
+ * WR9 000SXSSS enable master interrupt enable
+ *
+ * 1 = set to one, 0 = reset to zero
+ * X = user defined, S = same as previous init
+ *
+ *
+ * Note that the implementation differs in some points from above scheme.
+ *
+ */
+
+static void
+init_channel(struct scc_channel *scc)
+{
+ disable_irq(scc->irq);
+
+ if (scc->tx_t.next) del_timer(&scc->tx_t);
+ if (scc->tx_wdog.next) del_timer(&scc->tx_wdog);
+
+ wr(scc,R4,X1CLK|SDLC); /* *1 clock, SDLC mode */
+ wr(scc,R1,0); /* no W/REQ operation */
+ wr(scc,R3,Rx8|RxCRC_ENAB); /* RX 8 bits/char, CRC, disabled */
+ wr(scc,R5,Tx8|DTR|TxCRC_ENAB); /* TX 8 bits/char, disabled, DTR */
+ wr(scc,R6,0); /* SDLC address zero (not used) */
+ wr(scc,R7,FLAG); /* SDLC flag value */
+ wr(scc,R9,VIS); /* vector includes status */
+ wr(scc,R10,(scc->modem.nrz? NRZ : NRZI)|CRCPS|ABUNDER); /* abort on underrun, preset CRC generator, NRZ(I) */
+ wr(scc,R14, 0);
+
+
+/* set clock sources:
+
+ CLK_DPLL: normal halfduplex operation
+
+ RxClk: use DPLL
+ TxClk: use DPLL
+ TRxC mode DPLL output
+
+ CLK_EXTERNAL: external clocking (G3RUH or DF9IC modem)
+
+ BayCom: others:
+
+ TxClk = pin RTxC TxClk = pin TRxC
+ RxClk = pin TRxC RxClk = pin RTxC
+
+
+ CLK_DIVIDER:
+ RxClk = use DPLL
+ TxClk = pin RTxC
+
+ BayCom: others:
+ pin TRxC = DPLL pin TRxC = BRG
+ (RxClk * 1) (RxClk * 32)
+*/
+
+
+ switch(scc->modem.clocksrc)
+ {
+ case CLK_DPLL:
+ wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP);
+ init_brg(scc);
+ break;
+
+ case CLK_DIVIDER:
+ wr(scc, R11, ((scc->brand & BAYCOM)? TRxCDP : TRxCBR) | RCDPLL|TCRTxCP|TRxCOI);
+ init_brg(scc);
+ break;
+
+ case CLK_EXTERNAL:
+ wr(scc, R11, (scc->brand & BAYCOM)? RCTRxCP|TCRTxCP : RCRTxCP|TCTRxCP);
+ OutReg(scc->ctrl, R14, DISDPLL);
+ break;
+
+ }
+
+ set_speed(scc); /* set baudrate */
+
+ if(scc->enhanced)
+ {
+ or(scc,R15,SHDLCE|FIFOE); /* enable FIFO, SDLC/HDLC Enhancements (From now R7 is R7') */
+ wr(scc,R7,AUTOEOM);
+ }
+
+ if((InReg(scc->ctrl,R0)) & DCD) /* DCD is now ON */
+ {
+ if (scc->modem.clocksrc != CLK_EXTERNAL)
+ or(scc,R14, SEARCH);
+
+ or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */
+ }
+
+ /* enable ABORT, DCD & SYNC/HUNT interrupts */
+
+ wr(scc,R15, BRKIE|TxUIE|DCDIE);
+ if (scc->kiss.softdcd)
+ or(scc,R15, SYNCIE);
+
+ Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */
+ Outb(scc->ctrl,RES_EXT_INT); /* must be done twice */
+
+ or(scc,R1,INT_ALL_Rx|TxINT_ENAB|EXT_INT_ENAB); /* enable interrupts */
+
+ scc->status = InReg(scc->ctrl,R0); /* read initial status */
+
+ or(scc,R9,MIE); /* master interrupt enable */
+
+ scc_init_timer(scc);
+
+ enable_irq(scc->irq);
+}
+
+
+
+
+/* ******************************************************************** */
+/* * SCC timer functions * */
+/* ******************************************************************** */
+
+
+/* ----> scc_key_trx sets the time constant for the baudrate
+ generator and keys the transmitter <---- */
+
+static void
+scc_key_trx(struct scc_channel *scc, char tx)
+{
+ unsigned int time_const;
+
+ if (scc->brand & PRIMUS)
+ Outb(scc->ctrl + 4, scc->option | (tx? 0x80 : 0));
+
+ if (scc->modem.speed < 300)
+ scc->modem.speed = 1200;
+
+ time_const = (unsigned) (scc->clock / (scc->modem.speed * (tx? 2:64))) - 2;
+
+ disable_irq(scc->irq);
+
+ if (tx)
+ {
+ or(scc, R1, TxINT_ENAB); /* t_maxkeyup may have reset these */
+ or(scc, R15, TxUIE);
+ }
+
+ if (scc->modem.clocksrc == CLK_DPLL)
+ { /* force simplex operation */
+ if (tx)
+ {
+ cl(scc, R3, RxENABLE|ENT_HM); /* switch off receiver */
+ cl(scc, R15, DCDIE); /* No DCD changes, please */
+ set_brg(scc, time_const); /* reprogram baudrate generator */
+
+ /* DPLL -> Rx clk, BRG -> Tx CLK, TRxC mode output, TRxC = BRG */
+ wr(scc, R11, RCDPLL|TCBR|TRxCOI|TRxCBR);
+
+ or(scc,R5,RTS|TxENAB); /* set the RTS line and enable TX */
+ } else {
+ cl(scc,R5,RTS|TxENAB);
+
+ set_brg(scc, time_const); /* reprogram baudrate generator */
+
+ /* DPLL -> Rx clk, DPLL -> Tx CLK, TRxC mode output, TRxC = DPLL */
+ wr(scc, R11, RCDPLL|TCDPLL|TRxCOI|TRxCDP);
+
+ or(scc,R3,RxENABLE|ENT_HM);
+ or(scc,R15, DCDIE);
+ }
+ } else {
+ if (tx)
+ {
+ if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
+ {
+ cl(scc, R3, RxENABLE);
+ cl(scc, R15, DCDIE);
+ }
+
+
+ or(scc,R5,RTS|TxENAB); /* enable tx */
+ } else {
+ cl(scc,R5,RTS|TxENAB); /* disable tx */
+
+ if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
+ {
+ or(scc, R3, RxENABLE|ENT_HM);
+ or(scc, R15, DCDIE);
+ }
+ }
+ }
+
+ enable_irq(scc->irq);
+}
+
+
+/* ----> SCC timer interrupt handler and friends. <---- */
+
+static void
+scc_start_tx_timer(struct scc_channel *scc, void (*handler)(unsigned long), unsigned long when)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ if (scc->tx_t.next)
+ del_timer(&scc->tx_t);
+
+ if (when == 0)
+ {
+ handler((unsigned long) scc);
+ } else
+ if (when != TIMER_OFF)
+ {
+ scc->tx_t.data = (unsigned long) scc;
+ scc->tx_t.function = handler;
+ scc->tx_t.expires = jiffies + (when*HZ)/100;
+ add_timer(&scc->tx_t);
+ }
+
+ restore_flags(flags);
+}
+
+static void
+scc_start_defer(struct scc_channel *scc)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ if (scc->tx_wdog.next)
+ del_timer(&scc->tx_wdog);
+
+ if (scc->kiss.maxdefer != 0 && scc->kiss.maxdefer != TIMER_OFF)
+ {
+ scc->tx_wdog.data = (unsigned long) scc;
+ scc->tx_wdog.function = t_busy;
+ scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxdefer;
+ add_timer(&scc->tx_wdog);
+ }
+ restore_flags(flags);
+}
+
+static void
+scc_start_maxkeyup(struct scc_channel *scc)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ if (scc->tx_wdog.next)
+ del_timer(&scc->tx_wdog);
+
+ if (scc->kiss.maxkeyup != 0 && scc->kiss.maxkeyup != TIMER_OFF)
+ {
+ scc->tx_wdog.data = (unsigned long) scc;
+ scc->tx_wdog.function = t_maxkeyup;
+ scc->tx_wdog.expires = jiffies + HZ*scc->kiss.maxkeyup;
+ add_timer(&scc->tx_wdog);
+ }
+
+ restore_flags(flags);
+}
+
+/*
+ * This is called from scc_txint() when there are no more frames to send.
+ * Not exactly a timer function, but it is a close friend of the family...
+ */
+
+static void
+scc_tx_done(struct scc_channel *scc)
+{
+ /*
+ * trx remains keyed in fulldup mode 2 until t_idle expires.
+ */
+
+ switch (scc->kiss.fulldup)
+ {
+ case KISS_DUPLEX_LINK:
+ scc->stat.tx_state = TXS_IDLE2;
+ if (scc->kiss.idletime != TIMER_OFF)
+ scc_start_tx_timer(scc, t_idle, scc->kiss.idletime*100);
+ break;
+ case KISS_DUPLEX_OPTIMA:
+ scc_notify(scc, HWEV_ALL_SENT);
+ break;
+ default:
+ scc->stat.tx_state = TXS_BUSY;
+ scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime);
+ }
+
+ scc_unlock_dev(scc);
+}
+
+
+static unsigned char Rand = 17;
+
+static __inline__ int
+is_grouped(struct scc_channel *scc)
+{
+ int k;
+ struct scc_channel *scc2;
+ unsigned char grp1, grp2;
+
+ grp1 = scc->kiss.group;
+
+ for (k = 0; k < (Nchips * 2); k++)
+ {
+ scc2 = &SCC_Info[k];
+ grp2 = scc2->kiss.group;
+
+ if (scc2 == scc || !(scc2->dev && grp2))
+ continue;
+
+ if ((grp1 & 0x3f) == (grp2 & 0x3f))
+ {
+ if ( (grp1 & TXGROUP) && (scc2->wreg[R5] & RTS) )
+ return 1;
+
+ if ( (grp1 & RXGROUP) && (scc2->status & DCD) )
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* DWAIT and SLOTTIME expired
+ *
+ * fulldup == 0: DCD is active or Rand > P-persistence: start t_busy timer
+ * else key trx and start txdelay
+ * fulldup == 1: key trx and start txdelay
+ * fulldup == 2: mintime expired, reset status or key trx and start txdelay
+ */
+
+static void
+t_dwait(unsigned long channel)
+{
+ struct scc_channel *scc = (struct scc_channel *) channel;
+
+ if (scc->stat.tx_state == TXS_WAIT) /* maxkeyup or idle timeout */
+ {
+ if (scc->tx_next_buff == NULL) /* nothing to send */
+ {
+ scc->stat.tx_state = TXS_IDLE;
+ scc_unlock_dev(scc); /* t_maxkeyup locked it. */
+ return;
+ }
+
+ scc->stat.tx_state = TXS_BUSY;
+ }
+
+ if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
+ {
+ Rand = Rand * 17 + 31;
+
+ if ( (scc->kiss.softdcd? !(scc->status & SYNC_HUNT):(scc->status & DCD)) || (scc->kiss.persist) < Rand || (scc->kiss.group && is_grouped(scc)) )
+ {
+ scc_start_defer(scc);
+ scc_start_tx_timer(scc, t_dwait, scc->kiss.slottime);
+ return ;
+ }
+ }
+
+ if ( !(scc->wreg[R5] & RTS) )
+ {
+ scc_key_trx(scc, TX_ON);
+ scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay);
+ } else {
+ scc_start_tx_timer(scc, t_txdelay, 0);
+ }
+}
+
+
+/* TXDELAY expired
+ *
+ * kick transmission by a fake scc_txint(scc), start 'maxkeyup' watchdog.
+ */
+
+static void
+t_txdelay(unsigned long channel)
+{
+ struct scc_channel *scc = (struct scc_channel *) channel;
+
+ scc_start_maxkeyup(scc);
+
+ if (scc->tx_buff == NULL)
+ {
+ disable_irq(scc->irq);
+ scc_txint(scc);
+ enable_irq(scc->irq);
+ }
+}
+
+
+/* TAILTIME expired
+ *
+ * switch off transmitter. If we were stopped by Maxkeyup restart
+ * transmission after 'mintime' seconds
+ */
+
+static void
+t_tail(unsigned long channel)
+{
+ struct scc_channel *scc = (struct scc_channel *) channel;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ if (scc->tx_wdog.next)
+ del_timer(&scc->tx_wdog);
+
+ scc_key_trx(scc, TX_OFF);
+
+ restore_flags(flags);
+
+ if (scc->stat.tx_state == TXS_TIMEOUT) /* we had a timeout? */
+ {
+ scc->stat.tx_state = TXS_WAIT;
+
+ if (scc->kiss.mintime != TIMER_OFF) /* try it again */
+ scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100);
+ else
+ scc_start_tx_timer(scc, t_dwait, 0);
+ return;
+ }
+
+ scc->stat.tx_state = TXS_IDLE;
+ scc_unlock_dev(scc);
+}
+
+
+/* BUSY timeout
+ *
+ * throw away send buffers if DCD remains active too long.
+ */
+
+static void
+t_busy(unsigned long channel)
+{
+ struct scc_channel *scc = (struct scc_channel *) channel;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ if (scc->tx_t.next)
+ del_timer(&scc->tx_t);
+
+ restore_flags(flags);
+
+ scc_lock_dev(scc);
+
+ scc_discard_buffers(scc);
+
+ scc->stat.txerrs++;
+ scc->stat.tx_state = TXS_IDLE;
+
+ scc_unlock_dev(scc);
+}
+
+/* MAXKEYUP timeout
+ *
+ * this is our watchdog.
+ */
+
+static void
+t_maxkeyup(unsigned long channel)
+{
+ struct scc_channel *scc = (struct scc_channel *) channel;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ /*
+ * let things settle down before we start to
+ * accept new data.
+ */
+
+ scc_lock_dev(scc);
+ scc_discard_buffers(scc);
+
+ if (scc->tx_t.next)
+ del_timer(&scc->tx_t);
+
+ cl(scc, R1, TxINT_ENAB); /* force an ABORT, but don't */
+ cl(scc, R15, TxUIE); /* count it. */
+ OutReg(scc->ctrl, R0, RES_Tx_P);
+
+ restore_flags(flags);
+
+ scc->stat.txerrs++;
+ scc->stat.tx_state = TXS_TIMEOUT;
+ scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime);
+}
+
+/* IDLE timeout
+ *
+ * in fulldup mode 2 it keys down the transmitter after 'idle' seconds
+ * of inactivity. We will not restart transmission before 'mintime'
+ * expires.
+ */
+
+static void
+t_idle(unsigned long channel)
+{
+ struct scc_channel *scc = (struct scc_channel *) channel;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ if (scc->tx_wdog.next)
+ del_timer(&scc->tx_wdog);
+
+ restore_flags(flags);
+
+ scc_key_trx(scc, TX_OFF);
+
+ if (scc->kiss.mintime != TIMER_OFF)
+ scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100);
+ scc->stat.tx_state = TXS_WAIT;
+}
+
+static void
+scc_init_timer(struct scc_channel *scc)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ scc->stat.tx_state = TXS_IDLE;
+
+ restore_flags(flags);
+}
+
+
+/* ******************************************************************** */
+/* * Set/get L1 parameters * */
+/* ******************************************************************** */
+
+
+/*
+ * this will set the "hardware" parameters through KISS commands or ioctl()
+ */
+
+#define CAST(x) (unsigned long)(x)
+
+static unsigned int
+scc_set_param(struct scc_channel *scc, unsigned int cmd, unsigned int arg)
+{
+ int dcd;
+
+ switch (cmd)
+ {
+ case PARAM_TXDELAY: scc->kiss.txdelay=arg; break;
+ case PARAM_PERSIST: scc->kiss.persist=arg; break;
+ case PARAM_SLOTTIME: scc->kiss.slottime=arg; break;
+ case PARAM_TXTAIL: scc->kiss.tailtime=arg; break;
+ case PARAM_FULLDUP: scc->kiss.fulldup=arg; break;
+ case PARAM_DTR: break; /* does someone need this? */
+ case PARAM_GROUP: scc->kiss.group=arg; break;
+ case PARAM_IDLE: scc->kiss.idletime=arg; break;
+ case PARAM_MIN: scc->kiss.mintime=arg; break;
+ case PARAM_MAXKEY: scc->kiss.maxkeyup=arg; break;
+ case PARAM_WAIT: scc->kiss.waittime=arg; break;
+ case PARAM_MAXDEFER: scc->kiss.maxdefer=arg; break;
+ case PARAM_TX: scc->kiss.tx_inhibit=arg; break;
+
+ case PARAM_SOFTDCD:
+ scc->kiss.softdcd=arg;
+ if (arg)
+ or(scc, R15, SYNCIE);
+ else
+ cl(scc, R15, SYNCIE);
+ break;
+
+ case PARAM_SPEED:
+ if (arg < 256)
+ scc->modem.speed=arg*100;
+ else
+ scc->modem.speed=arg;
+
+ if (scc->stat.tx_state == 0) /* only switch baudrate on rx... ;-) */
+ set_speed(scc);
+ break;
+
+ case PARAM_RTS:
+ if ( !(scc->wreg[R5] & RTS) )
+ {
+ if (arg != TX_OFF)
+ scc_key_trx(scc, TX_ON);
+ scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay);
+ } else {
+ if (arg == TX_OFF)
+ {
+ scc->stat.tx_state = TXS_BUSY;
+ scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime);
+ }
+ }
+ break;
+
+ case PARAM_HWEVENT:
+ dcd = (scc->kiss.softdcd? !(scc->status & SYNC_HUNT):(scc->status & DCD));
+ scc_notify(scc, dcd? HWEV_DCD_ON:HWEV_DCD_OFF);
+ break;
+
+ default: return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+
+static unsigned long
+scc_get_param(struct scc_channel *scc, unsigned int cmd)
+{
+ switch (cmd)
+ {
+ case PARAM_TXDELAY: return CAST(scc->kiss.txdelay);
+ case PARAM_PERSIST: return CAST(scc->kiss.persist);
+ case PARAM_SLOTTIME: return CAST(scc->kiss.slottime);
+ case PARAM_TXTAIL: return CAST(scc->kiss.tailtime);
+ case PARAM_FULLDUP: return CAST(scc->kiss.fulldup);
+ case PARAM_SOFTDCD: return CAST(scc->kiss.softdcd);
+ case PARAM_DTR: return CAST((scc->wreg[R5] & DTR)? 1:0);
+ case PARAM_RTS: return CAST((scc->wreg[R5] & RTS)? 1:0);
+ case PARAM_SPEED: return CAST(scc->modem.speed);
+ case PARAM_GROUP: return CAST(scc->kiss.group);
+ case PARAM_IDLE: return CAST(scc->kiss.idletime);
+ case PARAM_MIN: return CAST(scc->kiss.mintime);
+ case PARAM_MAXKEY: return CAST(scc->kiss.maxkeyup);
+ case PARAM_WAIT: return CAST(scc->kiss.waittime);
+ case PARAM_MAXDEFER: return CAST(scc->kiss.maxdefer);
+ case PARAM_TX: return CAST(scc->kiss.tx_inhibit);
+ default: return NO_SUCH_PARAM;
+ }
+
+}
+
+#undef CAST
+#undef SVAL
+
+/* ******************************************************************* */
+/* * Init channel structures, special HW, etc... * */
+/* ******************************************************************* */
+
+/*
+ * Reset the Z8530s and setup special hardware
+ */
+
+static void
+z8530_init(void)
+{
+ struct scc_channel *scc;
+ int chip, k;
+ unsigned long flags;
+ char *flag;
+
+
+ printk(KERN_INFO "Init Z8530 driver: %u channels, IRQ", Nchips*2);
+
+ flag=" ";
+ for (k = 0; k < 16; k++)
+ if (Ivec[k].used)
+ {
+ printk("%s%d", flag, k);
+ flag=",";
+ }
+ printk("\n");
+
+
+ /* reset and pre-init all chips in the system */
+ for (chip = 0; chip < Nchips; chip++)
+ {
+ scc=&SCC_Info[2*chip];
+ if (!scc->ctrl) continue;
+
+ /* Special SCC cards */
+
+ if(scc->brand & EAGLE) /* this is an EAGLE card */
+ Outb(scc->special,0x08); /* enable interrupt on the board */
+
+ if(scc->brand & (PC100 | PRIMUS)) /* this is a PC100/PRIMUS card */
+ Outb(scc->special,scc->option); /* set the MODEM mode (0x22) */
+
+
+ /* Reset and pre-init Z8530 */
+
+ save_flags(flags);
+ cli();
+
+ Outb(scc->ctrl, 0);
+ OutReg(scc->ctrl,R9,FHWRES); /* force hardware reset */
+ udelay(100); /* give it 'a bit' more time than required */
+ wr(scc, R2, chip*16); /* interrupt vector */
+ wr(scc, R9, VIS); /* vector includes status */
+
+ restore_flags(flags);
+ }
+
+
+ Driver_Initialized = 1;
+}
+
+/*
+ * Allocate device structure, err, instance, and register driver
+ */
+
+static int
+scc_net_setup(struct scc_channel *scc, unsigned char *name)
+{
+ unsigned char *buf;
+ struct device *dev;
+
+ if (dev_get(name) != NULL)
+ {
+ printk(KERN_INFO "Z8530drv: device %s already exists.\n", name);
+ return -EEXIST;
+ }
+
+ if ((scc->dev = (struct device *) kmalloc(sizeof(struct device), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+ dev = scc->dev;
+ memset(dev, 0, sizeof(struct device));
+
+ buf = (unsigned char *) kmalloc(10, GFP_KERNEL);
+ strcpy(buf, name);
+
+ dev->priv = (void *) scc;
+ dev->name = buf;
+ dev->init = scc_net_init;
+
+ if (register_netdev(dev) != 0)
+ {
+ kfree(dev);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+
+
+/* ******************************************************************** */
+/* * Network driver methods * */
+/* ******************************************************************** */
+
+static unsigned char ax25_bcast[AX25_ADDR_LEN] =
+{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
+static unsigned char ax25_nocall[AX25_ADDR_LEN] =
+{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
+
+/* ----> Initialize device <----- */
+
+static int
+scc_net_init(struct device *dev)
+{
+ int k;
+
+ for (k=0; k < DEV_NUMBUFFS; k++)
+ skb_queue_head_init(&dev->buffs[k]);
+ dev->tx_queue_len = 16; /* should be enough... */
+
+ dev->open = scc_net_open;
+ dev->stop = scc_net_close;
+
+ dev->hard_start_xmit = scc_net_tx;
+ dev->hard_header = scc_net_header;
+ dev->rebuild_header = scc_net_rebuild_header;
+ dev->set_mac_address = scc_net_set_mac_address;
+ dev->get_stats = scc_net_get_stats;
+ dev->do_ioctl = scc_net_ioctl;
+
+ memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
+ memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN);
+
+ dev->flags = 0;
+ dev->family = AF_INET;
+ dev->pa_addr = 0;
+ dev->pa_brdaddr = 0;
+ dev->pa_mask = 0;
+ dev->pa_alen = 4;
+
+ dev->type = ARPHRD_AX25;
+ dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN;
+ dev->mtu = AX25_DEF_PACLEN;
+ dev->addr_len = AX25_ADDR_LEN;
+
+ return 0;
+}
+
+/* ----> open network device <---- */
+
+static int
+scc_net_open(struct device *dev)
+{
+ struct scc_channel *scc = (struct scc_channel *) dev->priv;
+
+ if (scc == NULL || scc->magic != SCC_MAGIC)
+ return -ENODEV;
+
+ if (!scc->init)
+ return -EINVAL;
+
+ MOD_INC_USE_COUNT;
+
+ scc->tx_buff = scc->tx_next_buff = NULL;
+
+ init_channel(scc);
+
+ dev->tbusy = 0;
+ dev->start = 1;
+
+ return 0;
+}
+
+/* ----> close network device <---- */
+
+static int
+scc_net_close(struct device *dev)
+{
+ struct scc_channel *scc = (struct scc_channel *) dev->priv;
+ unsigned long flags;
+
+ if (scc == NULL || scc->magic != SCC_MAGIC)
+ return -ENODEV;
+
+ MOD_DEC_USE_COUNT;
+
+ save_flags(flags);
+ cli();
+
+ Outb(scc->ctrl,0); /* Make sure pointer is written */
+ wr(scc,R1,0); /* disable interrupts */
+ wr(scc,R3,0);
+
+ del_timer(&scc->tx_t);
+ del_timer(&scc->tx_wdog);
+
+ restore_flags(flags);
+
+ scc_discard_buffers(scc);
+
+ dev->tbusy = 1;
+ dev->start = 0;
+
+ return 0;
+}
+
+/* ----> receive frame, called from scc_rxint() <---- */
+
+static void
+scc_net_rx(struct scc_channel *scc, struct sk_buff *skb)
+{
+ if (skb->len == 0)
+ {
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+
+ scc->dev_stat.rx_packets++;
+
+ skb->dev = scc->dev;
+ skb->protocol = htons(ETH_P_AX25);
+ skb->mac.raw = skb->data;
+
+ netif_rx(skb);
+ return;
+}
+
+/* ----> transmit frame <---- */
+
+static int
+scc_net_tx(struct sk_buff *skb, struct device *dev)
+{
+ struct scc_channel *scc = (struct scc_channel *) dev->priv;
+ unsigned long flags;
+ char kisscmd;
+ long ticks;
+
+ if (dev->tbusy)
+ {
+ ticks = (signed) (jiffies - dev->trans_start);
+
+ if (ticks < scc->kiss.maxdefer*HZ || scc == NULL)
+ return 1;
+
+ /*
+ * Throw away transmission queue.
+ */
+
+ if (scc->tx_wdog.next)
+ del_timer(&scc->tx_wdog);
+ t_busy((unsigned long) scc);
+ dev->trans_start = jiffies;
+ }
+
+ if (skb == NULL)
+ {
+ dev_tint(dev);
+ return 0;
+ }
+
+ if (scc == NULL || scc->magic != SCC_MAGIC)
+ {
+ dev_kfree_skb(skb, FREE_WRITE);
+ return 0;
+ }
+
+ if (skb->len > scc->stat.bufsize || skb->len < 2)
+ {
+ scc->dev_stat.tx_dropped++; /* bogus frame */
+ dev_kfree_skb(skb, FREE_WRITE);
+ return 0;
+ }
+
+ scc->dev_stat.tx_packets++;
+ scc->stat.txframes++;
+
+ kisscmd = *skb->data & 0x1f;
+ skb_pull(skb, 1);
+
+ if (kisscmd)
+ {
+ scc_set_param(scc, kisscmd, *skb->data);
+ dev_kfree_skb(skb, FREE_WRITE);
+ return 0;
+ }
+
+ save_flags(flags);
+ cli();
+
+ scc_lock_dev(scc);
+
+ if (scc->tx_next_buff != NULL)
+ {
+ printk(KERN_ERR "z8530drv: race condition, discarding frame\n");
+ dev_kfree_skb(skb, FREE_WRITE);
+ scc_lock_dev(scc);
+ restore_flags(flags);
+ return 0;
+ }
+
+ dev->trans_start = jiffies;
+ scc->tx_next_buff = skb;
+
+ /*
+ * Start transmission if the trx state is idle or
+ * t_idle hasn't expired yet. Use dwait/persistance/slottime
+ * algorithm for normal halfduplex operation.
+ */
+
+ if(scc->stat.tx_state == TXS_IDLE || scc->stat.tx_state == TXS_IDLE2)
+ {
+ scc->stat.tx_state = TXS_BUSY;
+ if (scc->kiss.fulldup == KISS_DUPLEX_HALF)
+ scc_start_tx_timer(scc, t_dwait, scc->kiss.waittime);
+ else
+ scc_start_tx_timer(scc, t_dwait, 0);
+ }
+
+ restore_flags(flags);
+
+ return 0;
+}
+
+/* ----> ioctl functions <---- */
+
+/*
+ * SIOCSCCCFG - configure driver arg: (struct scc_hw_config *) arg
+ * SIOCSCCINI - initialize driver arg: ---
+ * SIOCSCCCHANINI - initialize channel arg: (struct scc_modem *) arg
+ * SIOCSCCSMEM - set memory arg: (struct scc_mem_config *) arg
+ * SIOCSCCGKISS - get level 1 parameter arg: (struct scc_kiss_cmd *) arg
+ * SIOCSCCSKISS - set level 1 parameter arg: (struct scc_kiss_cmd *) arg
+ * SIOCSCCGSTAT - get driver status arg: (struct scc_stat *) arg
+ */
+
+static int
+scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+ struct scc_kiss_cmd kiss_cmd;
+ struct scc_mem_config memcfg;
+ struct scc_hw_config hwcfg;
+ unsigned char device_name[10];
+ struct scc_channel *scc;
+ int chan;
+ void *arg;
+
+ scc = (struct scc_channel *) dev->priv;
+ if (scc == NULL || scc->magic != SCC_MAGIC)
+ return -EINVAL;
+
+ arg = (void *) ifr->ifr_data;
+
+ if (!Driver_Initialized)
+ {
+ if (cmd == SIOCSCCCFG)
+ {
+ int found = 1;
+
+ if (!suser()) return -EPERM;
+ if (!arg) return -EFAULT;
+
+ if (Nchips >= MAXSCC)
+ return -EINVAL;
+
+ if (copy_from_user(&hwcfg, arg, sizeof(hwcfg)))
+ return -EFAULT;
+
+ if (hwcfg.irq == 2) hwcfg.irq = 9;
+
+ if (!Ivec[hwcfg.irq].used && hwcfg.irq)
+ {
+ if (request_irq(hwcfg.irq, scc_isr, SA_INTERRUPT, "AX.25 SCC", NULL))
+ printk(KERN_WARNING "z8530drv: warning, cannot get IRQ %d\n", hwcfg.irq);
+ else
+ Ivec[hwcfg.irq].used = 1;
+ }
+
+ if (hwcfg.vector_latch)
+ Vector_Latch = hwcfg.vector_latch;
+
+ if (hwcfg.clock == 0)
+ hwcfg.clock = DEFAULT_CLOCK;
+
+#ifndef DONT_CHECK
+ disable_irq(hwcfg.irq);
+
+ check_region(scc->ctrl, 1);
+ Outb(hwcfg.ctrl_a, 0);
+ udelay(5);
+ OutReg(hwcfg.ctrl_a,R13,0x55); /* is this chip really there? */
+ udelay(5);
+
+ if (InReg(hwcfg.ctrl_a,R13) != 0x55)
+ found = 0;
+
+ enable_irq(hwcfg.irq);
+#endif
+
+ if (found)
+ {
+ SCC_Info[2*Nchips ].ctrl = hwcfg.ctrl_a;
+ SCC_Info[2*Nchips ].data = hwcfg.data_a;
+ SCC_Info[2*Nchips ].irq = hwcfg.irq;
+ SCC_Info[2*Nchips+1].ctrl = hwcfg.ctrl_b;
+ SCC_Info[2*Nchips+1].data = hwcfg.data_b;
+ SCC_Info[2*Nchips+1].irq = hwcfg.irq;
+
+ SCC_ctrl[Nchips].chan_A = hwcfg.ctrl_a;
+ SCC_ctrl[Nchips].chan_B = hwcfg.ctrl_b;
+ SCC_ctrl[Nchips].irq = hwcfg.irq;
+ }
+
+
+ for (chan = 0; chan < 2; chan++)
+ {
+ sprintf(device_name, "%s%i", SCC_DriverName, 2*Nchips+chan);
+
+ SCC_Info[2*Nchips+chan].special = hwcfg.special;
+ SCC_Info[2*Nchips+chan].clock = hwcfg.clock;
+ SCC_Info[2*Nchips+chan].brand = hwcfg.brand;
+ SCC_Info[2*Nchips+chan].option = hwcfg.option;
+ SCC_Info[2*Nchips+chan].enhanced = hwcfg.escc;
+
+#ifdef DONT_CHECK
+ printk(KERN_INFO "%s: data port = 0x%3.3x control port = 0x%3.3x\n",
+ device_name,
+ SCC_Info[2*Nchips+chan].data,
+ SCC_Info[2*Nchips+chan].ctrl);
+
+#else
+ printk(KERN_INFO "%s: data port = 0x%3.3lx control port = 0x%3.3lx -- %s\n",
+ device_name,
+ chan? hwcfg.data_b : hwcfg.data_a,
+ chan? hwcfg.ctrl_b : hwcfg.ctrl_a,
+ found? "found" : "missing");
+#endif
+
+ if (found)
+ {
+ request_region(SCC_Info[2*Nchips+chan].ctrl, 1, "scc ctrl");
+ request_region(SCC_Info[2*Nchips+chan].data, 1, "scc data");
+ if (Nchips+chan != 0)
+ scc_net_setup(&SCC_Info[2*Nchips+chan], device_name);
+ }
+ }
+
+ if (found) Nchips++;
+
+ return 0;
+ }
+
+ if (cmd == SIOCSCCINI)
+ {
+ if (!suser())
+ return -EPERM;
+
+ if (Nchips == 0)
+ return -EINVAL;
+
+ z8530_init();
+ return 0;
+ }
+
+ return -EINVAL; /* confuse the user */
+ }
+
+ if (!scc->init)
+ {
+ if (cmd == SIOCSCCCHANINI)
+ {
+ if (!suser()) return -EPERM;
+ if (!arg) return -EINVAL;
+
+ scc->stat.bufsize = BUFSIZE;
+
+ if (copy_from_user(&scc->modem, arg, sizeof(struct scc_modem)))
+ return -EINVAL;
+
+ /* default KISS Params */
+
+ if (scc->modem.speed < 4800)
+ {
+ scc->kiss.txdelay = 36; /* 360 ms */
+ scc->kiss.persist = 42; /* 25% persistence */ /* was 25 */
+ scc->kiss.slottime = 16; /* 160 ms */
+ scc->kiss.tailtime = 4; /* minimal reasonable value */
+ scc->kiss.fulldup = 0; /* CSMA */
+ scc->kiss.waittime = 50; /* 500 ms */
+ scc->kiss.maxkeyup = 10; /* 10 s */
+ scc->kiss.mintime = 3; /* 3 s */
+ scc->kiss.idletime = 30; /* 30 s */
+ scc->kiss.maxdefer = 120; /* 2 min */
+ scc->kiss.softdcd = 0; /* hardware dcd */
+ } else {
+ scc->kiss.txdelay = 10; /* 100 ms */
+ scc->kiss.persist = 64; /* 25% persistence */ /* was 25 */
+ scc->kiss.slottime = 8; /* 160 ms */
+ scc->kiss.tailtime = 1; /* minimal reasonable value */
+ scc->kiss.fulldup = 0; /* CSMA */
+ scc->kiss.waittime = 50; /* 500 ms */
+ scc->kiss.maxkeyup = 7; /* 7 s */
+ scc->kiss.mintime = 3; /* 3 s */
+ scc->kiss.idletime = 30; /* 30 s */
+ scc->kiss.maxdefer = 120; /* 2 min */
+ scc->kiss.softdcd = 0; /* hardware dcd */
+ }
+
+ scc->tx_buff = scc->tx_next_buff = NULL;
+ scc->init = 1;
+
+ return 0;
+ }
+
+ return -EINVAL;
+ }
+
+ switch(cmd)
+ {
+ case SIOCSCCRESERVED:
+ return -ENOIOCTLCMD;
+
+ case SIOCSCCSMEM:
+ if (!suser()) return -EPERM;
+ if (!arg || copy_from_user(&memcfg, arg, sizeof(memcfg)))
+ return -EINVAL;
+ scc->stat.bufsize = memcfg.bufsize;
+ return 0;
+
+ case SIOCSCCGSTAT:
+ if (!arg || copy_to_user(arg, &scc->stat, sizeof(scc->stat)))
+ return -EINVAL;
+ return 0;
+
+ case SIOCSCCGKISS:
+ if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd)))
+ return -EINVAL;
+ kiss_cmd.param = scc_get_param(scc, kiss_cmd.command);
+ if (copy_to_user(arg, &kiss_cmd, sizeof(kiss_cmd)))
+ return -EINVAL;
+ return 0;
+
+ case SIOCSCCSKISS:
+ if (!suser()) return -EPERM;
+ if (!arg || copy_from_user(&kiss_cmd, arg, sizeof(kiss_cmd)))
+ return -EINVAL;
+ return scc_set_param(scc, kiss_cmd.command, kiss_cmd.param);
+
+ default:
+ return -ENOIOCTLCMD;
+
+ }
+
+ return -EINVAL;
+}
+
+/* ----> set interface callsign <---- */
+
+static int
+scc_net_set_mac_address(struct device *dev, void *addr)
+{
+ struct sockaddr *sa = (struct sockaddr *) addr;
+ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+ return 0;
+}
+
+/* ----> rebuild header <---- */
+
+static int
+scc_net_rebuild_header(void *buff, struct device *dev, unsigned long raddr, struct sk_buff *skb)
+{
+ return ax25_rebuild_header(buff, dev, raddr, skb);
+}
+
+/* ----> "hard" header <---- */
+
+static int
+scc_net_header(struct sk_buff *skb, struct device *dev, unsigned short type,
+ void *daddr, void *saddr, unsigned len)
+{
+ return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
+}
+
+/* ----> get statistics <---- */
+
+static struct enet_statistics *
+scc_net_get_stats(struct device *dev)
+{
+ struct scc_channel *scc = (struct scc_channel *) dev->priv;
+
+ if (scc == NULL || scc->magic != SCC_MAGIC)
+ return NULL;
+
+ scc->dev_stat.rx_errors = scc->stat.rxerrs + scc->stat.rx_over;
+ scc->dev_stat.tx_errors = scc->stat.txerrs + scc->stat.tx_under;
+ scc->dev_stat.rx_fifo_errors = scc->stat.rx_over;
+ scc->dev_stat.tx_fifo_errors = scc->stat.tx_under;
+
+ return &scc->dev_stat;
+}
+
+/* ******************************************************************** */
+/* * dump statistics to /proc/net/z8530drv * */
+/* ******************************************************************** */
+
+
+static int
+scc_net_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ struct scc_channel *scc;
+ struct scc_kiss *kiss;
+ struct scc_stat *stat;
+ int len = 0;
+ off_t pos = 0;
+ off_t begin = 0;
+ int k;
+
+ len += sprintf(buffer, "z8530drv-"VERSION"\n");
+
+ if (!Driver_Initialized)
+ {
+ len += sprintf(buffer+len, "not initialized\n");
+ goto done;
+ }
+
+ if (!Nchips)
+ {
+ len += sprintf(buffer+len, "chips missing\n");
+ goto done;
+ }
+
+ for (k = 0; k < Nchips*2; k++)
+ {
+ scc = &SCC_Info[k];
+ stat = &scc->stat;
+ kiss = &scc->kiss;
+
+ if (!scc->init)
+ continue;
+
+ /* dev data ctrl irq clock brand enh vector special option
+ * baud nrz clocksrc softdcd bufsize
+ * rxints txints exints spints
+ * rcvd rxerrs over / xmit txerrs under / nospace bufsize
+ * txd pers slot tail ful wait min maxk idl defr txof grp
+ * W ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
+ * R ## ## XX ## ## ## ## ## XX ## ## ## ## ## ## ##
+ */
+
+ len += sprintf(buffer+len, "%s\t%3.3lx %3.3lx %d %lu %2.2x %d %3.3lx %3.3lx %d\n",
+ scc->dev->name,
+ scc->data, scc->ctrl, scc->irq, scc->clock, scc->brand,
+ scc->enhanced, Vector_Latch, scc->special,
+ scc->option);
+ len += sprintf(buffer+len, "\t%lu %d %d %d %d\n",
+ scc->modem.speed, scc->modem.nrz,
+ scc->modem.clocksrc, kiss->softdcd,
+ stat->bufsize);
+ len += sprintf(buffer+len, "\t%lu %lu %lu %lu\n",
+ stat->rxints, stat->txints, stat->exints, stat->spints);
+ len += sprintf(buffer+len, "\t%lu %lu %d / %lu %lu %d / %d %d\n",
+ stat->rxframes, stat->rxerrs, stat->rx_over,
+ stat->txframes, stat->txerrs, stat->tx_under,
+ stat->nospace, stat->tx_state);
+
+#define K(x) kiss->x
+ len += sprintf(buffer+len, "\t%d %d %d %d %d %d %d %d %d %d %d %d\n",
+ K(txdelay), K(persist), K(slottime), K(tailtime),
+ K(fulldup), K(waittime), K(mintime), K(maxkeyup),
+ K(idletime), K(maxdefer), K(tx_inhibit), K(group));
+#undef K
+#ifdef SCC_DEBUG
+ {
+ int reg;
+
+ len += sprintf(buffer+len, "\tW ");
+ for (reg = 0; reg < 16; reg++)
+ len += sprintf(buffer+len, "%2.2x ", scc->wreg[reg]);
+ len += sprintf(buffer+len, "\n");
+
+ len += sprintf(buffer+len, "\tR %2.2x %2.2x XX ", InReg(scc->ctrl,R0), InReg(scc->ctrl,R1));
+ for (reg = 3; reg < 8; reg++)
+ len += sprintf(buffer+len, "%2.2x ", InReg(scc->ctrl, reg));
+ len += sprintf(buffer+len, "XX ");
+ for (reg = 9; reg < 16; reg++)
+ len += sprintf(buffer+len, "%2.2x ", InReg(scc->ctrl, reg));
+ len += sprintf(buffer+len, "\n");
+ }
+#endif
+ len += sprintf(buffer+len, "\n");
+
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+
+ if (pos > offset + length)
+ break;
+ }
+
+done:
+
+ *start = buffer + (offset - begin);
+ len -= (offset - begin);
+
+ if (len > length) len = length;
+
+ return len;
+}
+
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry scc_proc_dir_entry =
+{
+ PROC_NET_Z8530, 8, "z8530drv", S_IFREG | S_IRUGO, 1, 0, 0, 0,
+ &proc_net_inode_operations, scc_net_get_info
+};
+
+#define scc_net_procfs_init() proc_net_register(&scc_proc_dir_entry);
+#define scc_net_procfs_remove() proc_net_unregister(PROC_NET_Z8530);
+#else
+#define scc_net_procfs_init()
+#define scc_net_procfs_remove()
+#endif
+
+
+/* ******************************************************************** */
+/* * Init SCC driver * */
+/* ******************************************************************** */
+
+int scc_init (void)
+{
+ int chip, chan, k, result;
+ char devname[10];
+
+ printk(KERN_INFO BANNER);
+
+ memset(&SCC_ctrl, 0, sizeof(SCC_ctrl));
+
+ /* pre-init channel information */
+
+ for (chip = 0; chip < MAXSCC; chip++)
+ {
+ memset((char *) &SCC_Info[2*chip ], 0, sizeof(struct scc_channel));
+ memset((char *) &SCC_Info[2*chip+1], 0, sizeof(struct scc_channel));
+
+ for (chan = 0; chan < 2; chan++)
+ SCC_Info[2*chip+chan].magic = SCC_MAGIC;
+ }
+
+ for (k = 0; k < 16; k++) Ivec[k].used = 0;
+
+ sprintf(devname,"%s0", SCC_DriverName);
+
+ result = scc_net_setup(SCC_Info, devname);
+ if (result)
+ {
+ printk(KERN_ERR "z8530drv: cannot initialize module\n");
+ return result;
+ }
+
+ scc_net_procfs_init();
+
+ return 0;
+}
+
+/* ******************************************************************** */
+/* * Module support * */
+/* ******************************************************************** */
+
+
+#ifdef MODULE
+int init_module(void)
+{
+ int result = 0;
+
+ result = scc_init();
+
+ if (result == 0)
+ printk(KERN_INFO "Copyright 1993,1996 Joerg Reuter DL1BKE (jreuter@lykos.tng.oche.de)\n");
+
+ return result;
+}
+
+void cleanup_module(void)
+{
+ long flags;
+ io_port ctrl;
+ int k;
+ struct scc_channel *scc;
+
+ save_flags(flags);
+ cli();
+
+ if (Nchips == 0)
+ unregister_netdev(SCC_Info[0].dev);
+
+ for (k = 0; k < Nchips; k++)
+ if ( (ctrl = SCC_ctrl[k].chan_A) )
+ {
+ Outb(ctrl, 0);
+ OutReg(ctrl,R9,FHWRES); /* force hardware reset */
+ udelay(50);
+ }
+
+ for (k = 0; k < Nchips*2; k++)
+ {
+ scc = &SCC_Info[k];
+ if (scc)
+ {
+ release_region(scc->ctrl, 1);
+ release_region(scc->data, 1);
+ if (scc->dev)
+ {
+ unregister_netdev(scc->dev);
+ kfree(scc->dev);
+ }
+ }
+ }
+
+ for (k=0; k < 16 ; k++)
+ if (Ivec[k].used) free_irq(k, NULL);
+
+ restore_flags(flags);
+
+ scc_net_procfs_remove();
+}
+#endif
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/mm.h>
#include <net/checksum.h>
#include <net/slhc_vj.h>
#include <linux/module.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <stdlib.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
/*
/* Read Register 13 (upper byte of baud rate generator constant) */
/* Read Register 15 (value of WR 15) */
+
+/* 8580/85180/85280 Enhanced SCC register definitions */
+
+/* Write Register 7' (SDLC/HDLC Programmable Enhancements) */
+#define AUTOTXF 0x01 /* Auto Tx Flag */
+#define AUTOEOM 0x02 /* Auto EOM Latch Reset */
+#define AUTORTS 0x04 /* Auto RTS */
+#define TXDNRZI 0x08 /* TxD Pulled High in SDLC NRZI mode */
+#define FASTDTR 0x10 /* Fast DTR/REQ Mode */
+#define CRCCBCR 0x20 /* CRC Check Bytes Completely Received */
+#define EXTRDEN 0x40 /* Extended Read Enabled */
+
+/* Write Register 15 (external/status interrupt control) */
+#define SHDLCE 1 /* SDLC/HDLC Enhancements Enable */
+#define FIFOE 4 /* FIFO Enable */
+
+/* Read Register 6 (frame status FIFO) */
+#define BCLSB 0xff /* LSB of 14 bits count */
+
+/* Read Register 7 (frame status FIFO) */
+#define BCMSB 0x3f /* MSB of 14 bits count */
+#define FDA 0x40 /* FIFO Data Available Status */
+#define FOY 0x80 /* FIFO Overflow Status */
#define BusLogic_DriverVersion "2.0.6"
-#define BusLogic_DriverDate "17 July 1996"
+#define BusLogic_DriverDate "19 October 1996"
#include <linux/module.h>
static inline void BusLogic_Delay(int Seconds)
{
- unsigned long TimeoutJiffies = jiffies + Seconds * HZ;
unsigned long ProcessorFlags;
save_flags(ProcessorFlags);
sti();
- while (jiffies < TimeoutJiffies) barrier();
+ while (--Seconds >= 0) udelay(1000000);
restore_flags(ProcessorFlags);
}
dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI
dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI
dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI
-dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI
dep_tristate 'EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI
dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI
+dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI
dep_tristate 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
dep_tristate 'Generic NCR5380/53c400 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI
if [ "$CONFIG_SCSI_GENERIC_NCR5380" != "n" ]; then
*/
static void NCR5380_print_status (struct Scsi_Host *instance) {
- char pr_bfr[256];
+ static char pr_bfr[512];
char *start;
int len;
*/
#undef SPRINTF
-#define SPRINTF(args...) do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
+#define SPRINTF(args...) do { if(pos < buffer + length-80) pos += sprintf(pos, ## args); } while(0)
static
char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
static
+The BusLogic FlashPoint SCSI host adapters are now supported on Linux 2.0.x.
+See http://www.dandelion.com/Linux/ for the beta test BusLogic driver which
+includes FlashPoint support. The upgrade program described below will remain
+available through the end of 1996.
+
+
+ MYLEX INTRODUCES LINUX OPERATING SYSTEM SUPPORT FOR ITS
+ BUSLOGIC FLASHPOINT LINE OF SCSI HOST ADAPTERS
+
+
+FREMONT, CA, -- October 8, 1996 -- Mylex Corporation has expanded Linux
+operating system support to its BusLogic brand of FlashPoint Ultra SCSI
+host adapters. All of BusLogic's other SCSI host adapters, including the
+MultiMaster line, currently support the Linux operating system. Linux
+drivers and information will be available on October 15th at
+http://www.dandelion.com/Linux/.
+
+"Mylex is committed to supporting the Linux community," says Peter Shambora,
+vice president of marketing for Mylex. "We have supported Linux driver
+development and provided technical support for our host adapters for several
+years, and are pleased to now make our FlashPoint products available to this
+user base."
+
+The Linux Operating System
+
+Linux is a freely-distributed implementation of UNIX for Intel x86, Sun
+SPARC, SGI MIPS, Motorola 68k, Digital Alpha AXP and Motorola PowerPC
+machines. It supports a wide range of software, including the X Window
+System, Emacs, and TCP/IP networking. Further information is available at
+http://www.linux.org and http://www.ssc.com/linux.
+
+FlashPoint Host Adapters
+
+The FlashPoint family of Ultra SCSI host adapters, designed for workstation
+and file server environments, are available in narrow, wide, dual channel,
+and dual channel wide versions. These adapters feature SeqEngine
+automation technology, which minimizes SCSI command overhead and reduces
+the number of interrupts generated to the CPU.
+
+About Mylex
+
+Mylex Corporation (NASDAQ/NM SYMBOL: MYLX), founded in 1983, is a leading
+producer of RAID technology and network management products. The company
+produces high performance disk array (RAID) controllers, and complementary
+computer products for network servers, mass storage systems, workstations
+and system boards. Through its wide range of RAID controllers and its
+BusLogic line of Ultra SCSI host adapter products, Mylex provides enabling
+intelligent I/O technologies that increase network management control,
+enhance CPU utilization, optimize I/O performance, and ensure data security
+and availability. Products are sold globally through a network of OEMs,
+major distributors, VARs, and system integrators. Mylex Corporation is
+headquartered at 34551 Ardenwood Blvd., Fremont, CA.
+
+ ####
+
+Contact:
+
+Peter Shambora
+Vice President of Marketing
+Mylex Corp.
+510/796-6100
+peters@mylex.com
+\f
ANNOUNCEMENT
BusLogic FlashPoint LT/BT-948 Upgrade Program
1 February 1996
+#define EXPERIMENTAL_FLAGS 0
+
/*+M*************************************************************************
* Adaptec AIC7xxx device driver for Linux.
*
p->flags = config->flags;
p->chan_num = config->chan_num;
p->scb_link = &(p->scb_usage);
-#ifdef AIC7XXX_SHARE_SCBS
+#if defined(CONFIG_PCI) && defined(AIC7XXX_SHARE_SCBS)
if ((p->chan_num == 0) && ((p->type == AIC_7873) | (p->type == AIC_7883)))
{
shared_3985_scbs = &(p->scb_usage);
outb(config->scsi_id_b, SCSIID + base);
scsi_conf = inb(SCSICONF + base + 1) & (ENSPCHK | STIMESEL);
outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-#if 1
+#if EXPERIMENTAL_FLAGS
outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
#else
outb(ENSELTIMO, SIMODE1 + base);
outb(config->scsi_id, SCSIID + base);
scsi_conf = inb(SCSICONF + base) & (ENSPCHK | STIMESEL);
outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-#if 1
+#if EXPERIMENTAL_FLAGS
outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
#else
outb(ENSELTIMO, SIMODE1 + base);
* Jagdis who did a lot of testing and found quite a number *
* of bugs during the development. *
************************************************************
- * last change: 96/08/13 OS: Linux 2.0.12 *
+ * last change: 96/10/21 OS: Linux 2.0.23 *
************************************************************/
/* Look in eata_dma.h for configuration and revision information */
sp->EOC = FALSE; /* Clean out this flag */
if (ccb->status == LOCKED || ccb->status == RESET) {
- ccb->status = FREE;
- eata_stat = inb(base + HA_RSTATUS);
- printk("eata_dma: int_handler, reseted command returned,"
- " freeing reseted queueslot\n");
+ printk("eata_dma: int_handler, reseted command pid %ld returned"
+ "\n", cmd->pid);
DBG(DBG_INTR && DBG_DELAY, DELAY(1));
- break;
}
eata_stat = inb(base + HA_RSTATUS);
struct Scsi_Host *sh;
struct eata_ccb *ccb;
struct scatterlist *sl;
+
save_flags(flags);
cli();
+
+#if 0
+ for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
+ if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
+ printk("eata_dma: scsi%d interrupt pending in eata_queue.\n"
+ " Calling interrupt handler.\n", sh->host_no);
+ eata_int_handler(sh->irq, 0, 0);
+ }
+ }
+#endif
queue_counter++;
hd = HD(cmd);
sh = cmd->host;
-#if 1
if (cmd->cmnd[0] == REQUEST_SENSE && cmd->sense_buffer[0] != 0) {
DBG(DBG_REQSENSE, printk(KERN_DEBUG "Tried to REQUEST SENSE\n"));
cmd->result = DID_OK << 16;
done(cmd);
+
return(0);
}
-#endif
/* check for free slot */
for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) {
" reason %x\n", cmd->pid, cmd->target, cmd->lun,
cmd->abort_reason));
- /* Some interrupt controllers seem to loose interrupts */
for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
printk("eata_dma: scsi%d interrupt pending in eata_reset.\n"
eata_int_handler(sh->irq, 0, 0);
}
}
+
if (HD(cmd)->state == RESET) {
printk("eata_reset: exit, already in reset.\n");
restore_flags(flags);
restore_flags(flags);
if (success) {
- DBG(DBG_ABNORM, printk("eata_reset: exit, success.\n"));
+ DBG(DBG_ABNORM, printk("eata_reset: exit, pending.\n"));
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
- return (SCSI_RESET_SUCCESS);
+ return (SCSI_RESET_PENDING);
} else {
DBG(DBG_ABNORM, printk("eata_reset: exit, wakeup.\n"));
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
device->queue_depth = (TYPE_OTHER_QUEUE * factor) / 10;
break;
}
- } else /* ISA forces us to limit the QS because of bounce buffers*/
- device->queue_depth = 2; /* I know this is cruel */
+ } else /* ISA forces us to limit the queue depth because of the
+ * bounce buffer memory overhead. I know this is cruel */
+ device->queue_depth = 2;
/*
* It showed that we need to set an upper limit of commands
*/
if(device->queue_depth > UPPER_DEVICE_QUEUE_LIMIT)
device->queue_depth = UPPER_DEVICE_QUEUE_LIMIT;
+ if(device->queue_depth == 0)
+ device->queue_depth = 1;
printk(KERN_INFO "scsi%d: queue depth for target %d on channel %d "
"set to %d\n", host->host_no, device->id, device->channel,
* mike@i-Connect.Net *
* neuffer@mail.uni-mainz.de *
*********************************************************
-* last change: 96/08/14 *
+* last change: 96/10/14 *
********************************************************/
#ifndef _EATA_DMA_H
#define VER_MAJOR 2
#define VER_MINOR 5
-#define VER_SUB "9a"
+#define VER_SUB "9b"
/************************************************************************
#define SG_SIZE 64
#define SG_SIZE_BIG 252 /* max. 8096 elements, 64k */
-#define UPPER_DEVICE_QUEUE_LIMIT 24 /* The limit we have to set for the
+#define UPPER_DEVICE_QUEUE_LIMIT 64 /* The limit we have to set for the
* device queue to keep the broken
* midlevel SCSI code from producing
* bogus timeouts
#ifdef CONFIG_SCSI_ADVANSYS
ADVANSYS,
#endif
+#ifdef CONFIG_SCSI_EATA_DMA
+ EATA_DMA,
+#endif
+#ifdef CONFIG_SCSI_EATA_PIO
+ EATA_PIO,
+#endif
/* BusLogic must come before aha1542.c */
#ifdef CONFIG_SCSI_BUSLOGIC
BUSLOGIC,
#ifdef CONFIG_SCSI_NCR53C8XX
NCR53C8XX,
#endif
-#ifdef CONFIG_SCSI_EATA_DMA
- EATA_DMA,
-#endif
-#ifdef CONFIG_SCSI_EATA_PIO
- EATA_PIO,
-#endif
#ifdef CONFIG_SCSI_7000FASST
WD7000,
#endif
* add scatter-gather, multiple outstanding request, and other
* enhancements.
*
- * Native multichannel and wide scsi support added
- * by Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
+ * Native multichannel, wide scsi, /proc/scsi and hot plugging
+ * support added by Michael Neuffer <mike@i-connect.net>
*
* Added request_module("scsi_hostadapter") for kerneld:
* (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules)
#include <linux/stat.h>
#include <linux/blk.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <asm/system.h>
#include <asm/irq.h>
*/
{"SONY","CD-ROM CDU-8001","*", BLIST_BORKEN},
{"TEXEL","CD-ROM","1.06", BLIST_BORKEN},
+{"IOMEGA","Io20S *F","*", BLIST_KEY},
{"INSITE","Floptical F*8I","*", BLIST_KEY},
{"INSITE","I325VM","*", BLIST_KEY},
{"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN},
*/
timeout = host->last_reset + MIN_RESET_DELAY;
if (jiffies < timeout) {
- /*
- * NOTE: This may be executed from within an interrupt
- * handler! This is bad, but for now, it'll do. The irq
- * level of the interrupt handler has been masked out by the
- * platform dependent interrupt handling code already, so the
- * sti() here will not cause another call to the SCSI host's
- * interrupt handler (assuming there is one irq-level per
- * host).
- */
- sti();
- while (jiffies < timeout) barrier();
+ int ticks_remaining = timeout - jiffies;
+ /*
+ * NOTE: This may be executed from within an interrupt
+ * handler! This is bad, but for now, it'll do. The irq
+ * level of the interrupt handler has been masked out by the
+ * platform dependent interrupt handling code already, so the
+ * sti() here will not cause another call to the SCSI host's
+ * interrupt handler (assuming there is one irq-level per
+ * host).
+ */
+ sti();
+ while (--ticks_remaining >= 0) udelay(1000000/HZ);
+ host->last_reset = jiffies - MIN_RESET_DELAY;
}
restore_flags(flags);
*/
for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
- if(shpnt->hostt == tpnt) scan_scsis(shpnt,0,0,0,0);
+ if(shpnt->hostt == tpnt) {
+ scan_scsis(shpnt,0,0,0,0);
+ if (shpnt->select_queue_depths != NULL)
+ (shpnt->select_queue_depths)(shpnt, scsi_devices);
+ }
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
#include <linux/module.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/errno.h>
if (flag++ == 0)
SCpnt = allocate_device(&CURRENT,
- rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0);
+ rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0);
else SCpnt = NULL;
/*
cli();
req = CURRENT;
while(req){
- SCpnt = request_queueable(req, rscsi_disks[DEVICE_NR(req->rq_dev)].device);
+ SCpnt = request_queueable(req,
+ rscsi_disks[DEVICE_NR(req->rq_dev)].device);
if(SCpnt) break;
req1 = req;
req = req->next;
#include <linux/hdreg.h>
#include <linux/errno.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/blk.h>
#include "scsi.h"
return SCSI_RESET_WAKEUP;
}
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "sd.h"
#include <scsi/scsi_ioctl.h>
#include <linux/ioctl.h>
#include <linux/fcntl.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/blk.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/fs.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/string.h>
Copyright 1992 - 1996 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Tue Oct 1 22:53:51 1996 by makisara@kai.makisara.fi
+ Last modified: Tue Oct 22 20:59:52 1996 by root@kai.makisara.fi
Some small formal changes - aeb, 950809
*/
#include <linux/mtio.h>
#include <linux/ioctl.h>
#include <linux/fcntl.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/dma.h>
#include <asm/system.h>
\f
/* Write command */
- static int
-st_write(struct inode * inode, struct file * filp, const char * buf, int count)
+ static long
+st_write(struct inode * inode, struct file * filp, const char * buf,
+ unsigned long count)
{
- int total, do_count, blks, retval, transfer;
+ long total;
+ int do_count, blks, retval, transfer;
int write_threshold;
int doing_write = 0;
static unsigned char cmd[10];
\f
/* Read command */
- static int
-st_read(struct inode * inode, struct file * filp, char * buf, int count)
+ static long
+st_read(struct inode * inode, struct file * filp, char * buf, unsigned long count)
{
- int total;
+ long total;
int transfer, blks, bytes;
static unsigned char cmd[10];
Scsi_Cmnd * SCpnt = NULL;
(STp->buffer)->buffer_bytes = (blks - transfer) * STp->block_size;
#if DEBUG
if (debugging)
- printk(ST_DEB_MSG "st%d: ILI but enough data received %d %d.\n",
+ printk(ST_DEB_MSG "st%d: ILI but enough data received %ld %d.\n",
dev, count - total, (STp->buffer)->buffer_bytes);
#endif
if (count - total > (STp->buffer)->buffer_bytes)
#if DEBUG
if (debugging)
printk(ST_DEB_MSG
- "st%d: EOF detected (%d bytes read, transferred %d bytes).\n",
+ "st%d: EOF detected (%d bytes read, transferred %ld bytes).\n",
dev, (STp->buffer)->buffer_bytes, total);
#endif
}
return (-EBUSY);
STp->drv_block = (STp->mt_status)->mt_fileno = (-1);
+ STp->eof = ST_NOEOF;
if ((STp->buffer)->last_result_fatal != 0) {
result = (-EIO);
if (STp->can_partitions &&
+++ /dev/null
-audio.o
-dmabuf.o
-opl3.o
-sequencer.o
-midibuf.o
-sb_card.o
-pas2_card.o
-adlib_card.o
-pas2_pcm.o
-pas2_mixer.o
-pas2_midi.o
-gus_card.o
-gus_wave.o
-mpu401.o
-gus_midi.o
-gus_vol.o
-patmgr.o
-sb_mixer.o
-sb_common.o
-midi_synth.o
-uart6850.o
-uart401.o
-sound_timer.o
-sb_midi.o
-sb_audio.o
-sys_timer.o
-ics2101.o
-ad1848.o
-pss.o
-sscape.o
-trix.o
-aedsp16.o
-mad16.o
-cs4232.o
-maui.o
OBJS := $(OBJS) dmabuf.o
endif
-ifdef CONFIG_GUS
+ifdef CONFIG_GUSHW
OBJS := $(OBJS) gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
endif
OBJS := $(OBJS) sound_timer.o
endif
-ifdef CONFIG_SSCAPE
+ifdef CONFIG_SSCAPEHW
OBJS := $(OBJS) sscape.o
endif
ifdef CONFIG_UART401
OBJS := $(OBJS) uart401.o
endif
+
-3.5.5-beta1
-0x030504
+3.7-beta6
+0x030701
-Changelog for version 3.5.4
----------------------------
+Changelog for version 3.7-beta5
+-------------------------------
+
+Since 3.5
+- Changes almost everywhere.
+- Support for OPTi 82C924 based soundcards.
Since 3.5.4-beta8
- Fixed a bug in handling of non-fragment sized writes in 16 bit/stereo mode
if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER
+ bool 'AWE32 synth' CONFIG_AWE32_SYNTH
fi
# Sound driver configuration
#
#--------
-# There is another config script which is compatible with rest of
+# There is another confic script which is compatible with rest of
# the kernel. It can be activated by running 'make mkscript' in this
# directory. Please note that this is an _experimental_ feature which
-# doesn't work with all cards (PSS, SM Wave, AudioTrix Pro, Maui).
+# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui).
#--------
#
$MAKE -C drivers/sound config || exit 1
if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER
+ bool 'AWE32 synth' CONFIG_AWE32_SYNTH
fi
ifeq (.defines,$(wildcard .defines))
include .defines
include .objects
-else
-OBJS = `cat .object_files`
endif
ifndef TOPDIR
clean:
rm -f core core.* *.o *.a tmp_make *~ x y z *%
- rm -f configure sound_stub.c objects/*.o
+ rm -f configure
cd lowlevel;make clean
indent:
local.h:
$(MAKE) clean
- $(MAKE) setup-$(TARGET_OS)
+ $(MAKE) setup
$(MAKE) oldconfig
$(MAKE) dep
@echo
@echo
config: configure
- @$(MAKE) setup-$(TARGET_OS)
+ @$(MAKE) setup
@./configure > local.h
@echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h
@echo \#define SOUND_CONFIG_BY \"`whoami`\" >> local.h
# @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null
@echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h
-oldconfig: setup-$(TARGET_OS) configure
+oldconfig: setup configure
@./configure -o > local.h
@echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h
@echo \#define SOUND_CONFIG_BY \"`whoami`\" >> local.h
# @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null
@echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h
-kernelconfig: setup-$(TARGET_OS)
+kernelconfig: setup
rm -f configure
$(HOSTCC) -o configure configure.c
./configure fixedlocal > local.h
# @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null
@echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h
-mkscript: setup-$(TARGET_OS)
+mkscript: setup
rm -f configure
$(HOSTCC) -o configure configure.c
./configure script > Config.in
@cat .blurb
dep:
- $(CPP) -M *.c > .depend
+ $(CPP) -M $(CFLAGS) -I. *.c > .depend
-setup-linux:
+setup:
@echo Compiling Sound Driver v $(VERSION) for Linux
sound.o: local.h $(FIXEDOBJS) sound.a
lowlevel/lowlevel.o: dummy
cd lowlevel;make
+contrib:
+ cd lowlevel;make clean;make module CFLAGS="$(CFLAGS)"
+
ifdef USE_DEPEND
#
# include a dependency file if one exists
-USS Lite version 3.5.4 release notes
-------------------------------------
+OSS Lite version 3.7-beta release notes
+---------------------------------------
Most up to date information about this driver is available from
-http://www.4front-tech.com/usslite or http://personal.eunet.fi/pp/voxware
+http://www.4front-tech.com/ossfree or http://personal.eunet.fi/pp/voxware
(European mirror).
check http://www.4front-tech.com/pguide for more info.
====================================================
-- THIS VERSION ____REQUIRES____ Linux 1.3.70 OR LATER.
+- THIS VERSION ____REQUIRES____ Linux 2.1.5 OR LATER.
====================================================
-It's very likely that this driver version is incompatible with
-Linux versions later than 2.0.x.
-
Packages "snd-util-3.5.tar.gz" and "snd-data-0.1.tar.Z"
contain useful utilities to be used with this driver.
-See http://www.4front-tech.com/usslite/getting.html for
+See http://www.4front-tech.com/ossfree/getting.html for
download instructions.
If you are looking for the installation instructions, please
See Readme.cards.
-Please check http://www.4front-tech.com/usslite if you don't find
+Please check http://www.4front-tech.com/ossfree if you don't find
your soundcard there.
Contributors
Gregor Hoffleit Mozart support (initial version)
Riccardo Facchetti Audio Excel DSP 16 (aedsp16) support
James Hightower Spotting a tiny but important bug in CS423x support.
+ Denis Sablic OPTi 82C924 spesific enhancements (non PnP mode)
+ Tim MacKenzie Full duplex support for OPTi 82C930.
Please look at lowlevel/README for more contributors.
=========================
Read the sound HOWTO (sunsite.unc.edu:/pub/Linux/docs/...?).
-Also look at the home page (http://www.4front-tech.com/usslite). It may
+Also look at the home page (http://www.4front-tech.com/ossfree). It may
contain info about some recent bug fixes.
It's likely that you have some problems when trying to use the sound driver
Hannu Savolainen
hannu@voxware.pp.fi, hannu@4front-tech.com
-(Please check http://www.4front-tech.com/usslite before mailing me).
+(Please check http://www.4front-tech.com/ossfree before mailing me).
Snail mail: Hannu Savolainen
Hiekkalaiturintie 3 A 8
-Information about Audio Excel DSP 16 can be found in the source
+Informations about Audio Excel DSP 16 can be found in the source
file aedsp16.c
Please, read the head of the source before using it. It contain useful
-information.
+informations.
Riccardo
-Configuring version 3.5.4 (for Linux) with some most common soundcards
-======================================================================
+Configuring version 3.7 (for Linux) with some most common soundcards
+====================================================================
+
+This document describes configuring soundcards with freeware version of
+Open Sound Systems (OSS/Free). Information about the commercial version
+(OSS/Linux) and it's configuration is available from
+http://www.4front-tech.com/linux.html. Information presented here is
+not valid for OSS/Linux.
IMPORTANT! This document covers only cards that were "known" when
this driver version was released. Please look at
- http://www.4front-tech.com/usslite for info about
+ http://www.4front-tech.com/ossfree for info about
cards introduced recently.
The following covers mainly the "old" configuration
Cards that are not (fully) supported by this driver
---------------------------------------------------
-There are many soundcards which don't work with this driver
-version (v3.5). Support for some of them is expected to be
-available during/after summer 1996 (in version 3.6). Please check
-http://www.4front-tech.com/usslite for latest news. Please don't
-mail me and ask about these cards. The unsupported cards are:
-
- - All PnP soundcards (SB PnP, GUS PnP, Soundscape PnP etc.)
- Schedule for availability of PnP soundcard support in
- USS/Lite depends on progress made by kernel PnP team
- (probably in Linux 2.1.xx versions). With Linux 2.0.x
- versions there are two ways to get PnP soundcards to work:
- - Use isapnptools, DOS, Win95 or PnP aware BIOS to wake up the
- card before starting the sound driver. See "Configuring PnP
- soundcards" below for some hints.
- - Support for SB PnP and GUS PnP is present in USS/Linux (the
- commercial version of this driver).
- - Mwave soundcards and motherboards
- (Version 3.6 or 3.7. Depends on how fast I get
- suitable documents for Mwave).
- - Emu8k (SB 32/AWE)
- (Probably not _before_ summer 97. I know the unofficial
- AWE programmers guide so don't send me more copies of it).
- - Diamond Edge 3D
- (ASAP. In practice this may take relatively long time).
- - Compaq Deskpro
- (Version 3.5.4-beta6 (already released))
- - Sound Galaxy Washington/Waverider
- (Audio features already in USS/Linux (USS/Lite soon).
- Can't promise the waverider synth since
- availability of chip specs is uncertain).
- - Yamaha OPL4 (on cards having _RAM_ for samples)
- (Late 96?. Works as OPL3 with current driver versions)
+See http://www.4front-tech.com/ossfree for information about soundcards
+to be supported in future.
How to use sound without recompiling kernel and/or sound driver
---------------------------------------------------------------
There is commercial sound driver which should be released during Apr 96.
It comes in precompiled form and doesn't require recompiling of kernel. See
-http://www.4Front-tech.com/uss.html for more info.
+http://www.4Front-tech.com/oss.html for more info.
Configuring PnP cards
---------------------
available for it (see information about CS4232 later in this document).
PnP soundcards (as well as most other PnP ISA cards) are not supported
-by version 3.5 of this driver (Linux 1.3.xx and Linux 2.0.x). Proper
-support for them should be released during spring 96
-(see http://www.4front-tech.com/usslite for latest info).
+by this version of the driver . Proper
+support for them should be released during spring 97 once kernel level
+PnP support is available.
There is a method to get most of the PnP cards to work. The basic method
is the following:
Some machines have BIOS utility for setting PnP resources. This is a good
way to configure some cards. In this case you don't need to boot DOS/Win95
prior starting Linux.
+
Another way to initialize PnP cards without DOS/Win95 is a Linux based
PnP isolation tool. When writing this there is a pre alpha test version
of such tool available from ftp://ftp.demon.co.uk/pub/unix/linux/utils. The
solution which may be incompatible with future kernel versions having proper
support for PnP cards. There are bugs in setting DMA channels in earlier
versions of isapnptools so at least version 1.6 is required with soundcards.
-You can find latest version of isapnptools from
-ftp://ftp.demon.co.uk/pub/unix/linux/utils/
-These two methods don't work with GUS PnP which requires some additional
-initialization (cards DOS/Win95 driver does it).
+Yet another way to use PnP cards is to use (commercial) OSS/Linux drivers.
+See http://www.4front-tech.com/linux.html for more info.
Read this before trying to configure the driver
-----------------------------------------------
SB 1.0 to 2.0
SB Pro
SB 16
- NOTE! The ASP chip and the EMU synth of AWE32 are not supported
- since their manufacturer doesn't release information about
- the card. However, both SB16ASP and AWE32 work with
- the driver just like a SB16. Also see the comment about some
- unsupported cards at the end of this file.
- (The OPL3 FM chip of SB32/AWE works but you cannot hear it).
+ SB32/AWE
+ Configure SB32/AWE just like SB16. See lowlevel/README.awe
+ for information about using the wave table synth.
SB16 compatible cards by other manufacturers than Creative.
- You have been fooled since there are no SB16 compatible
+ You have been fooled since there are _no_ SB16 compatible
cards on the market (Feb 96). It's likely that your card
is compatible just with SB Pro but there is also a non-SB-
compatible 16 bit mode. Usually it's MSS/WSS but it could also
- be a proprietary one like MV Jazz16 or ESS ES688.
+ be a proprietary one like MV Jazz16 or ESS ES688. OPTi
+ MAD16 chips are very common in so called "SB 16 bit cards".
+ "Supposed to be SB compatible" cards.
+ Forget the SB compatibility and check for other alternatives
+ first. The only cards that work with the SB driver in
+ Linux have been made by Creative Technology (there is at least
+ one chip on the card with "CREATIVE" printed on it). The
+ only other SB compatible chips are ESS and Jazz16 chips
+ (maybe ALSxxx chips too but they propably don't work).
+
+ Practically all soundcards have some kind of SB emulation mode
+ in addition to their native (16 bit) mode. In most cases this
+ (8 bit only) SB compatible mode doesn't work with Linux. However
+ in most cases the native 16 bit mode is supported by Linux.
Gravis Ultrasound (GUS)
GUS
GUS + the 16 bit option
GUS MAX
GUS ACE (No MIDI port and audio recording)
- GUS PnP (Partially supported)
+ GUS PnP (in GUS MAX compatible mode)
MPU-401 and compatibles
The driver works both with the full (intelligent mode) MPU-401
NOTE! The new PnP SoundScape is not supported yet.
MAD16 and Mozart based cards
- The Mozart (OAK OTI-601), MAD16 (OPTi 82C928), MAD16 Pro (OPTi 82C929)
- and OPTi 82C930 interface
+ The Mozart (OAK OTI-601), MAD16 (OPTi 82C928), MAD16 Pro (OPTi 82C929),
+ OPTi 82C924 (non PnP mode) and OPTi 82C930 interface
chips are used in many different soundcards, including some
cards by Reveal miro and Turtle Beach (Tropez). The purpose of these
chips is to connect other audio components to the PC bus. The
Audio Excel DSP16
Support for this card was written by Riccardo Faccetti
- (riccardo@cdc8g5.cdc.polimi.it). See aedsp16.c for more info.
- (This driver is not functional in version 3.5 of this driver. A
- patch should be made available during April 96 (sunsite.unc.edu)).
+ (riccardo@cdc8g5.cdc.polimi.it). The AEDSP16 driver included in
+ this source distribution is not fully functional. A patch is
+ available from sunsite.unc.edu/pub/Linux/kernel/sound.
Crystal CS4232 based cards such as AcerMagic S23, TB Tropez _Plus_ and
many PC motherboards (Compaq, HP, Intel, ...)
CS4232 is a PnP multimedia chip which contains a CS3231A codec,
SB and MPU401 emulations. There is support for OPL3 too.
- This is a temporary driver which uses the chip in non PnP mode
- (The final driver should be included in version 3.6 of the driver).
Unfortunately the MPU401 mode doesn't work (I don't know how to
initialize it).
- Answer 'y' if you have the AudioTrix Pro.
"Support for MAD16 and/or Mozart based cards",
- Answer y if your card has a Mozart (OAK OTI-601) or MAD16
- (OPTi 82C928, 82C929 or 82C930) audio interface chip. These chips are
+ (OPTi 82C928, 82C929, 82C924 or 82C930) audio interface chip.
+ These chips are
currently quite common so it's possible that many no-name cards
have one of them. In addition the MAD16 chip is used in some
cards made by known manufacturers such as Turtle Beach (Tropez),
- This enables TB Maui specific initialization. Works with TB Maui
and TB Tropez (may not work with Tropez Plus).
- "Audio Excel DSP 16 initialization support",
- - Don't know much about this card. Look at aedsp16.c for more info.
Then the configuration program asks some y/n questions about the higher
level services. It's recommended to answer 'y' to each of these questions.
Answer 'n' only if you know you will not need the option.
- "/dev/dsp and /dev/audio supports (usually required)",
- - Answering 'n' disables /dev/dsp and /dev/audio. Answer 'y'.
"MIDI interface support",
- Answering 'n' disables /dev/midi## devices and access to any
MIDI ports using /dev/sequencer and /dev/music. This option
Ensoniq SoundScape
------------------
-NOTE! The new PnP SoundScape is not supported yet.
+NOTE! The new PnP SoundScape is not supported yet. Soundscape compatible
+ cards made by Reveal don't work with Linux. They use older revision
+ of the Soundscape chipset which is not fully compatible with
+ newer cards made by Ensoniq.
The SoundScape driver handles initialization of MSS and MPU supports
itself so you don't need to enable other drivers than SoundScape
!!!!! purposes. It WAS required to change /dev/dsp (a symlink) to !!!!
!!!!! point to /dev/dsp1. !!!!
!!!!! !!!!
-!!!!! This is not required with USS versions 3.5-beta6 and later !!!!
+!!!!! This is not required with OSS versions 3.5-beta6 and later !!!!
!!!!! since there is now just one audio device file. Please !!!!
!!!!! change /dev/dsp to point back to /dev/dsp0 if you are !!!!
!!!!! upgrading from an earlier driver version using !!!!
soundscape.co0. New Soundscape revisions such as Elite and PnP use
code files with higher numbers (.co2, .co3, etc.).
+NOTE! Ensoniq Soundscape VIVO is not compatible with other Soundscape cards.
+ Currently it's possible to use it in Linux only with OSS/Linux
+ drivers.
+
Check /var/adm/messages after running ssinit. The driver prints
the board version after downloading the microcode file. That version
number must match the number in the name of the microcode file (extension).
can be enabled by configuring the card to use two DMA channels. Possible
DMA channel pairs are: 0&1, 1&0 and 3&0.
+NOTE! Cards having an OPTi 82C924 chip work with OSS/Free only in
+non-PnP mode (usually jumper selectable). The PnP mode is supported only
+by OSS/Linux.
+
MV Jazz (ProSonic)
------------------
for all of the settings. Configure driver for MSS, MPU, SB/SB Pro and OPL3
supports with these cards.
-The config program asks if you want support for the mixer of
-SG NX Pro. Answer 'y' to these questions if you have one of the above 8 or
-16 bit Aztech cards.
-
There are some new Sound Galaxies in the market. I have no experience with
them so read the card's manual carefully.
to all low level drivers and be tested too, maybe with multiple
operating systems). For this reason I have made a decision to not support
obsolete cards. It's possible that someone else makes a separately
-distributed driver (diffs) for the card. Version v3.6 will be much more
-modular so making separately distributed drivers will be easier with it.
-(The bad news is that v3.6 will not be available before summer -96).
+distributed driver (diffs) for the card.
Writing a driver for a new card is not possible if there are no
programming information available about the card. If you don't
find your new card from this file, look from the home page
-(http://www.4front-tech.com/usslite). Then please contact
+(http://www.4front-tech.com/ossfree). Then please contact
manufacturer of the card and ask if they have (or are willing to)
released technical details of the card. Do this before contacting me. I
can only answer 'no' if there are no programming information available.
products to public or at least their require signing a NDA. It's not
possible to implement a freeware driver for them. However it's possible
that support for such cards become available in the commercial version
-of this driver (see http://www.4Front-tech.com/uss.html for more info).
+of this driver (see http://www.4Front-tech.com/oss.html for more info).
There are some common audio chipsets that are not supported yet. For example
Sierra Aria and IBM Mwave. It's possible that these architectures
get some support in future but I can't make any promises. Just look
-at the home page (http://www.4front-tech.com/usslite/new_cards.html)
+at the home page (http://www.4front-tech.com/ossfree/new_cards.html)
for latest info.
Information about unsupported soundcards and chipsets is welcome as well
hannu@voxware.pp.fi
Personal home page: http://personal.eunet.fi/pp/voxware/hannu.html
-www home page of USS/Lite: http://www.4front-tech.com/usslite
+www home page of OSS/Free: http://www.4front-tech.com/ossfree
European/Finnish mirror: http://personal.eunet.fi/pp/voxware
-www home page of commercial
-Open Sound System drivers: http://www.4front-tech.com/uss.html
+www home page of commercial OSS
+(Open Sound System) drivers: http://www.4front-tech.com/oss.html
check for possible boot (insmod) time error messages in /var/adm/messages.
- Other messages or problems
-Please check http://www.4front-tech.com/usslite for more info.
+Please check http://www.4front-tech.com/osslite for more info.
Hannu Savolainen
hannu@voxware.pp.fi
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
{
int base;
int irq;
+ int dma1, dma2;
int dual_dma; /* 1, when two DMA channels allocated */
unsigned char MCE_bit;
unsigned char saved_regs[16];
int channels;
int audio_format;
unsigned char format_bits;
+ int audio_flags;
int xfer_count;
int audio_mode;
/* Mixer parameters */
int recmask;
- int supported_devices;
- int supported_rec_devices;
- unsigned short levels[32];
+ int supported_devices, orig_devices;
+ int supported_rec_devices, orig_rec_devices;
+ int *levels;
+ short mixer_reroute[32];
int dev_no;
volatile unsigned long timer_ticks;
int timer_running;
int irq_ok;
- int *osp;
+ mixer_ents *mix_devices;
}
ad1848_info;
{
0,
AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
- AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM,
- AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM,
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, /* AD1845 */
- AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM,
- AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM,
- AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
+ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM
};
static ad1848_info dev_info[MAX_AUDIO_DEV];
save_flags (flags);
cli ();
- outb ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
+ outb (((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr (devc));
x = inb (io_Indexed_Data (devc));
/* printk("(%02x<-%02x) ", reg|devc->MCE_bit, x); */
restore_flags (flags);
save_flags (flags);
cli ();
- outb ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
- outb ((unsigned char) (data & 0xff), io_Indexed_Data (devc));
+ outb (((unsigned char) (reg & 0xff) | devc->MCE_bit), io_Index_Addr (devc));
+ outb (((unsigned char) (data & 0xff)), io_Indexed_Data (devc));
/* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */
restore_flags (flags);
}
/*
* Let's have some delay
*/
+
for (i = 0; i < 1000; i++)
inb (devc->base);
}
inb (devc->base);
/*
- * Restore back old volume registers (unmute)
+ * Restore back old volume registers (unmute)
*/
for (i = 6; i < 8; i++)
{
return;
}
- outb (devc->MCE_bit, io_Index_Addr (devc));
+ outb ((devc->MCE_bit), io_Index_Addr (devc));
restore_flags (flags);
}
devc->MCE_bit = 0x00;
prev = inb (io_Index_Addr (devc));
- outb (0x00, io_Index_Addr (devc)); /* Clear the MCE bit */
+ outb ((0x00), io_Index_Addr (devc)); /* Clear the MCE bit */
if ((prev & 0x40) == 0) /* Not in MCE mode */
{
return;
}
- outb (0x00, io_Index_Addr (devc)); /* Clear the MCE bit */
+ outb ((0x00), io_Index_Addr (devc)); /* Clear the MCE bit */
wait_for_calibration (devc);
restore_flags (flags);
}
mask &= devc->supported_rec_devices;
+ /* Rename the mixer bits if necessary */
+ for (i = 0; i < 32; i++)
+ if (devc->mixer_reroute[i] != i)
+ if (mask & (1 << i))
+ {
+ mask &= ~(1 << i);
+ mask |= (1 << devc->mixer_reroute[i]);
+ }
+
n = 0;
for (i = 0; i < 32; i++) /* Count selected device bits */
if (mask & (1 << i))
ad_write (devc, 0, (ad_read (devc, 0) & 0x3f) | recdev);
ad_write (devc, 1, (ad_read (devc, 1) & 0x3f) | recdev);
+ /* Rename the mixer bits back if necessary */
+ for (i = 0; i < 32; i++)
+ if (devc->mixer_reroute[i] != i)
+ if (mask & (1 << devc->mixer_reroute[i]))
+ {
+ mask &= ~(1 << devc->mixer_reroute[i]);
+ mask |= (1 << i);
+ }
+
devc->recmask = mask;
return mask;
}
static void
-change_bits (unsigned char *regval, int dev, int chn, int newval)
+change_bits (ad1848_info * devc, unsigned char *regval, int dev, int chn, int newval)
{
unsigned char mask;
int shift;
- if (mix_devices[dev][chn].polarity == 1) /* Reverse */
+ if (devc->mix_devices[dev][chn].polarity == 1) /* Reverse */
newval = 100 - newval;
- mask = (1 << mix_devices[dev][chn].nbits) - 1;
- shift = mix_devices[dev][chn].bitpos;
+ mask = (1 << devc->mix_devices[dev][chn].nbits) - 1;
+ shift = devc->mix_devices[dev][chn].bitpos;
newval = (int) ((newval * mask) + 50) / 100; /* Scale it */
*regval &= ~(mask << shift); /* Clear bits */
ad1848_mixer_get (ad1848_info * devc, int dev)
{
if (!((1 << dev) & devc->supported_devices))
- return -(EINVAL);
+ return -EINVAL;
+
+ dev = devc->mixer_reroute[dev];
return devc->levels[dev];
}
int regoffs;
unsigned char val;
+ if (dev > 31)
+ return -EINVAL;
+
+ if (!(devc->supported_devices & (1 << dev)))
+ return -EINVAL;
+
+ dev = devc->mixer_reroute[dev];
+
if (left > 100)
left = 100;
if (right > 100)
right = 100;
- if (mix_devices[dev][RIGHT_CHN].nbits == 0) /* Mono control */
+ if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) /* Mono control */
right = left;
retvol = left | (right << 8);
left = mix_cvt[left];
right = mix_cvt[right];
- if (dev > 31)
- return -(EINVAL);
-
- if (!(devc->supported_devices & (1 << dev)))
- return -(EINVAL);
-
- if (mix_devices[dev][LEFT_CHN].nbits == 0)
- return -(EINVAL);
+ if (devc->mix_devices[dev][LEFT_CHN].nbits == 0)
+ return -EINVAL;
devc->levels[dev] = retvol;
* Set the left channel
*/
- regoffs = mix_devices[dev][LEFT_CHN].regno;
+ regoffs = devc->mix_devices[dev][LEFT_CHN].regno;
val = ad_read (devc, regoffs);
- change_bits (&val, dev, LEFT_CHN, left);
+ change_bits (devc, &val, dev, LEFT_CHN, left);
ad_write (devc, regoffs, val);
devc->saved_regs[regoffs] = val;
* Set the right channel
*/
- if (mix_devices[dev][RIGHT_CHN].nbits == 0)
+ if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0)
return retvol; /* Was just a mono channel */
- regoffs = mix_devices[dev][RIGHT_CHN].regno;
+ regoffs = devc->mix_devices[dev][RIGHT_CHN].regno;
val = ad_read (devc, regoffs);
- change_bits (&val, dev, RIGHT_CHN, right);
+ change_bits (devc, &val, dev, RIGHT_CHN, right);
ad_write (devc, regoffs, val);
devc->saved_regs[regoffs] = val;
ad1848_mixer_reset (ad1848_info * devc)
{
int i;
+ char name[32];
+
+ devc->mix_devices = &(ad1848_mix_devices[0]);
+
+ sprintf (name, "%s_%d", devc->chip_name, nr_ad1848_devs);
+
+ for (i = 0; i < 32; i++)
+ devc->mixer_reroute[i] = i;
switch (devc->model)
{
case MD_4231:
case MD_4231A:
- case MD_C930:
- case MD_IWAVE:
case MD_1845:
devc->supported_devices = MODE2_MIXER_DEVICES;
break;
+ case MD_C930:
+ devc->supported_devices = C930_MIXER_DEVICES;
+ devc->mix_devices = &(c930_mix_devices[0]);
+ break;
+
+ case MD_IWAVE:
+ devc->supported_devices = MODE3_MIXER_DEVICES;
+ devc->mix_devices = &(iwave_mix_devices[0]);
+ break;
+
case MD_4232:
devc->supported_devices = MODE3_MIXER_DEVICES;
break;
}
devc->supported_rec_devices = MODE1_REC_DEVICES;
+ devc->orig_devices = devc->supported_devices;
+ devc->orig_rec_devices = devc->supported_rec_devices;
+
+ devc->levels = load_mixer_volumes (name, default_mixer_levels, 1);
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
if (devc->supported_devices & (1 << i))
- ad1848_mixer_set (devc, i, default_mixer_levels[i]);
+ ad1848_mixer_set (devc, i, devc->levels[i]);
ad1848_set_recmask (devc, SOUND_MASK_MIC);
}
if (((cmd >> 8) & 0xff) == 'M')
{
+ int val;
if (_IOC_DIR (cmd) & _IOC_WRITE)
switch (cmd & 0xff)
{
case SOUND_MIXER_RECSRC:
- return snd_ioctl_return ((int *) arg, ad1848_set_recmask (devc, get_user ((int *) arg)));
+ get_user (val, (int *) arg);
+ return ioctl_out (arg, ad1848_set_recmask (devc, val));
break;
default:
- return snd_ioctl_return ((int *) arg, ad1848_mixer_set (devc, cmd & 0xff, get_user ((int *) arg)));
+ get_user (val, (int *) arg);
+ return ioctl_out (arg, ad1848_mixer_set (devc, cmd & 0xff, val));
}
else
switch (cmd & 0xff) /*
{
case SOUND_MIXER_RECSRC:
- return snd_ioctl_return ((int *) arg, devc->recmask);
+ return ioctl_out (arg, devc->recmask);
break;
case SOUND_MIXER_DEVMASK:
- return snd_ioctl_return ((int *) arg, devc->supported_devices);
+ return ioctl_out (arg, devc->supported_devices);
break;
case SOUND_MIXER_STEREODEVS:
- return snd_ioctl_return ((int *) arg, devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX));
+ if (devc->model == MD_C930)
+ return ioctl_out (arg, devc->supported_devices);
+ else
+ return ioctl_out (arg, devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX));
break;
case SOUND_MIXER_RECMASK:
- return snd_ioctl_return ((int *) arg, devc->supported_rec_devices);
+ return ioctl_out (arg, devc->supported_rec_devices);
break;
case SOUND_MIXER_CAPS:
- return snd_ioctl_return ((int *) arg, SOUND_CAP_EXCL_INPUT);
+ return ioctl_out (arg, SOUND_CAP_EXCL_INPUT);
break;
default:
- return snd_ioctl_return ((int *) arg, ad1848_mixer_get (devc, cmd & 0xff));
+ return ioctl_out (arg, ad1848_mixer_get (devc, cmd & 0xff));
}
}
else
- return -(EINVAL);
+ return -EINVAL;
}
static int
n = sizeof (speed_table) / sizeof (speed_struct);
- if (arg == 0)
+ if (arg <= 0)
return devc->speed;
if (devc->model == MD_1845) /* AD1845 has different timer than others */
unsigned long flags;
if (dev < 0 || dev >= num_audiodevs)
- return -(ENXIO);
+ return -ENXIO;
devc = (ad1848_info *) audio_devs[dev]->devc;
if (devc->opened)
{
restore_flags (flags);
- return -(EBUSY);
+ return -EBUSY;
}
devc->dual_dma = 0;
static int
ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
{
- return -(EINVAL);
+ return -EINVAL;
}
static void
save_flags (flags);
cli ();
- /* ad_write (devc, 9, ad_read (devc, 9) & ~ 0x01); / * Playback disable */
- ad1848_halt (dev);
+ ad1848_halt_output (dev);
DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
ad_write (devc, 15, (unsigned char) (cnt & 0xff));
if (dma_restart)
{
- /* ad1848_halt (dev); */
- ad_write (devc, 9, ad_read (devc, 9) & ~0x02); /* Capture disable */
+ ad1848_halt_input (dev);
DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
}
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
ad_mute (devc);
+ {
+/*
+ * This code fragment ensures that the playback FIFO is empty before
+ * setting the codec for playback. Enabling playback for a moment should
+ * be enough to do that.
+ */
+ int tmout;
+
+ ad_write (devc, 9, ad_read (devc, 9) | 0x01); /* Enable playback */
+ disable_dma (audio_devs[dev]->dmachan1);
+ for (tmout = 0; tmout < 1000000; tmout++)
+ if (ad_read (devc, 11) & 0x10) /* DRQ active */
+ if (tmout > 10000)
+ break;
+ ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */
+
+ enable_dma (audio_devs[dev]->dmachan1);
+ devc->audio_mode &= ~PCM_ENABLE_OUTPUT;
+ }
return ad1848_prepare_for_IO (dev, bsize, bcount);
}
old_fs = ad_read (devc, 8);
- if (devc->model != MD_4232)
- if (fs == old_fs) /* No change */
- {
- restore_flags (flags);
- devc->xfer_count = 0;
- return 0;
- }
ad_enter_MCE (devc); /* Enables changes to the format select reg */
/*
* Write to I8 starts resynchronization. Wait until it completes.
*/
- timeout = 10000;
- while (timeout > 0 && inb (devc->base) == 0x80)
- timeout--;
+ timeout = 0;
+ while (timeout < 100 && inb (devc->base) != 0x80)
+ timeout++;
+ timeout = 0;
+ while (timeout < 10000 && inb (devc->base) == 0x80)
+ timeout++;
/*
* If mode >= 2 (CS4231), set I28 also. It's the capture format register.
ad_write (devc, 28, fs);
/*
- * Write to I28 starts resynchronization. Wait until it completes.
+ * Write to I28 starts resynchronization. Wait until it completes.
*/
- timeout = 10000;
- while (timeout > 0 && inb (devc->base) == 0x80)
- timeout--;
+ timeout = 0;
+ while (timeout < 100 && inb (devc->base) != 0x80)
+ timeout++;
+ timeout = 0;
+ while (timeout < 10000 && inb (devc->base) == 0x80)
+ timeout++;
}
if (devc->model == MD_4232)
if (bits & 0x02)
ad1848_halt_input (dev);
+ devc->audio_mode = 0;
}
static void
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
unsigned long flags;
+ if (!(ad_read (devc, 9) & 0x02))
+ return; /* Capture not enabled */
+
save_flags (flags);
cli ();
ad_mute (devc);
- if (devc->model == MD_4232) /* Use applied black magic */
- {
- int tmout;
+ {
+ int tmout;
- disable_dma (audio_devs[dev]->dmachan1);
+ disable_dma (audio_devs[dev]->dmachan1);
- for (tmout = 0; tmout < 100000; tmout++)
- if (ad_read (devc, 11) & 0x10)
- break;
- ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */
+ for (tmout = 0; tmout < 100000; tmout++)
+ if (ad_read (devc, 11) & 0x10)
+ break;
+ ad_write (devc, 9, ad_read (devc, 9) & ~0x02); /* Stop capture */
- enable_dma (audio_devs[dev]->dmachan1);
- restore_flags (flags);
- return;
- }
- ad_write (devc, 9, ad_read (devc, 9) & ~0x02); /* Stop capture */
+ enable_dma (audio_devs[dev]->dmachan1);
+ devc->audio_mode &= ~PCM_ENABLE_INPUT;
+ }
- outb (0, io_Status (devc)); /* Clear interrupt status */
- outb (0, io_Status (devc)); /* Clear interrupt status */
+ outb ((0), io_Status (devc)); /* Clear interrupt status */
+ outb ((0), io_Status (devc)); /* Clear interrupt status */
devc->audio_mode &= ~PCM_ENABLE_INPUT;
ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
unsigned long flags;
+ if (!(ad_read (devc, 9) & 0x01))
+ return; /* Playback not enabled */
+
save_flags (flags);
cli ();
ad_mute (devc);
- if (devc->model == MD_4232) /* Use applied black magic */
- {
- int tmout;
+ {
+ int tmout;
- disable_dma (audio_devs[dev]->dmachan1);
+ disable_dma (audio_devs[dev]->dmachan1);
- for (tmout = 0; tmout < 100000; tmout++)
- if (ad_read (devc, 11) & 0x10)
- break;
- ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */
+ for (tmout = 0; tmout < 100000; tmout++)
+ if (ad_read (devc, 11) & 0x10)
+ break;
+ ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */
- enable_dma (audio_devs[dev]->dmachan1);
- restore_flags (flags);
- return;
- }
- ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Stop playback */
+ enable_dma (audio_devs[dev]->dmachan1);
+ devc->audio_mode &= ~PCM_ENABLE_OUTPUT;
+ }
- outb (0, io_Status (devc)); /* Clear interrupt status */
- outb (0, io_Status (devc)); /* Clear interrupt status */
+ outb ((0), io_Status (devc)); /* Clear interrupt status */
+ outb ((0), io_Status (devc)); /* Clear interrupt status */
devc->audio_mode &= ~PCM_ENABLE_OUTPUT;
if (state & PCM_ENABLE_OUTPUT)
tmp |= 0x01;
- if (!(state & PCM_ENABLE_OUTPUT) && old & 0x01);
ad_mute (devc);
ad_write (devc, 9, tmp);
- if (state & PCM_ENABLE_OUTPUT && !(old & 0x01));
ad_unmute (devc);
restore_flags (flags);
}
-int
-ad1848_detect (int io_base, int *ad_flags, int *osp)
+void
+ad1848_init_hw (ad1848_info * devc)
{
+ int i;
+
/*
* Initial values for the indirect registers of CS4248/AD1848.
*/
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+
+ for (i = 0; i < 16; i++)
+ ad_write (devc, i, init_values[i]);
+
+
+ ad_mute (devc); /* Initialize some variables */
+ ad_unmute (devc); /* Leave it unmuted now */
+
+ if (devc->model > MD_1848)
+ {
+ ad_write (devc, 12, ad_read (devc, 12) | 0x40); /* Mode2 = enabled */
+
+ if (devc->model == MD_IWAVE)
+ ad_write (devc, 12, 0x6c); /* Select codec mode 3 */
+
+ for (i = 16; i < 32; i++)
+ ad_write (devc, i, init_values[i]);
+
+ }
+
+ if (devc->model > MD_1848)
+ {
+ if (devc->audio_flags & DMA_DUPLEX)
+ ad_write (devc, 9, ad_read (devc, 9) & ~0x04); /* Dual DMA mode */
+ else
+ ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */
+
+ if (devc->model == MD_1845)
+ ad_write (devc, 27, ad_read (devc, 27) | 0x08); /* Alternate freq select enabled */
+
+ if (devc->model == MD_IWAVE)
+ { /* Some magic Interwave specific initialization */
+ ad_write (devc, 12, 0x6c); /* Select codec mode 3 */
+ ad_write (devc, 17, 0xc2); /* Alternate feature enable */
+ }
+ }
+ else
+ {
+ devc->audio_flags &= ~DMA_DUPLEX;
+ ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */
+ }
+
+ outb ((0), io_Status (devc)); /* Clear pending interrupts */
+
+ /*
+ * Toggle the MCE bit. It completes the initialization phase.
+ */
+
+ ad_enter_MCE (devc); /* In case the bit was off */
+ ad_leave_MCE (devc);
+
+ ad1848_mixer_reset (devc);
+}
+
+int
+ad1848_detect (int io_base, int *ad_flags, int *osp)
+{
+
unsigned char tmp;
ad1848_info *devc = &dev_info[nr_ad1848_devs];
unsigned char tmp1 = 0xff, tmp2 = 0xff;
if (ad_flags)
{
if (*ad_flags == 0x12345678)
- interwave = 1;
- *ad_flags = 0;
+ {
+ interwave = 1;
+ *ad_flags = 0;
+ }
}
if (nr_ad1848_devs >= MAX_AUDIO_DEV)
devc->opened = 0;
devc->chip_name = "AD1848";
devc->model = MD_1848; /* AD1848 or CS4248 */
- devc->osp = osp;
+ devc->levels = NULL;
devc->debug_flag = 0;
/*
*/
DDB (printk ("ad1848_detect() - step A\n"));
+
+/*
+ * Wait for the device to stop initialization
+ */
+ /* outb(( 0x0b), devc->base); */
+
+ for (i = 0; i < 10000000; i++)
+ {
+ unsigned char x = inb (devc->base);
+
+ if (x == 0xff || !(x & 0x80))
+ break;
+ }
+
if ((inb (devc->base) & 0x80) != 0x00) /* Not a AD1848 */
{
DDB (printk ("ad1848 detect error - step A (%02x)\n",
*/
DDB (printk ("ad1848_detect() - step G\n"));
- ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */
+
+ if (ad_flags && *ad_flags == 400)
+ *ad_flags = 0;
+ else
+ ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */
+
+ if (ad_flags)
+ *ad_flags = 0;
tmp1 = ad_read (devc, 12);
if (tmp1 & 0x80)
if (devc->model == MD_1848 && ad1847_flag)
devc->chip_name = "AD1847";
- for (i = 0; i < 16; i++)
- ad_write (devc, i, init_values[i]);
-
- ad_mute (devc); /* Initialize some variables */
- ad_unmute (devc); /* Leave it unmuted now */
-
- if (devc->model > MD_1848)
- {
- ad_write (devc, 12, ad_read (devc, 12) | 0x40); /* Mode2 = enabled */
-
- if (devc->model == MD_IWAVE)
- ad_write (devc, 12, 0x6c); /* Select codec mode 3 */
-
- for (i = 16; i < 32; i++)
- ad_write (devc, i, init_values[i]);
- }
return 1;
}
ad1848_info *devc = &dev_info[nr_ad1848_devs];
- int audio_flags = DMA_AUTOMODE;
request_region (devc->base, 4, devc->chip_name);
devc->irq = (irq > 0) ? irq : 0;
devc->opened = 0;
devc->timer_ticks = 0;
- devc->osp = osp;
-
- if (devc->model > MD_1848)
- {
- if (dma_capture == dma_playback || dma_capture == -1 || dma_playback == -1)
- {
- ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */
- audio_flags &= ~DMA_DUPLEX;
- }
- else
- {
- ad_write (devc, 9, ad_read (devc, 9) & ~0x04); /* Dual DMA mode */
- audio_flags |= DMA_DUPLEX;
- }
-
- if (devc->model == MD_1845)
- ad_write (devc, 27, ad_read (devc, 27) | 0x08); /* Alternate freq select enabled */
-
- if (devc->model == MD_IWAVE)
- { /* Some magic Interwave specific initialization */
- ad_write (devc, 12, 0x6c); /* Select codec mode 3 */
- ad_write (devc, 17, 0xc2); /* Alternate feature enable */
- }
- }
- else
- {
- audio_flags &= ~DMA_DUPLEX;
- ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */
- }
-
- outb (0, io_Status (devc)); /* Clear pending interrupts */
+ devc->dma1 = dma_playback;
+ devc->dma2 = dma_capture;
+ devc->audio_flags = DMA_AUTOMODE;
if (name != NULL && name[0] != 0)
sprintf (dev_name,
conf_printf2 (dev_name,
devc->base, devc->irq, dma_playback, dma_capture);
- if (devc->model == MD_1848)
- audio_flags |= DMA_HARDSTOP;
+ if (devc->model == MD_1848 || devc->model == MD_C930)
+ devc->audio_flags |= DMA_HARDSTOP;
+
+ if (devc->model > MD_1848)
+ {
+ if (devc->dma1 == devc->dma2 || devc->dma2 == -1 || devc->dma1 == -1)
+ devc->audio_flags &= ~DMA_DUPLEX;
+ else
+ devc->audio_flags |= DMA_DUPLEX;
+ }
if ((my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION,
dev_name,
&ad1848_audio_driver,
sizeof (struct audio_driver),
- audio_flags,
+ devc->audio_flags,
ad_format_mask[devc->model],
devc,
dma_playback,
return;
}
+ nr_ad1848_devs++;
+
+ ad1848_init_hw (devc);
+
if (irq > 0)
{
irq2dev[irq] = devc->dev_no = my_dev;
if (snd_set_irq_handler (devc->irq, ad1848_interrupt,
"SoundPort",
- devc->osp) < 0)
+ NULL) < 0)
{
printk ("ad1848: IRQ in use\n");
}
- if (devc->model != MD_1848)
+ if (devc->model != MD_1848 && devc->model != MD_C930)
{
int x;
unsigned char tmp = ad_read (devc, 16);
if (devc->timer_ticks == 0)
printk ("ad1848: Interrupt test failed (IRQ%d)\n", devc->irq);
else
- devc->irq_ok = 1;
+ {
+ DDB (printk ("Interrupt test OK\n"));
+ devc->irq_ok = 1;
+ }
}
else
devc->irq_ok = 1; /* Couldn't test. assume it's OK */
}
else if (irq < 0)
irq2dev[-irq] = devc->dev_no = my_dev;
- nr_ad1848_devs++;
#ifdef CONFIG_SEQUENCER
- if (devc->model != MD_1848 && devc->model != MD_1845 && devc->irq_ok)
+ if (devc->model != MD_1848 &&
+ devc->model != MD_C930 && devc->irq_ok)
ad1848_tmr_install (my_dev);
#endif
printk ("ad1848.c: Can't allocate DMA%d\n", dma_capture);
}
- /*
- * Toggle the MCE bit. It completes the initialization phase.
- */
-
- ad_enter_MCE (devc); /* In case the bit was off */
- ad_leave_MCE (devc);
- ad1848_mixer_reset (devc);
-
if (sound_install_mixer (MIXER_DRIVER_VERSION,
dev_name,
&ad1848_mixer_operations,
}
}
+void
+ad1848_control (int cmd, int arg)
+{
+ ad1848_info *devc;
+
+ if (nr_ad1848_devs < 1)
+ return;
+
+ devc = &dev_info[nr_ad1848_devs - 1];
+
+ switch (cmd)
+ {
+ case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */
+ if (devc->model != MD_1845)
+ return;
+ ad_enter_MCE (devc);
+ ad_write (devc, 29, (ad_read (devc, 29) & 0x1f) | (arg << 5));
+ ad_leave_MCE (devc);
+ break;
+
+ case AD1848_MIXER_REROUTE:
+ {
+ int o = (arg >> 8) & 0xff;
+ int n = arg & 0xff;
+
+ if (n == SOUND_MIXER_NONE)
+ { /* Just hide this control */
+ ad1848_mixer_set (devc, o, 0); /* Shut up it */
+ devc->supported_devices &= ~(1 << o);
+ devc->supported_rec_devices &= ~(1 << o);
+ return;
+ }
+
+ /* Make the mixer control identified by o to appear as n */
+
+ if (o < 0 || o > SOUND_MIXER_NRDEVICES)
+ return;
+ if (n < 0 || n > SOUND_MIXER_NRDEVICES)
+ return;
+ if (!(devc->supported_devices & (1 << o)))
+ return; /* Not supported */
+
+ devc->mixer_reroute[n] = o; /* Rename the control */
+ devc->supported_devices &= ~(1 << o);
+ devc->supported_devices |= (1 << n);
+ if (devc->supported_rec_devices & (1 << o))
+ devc->supported_rec_devices |= (1 << n);
+ devc->supported_rec_devices &= ~(1 << o);
+ }
+ break;
+ }
+}
+
void
ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int share_dma)
{
ad1848_info *devc;
int dev;
int alt_stat = 0xff;
+ unsigned char c930_stat = 0;
if (irq < 0 || irq > 15)
{
else
devc = (ad1848_info *) audio_devs[dev]->devc;
+interrupt_again: /* Jump back here if int status doesn't reset */
+
status = inb (io_Status (devc));
if (status == 0x80)
if (status & 0x01)
{
+ if (devc->model == MD_C930)
+ { /* 82C930 has interrupt status register in MAD16 register MC11 */
+ unsigned long flags;
- if (devc->model != MD_1848)
+ save_flags (flags);
+ cli ();
+
+ alt_stat = 0;
+
+ outb ((11), 0xe0e);
+ c930_stat = inb (0xe0f);
+
+ if (c930_stat & 0x04)
+ alt_stat |= 0x10; /* Playback intr */
+ if (c930_stat & 0x08)
+ alt_stat |= 0x20; /* Playback intr */
+ restore_flags (flags);
+ }
+ else if (devc->model != MD_1848)
alt_stat = ad_read (devc, 24);
if (devc->opened && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20)
}
}
- if (devc->model != MD_1848)
+ if (devc->model == MD_C930)
+ { /* 82C930 has interrupt status register in MAD16 register MC11 */
+ unsigned long flags;
+
+ save_flags (flags);
+ cli ();
+
+ outb ((11), 0xe0e);
+ outb ((~c930_stat), 0xe0f);
+ restore_flags (flags);
+ }
+ else if (devc->model != MD_1848)
ad_write (devc, 24, ad_read (devc, 24) & ~alt_stat); /* Selective ack */
else
- outb (0, io_Status (devc)); /* Clear interrupt status */
+ outb ((0), io_Status (devc)); /* Clear interrupt status */
+
+/*
+ * Sometimes playback or capture interrupts occur while a timer interrupt
+ * is being handled. The interrupt will not be retriggered if we don't
+ * handle it now. Check if an interrupt is still pending and restart
+ * the handler in this case.
+ */
+ if (inb (io_Status (devc)) & 0x01)
+ goto interrupt_again;
}
/*
return 0;
}
- outb (tmp | 0x04, 0xc44); /* Select bank 1 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank 1 */
if (inb (0xc44) != 0x04)
{
DDB (printk ("init_deskpro: Invalid bank1 signature in port 0xc44\n"));
#ifdef DEBUGXL
/* Debug printing */
printk ("Port 0xc44 (before): ");
- outb (tmp & ~0x04, 0xc44);
+ outb ((tmp & ~0x04), 0xc44);
printk ("%02x ", inb (0xc44));
- outb (tmp | 0x04, 0xc44);
+ outb ((tmp | 0x04), 0xc44);
printk ("%02x\n", inb (0xc44));
#endif
hw_config->io_base));
return 0;
}
- outb (tmp & ~0x04, 0xc44); /* Write to bank=0 */
+ outb ((tmp & ~0x04), 0xc44); /* Write to bank=0 */
#ifdef DEBUGXL
/* Debug printing */
printk ("Port 0xc44 (after): ");
- outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
printk ("%02x ", inb (0xc44));
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank=1 */
printk ("%02x\n", inb (0xc44));
#endif
#ifdef DEBUGXL
/* Debug printing */
printk ("Port 0xc45 (before): ");
- outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
printk ("%02x ", inb (0xc45));
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank=1 */
printk ("%02x\n", inb (0xc45));
#endif
- outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
- outb (0x88, 0xc45); /* FM base 7:0 = 0x88 */
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
- outb (0x10, 0xc45); /* MSS ID = 0x10 (MSS port returns 0x04) */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
+ outb ((0x88), 0xc45); /* FM base 7:0 = 0x88 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank=1 */
+ outb ((0x10), 0xc45); /* MSS ID = 0x10 (MSS port returns 0x04) */
#ifdef DEBUGXL
/* Debug printing */
printk ("Port 0xc45 (after): ");
- outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
printk ("%02x ", inb (0xc45));
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank=1 */
printk ("%02x\n", inb (0xc45));
#endif
#ifdef DEBUGXL
/* Debug printing */
printk ("Port 0xc46 (before): ");
- outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
printk ("%02x ", inb (0xc46));
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank=1 */
printk ("%02x\n", inb (0xc46));
#endif
- outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
- outb (0x03, 0xc46); /* FM base 15:8 = 0x03 */
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
- outb (0x11, 0xc46); /* ASIC ID = 0x11 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
+ outb ((0x03), 0xc46); /* FM base 15:8 = 0x03 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank=1 */
+ outb ((0x11), 0xc46); /* ASIC ID = 0x11 */
#ifdef DEBUGXL
/* Debug printing */
printk ("Port 0xc46 (after): ");
- outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
printk ("%02x ", inb (0xc46));
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank=1 */
printk ("%02x\n", inb (0xc46));
#endif
#ifdef DEBUGXL
/* Debug printing */
printk ("Port 0xc47 (before): ");
- outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
printk ("%02x ", inb (0xc47));
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank=1 */
printk ("%02x\n", inb (0xc47));
#endif
- outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
- outb (0x7c, 0xc47); /* FM decode enable bits = 0x7c */
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
- outb (0x00, 0xc47); /* Reserved bank1 = 0x00 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
+ outb ((0x7c), 0xc47); /* FM decode enable bits = 0x7c */
+ outb ((tmp | 0x04), 0xc44); /* Select bank=1 */
+ outb ((0x00), 0xc47); /* Reserved bank1 = 0x00 */
#ifdef DEBUGXL
/* Debug printing */
printk ("Port 0xc47 (after): ");
- outb (tmp & ~0x04, 0xc44); /* Select bank=0 */
+ outb ((tmp & ~0x04), 0xc44); /* Select bank=0 */
printk ("%02x ", inb (0xc47));
- outb (tmp | 0x04, 0xc44); /* Select bank=1 */
+ outb ((tmp | 0x04), 0xc44); /* Select bank=1 */
printk ("%02x\n", inb (0xc47));
#endif
printk ("Port 0xc6f (before) = %02x\n", inb (0xc6f));
#endif
- outb (0x80, 0xc6f);
+ outb ((0x80), 0xc6f);
#ifdef DEBUGXL
printk ("Port 0xc6f (after) = %02x\n", inb (0xc6f));
int dma = hw_config->dma;
int dma2 = hw_config->dma2;
- if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, hw_config->osp))
- return;
if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */
{
if (bits == -1)
return;
- outb (bits | 0x40, config_port);
+ outb ((bits | 0x40), config_port);
if ((inb (version_port) & 0x40) == 0)
- printk ("[IRQ Conflict?]");
+ printk ("[MSS: IRQ Conflict?]");
/*
* Handle the capture DMA channel
else
dma2 = dma;
- outb (bits | dma_bits[dma] | dma2_bit, config_port); /* Write IRQ+DMA setup */
+ outb ((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */
ad1848_init ("MSS audio codec", hw_config->io_base + 4,
hw_config->irq,
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
SOUND_MASK_IGAIN | \
SOUND_MASK_PCM | SOUND_MASK_IMIX)
-#define MODE2_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_MIC | \
+#define MODE2_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | \
+ SOUND_MASK_MIC | \
SOUND_MASK_LINE3 | SOUND_MASK_SPEAKER | \
SOUND_MASK_IGAIN | \
SOUND_MASK_PCM | SOUND_MASK_IMIX)
#define MODE3_MIXER_DEVICES (MODE2_MIXER_DEVICES | SOUND_MASK_VOLUME)
+/* OPTi 82C930 has no IMIX level control, but it can still be selected as an
+ * input
+ */
+#define C930_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | \
+ SOUND_MASK_MIC | SOUND_MASK_VOLUME | \
+ SOUND_MASK_LINE3 | \
+ SOUND_MASK_IGAIN | SOUND_MASK_PCM)
+
struct mixer_def {
unsigned int regno: 7;
unsigned int polarity:1; /* 0=normal, 1=reversed */
};
typedef struct mixer_def mixer_ent;
+typedef mixer_ent mixer_ents[2];
/*
* Most of the mixer entries work in backwards. Setting the polarity field
#define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r) \
{{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r}}
-mixer_ent mix_devices[32][2] = {
+mixer_ents ad1848_mix_devices[32] = {
MIX_ENT(SOUND_MIXER_VOLUME, 27, 1, 0, 4, 29, 1, 0, 4),
MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0),
MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0),
MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5)
};
-static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] =
+mixer_ents iwave_mix_devices[32] = {
+MIX_ENT(SOUND_MIXER_VOLUME, 25, 1, 0, 5, 27, 1, 0, 5),
+MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5),
+MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6),
+MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5),
+MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1),
+MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5),
+MIX_ENT(SOUND_MIXER_IMIX, 13, 1, 2, 6, 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4),
+MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5),
+MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5),
+MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5)
+};
+
+/* OPTi 82C930 has somewhat different port addresses.
+ * Note: VOLUME == SPEAKER, SYNTH == LINE2, LINE == LINE3, CD == LINE1
+ * VOLUME, SYNTH, LINE, CD are not enabled above.
+ * MIC is level of mic monitoring direct to output. Same for CD, LINE, etc.
+ */
+mixer_ents c930_mix_devices[32] = {
+MIX_ENT(SOUND_MIXER_VOLUME, 22, 1, 0, 5, 23, 1, 0, 5),
+MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5),
+MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6),
+MIX_ENT(SOUND_MIXER_SPEAKER, 22, 1, 0, 5, 23, 1, 0, 5),
+MIX_ENT(SOUND_MIXER_LINE, 18, 1, 1, 4, 19, 1, 1, 4),
+MIX_ENT(SOUND_MIXER_MIC, 20, 1, 0, 4, 21, 1, 0, 4),
+MIX_ENT(SOUND_MIXER_CD, 2, 1, 1, 4, 3, 1, 1, 4),
+MIX_ENT(SOUND_MIXER_IMIX, 0, 0, 0, 0, 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4),
+MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 1, 4, 3, 1, 1, 4),
+MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 1, 4, 5, 1, 1, 4),
+MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 1, 4, 19, 1, 1, 4)
+};
+
+static int default_mixer_levels[32] =
{
0x3232, /* Master Volume */
0x3232, /* Bass */
0x3232, /* Treble */
0x4b4b, /* FM */
0x3232, /* PCM */
- 0x4b4b, /* PC Speaker */
+ 0x1515, /* PC Speaker */
0x2020, /* Ext Line */
0x1010, /* Mic */
0x4b4b, /* CD */
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
if (check_region (hw_config->io_base, 4))
{
- printk ("\n\nopl3.c: I/O port %x already in use\n\n", hw_config->io_base);
+ DDB (printk ("opl3.c: I/O port %x already in use\n",
+ hw_config->io_base));
return 0;
}
};
/*
- * Buffers to store audio card information
+ * Buffers to store audio card informations
*/
static char AudioExcelName[CARDNAMELEN + 1];
static char AudioExcelVersion[CARDVERLEN + 1];
/*
* Reset DSP
*/
- outb (1, (port + DSP_RESET));
+ outb ((1), (port + DSP_RESET));
tenmicrosec ();
- outb (0, (port + DSP_RESET));
+ outb ((0), (port + DSP_RESET));
tenmicrosec ();
tenmicrosec ();
return CheckDSPOkay (port);
*/
if (!(ret & 0x80))
{
- outb (cmd, port + DSP_COMMAND);
+ outb ((cmd), port + DSP_COMMAND);
return 0;
}
}
* can allow me to release the requested region.
*/
if (!(ae_init & INIT_MPU401))
- request_region (hw_config->io_base, 0x0f, "AEDSP16 (SBPro)");
+ request_region (hw_config->io_base, 0x0f, "aedsp16 (sbpro)");
#endif
ae_init |= INIT_SBPRO;
* can allow me to release the requested region. So when unloading
* and then reloading it, we are going to have some nice Oops!
*/
- request_region (hw_config->io_base, 0x08, "AEDSP16 (MSS)");
+ request_region (hw_config->io_base, 0x08, "aedsp16 (mss)");
#endif
if (!(ae_init & INIT_MPU401))
- request_region (AEDSP16_BASE, 0x0f, "AEDSP16 (SBPro)");
+ request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)");
ae_init |= INIT_MSS;
return 0;
* request any region because there is not a uninit routine that
* can allow me to release the requested region.
*/
- request_region (hw_config->io_base, 0x02, "AEDSP16 (mpu401)");
+ request_region (hw_config->io_base, 0x02, "aedsp16 (mpu401)");
#endif
if (!(ae_init & (INIT_MSS | INIT_SBPRO)))
- request_region (AEDSP16_BASE, 0x0f, "AEDSP16 (SBPro)");
+ request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)");
ae_init |= INIT_MPU401;
return 0;
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#define AM_WRITE 1
#define AM_READ 2
+
static int audio_format[MAX_AUDIO_DEV];
static int local_conversion[MAX_AUDIO_DEV];
+#define CNV_MU_LAW 0x00000001
static int
-set_format (int dev, long fmt)
+set_format (int dev, int fmt)
{
if (fmt != AFMT_QUERY)
{
if (fmt == AFMT_MU_LAW)
{
fmt = AFMT_U8;
- local_conversion[dev] = AFMT_MU_LAW;
+ local_conversion[dev] = CNV_MU_LAW;
}
else
fmt = AFMT_U8; /* This is always supported */
- audio_format[dev] = DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) fmt, 1);
+ audio_format[dev] = audio_devs[dev]->d->set_bits (dev, fmt);
}
if (local_conversion[dev]) /* This shadows the HW format */
audio_open (int dev, struct fileinfo *file)
{
int ret;
- long bits;
+ int bits;
int dev_type = dev & 0x0f;
int mode = file->mode & O_ACCMODE;
else
bits = 8;
+ if (dev < 0 || dev >= num_audiodevs)
+ return -ENXIO;
+
if ((ret = DMAbuf_open (dev, mode)) < 0)
return ret;
local_conversion[dev] = 0;
- if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) bits, 1) != bits)
+ if (audio_devs[dev]->d->set_bits (dev, bits) != bits)
{
- printk ("audio: Can't set number of bits on device %d\n", dev);
- audio_release (dev, file);
- return -(ENXIO);
}
if (dev_type == SND_DEV_AUDIO)
audio_mode[dev] = AM_NONE;
dev_nblock[dev] = 0;
+
return ret;
}
if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0)
{
+ int i, n = buf_size & 3;
+
+ if (n) /* Not 4 byte aligned */
+ {
+ for (i = 0; i < n; i++)
+ dma_buf[buf_ptr++] = dmap->neutral_byte;
+ }
DMAbuf_start_output (dev, buf_no, buf_ptr);
}
for (i = dmap->qlen + 1; i < dmap->nbufs; i++)
{
+ p = (p + 1) % dmap->nbufs;
memset (dmap->raw_buf + p * dmap->fragment_size,
dmap->neutral_byte,
dmap->fragment_size);
-
- p = (p + 1) % dmap->nbufs;
}
dmap->flags |= DMA_CLEAN;
dev_nblock[dev])) < 0)
{
/* Handle nonblocking mode */
- if (dev_nblock[dev] && buf_no == -(EAGAIN))
+ if (dev_nblock[dev] && buf_no == -EAGAIN)
return p; /* No more space. Return # of accepted bytes */
return buf_no;
}
if (l > (buf_size - buf_ptr))
l = (buf_size - buf_ptr);
- if (!audio_devs[dev]->d->copy_from_user)
+
+ if (!audio_devs[dev]->d->copy_user)
{ /*
* No device specific copy routine
*/
copy_from_user (&dma_buf[buf_ptr], &(buf)[p], l);
}
else
- audio_devs[dev]->d->copy_from_user (dev,
- dma_buf, buf_ptr, buf, p, l);
+ audio_devs[dev]->d->copy_user (dev,
+ dma_buf, buf_ptr, buf, p, l);
- if (local_conversion[dev] == AFMT_MU_LAW)
+ if (local_conversion[dev] & CNV_MU_LAW)
{
/*
* This just allows interrupts while the conversion is running
{
/* Nonblocking mode handling. Return current # of bytes */
- if (dev_nblock[dev] && buf_no == -(EAGAIN))
+ if (dev_nblock[dev] && buf_no == -EAGAIN)
return p;
return buf_no;
* Insert any local processing here.
*/
- if (local_conversion[dev] == AFMT_MU_LAW)
+ if (local_conversion[dev] & CNV_MU_LAW)
{
/*
* This just allows interrupts while the conversion is running
translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l);
}
- copy_to_user (&(buf)[p], dmabuf, l);
+ {
+ char *fixit = dmabuf;
+
+ copy_to_user (&(buf)[p], fixit, l);
+ };
DMAbuf_rmchars (dev, buf_no, l);
audio_ioctl (int dev, struct fileinfo *file,
unsigned int cmd, caddr_t arg)
{
+ int val;
+
+/* printk("audio_ioctl(%x, %x)\n", cmd, arg); */
dev = dev >> 4;
else
printk ("/dev/dsp%d: No coprocessor for this device\n", dev);
- return -(ENXIO);
+ return -ENXIO;
}
else
switch (cmd)
return 0;
sync_output (dev);
- return DMAbuf_ioctl (dev, cmd, arg, 0);
+ DMAbuf_sync (dev);
+ DMAbuf_reset (dev);
+ return 0;
break;
case SNDCTL_DSP_POST:
if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
return 0;
+ audio_devs[dev]->dmap_out->flags |= DMA_POST;
sync_output (dev);
+ DMAbuf_ioctl (dev, SNDCTL_DSP_POST, 0, 1);
return 0;
break;
case SNDCTL_DSP_RESET:
audio_mode[dev] = AM_NONE;
- return DMAbuf_ioctl (dev, cmd, arg, 0);
+ DMAbuf_reset (dev);
+ return 0;
break;
case SNDCTL_DSP_GETFMTS:
- return snd_ioctl_return ((int *) arg, audio_devs[dev]->format_mask | AFMT_MU_LAW);
+ return ioctl_out (arg, audio_devs[dev]->format_mask);
break;
case SNDCTL_DSP_SETFMT:
- return snd_ioctl_return ((int *) arg, set_format (dev, get_user ((int *) arg)));
+ get_user (val, (int *) arg);
+ return ioctl_out (arg, set_format (dev, val));
case SNDCTL_DSP_GETISPACE:
if (!(audio_devs[dev]->open_mode & OPEN_READ))
return 0;
if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
- return -(EBUSY);
+ return -EBUSY;
{
audio_buf_info info;
if (err < 0)
return err;
- copy_to_user (&((char *) arg)[0], (char *) &info, sizeof (info));
+ {
+ char *fixit = (char *) &info;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (info));
+ };
return 0;
}
if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
return -EPERM;
if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
- return -(EBUSY);
+ return -EBUSY;
{
audio_buf_info info;
if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0)
info.bytes -= buf_ptr;
- copy_to_user (&((char *) arg)[0], (char *) &info, sizeof (info));
+ {
+ char *fixit = (char *) &info;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (info));
+ };
return 0;
}
info |= DSP_CAP_MMAP;
- copy_to_user (&((char *) arg)[0], (char *) &info, sizeof (info));
+ {
+ char *fixit = (char *) &info;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (info));
+ };
return 0;
}
break;
+ case SOUND_PCM_WRITE_RATE:
+ get_user (val, (int *) arg);
+ return ioctl_out (arg, audio_devs[dev]->d->set_speed (dev, val));
+
+ case SOUND_PCM_READ_RATE:
+ return ioctl_out (arg, audio_devs[dev]->d->set_speed (dev, 0));
+
+ case SNDCTL_DSP_STEREO:
+ {
+ int n;
+
+ get_user (n, (int *) arg);
+ if (n > 1)
+ {
+ printk ("sound: SNDCTL_DSP_STEREO called with invalid argument %d\n",
+ n);
+ return ioctl_out (arg, audio_devs[dev]->d->set_channels (dev, n));
+ }
+
+ if (n < 0)
+ return -EINVAL;
+
+ return ioctl_out (arg, audio_devs[dev]->d->set_channels (dev, n + 1) - 1);
+ }
+
+ case SOUND_PCM_WRITE_CHANNELS:
+ get_user (val, (int *) arg);
+ return ioctl_out (arg, audio_devs[dev]->d->set_channels (dev, val));
+
+ case SOUND_PCM_READ_CHANNELS:
+ return ioctl_out (arg, audio_devs[dev]->d->set_channels (dev, 0));
+
+ case SOUND_PCM_READ_BITS:
+ return ioctl_out (arg, audio_devs[dev]->d->set_bits (dev, 0));
+
+ case SNDCTL_DSP_SETDUPLEX:
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ return 0;
+ else
+ return -EIO;
+ break;
+
default:
return DMAbuf_ioctl (dev, cmd, arg, 0);
}
}
void
-audio_init (void)
+audio_init_devices (void)
{
/*
* NOTE! This routine could be called several times during boot.
}
int
-audio_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait)
+audio_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
{
char *dma_buf;
int buf_no, buf_ptr, buf_size;
/*
* PnP soundcard support is not included in this version.
*
- * AEDSP16 will not work without significant changes.
+ * There is a separately distributed patch available for AEDSP16.
*/
-#define DISABLED_OPTIONS (B(OPT_SPNP)|B(OPT_AEDSP16)|B(OPT_UNUSED1)|B(OPT_UNUSED2))
+#define DISABLED_OPTIONS (B(OPT_SPNP)|B(OPT_AEDSP16)|B(OPT_UNUSED1)|B(OPT_UNUSED2)|B(OPT_UNUSED3)|B(OPT_UNUSED4)|B(OPT_UNUSED5))
/*
* sound/configure.c - Configuration program for the Linux Sound Driver
*/
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#define OPT_UNUSED1 16
#define OPT_UNUSED2 17
#define OPT_AEDSP16 18
-#define OPT_AUDIO 19
-#define OPT_MIDI_AUTO 20
-#define OPT_MIDI 21
+#define OPT_UNUSED3 19
+#define OPT_UNUSED4 20
+#define OPT_UNUSED5 21
#define OPT_YM3812_AUTO 22
#define OPT_YM3812 23
#define OPT_LAST 23 /* Last defined OPT number */
-#define DUMMY_OPTS (B(OPT_MIDI_AUTO)|B(OPT_YM3812_AUTO))
+#define DUMMY_OPTS (B(OPT_YM3812_AUTO))
-#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_GUS)| \
+#define ANY_DEVS (B(OPT_SB)|B(OPT_PAS)|B(OPT_GUS)| \
B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)| \
B(OPT_MSS)|B(OPT_SSCAPE)|B(OPT_UART6850)|B(OPT_TRIX)| \
- B(OPT_MAD16)|B(OPT_CS4232)|B(OPT_MAUI)|B(OPT_ADLIB))
-#define AUDIO_CARDS (B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS) | \
- B (OPT_MSS) | B (OPT_GUS16) | B (OPT_GUSMAX) | B (OPT_TRIX) | \
- B (OPT_SSCAPE)| B(OPT_MAD16) | B(OPT_CS4232))
+ B(OPT_MAD16)|B(OPT_CS4232)|B(OPT_MAUI)|B(OPT_ADLIB)| \
+ B(OPT_SPNP))
#define MPU_DEVS (B(OPT_PSS)|\
B(OPT_CS4232)|B(OPT_SPNP)|B(OPT_MAUI)|B(OPT_SSCAPE))
-#define UART401_DEVS (SBDSP_DEVS|B(OPT_TRIX)|B(OPT_MAD16))
-#define MIDI_CARDS (MPU_DEVS | UART401_DEVS | \
- B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | \
- B (OPT_GUS) | B (OPT_TRIX) | B (OPT_SSCAPE)|B(OPT_MAD16) | \
- B (OPT_CS4232)|B(OPT_MAUI))
+#define UART401_DEVS (SBDSP_DEVS|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_SPNP))
+#define NON_AUDIO_CARDS (B(OPT_ADLIB)|B(OPT_MPU401)|B(OPT_UART6850)|B(OPT_MAUI))
+#define AUDIO_CARDS (ANY_DEVS & ~NON_AUDIO_CARDS)
+#define MIDI_CARDS (ANY_DEVS & ~(B(OPT_ADLIB)|B(OPT_MSS)))
#define AD1848_DEVS (B(OPT_GUS16)|B(OPT_MSS)|B(OPT_PSS)|B(OPT_GUSMAX)|\
B(OPT_SSCAPE)|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_CS4232)|\
B(OPT_SPNP))
#define SBDSP_DEVS (B(OPT_SB)|B(OPT_SPNP)|B(OPT_MAD16)|B(OPT_TRIX))
-#define SEQUENCER_DEVS (OPT_MIDI|OPT_YM3812|OPT_ADLIB|OPT_GUS|OPT_MAUI|MIDI_CARDS)
+#define SEQUENCER_DEVS (MIDI_CARDS|B(OPT_YM3812)|B(OPT_ADLIB)|B(OPT_GUS)|B(OPT_MAUI))
/*
* Options that have been disabled for some reason (incompletely implemented
* and/or tested). Don't remove from this list before looking at file
{B (OPT_SB), B (OPT_PAS), "UNUSED1", 1, 0, 1},
{B (OPT_SB) | B (OPT_UNUSED1), B (OPT_PAS), "UNUSED2", 1, 0, 1},
{B (OPT_UNUSED1) | B (OPT_MSS) | B (OPT_MPU401), 0, "AEDSP16", 1, 0, 0},
- {AUDIO_CARDS, 0, "AUDIO", 1, 0, 1},
- {B (OPT_MPU401) | B (OPT_MAUI), 0, "MIDI_AUTO", 0, OPT_MIDI, 0},
- {MIDI_CARDS, 0, "MIDI", 1, 0, 1},
+ {AUDIO_CARDS, 0, "UNUSED3", 1, 0, 1},
+ {B (OPT_MPU401) | B (OPT_MAUI), 0, "UNUSED4", 0, 0, 0},
+ {MIDI_CARDS, 0, "UNUSED5", 1, 0, 1},
{B (OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0},
{B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB) | B (OPT_MSS) | B (OPT_PSS), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1}
};
"*** Unused option 1 ***",
"*** Unused option 2 ***",
"Audio Excel DSP 16 initialization support",
- "/dev/dsp and /dev/audio support",
- "This should not be asked",
- "MIDI interface support",
+ "*** Unused option 3 ***",
+ "*** Unused option 4 ***",
+ "*** Unused option 5 ***",
"This should not be asked",
"FM synthesizer (YM3812/OPL-3) support",
"Is the sky really falling"
"UART401", UART401_DEVS
}
,
+ {
+ "GUSHW", B (OPT_GUS) | B (OPT_SPNP)
+ }
+ ,
+ {
+ "SSCAPEHW", B (OPT_SSCAPE) | B (OPT_SPNP)
+ }
+ ,
{
"SEQUENCER", SEQUENCER_DEVS
}
,
+ {
+ "AUDIO", AUDIO_CARDS
+ }
+ ,
+ {
+ "MIDI", MIDI_CARDS
+ }
+ ,
{
NULL, 0
}
#define FMT_HEX 1
#define FMT_INT 2
+void
+show_comment (int mask, char *txt)
+{
+ int i;
+
+ if (dump_only)
+ {
+
+ for (i = 0; i < OPT_LAST; i++)
+ if (mask == B (i))
+ {
+ printf ("\n\nif [ \"$CONFIG_%s\" = \"y\" ]; then\n",
+ hw_table[i].macro);
+ printf ("comment '%s'\n", txt);
+ printf ("fi\n");
+ }
+ }
+ else
+ {
+ if (!(mask & selected_options))
+ return;
+
+ fprintf (stderr, "%s\n", txt);
+ }
+}
+
void
ask_int_choice (int mask, char *macro,
char *question,
printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options);
fprintf (stderr, "Old configuration copied.\n");
-#if defined(linux) || defined(Solaris)
build_defines ();
-#endif
old_config_used = 1;
return 1;
}
-#if defined(linux) || defined(Solaris)
void
build_defines (void)
{
fprintf (optf, "\n");
fclose (optf);
}
-#endif
void
ask_parameters (void)
* IRQ and DMA settings
*/
-#if 0 /* Disable this broken question. */
ask_int_choice (B (OPT_AEDSP16), "AEDSP16_BASE",
"I/O base for Audio Excel DSP 16",
FMT_HEX,
0x220,
"220 or 240");
-#endif
ask_int_choice (B (OPT_SB), "SBC_BASE",
"I/O base for SB",
"0, 1 or 3");
ask_int_choice (B (OPT_SB), "SB_DMA2",
- "Sound Blaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW)",
+ "Sound Blaster 16 bit DMA (SB16, Jazz16, SMW)",
FMT_INT,
5,
"5, 6 or 7 (use 1 for 8 bit cards)");
ask_int_choice (B (OPT_SB), "SB_MPU_BASE",
"MPU401 I/O base of SB16, Jazz16 and ES1688",
FMT_HEX,
- 0,
+ 0x330,
"Check from manual of the card");
+ show_comment (B (OPT_SB),
+ "MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688.");
+ show_comment (B (OPT_SB),
+ "Enter -1 to the following question if you have something else such as SB16/32.");
+
ask_int_choice (B (OPT_SB), "SB_MPU_IRQ",
"SB MPU401 IRQ (Jazz16, SM Wave and ES1688)",
FMT_INT,
-1,
- "Use -1 with SB16");
+ "Check from manual of the card");
ask_int_choice (B (OPT_PAS), "PAS_IRQ",
"PAS16 IRQ",
9,
"Check from manual of the card");
+ if (dump_only)
+ show_comment (B (OPT_MAUI),
+ "ERROR! You have to use old sound configuration method with Maui.");
+
ask_int_choice (B (OPT_MAUI), "MAUI_BASE",
"I/O base for Maui",
FMT_HEX,
-1,
"(Unknown)");
+ if (dump_only)
+ show_comment (B (OPT_PSS),
+ "ERROR! You have to use old sound configuration method with PSS cards.");
+
ask_int_choice (B (OPT_PSS), "PSS_BASE",
"PSS I/O base",
FMT_HEX,
}
+ if (dump_only)
+ show_comment (B (OPT_MAUI),
+ "ERROR! You have to use old sound configuration method with AudioTrix.");
+
ask_int_choice (B (OPT_TRIX), "TRIX_BASE",
"AudioTrix audio I/O base",
FMT_HEX,
FMT_INT,
9,
"5, 7, 9 or 10");
- ask_int_choice (B (OPT_AUDIO), "DSP_BUFFSIZE",
- "Audio DMA buffer size",
- FMT_INT,
- 65536,
- "4096, 16384, 32768 or 65536");
}
void
{
if (think_positively (
- "Do you want support for the Audio Excel Sound Blaster Pro mode",
+ "Do you want support for the Audio Excel Sound Blaster Pro mode",
1,
"Enable this option if you want the Audio Excel sound card to operate\n"
"in Sound Blaster Pro mode.\n"))
if (think_positively ("Do you want to include TRXPRO.HEX in your kernel",
1,
- "The MediaTrix AudioTrix Pro has an on-board microcontroller which\n"
+ "The MediaTrix AudioTrix Pro has an on-board microcontroller which\n"
"needs to be initialized by downloading the code from the file TRXPRO.HEX\n"
"in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n"
"you may skip this step. However, the SB and MPU-401 modes of AudioTrix\n"
printf ("#define SELECTED_SOUND_OPTIONS\t0x%08lx\n", selected_options);
fprintf (stderr, "\nThe sound driver is now configured.\n");
-#if defined(SCO) || defined(ISC) || defined(SYSV)
- fprintf (stderr, "Remember to update the System file\n");
-#endif
-
if (!old_config_used)
{
char str[255];
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
static void
CS_OUT (unsigned char a)
{
- outb (a, KEY_PORT);
+ outb ((a), KEY_PORT);
}
#define CS_OUT2(a, b) {CS_OUT(a);CS_OUT(b);}
#define CS_OUT3(a, b, c) {CS_OUT(a);CS_OUT(b);CS_OUT(c);}
int base = hw_config->io_base, irq = hw_config->irq;
int dma1 = hw_config->dma, dma2 = hw_config->dma2;
- static wait_handle *cs_sleeper = NULL;
+ static struct wait_queue *cs_sleeper = NULL;
static volatile struct snd_wait cs_sleep_flag =
{0};
- osp = hw_config->osp;
/*
* Verify that the I/O port range is free.
for (n = 0; n < 4; n++)
{
- cs_sleep_flag.flags = WK_NONE;
+ cs_sleep_flag.opts = WK_NONE;
/*
* Wake up the card by sending a 32 byte Crystal key to the key port.
*/
unsigned long tlimit;
if (HZ / 10)
- current_set_timeout (tlimit = jiffies + (HZ / 10));
+ current->timeout = tlimit = jiffies + (HZ / 10);
else
tlimit = (unsigned long) -1;
- cs_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&cs_sleeper);
- if (!(cs_sleep_flag.flags & WK_WAKEUP))
+ cs_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&cs_sleeper);
+ if (!(cs_sleep_flag.opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- cs_sleep_flag.flags |= WK_TIMEOUT;
+ cs_sleep_flag.opts |= WK_TIMEOUT;
}
- cs_sleep_flag.flags &= ~WK_SLEEP;
+ cs_sleep_flag.opts &= ~WK_SLEEP;
}; /* Delay */
/*
unsigned long tlimit;
if (HZ / 10)
- current_set_timeout (tlimit = jiffies + (HZ / 10));
+ current->timeout = tlimit = jiffies + (HZ / 10);
else
tlimit = (unsigned long) -1;
- cs_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&cs_sleeper);
- if (!(cs_sleep_flag.flags & WK_WAKEUP))
+ cs_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&cs_sleeper);
+ if (!(cs_sleep_flag.opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- cs_sleep_flag.flags |= WK_TIMEOUT;
+ cs_sleep_flag.opts |= WK_TIMEOUT;
}
- cs_sleep_flag.flags &= ~WK_SLEEP;
+ cs_sleep_flag.opts &= ~WK_SLEEP;
}; /* Delay */
/*
unsigned long tlimit;
if (HZ / 5)
- current_set_timeout (tlimit = jiffies + (HZ / 5));
+ current->timeout = tlimit = jiffies + (HZ / 5);
else
tlimit = (unsigned long) -1;
- cs_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&cs_sleeper);
- if (!(cs_sleep_flag.flags & WK_WAKEUP))
+ cs_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&cs_sleeper);
+ if (!(cs_sleep_flag.opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- cs_sleep_flag.flags |= WK_TIMEOUT;
+ cs_sleep_flag.opts |= WK_TIMEOUT;
}
- cs_sleep_flag.flags &= ~WK_SLEEP;
+ cs_sleep_flag.opts &= ~WK_SLEEP;
}; /* Delay */
/*
unsigned long tlimit;
if (HZ)
- current_set_timeout (tlimit = jiffies + (HZ));
+ current->timeout = tlimit = jiffies + (HZ);
else
tlimit = (unsigned long) -1;
- cs_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&cs_sleeper);
- if (!(cs_sleep_flag.flags & WK_WAKEUP))
+ cs_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&cs_sleeper);
+ if (!(cs_sleep_flag.opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- cs_sleep_flag.flags |= WK_TIMEOUT;
+ cs_sleep_flag.opts |= WK_TIMEOUT;
}
- cs_sleep_flag.flags &= ~WK_SLEEP;
+ cs_sleep_flag.opts &= ~WK_SLEEP;
}; /* Longer delay */
}
{
int base = hw_config->io_base, irq = hw_config->irq;
int dma1 = hw_config->dma, dma2 = hw_config->dma2;
+ int old_num_mixers = num_mixers;
if (dma2 == -1)
dma2 = dma1;
0,
hw_config->osp);
+ if (num_mixers > old_num_mixers)
+ { /* Assume the mixer map is as suggested in the CS4232 databook */
+ AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_LINE);
+ AD1848_REROUTE (SOUND_MIXER_LINE2, SOUND_MIXER_CD);
+ AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM synth */
+ }
+
#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
if (mpu_base != 0 && mpu_irq != 0)
{
hw_config2.driver_use_1 = 0;
hw_config2.driver_use_2 = 0;
hw_config2.card_subtype = 0;
- hw_config2.osp = hw_config->osp;
if (probe_mpu401 (&hw_config2))
{
hw_config2.driver_use_1 = 0;
hw_config2.driver_use_2 = 0;
hw_config2.card_subtype = 0;
- hw_config2.osp = hw_config->osp;
unload_mpu401 (&hw_config2);
}
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
if (num_audiodevs) /* Audio devices present */
{
DMAbuf_init ();
- audio_init ();
+ audio_init_devices ();
}
#endif
if (trace_init)
printk ("Sound initialization started\n");
+#ifdef CONFIG_LOWLEVEL_SOUND
+ {
+ extern void sound_preinit_lowlevel_drivers (void);
+
+ sound_preinit_lowlevel_drivers ();
+ }
+#endif
+
/*
* Check the number of cards actually defined in the table
*/
*/
}
+#ifdef CONFIG_LOWLEVEL_SOUND
+ {
+ extern void sound_init_lowlevel_drivers (void);
+
+ sound_init_lowlevel_drivers ();
+ }
+#endif
+
if (trace_init)
printk ("Sound initialization complete\n");
}
void
sndtable_init (void)
{
- return start_cards ();
+ start_cards ();
}
void
unsigned long flags;
- DDB (printk ("unload driver %d: ", type));
+ DEB (printk ("unload driver %d: ", type));
for (i = 0; i < n && snd_installed_cards[i].card_type; i++)
if (snd_installed_cards[i].card_type == type)
{
if ((drv = snd_find_driver (type)) != -1)
{
- DDB (printk (" card %d", i));
+ DEB (printk (" card %d", i));
if (sound_drivers[drv].unload)
{
sound_drivers[drv].unload (&snd_installed_cards[i].config);
}
}
}
- DDB (printk ("\n"));
+ DEB (printk ("\n"));
save_flags (flags);
cli ();
{
int sel = -1;
- DDB (printk ("sndtable_probe(%d)\n", unit));
+ DEB (printk ("sndtable_probe(%d)\n", unit));
if (!unit)
- return TRUE;
-
- sound_started = 1;
+ return 1;
if (sel == -1 && num_sound_cards < max_sound_cards)
snd_installed_cards[sel].config.driver_use_1 = hw_config->driver_use_1;
snd_installed_cards[sel].config.driver_use_2 = hw_config->driver_use_2;
snd_installed_cards[sel].config.card_subtype = hw_config->card_subtype;
- snd_installed_cards[sel].config.osp = hw_config->osp;
if ((drv = snd_find_driver (snd_installed_cards[sel].card_type)) == -1)
{
snd_installed_cards[sel].enabled = 0;
- DDB (printk ("Failed to find driver\n"));
- return FALSE;
+ DEB (printk ("Failed to find driver\n"));
+ return 0;
}
- DDB (printk ("Driver name '%s'\n", sound_drivers[drv].name));
+ DEB (printk ("Driver name '%s'\n", sound_drivers[drv].name));
hw_config->card_subtype =
snd_installed_cards[sel].config.card_subtype =
if (sound_drivers[drv].probe (hw_config))
{
- DDB (printk ("Hardware probed OK\n"));
- return TRUE;
+ DEB (printk ("Hardware probed OK\n"));
+ return 1;
}
- DDB (printk ("Failed to find hardware\n"));
+ DEB (printk ("Failed to find hardware\n"));
snd_installed_cards[sel].enabled = 0; /*
* Mark as not detected
*/
- return FALSE;
+ return 0;
}
- return FALSE;
+ return 0;
}
-int
-sndtable_start_card (int unit, struct address_info *hw_config)
-{
- int sel = -1;
-
- DDB (printk ("sndtable_probe(%d)\n", unit));
-
- if (!unit)
- return TRUE;
-
- sound_started = 1;
-
- if (sel == -1 && num_sound_cards < max_sound_cards)
- {
- int i;
-
- i = sel = (num_sound_cards++);
-
- snd_installed_cards[sel].card_type = unit;
- snd_installed_cards[sel].enabled = 1;
- }
-
- if (sel != -1)
- {
- int drv;
-
- snd_installed_cards[sel].for_driver_use = NULL;
- snd_installed_cards[sel].config.io_base = hw_config->io_base;
- snd_installed_cards[sel].config.irq = hw_config->irq;
- snd_installed_cards[sel].config.dma = hw_config->dma;
- snd_installed_cards[sel].config.dma2 = hw_config->dma2;
- snd_installed_cards[sel].config.name = hw_config->name;
- snd_installed_cards[sel].config.always_detect = hw_config->always_detect;
- snd_installed_cards[sel].config.driver_use_1 = hw_config->driver_use_1;
- snd_installed_cards[sel].config.driver_use_2 = hw_config->driver_use_2;
- snd_installed_cards[sel].config.card_subtype = hw_config->card_subtype;
- snd_installed_cards[sel].config.osp = hw_config->osp;
-
- if ((drv = snd_find_driver (snd_installed_cards[sel].card_type)) == -1)
- {
- snd_installed_cards[sel].enabled = 0;
- DDB (printk ("Failed to find driver\n"));
- return FALSE;
- }
- DDB (printk ("Driver name '%s'\n", sound_drivers[drv].name));
-
- hw_config->card_subtype =
- snd_installed_cards[sel].config.card_subtype =
- sound_drivers[drv].card_subtype;
-
- if (sound_drivers[drv].probe (hw_config))
- {
- DDB (printk ("Hardware probed OK\n"));
- sound_drivers[drv].attach (hw_config);
- start_services ();
- return TRUE;
- }
-
- DDB (printk ("Failed to find hardware\n"));
- snd_installed_cards[sel].enabled = 0; /*
- * Mark as not detected
- */
- return FALSE;
- }
-
- return FALSE;
-}
int
sndtable_init_card (int unit, struct address_info *hw_config)
{
int i, n = num_sound_cards;
- DDB (printk ("sndtable_init_card(%d) entered\n", unit));
+ DEB (printk ("sndtable_init_card(%d) entered\n", unit));
if (!unit)
{
sndtable_init ();
- return TRUE;
+ return 1;
}
for (i = 0; i < n && snd_installed_cards[i].card_type; i++)
snd_installed_cards[i].config.driver_use_1 = hw_config->driver_use_1;
snd_installed_cards[i].config.driver_use_2 = hw_config->driver_use_2;
snd_installed_cards[i].config.card_subtype = hw_config->card_subtype;
- snd_installed_cards[i].config.osp = hw_config->osp;
if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
snd_installed_cards[i].enabled = 0; /*
else
{
- DDB (printk ("Located card - calling attach routine\n"));
+ DEB (printk ("Located card - calling attach routine\n"));
sound_drivers[drv].attach (hw_config);
- DDB (printk ("attach routine finished\n"));
+ DEB (printk ("attach routine finished\n"));
}
start_services ();
- return TRUE;
+ return 1;
}
- DDB (printk ("sndtable_init_card: No card defined with type=%d, num cards: %d\n",
+ DEB (printk ("sndtable_init_card: No card defined with type=%d, num cards: %d\n",
unit, num_sound_cards));
- return FALSE;
+ return 0;
}
int
snd_installed_cards[ptr].config.driver_use_1 = 0;
snd_installed_cards[ptr].config.driver_use_2 = 0;
snd_installed_cards[ptr].config.card_subtype = 0;
- snd_installed_cards[ptr].config.osp = NULL;
}
}
}
int dma1,
int dma2)
{
+#ifdef CONFIG_AUDIO
struct audio_driver *d;
struct audio_operations *op;
int l, num;
if (num_audiodevs >= MAX_AUDIO_DEV)
{
printk ("Sound: Too many audio drivers\n");
- return -(EIO);
+ return -EIO;
}
if (vers != AUDIO_DRIVER_VERSION ||
driver_size > sizeof (struct audio_driver))
{
printk ("Sound: Incompatible audio driver for %s\n", name);
- return -(EIO);
+ return -EIO;
}
if (d == NULL || op == NULL)
{
printk ("Sound: Can't allocate driver for (%s)\n", name);
- return -(ENOSPC);
+ return -ENOSPC;
}
memset ((char *) op, 0, sizeof (struct audio_operations));
audio_devs[num_audiodevs] = op;
num = num_audiodevs++;
-#ifdef CONFIG_AUDIO
DMAbuf_init ();
- audio_init ();
-#endif
+ audio_init_devices ();
return num;
+#else
+ return -EINVAL;
+#endif
}
int
if (num_mixers >= MAX_MIXER_DEV)
{
printk ("Sound: Too many mixer drivers\n");
- return -(EIO);
+ return -EIO;
}
if (vers != MIXER_DRIVER_VERSION ||
driver_size > sizeof (struct mixer_operations))
{
printk ("Sound: Incompatible mixer driver for %s\n", name);
- return -(EIO);
+ return -EIO;
}
if (op == NULL)
{
printk ("Sound: Can't allocate mixer driver for (%s)\n", name);
- return -(ENOSPC);
+ return -ENOSPC;
}
memset ((char *) op, 0, sizeof (struct mixer_operations));
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
* Numbers 1000 to N are reserved for driver's internal use.
*/
#define SNDCARD_DESKPROXL 27 /* Compaq Deskpro XL */
+#define SNDCARD_SBPNP 29
/*
* NOTE! NOTE! NOTE! NOTE!
void *for_driver_use;
};
-typedef struct pnp_sounddev
-{
- int id;
- void (*setup)(void *dev);
- char *driver_name;
-}pnp_sounddev;
/*
* Device specific parameters (used only by dmabuf.c)
#define DMA_ALLOC_DONE 0x00000020
#define DMA_SYNCING 0x00000040
#define DMA_CLEAN 0x00000080
+#define DMA_POST 0x00000100
int open_mode;
int underrun_count;
int byte_counter;
+ int data_rate; /* Bytes/second */
int mapping_flags;
#define DMA_MAP_MAPPED 0x00000001
* in the recent soundcards.
*/
typedef struct coproc_operations {
- char name[32];
+ char name[64];
int (*open) (void *devc, int sub_device);
void (*close) (void *devc, int sub_device);
int (*ioctl) (void *devc, unsigned int cmd, caddr_t arg, int local);
void (*reset) (int dev);
void (*halt_xfer) (int dev);
int (*local_qlen)(int dev);
- void (*copy_from_user)(int dev, char *localbuf, int localoffs,
+ void (*copy_user)(int dev, char *localbuf, int localoffs,
const char *userbuf, int useroffs, int len);
void (*halt_input) (int dev);
void (*halt_output) (int dev);
};
struct audio_operations {
- char name[32];
+ char name[64];
int flags;
#define NOTHING_SPECIAL 0x00
#define NEEDS_RESTART 0x01
#define DMA_DUPLEX 0x04
#define DMA_PSEUDO_AUTOMODE 0x08
#define DMA_HARDSTOP 0x10
+#define DMA_NODMA 0x20
int format_mask; /* Bitmask for supported audio formats */
void *devc; /* Driver specific info */
struct audio_driver *d;
int min_fragment; /* 0 == unlimited */
};
+int *load_mixer_volumes(char *name, int *levels, int present);
+
struct mixer_operations {
char id[16];
- char name[32];
+ char name[64];
int (*ioctl) (int dev, unsigned int cmd, caddr_t arg);
void *devc;
+ int modify_counter;
};
struct synth_operations {
);
void (*close) (int dev);
int (*ioctl) (int dev, unsigned int cmd, caddr_t arg);
- int (*putc) (int dev, unsigned char data);
+ int (*outputc) (int dev, unsigned char data);
int (*start_read) (int dev);
int (*end_read) (int dev);
void (*kick)(int dev);
};
#ifdef _DEV_TABLE_C_
+
struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL}; int num_audiodevs = 0;
struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0;
struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0;
#endif
#ifdef CONFIG_MSS
{"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound},
- /* MSS without IRQ/DMA config registers (for DEC Alphas) */
- {"PCXBJ", 1, SNDCARD_PSEUDO_MSS, "MS Sound System (AXP)", attach_ms_sound, probe_ms_sound, unload_ms_sound},
/* Compaq Deskpro XL */
{"DESKPROXL", 2, SNDCARD_DESKPROXL, "Compaq Deskpro XL", attach_ms_sound, probe_ms_sound, unload_ms_sound},
#endif
{"CS4232", 0, SNDCARD_CS4232, "CS4232", attach_cs4232, probe_cs4232, unload_cs4232},
{"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI", attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu},
#endif
-#ifdef CONFIG_YM3812
+#if defined(CONFIG_YM3812)
{"OPL3", 0, SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib, unload_adlib},
#endif
#ifdef CONFIG_PAS
{"PAS16", 0, SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, unload_pas},
#endif
-#if defined(CONFIG_MPU401) && defined(CONFIG_MIDI)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
{"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401, unload_mpu401},
#endif
+#if (defined(CONFIG_UART401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ {"UART401", 0, SNDCARD_UART401,"MPU-401 (UART)",
+ attach_uart401, probe_uart401, unload_uart401},
+#endif
#if defined(CONFIG_MAUI)
{"MAUI", 0, SNDCARD_MAUI,"TB Maui", attach_maui, probe_maui, unload_maui},
#endif
#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI)
{"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850, unload_uart6850},
#endif
-#ifdef CONFIG_SB
+
+
+
+
+#ifdef CONFIG_SBDSP
{"SBLAST", 0, SNDCARD_SB, "Sound Blaster", attach_sb_card, probe_sb, unload_sb},
-#ifdef CONFIG_MIDI
+ {"SBPNP", 6, SNDCARD_SBPNP, "Sound Blaster PnP", attach_sb_card, probe_sb, unload_sb},
+
+# ifdef CONFIG_MIDI
{"SBMPU", 0, SNDCARD_SB16MIDI,"SB MPU-401", attach_sbmpu, probe_sbmpu, unload_sbmpu},
+# endif
#endif
-#endif
+
+
+
#ifdef CONFIG_GUS16
{"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16},
#endif
-#ifdef CONFIG_GUS
+#ifdef CONFIG_GUSHW
{"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, unload_gus},
{"GUSPNP", 1, SNDCARD_GUSPNP, "GUS PnP", attach_gus_card, probe_gus, unload_gus},
#endif
-#ifdef CONFIG_SSCAPE
+#ifdef CONFIG_SSCAPEHW
{"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape", attach_sscape, probe_sscape, unload_sscape},
{"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound, unload_ss_ms_sound},
#endif
{"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTrix (SB mode)", attach_trix_sb, probe_trix_sb, unload_trix_sb},
{"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTrix MIDI", attach_trix_mpu, probe_trix_mpu, unload_trix_mpu},
#endif
+
{NULL, 0, 0, "*?*", NULL, NULL, NULL}
};
#ifdef CONFIG_YM3812
{SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE},
#endif
-/* Define some expansion space */
- {0, {0}, 0},
- {0, {0}, 0},
- {0, {0}, 0},
- {0, {0}, 0},
{0, {0}, 0}
};
int max_sound_cards = 20;
#endif
-# ifdef MODULE
+#if defined(MODULE) || (!defined(linux) && !defined(_AIX))
int trace_init = 0;
# else
int trace_init = 1;
# endif
+
#else
extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; extern int num_audiodevs;
extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers;
void sound_setup (char *str, int *ints);
int sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan);
-void sound_free_dmap (int dev, struct dma_buffparms *dmap);
+void sound_free_dmap (int dev, struct dma_buffparms *dmap, int chn);
extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info);
-void install_pnp_sounddrv(struct pnp_sounddev *drv);
int sndtable_probe (int unit, struct address_info *hw_config);
int sndtable_init_card (int unit, struct address_info *hw_config);
int sndtable_start_card (int unit, struct address_info *hw_config);
int count, int dma_mode, int autoinit);
void sound_dma_intr (int dev, struct dma_buffparms *dmap, int chan);
-#define AUDIO_DRIVER_VERSION 1
-#define MIXER_DRIVER_VERSION 1
+#define AUDIO_DRIVER_VERSION 2
+#define MIXER_DRIVER_VERSION 2
int sound_install_audiodrv(int vers,
char *name,
struct audio_driver *driver,
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#include "sound_config.h"
-#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS)
+#if defined(CONFIG_AUDIO) || defined(CONFIG_GUSHW)
-static wait_handle *in_sleeper[MAX_AUDIO_DEV] =
+static struct wait_queue *in_sleeper[MAX_AUDIO_DEV] =
{NULL};
static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] =
{
{0}};
-static wait_handle *out_sleeper[MAX_AUDIO_DEV] =
+static struct wait_queue *out_sleeper[MAX_AUDIO_DEV] =
{NULL};
static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] =
{
unsigned i, n;
unsigned sr, nc, sz, bsz;
- if (dmap->fragment_size == 0)
- { /* Compute the fragment size using the default algorithm */
+ sr = dsp_dev->d->set_speed (dev, 0);
+ nc = dsp_dev->d->set_channels (dev, 0);
+ sz = dsp_dev->d->set_bits (dev, 0);
- sr = dsp_dev->d->set_speed (dev, 0);
- nc = dsp_dev->d->set_channels (dev, 0);
- sz = dsp_dev->d->set_bits (dev, 0);
+ if (sz == 8)
+ dmap->neutral_byte = NEUTRAL8;
+ else
+ dmap->neutral_byte = NEUTRAL16;
- if (sz == 8)
- dmap->neutral_byte = NEUTRAL8;
- else
- dmap->neutral_byte = NEUTRAL16;
+ if (sr < 1 || nc < 1 || sz < 1)
+ {
+ printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n",
+ dev, sr, nc, sz);
+ sr = DSP_DEFAULT_SPEED;
+ nc = 1;
+ sz = 8;
+ }
- if (sr < 1 || nc < 1 || sz < 1)
- {
- printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n",
- dev, sr, nc, sz);
- sr = DSP_DEFAULT_SPEED;
- nc = 1;
- sz = 8;
- }
+ sz = sr * nc * sz;
- sz = sr * nc * sz;
+ sz /= 8; /* #bits -> #bytes */
+ dmap->data_rate = sz;
- sz /= 8; /* #bits -> #bytes */
+ if (dmap->fragment_size == 0)
+ { /* Compute the fragment size using the default algorithm */
/*
* Compute a buffer size for time not exceeding 1 second.
if (dmap->subdivision == 0) /* Not already set */
{
- dmap->subdivision = 1; /* Init to the default value */
-#ifndef V35A9_COMPATIBLE
- if (recording)
- dmap->subdivision = 4; /* Use shorter fragments when recording */
-#endif
+ dmap->subdivision = 4; /* Init to the default value */
+
+ if ((bsz / dmap->subdivision) > 4096)
+ dmap->subdivision *= 2;
+ if ((bsz / dmap->subdivision) < 4096)
+ dmap->subdivision = 1;
}
bsz /= dmap->subdivision;
n = MAX_SUB_BUFFERS;
if (n > dmap->max_fragments)
n = dmap->max_fragments;
+
+ if (n < 2)
+ {
+ n = 2;
+ bsz /= 2;
+ }
+
dmap->nbufs = n;
dmap->bytes_in_use = n * bsz;
+ dmap->fragment_size = bsz;
if (dmap->raw_buf)
memset (dmap->raw_buf,
{
if (dmap == audio_devs[dev]->dmap_out)
{
- out_sleep_flag[dev].flags = WK_NONE;
+ out_sleep_flag[dev].opts = WK_NONE;
}
else
{
- in_sleep_flag[dev].flags = WK_NONE;
+ in_sleep_flag[dev].opts = WK_NONE;
}
dmap->flags = DMA_BUSY; /* Other flags off */
dmap->dma_mode = DMODE_NONE;
dmap->mapping_flags = 0;
dmap->neutral_byte = NEUTRAL8;
+ dmap->data_rate = 8000;
dmap->cfrag = -1;
dmap->closing = 0;
}
open_dmap (int dev, int mode, struct dma_buffparms *dmap, int chan)
{
if (dmap->flags & DMA_BUSY)
- return -(EBUSY);
+ return -EBUSY;
{
int err;
}
if (dmap->raw_buf == NULL)
- return -(ENOSPC); /* Memory allocation failed during boot */
+ return -ENOSPC; /* Memory allocation failed during boot */
if (sound_open_dma (chan, audio_devs[dev]->name))
{
printk ("Unable to grab(2) DMA%d for the audio driver\n", chan);
- return -(EBUSY);
+ return -EBUSY;
}
dmap->open_mode = mode;
dmap->max_fragments = 65536; /* Just a large value */
dmap->byte_counter = 0;
+
dma_init_buffers (dev, dmap);
return 0;
dmap->flags &= ~DMA_BUSY;
disable_dma (chan);
- sound_free_dmap (dev, dmap);
+ sound_free_dmap (dev, dmap, chan);
}
static unsigned int
default_set_bits (int dev, unsigned int bits)
{
- return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) (long) bits, 1);
+ return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) bits, 1);
}
static int
default_set_speed (int dev, int speed)
{
- return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) (long) speed, 1);
+ return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) speed, 1);
}
static short
{
int c = channels;
- return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) (long) c, 1);
+ return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) c, 1);
}
static void
if (dev >= num_audiodevs)
{
/* printk ("PCM device %d not installed.\n", dev); */
- return -(ENXIO);
+ return -ENXIO;
}
if (!audio_devs[dev])
{
/* printk ("PCM device %d not initialized\n", dev); */
- return -(ENXIO);
+ return -ENXIO;
}
if (!(audio_devs[dev]->flags & DMA_DUPLEX))
audio_devs[dev]->enable_bits = mode;
if (mode & OPEN_READ &&
- audio_devs[dev]->flags & DMA_DUPLEX && dmap_out != dmap_in)
+ audio_devs[dev]->flags & DMA_DUPLEX &&
+ dmap_out != dmap_in)
if ((retval = open_dmap (dev, mode, dmap_in, audio_devs[dev]->dmachan2)) < 0)
{
audio_devs[dev]->d->close (dev);
}
audio_devs[dev]->open_mode = mode;
audio_devs[dev]->go = 1;
- in_sleep_flag[dev].flags = WK_NONE;
- out_sleep_flag[dev].flags = WK_NONE;
+ in_sleep_flag[dev].opts = WK_NONE;
+ out_sleep_flag[dev].opts = WK_NONE;
audio_devs[dev]->d->set_bits (dev, 8);
audio_devs[dev]->d->set_channels (dev, 1);
return 0;
}
-static void
-dma_reset (int dev)
+void
+DMAbuf_reset (int dev)
{
unsigned long flags;
dma_reset_output (int dev)
{
unsigned long flags;
+ int tmout;
+
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+
+ if (dmap->dma_mode != DMODE_OUTPUT)
+ return;
+
+ if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */
+ return;
+/*
+ * First wait until the current fragment has been played completely
+ */
save_flags (flags);
cli ();
+
+ tmout =
+ (dmap->fragment_size * HZ) / dmap->data_rate;
+
+ tmout += HZ / 10; /* Some safety distance */
+
+ if (tmout < (HZ / 2))
+ tmout = HZ / 2;
+ if (tmout > 20 * HZ)
+ tmout = 20 * HZ;
+
+ audio_devs[dev]->dmap_out->flags |= DMA_SYNCING;
+
+ audio_devs[dev]->dmap_out->underrun_count = 0;
+ if (!(current->signal & ~current->blocked)
+ && audio_devs[dev]->dmap_out->qlen
+ && audio_devs[dev]->dmap_out->underrun_count == 0)
+ {
+
+ {
+ unsigned long tlimit;
+
+ if (tmout)
+ current->timeout = tlimit = jiffies + (tmout);
+ else
+ tlimit = (unsigned long) -1;
+ out_sleep_flag[dev].opts = WK_SLEEP;
+ interruptible_sleep_on (&out_sleeper[dev]);
+ if (!(out_sleep_flag[dev].opts & WK_WAKEUP))
+ {
+ if (jiffies >= tlimit)
+ out_sleep_flag[dev].opts |= WK_TIMEOUT;
+ }
+ out_sleep_flag[dev].opts &= ~WK_SLEEP;
+ };
+ }
+ audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
+ audio_devs[dev]->dmap_out->flags |= DMA_RESTART;
+
+/*
+ * Finally shut the device off
+ */
+
if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
!audio_devs[dev]->d->halt_output)
audio_devs[dev]->d->reset (dev);
else
audio_devs[dev]->d->halt_output (dev);
+ audio_devs[dev]->dmap_out->flags &= ~DMA_STARTED;
restore_flags (flags);
dma_init_buffers (dev, audio_devs[dev]->dmap_out);
audio_devs[dev]->d->reset (dev);
else
audio_devs[dev]->d->halt_input (dev);
+ audio_devs[dev]->dmap_in->flags &= ~DMA_STARTED;
restore_flags (flags);
dma_init_buffers (dev, audio_devs[dev]->dmap_in);
reorganize_buffers (dev, audio_devs[dev]->dmap_in, 1);
}
-static int
-dma_sync (int dev)
+static void
+launch_output (int dev, struct dma_buffparms *dmap)
+{
+ dmap->flags |= DMA_ACTIVE;
+
+ if (dmap->dma_mode == DMODE_NONE || dmap->flags & DMA_RESTART)
+ {
+ reorganize_buffers (dev, audio_devs[dev]->dmap_out, 0);
+ audio_devs[dev]->d->prepare_for_output (dev,
+ dmap->fragment_size, dmap->nbufs);
+ }
+
+ dmap->dma_mode |= DMODE_OUTPUT;
+
+ audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 0,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
+ !(dmap->flags & DMA_STARTED));
+ dmap->flags |= DMA_STARTED;
+ if (audio_devs[dev]->d->trigger)
+ audio_devs[dev]->d->trigger (dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+}
+
+int
+DMAbuf_sync (int dev)
{
unsigned long flags;
+ int tmout;
if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))
return 0;
if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)
{
+
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+
save_flags (flags);
cli ();
+ tmout =
+ (dmap->fragment_size * HZ) / dmap->data_rate;
+
+ tmout += HZ / 10; /* Some safety distance */
+
+ if (tmout < (HZ / 2))
+ tmout = HZ / 2;
+ if (tmout > 20 * HZ)
+ tmout = 20 * HZ;
+
+ ;
+ if (dmap->qlen > 0)
+ if (!(dmap->flags & DMA_ACTIVE))
+ launch_output (dev, dmap);
+ ;
+
audio_devs[dev]->dmap_out->flags |= DMA_SYNCING;
audio_devs[dev]->dmap_out->underrun_count = 0;
- while (!current_got_fatal_signal ()
+ while (!(current->signal & ~current->blocked)
&& audio_devs[dev]->dmap_out->qlen
&& audio_devs[dev]->dmap_out->underrun_count == 0)
{
{
unsigned long tlimit;
- if (HZ)
- current_set_timeout (tlimit = jiffies + (HZ));
+ if (tmout)
+ current->timeout = tlimit = jiffies + (tmout);
else
tlimit = (unsigned long) -1;
- out_sleep_flag[dev].flags = WK_SLEEP;
- module_interruptible_sleep_on (&out_sleeper[dev]);
- if (!(out_sleep_flag[dev].flags & WK_WAKEUP))
+ out_sleep_flag[dev].opts = WK_SLEEP;
+ interruptible_sleep_on (&out_sleeper[dev]);
+ if (!(out_sleep_flag[dev].opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- out_sleep_flag[dev].flags |= WK_TIMEOUT;
+ out_sleep_flag[dev].opts |= WK_TIMEOUT;
}
- out_sleep_flag[dev].flags &= ~WK_SLEEP;
+ out_sleep_flag[dev].opts &= ~WK_SLEEP;
};
- if ((out_sleep_flag[dev].flags & WK_TIMEOUT))
+ if ((out_sleep_flag[dev].opts & WK_TIMEOUT))
{
audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING;
restore_flags (flags);
return audio_devs[dev]->dmap_out->qlen;
}
}
- audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING;
+ audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
+ audio_devs[dev]->dmap_out->flags |= DMA_RESTART;
restore_flags (flags);
-
/*
* Some devices such as GUS have huge amount of on board RAM for the
* audio data. We have to wait until the device has finished playing.
cli ();
if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */
{
- while (!(current_got_fatal_signal ())
+ while (!((current->signal & ~current->blocked))
&& audio_devs[dev]->d->local_qlen (dev))
{
{
unsigned long tlimit;
- if (HZ)
- current_set_timeout (tlimit = jiffies + (HZ));
+ if (tmout)
+ current->timeout = tlimit = jiffies + (tmout);
else
tlimit = (unsigned long) -1;
- out_sleep_flag[dev].flags = WK_SLEEP;
- module_interruptible_sleep_on (&out_sleeper[dev]);
- if (!(out_sleep_flag[dev].flags & WK_WAKEUP))
+ out_sleep_flag[dev].opts = WK_SLEEP;
+ interruptible_sleep_on (&out_sleeper[dev]);
+ if (!(out_sleep_flag[dev].opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- out_sleep_flag[dev].flags |= WK_TIMEOUT;
+ out_sleep_flag[dev].opts |= WK_TIMEOUT;
}
- out_sleep_flag[dev].flags &= ~WK_SLEEP;
+ out_sleep_flag[dev].opts &= ~WK_SLEEP;
};
}
}
restore_flags (flags);
}
+ audio_devs[dev]->dmap_out->dma_mode = DMODE_NONE;
return audio_devs[dev]->dmap_out->qlen;
}
audio_devs[dev]->dmap_out->closing = 1;
audio_devs[dev]->dmap_in->closing = 1;
- if (!(current_got_fatal_signal ())
+ if (!((current->signal & ~current->blocked))
&& (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT))
{
- dma_sync (dev);
+ DMAbuf_sync (dev);
}
if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)
if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */
{
- dma_sync (dev);
- dma_reset (dev);
+ DMAbuf_sync (dev);
+ DMAbuf_reset (dev);
dmap->dma_mode = DMODE_NONE;
}
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev, dmap, 1);
if (prepare || !dmap->dma_mode)
{
int err;
+ reorganize_buffers (dev, dmap, 1);
if ((err = audio_devs[dev]->d->prepare_for_input (dev,
dmap->fragment_size, dmap->nbufs)) < 0)
{
if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
{
printk ("Sound: Can't read from mmapped device (1)\n");
- return -(EINVAL);
+ return -EINVAL;
}
else if (!dmap->qlen)
{
int tmout;
+ if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) ||
+ !audio_devs[dev]->go)
+ {
+ restore_flags (flags);
+ return -EAGAIN;
+ }
+
if ((err = activate_recording (dev, dmap)) < 0)
{
restore_flags (flags);
if (dontblock)
{
restore_flags (flags);
- return -(EAGAIN);
- }
-
- if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) &
- audio_devs[dev]->go)
- {
- restore_flags (flags);
- return -(EAGAIN);
+ return -EAGAIN;
}
if (!audio_devs[dev]->go)
tmout = 0;
else
- tmout = 10 * HZ;
+ {
+ tmout =
+ (dmap->fragment_size * HZ) / dmap->data_rate;
+
+ tmout += HZ / 10; /* Some safety distance */
+
+ if (tmout < (HZ / 2))
+ tmout = HZ / 2;
+ if (tmout > 20 * HZ)
+ tmout = 20 * HZ;
+ }
{
unsigned long tlimit;
if (tmout)
- current_set_timeout (tlimit = jiffies + (tmout));
+ current->timeout = tlimit = jiffies + (tmout);
else
tlimit = (unsigned long) -1;
- in_sleep_flag[dev].flags = WK_SLEEP;
- module_interruptible_sleep_on (&in_sleeper[dev]);
- if (!(in_sleep_flag[dev].flags & WK_WAKEUP))
+ in_sleep_flag[dev].opts = WK_SLEEP;
+ interruptible_sleep_on (&in_sleeper[dev]);
+ if (!(in_sleep_flag[dev].opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- in_sleep_flag[dev].flags |= WK_TIMEOUT;
+ in_sleep_flag[dev].opts |= WK_TIMEOUT;
}
- in_sleep_flag[dev].flags &= ~WK_SLEEP;
+ in_sleep_flag[dev].opts &= ~WK_SLEEP;
};
- if ((in_sleep_flag[dev].flags & WK_TIMEOUT))
+ if ((in_sleep_flag[dev].opts & WK_TIMEOUT))
{
printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n");
err = EIO;
restore_flags (flags);
if (!dmap->qlen)
- return -(err);
+ return -err;
*buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]];
*len = dmap->fragment_size - dmap->counts[dmap->qhead];
if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
{
printk ("Sound: Can't read from mmapped device (2)\n");
- return -(EINVAL);
+ return -EINVAL;
}
else if (p >= dmap->fragment_size)
{ /* This buffer is completely empty */
fact = dmap->subdivision;
if (fact == 0)
fact = 1;
- return snd_ioctl_return ((int *) arg, fact);
+ return ioctl_out (arg, fact);
}
if (dmap->subdivision != 0 ||
dmap->fragment_size) /* Too late to change */
- return -(EINVAL);
+ return -EINVAL;
if (fact > MAX_REALTIME_FACTOR)
- return -(EINVAL);
+ return -EINVAL;
if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
- return -(EINVAL);
+ return -EINVAL;
dmap->subdivision = fact;
- return snd_ioctl_return ((int *) arg, fact);
+ return ioctl_out (arg, fact);
}
static int
int bytes, count;
if (fact == 0)
- return -(EIO);
+ return -EIO;
if (dmap->subdivision != 0 ||
dmap->fragment_size) /* Too late to change */
- return -(EINVAL);
+ return -EINVAL;
bytes = fact & 0xffff;
count = (fact >> 16) & 0x7fff;
count = MAX_SUB_BUFFERS;
if (bytes < 4 || bytes > 17) /* <16 || > 512k */
- return -(EINVAL);
+ return -EINVAL;
if (count < 2)
- return -(EINVAL);
+ return -EINVAL;
if (audio_devs[dev]->min_fragment > 0)
if (bytes < audio_devs[dev]->min_fragment)
dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */
if (arg)
- return snd_ioctl_return ((int *) arg, bytes | (count << 16));
+ return ioctl_out (arg, bytes | (count << 16));
else
return 0;
}
static int
get_buffer_pointer (int dev, int chan, struct dma_buffparms *dmap)
{
+/*
+ * Try to approximate the active byte position of the DMA pointer within the
+ * buffer area as well as possible.
+ */
int pos;
unsigned long flags;
clear_dma_ff (chan);
disable_dma (chan);
pos = get_dma_residue (chan);
+ if (chan > 3) /* Word count */
+ pos *= 2;
+ pos = dmap->bytes_in_use - pos;
+ if (pos < 0)
+ pos = 0;
+ if (pos > dmap->bytes_in_use)
+ pos = dmap->bytes_in_use;
enable_dma (chan);
}
restore_flags (flags);
/* printk ("%04x ", pos); */
- if (audio_devs[dev]->flags & DMA_AUTOMODE)
- return dmap->bytes_in_use - pos;
- else
- {
- pos = dmap->fragment_size - pos;
- if (pos < 0)
- return 0;
- return pos;
- }
+ return pos;
}
{
struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out;
struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in;
- long larg = (long) arg;
switch (cmd)
{
- case SOUND_PCM_WRITE_RATE:
- if (local)
- return audio_devs[dev]->d->set_speed (dev, larg);
- return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, get_user ((int *) arg)));
-
- case SOUND_PCM_READ_RATE:
- if (local)
- return audio_devs[dev]->d->set_speed (dev, 0);
- return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, 0));
-
- case SNDCTL_DSP_STEREO:
- if (local)
- return audio_devs[dev]->d->set_channels (dev, larg + 1) - 1;
- return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_user ((int *) arg) + 1) - 1);
-
- case SOUND_PCM_WRITE_CHANNELS:
- if (local)
- return audio_devs[dev]->d->set_channels (dev, (short) larg);
- return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_user ((int *) arg)));
-
- case SOUND_PCM_READ_CHANNELS:
- if (local)
- return audio_devs[dev]->d->set_channels (dev, 0);
- return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, 0));
-
- case SNDCTL_DSP_SAMPLESIZE:
- if (local)
- return audio_devs[dev]->d->set_bits (dev, larg);
- return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, get_user ((int *) arg)));
-
- case SOUND_PCM_READ_BITS:
- if (local)
- return audio_devs[dev]->d->set_bits (dev, 0);
- return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, 0));
-
- case SNDCTL_DSP_RESET:
- dma_reset (dev);
- return 0;
- break;
-
- case SNDCTL_DSP_SYNC:
- dma_sync (dev);
- dma_reset (dev);
- return 0;
- break;
-
case SNDCTL_DSP_GETBLKSIZE:
if (!(dmap_out->flags & DMA_ALLOC_DONE))
{
(audio_devs[dev]->open_mode == OPEN_READ));
}
- return snd_ioctl_return ((int *) arg, dmap_out->fragment_size);
+ if (local)
+ return dmap_out->fragment_size;
+ else
+ return ioctl_out (arg, dmap_out->fragment_size);
break;
case SNDCTL_DSP_SUBDIVIDE:
{
- int fact = get_user ((int *) arg);
+ int fact;
int ret;
+ get_user (fact, (int *) arg);
+
ret = dma_subdivide (dev, dmap_out, arg, fact);
if (ret < 0)
return ret;
}
break;
- case SNDCTL_DSP_SETDUPLEX:
- if (audio_devs[dev]->flags & DMA_DUPLEX)
- return 0;
- else
- return -(EIO);
- break;
-
case SNDCTL_DSP_SETFRAGMENT:
{
- int fact = get_user ((int *) arg);
+ int fact;
int ret;
+ get_user (fact, (int *) arg);
ret = dma_set_fragment (dev, dmap_out, arg, fact);
if (ret < 0)
return ret;
case SNDCTL_DSP_GETISPACE:
case SNDCTL_DSP_GETOSPACE:
if (!local)
- return -(EINVAL);
+ return -EINVAL;
else
{
struct dma_buffparms *dmap = dmap_out;
if (cmd == SNDCTL_DSP_GETISPACE &&
!(audio_devs[dev]->open_mode & OPEN_READ))
- return -(EINVAL);
+ return -EINVAL;
if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
dmap = dmap_in;
if (dmap->mapping_flags & DMA_MAP_MAPPED)
- return -(EINVAL);
+ return -EINVAL;
if (!(dmap->flags & DMA_ALLOC_DONE))
reorganize_buffers (dev, dmap, (cmd == SNDCTL_DSP_GETISPACE));
{
unsigned long flags;
- int bits = get_user ((int *) arg) & audio_devs[dev]->open_mode;
+ int bits;
int changed;
+ get_user (bits, (int *) arg);
+ bits &= audio_devs[dev]->open_mode;
+
if (audio_devs[dev]->d->trigger == NULL)
- return -(EINVAL);
+ return -EINVAL;
if (!(audio_devs[dev]->flags & DMA_DUPLEX))
if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT))
{
printk ("Sound: Device doesn't have full duplex capability\n");
- return -(EINVAL);
+ return -EINVAL;
}
save_flags (flags);
{
int err;
- if (!(dmap_in->flags & DMA_ALLOC_DONE))
- {
- reorganize_buffers (dev, dmap_in, 1);
- }
+ reorganize_buffers (dev, dmap_in, 1);
if ((err = audio_devs[dev]->d->prepare_for_input (dev,
dmap_in->fragment_size, dmap_in->nbufs)) < 0)
- return -(err);
+ return -err;
audio_devs[dev]->enable_bits = bits;
activate_recording (dev, dmap_in);
}
+
if ((changed & bits) & PCM_ENABLE_OUTPUT &&
dmap_out->mapping_flags & DMA_MAP_MAPPED &&
audio_devs[dev]->go)
{
- int err;
if (!(dmap_out->flags & DMA_ALLOC_DONE))
{
reorganize_buffers (dev, dmap_out, 0);
}
- if ((err = audio_devs[dev]->d->prepare_for_output (dev,
- dmap_out->fragment_size, dmap_out->nbufs)) < 0)
- return -(err);
-
+ ;
dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
- DMAbuf_start_output (dev, 0, dmap_out->fragment_size);
+ launch_output (dev, dmap_out);
+ ;
}
audio_devs[dev]->enable_bits = bits;
restore_flags (flags);
}
case SNDCTL_DSP_GETTRIGGER:
- return snd_ioctl_return ((int *) arg, audio_devs[dev]->enable_bits);
+ return ioctl_out (arg, audio_devs[dev]->enable_bits);
break;
case SNDCTL_DSP_SETSYNCRO:
if (!audio_devs[dev]->d->trigger)
- return -(EINVAL);
+ return -EINVAL;
audio_devs[dev]->d->trigger (dev, 0);
audio_devs[dev]->go = 0;
unsigned long flags;
if (!(audio_devs[dev]->open_mode & OPEN_READ))
- return -(EINVAL);
+ return -EINVAL;
save_flags (flags);
cli ();
info.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan2, audio_devs[dev]->dmap_in);
info.blocks = audio_devs[dev]->dmap_in->qlen;
info.bytes += info.ptr;
- copy_to_user (&((char *) arg)[0], (char *) &info, sizeof (info));
+ {
+ char *fixit = (char *) &info;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (info));
+ };
if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
audio_devs[dev]->dmap_in->qlen = 0; /* Acknowledge interrupts */
unsigned long flags;
if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
- return -(EINVAL);
+ return -EINVAL;
save_flags (flags);
cli ();
info.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan1, audio_devs[dev]->dmap_out);
info.blocks = audio_devs[dev]->dmap_out->qlen;
info.bytes += info.ptr;
- copy_to_user (&((char *) arg)[0], (char *) &info, sizeof (info));
+ {
+ char *fixit = (char *) &info;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (info));
+ };
if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
audio_devs[dev]->dmap_out->qlen = 0; /* Acknowledge interrupts */
break;
+ case SNDCTL_DSP_POST:
+ ;
+ if (audio_devs[dev]->dmap_out->qlen > 0)
+ if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE))
+ launch_output (dev, audio_devs[dev]->dmap_out);
+ ;
+ return 0;
+ break;
+
default:
return audio_devs[dev]->d->ioctl (dev, cmd, arg, local);
}
* one or more audio devices at desired moment.
*/
+void
+DMAbuf_start_device (int dev)
+{
+ if (audio_devs[dev]->open_mode != 0)
+ if (!audio_devs[dev]->go)
+ {
+ /* OK to start the device */
+ audio_devs[dev]->go = 1;
+
+ if (audio_devs[dev]->d->trigger)
+ audio_devs[dev]->d->trigger (dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+}
+
void
DMAbuf_start_devices (unsigned int devmask)
{
for (dev = 0; dev < num_audiodevs; dev++)
if (devmask & (1 << dev))
- if (audio_devs[dev]->open_mode != 0)
- if (!audio_devs[dev]->go)
- {
- /* OK to start the device */
- audio_devs[dev]->go = 1;
-
- if (audio_devs[dev]->d->trigger)
- audio_devs[dev]->d->trigger (dev,
- audio_devs[dev]->enable_bits * audio_devs[dev]->go);
- }
+ DMAbuf_start_device (dev);
}
static int
int len, max, tmp;
struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
- if (dmap->qlen >= dmap->nbufs) /* No space at all */
+ /* Don't allow touching pages too close to the playing ones */
+ int lim = dmap->nbufs - 1;
+
+ if (lim < 2)
+ lim = 2;
+
+ if (dmap->qlen >= lim) /* No space at all */
return 0;
/*
- * Verify that there are no more pending buffers than the limit
- * defined by the process.
+ * Verify that there are no more pending buffers than the limit
+ * defined by the process.
*/
max = dmap->max_fragments;
tmp = audio_devs[dev]->d->local_qlen (dev);
if (tmp && len)
tmp--; /*
- * This buffer has been counted twice
+ * This buffer has been counted twice
*/
len += tmp;
}
if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
{
printk ("Sound: Can't write to mmapped device (3)\n");
- return -(EINVAL);
+ return -EINVAL;
}
if (dmap->dma_mode == DMODE_INPUT) /* Direction change */
{
- dma_reset (dev);
+ DMAbuf_reset (dev);
dmap->dma_mode = DMODE_NONE;
}
else if (dmap->flags & DMA_RESTART) /* Restart buffering */
{
- dma_sync (dev);
+ DMAbuf_sync (dev);
dma_reset_output (dev);
+ dmap->dma_mode = DMODE_NONE;
}
dmap->flags &= ~(DMA_RESTART | DMA_EMPTY);
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev, dmap, 0);
-
if (!dmap->dma_mode)
{
int err;
+ reorganize_buffers (dev, dmap, 0);
dmap->dma_mode = DMODE_OUTPUT;
if ((err = audio_devs[dev]->d->prepare_for_output (dev,
dmap->fragment_size, dmap->nbufs)) < 0)
if (dontblock)
{
restore_flags (flags);
- return -(EAGAIN);
+ return -EAGAIN;
}
- if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT) &&
- audio_devs[dev]->go)
+ if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))
{
restore_flags (flags);
- return -(EAGAIN);
+ return -EAGAIN;
}
/*
if (!audio_devs[dev]->go)
tmout = 0;
else
- tmout = 10 * HZ;
+ {
+ tmout =
+ (dmap->fragment_size * HZ) / dmap->data_rate;
+
+ tmout += HZ / 10; /* Some safety distance */
+
+ if (tmout < (HZ / 2))
+ tmout = HZ / 2;
+ if (tmout > 20 * HZ)
+ tmout = 20 * HZ;
+ }
{
unsigned long tlimit;
if (tmout)
- current_set_timeout (tlimit = jiffies + (tmout));
+ current->timeout = tlimit = jiffies + (tmout);
else
tlimit = (unsigned long) -1;
- out_sleep_flag[dev].flags = WK_SLEEP;
- module_interruptible_sleep_on (&out_sleeper[dev]);
- if (!(out_sleep_flag[dev].flags & WK_WAKEUP))
+ out_sleep_flag[dev].opts = WK_SLEEP;
+ interruptible_sleep_on (&out_sleeper[dev]);
+ if (!(out_sleep_flag[dev].opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- out_sleep_flag[dev].flags |= WK_TIMEOUT;
+ out_sleep_flag[dev].opts |= WK_TIMEOUT;
}
- out_sleep_flag[dev].flags &= ~WK_SLEEP;
+ out_sleep_flag[dev].opts &= ~WK_SLEEP;
};
- if ((out_sleep_flag[dev].flags & WK_TIMEOUT))
+ if ((out_sleep_flag[dev].opts & WK_TIMEOUT))
{
printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
err = EIO;
dmap->flags &= ~DMA_RESTART;
audio_devs[dev]->d->reset (dev);
}
- else if (current_got_fatal_signal ())
+ else if ((current->signal & ~current->blocked))
{
err = EINTR;
abort = 1;
if (!space_in_queue (dev))
{
- return -(err); /* Caught a signal ? */
+ return -err; /* Caught a signal ? */
}
*buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;
{
struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
int restart = 0;
+ int post = dmap->flags & DMA_POST;
+
+ ;
+
+ dmap->flags &= ~DMA_POST;
dmap->cfrag = -1;
if (dmap->flags & DMA_RESTART)
{
dmap->qlen++;
- if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
- printk ("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n",
- dev, dmap->qlen, dmap->nbufs);
dmap->counts[dmap->qtail] = l;
if (l < dmap->fragment_size)
{
int p = dmap->fragment_size * dmap->qtail;
+#if defined(PPC) || defined(sparc) || defined(HPPA)
+ dmap->neutral_byte = dmap->raw_buf[p + l - 2];
+#else
dmap->neutral_byte = dmap->raw_buf[p + l - 1];
+#endif
memset (dmap->raw_buf + p + l,
dmap->neutral_byte,
dmap->neutral_byte =
dmap->raw_buf[dmap->fragment_size * dmap->qtail - 1];
- if ((l != dmap->fragment_size) &&
- ((audio_devs[dev]->flags & DMA_AUTOMODE) &&
- audio_devs[dev]->flags & NEEDS_RESTART))
- dmap->flags |= DMA_RESTART;
- else
- dmap->flags &= ~DMA_RESTART;
-
dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
}
- if (!(dmap->flags & DMA_ACTIVE))
- {
- dmap->flags |= DMA_ACTIVE;
-
- if (restart)
- audio_devs[dev]->d->prepare_for_output (dev,
- dmap->fragment_size, dmap->nbufs);
-
- audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys +
- dmap->qhead * dmap->fragment_size,
- dmap->counts[dmap->qhead], 0,
- !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
- !(dmap->flags & DMA_STARTED));
- dmap->flags |= DMA_STARTED;
- if (audio_devs[dev]->d->trigger)
- audio_devs[dev]->d->trigger (dev,
- audio_devs[dev]->enable_bits * audio_devs[dev]->go);
- }
+ /* Delay playback until there are at least two fragments (to prevent hiccup) */
+ if (dmap->qlen > 1 || post ||
+ (dmap->qlen > 0 && dmap->nbufs <= 2) ||
+ (dmap->qlen > 0 && dmap->flags & DMA_SYNCING) ||
+ restart || l != dmap->fragment_size)
+ if (!(dmap->flags & DMA_ACTIVE))
+ {
+ launch_output (dev, dmap);
+ }
+ ;
return 0;
}
{
int chan;
struct dma_buffparms *dmap;
- unsigned long flags;
if (dma_mode == DMA_MODE_WRITE)
{
dmap = audio_devs[dev]->dmap_in;
}
- if (dmap->raw_buf_phys == 0)
+ if (dmap->raw_buf == NULL)
{
printk ("sound: DMA buffer == NULL\n");
return 0;
}
+ /* Handle cards with non automode DMA in new way */
+ if (physaddr != dmap->raw_buf_phys) /* Not fragment 0 */
+ return count;
+ count = dmap->bytes_in_use;
+
+ if (chan < 0)
+ return 0;
+
/*
* The count must be one less than the actual size. This is handled by
* set_dma_addr()
* Auto restart mode. Transfer the whole *
* buffer
*/
+ unsigned long flags;
+
save_flags (flags);
cli ();
disable_dma (chan);
}
else
{
+ unsigned long flags;
+
save_flags (flags);
cli ();
disable_dma (chan);
}
}
-static void
-polish_buffers (struct dma_buffparms *dmap)
-{
- int i;
- int p, l;
-
- i = dmap->qhead;
-
- p = dmap->fragment_size * i;
-
- if (i == dmap->cfrag)
- {
- l = dmap->fragment_size - dmap->counts[i];
- }
- else
- l = dmap->fragment_size;
-
- if (l)
- {
- memset (dmap->raw_buf + p,
- dmap->neutral_byte,
- l);
- }
-}
-
static void
force_restart (int dev, struct dma_buffparms *dmap)
{
+ unsigned long flags;
+
if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
audio_devs[dev]->d->halt_output)
audio_devs[dev]->d->halt_output (dev);
audio_devs[dev]->d->halt_xfer (dev);
dmap->flags &= ~(DMA_ACTIVE | DMA_STARTED);
- if (audio_devs[dev]->flags & DMA_AUTOMODE)
- dmap->flags |= DMA_RESTART;
- else
- dmap->flags &= ~DMA_RESTART;
+ dmap->flags |= DMA_RESTART;
+ dmap->qlen = dmap->qhead = dmap->qtail = 0;
+
+ save_flags (flags);
+ cli ();
+ if ((out_sleep_flag[dev].opts & WK_SLEEP))
+ {
+ {
+ out_sleep_flag[dev].opts = WK_WAKEUP;
+ wake_up (&out_sleeper[dev]);
+ };
+ }
+ restore_flags (flags);
}
void
struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
int this_fragment;
- dmap->byte_counter += dmap->counts[dmap->qhead];
-
#ifdef OS_DMA_INTR
- sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
+ if (audio_devs[dev]->dmachan1 >= 0)
+ sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
#endif
if (dmap->raw_buf == NULL)
{
/* mmapped access */
dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+ if (dmap->qhead == 0) /* Wrapped */
+ dmap->byte_counter += dmap->bytes_in_use;
dmap->qlen++; /* Yes increment it (don't decrement) */
dmap->flags &= ~DMA_ACTIVE;
dmap->counts[dmap->qhead] = dmap->fragment_size;
{
printk ("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n",
dev, dmap->qlen, dmap->nbufs);
+ force_restart (dev, dmap);
return;
}
+ save_flags (flags);
+ cli ();
+
dmap->qlen--;
this_fragment = dmap->qhead;
dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+
+ if (dmap->qhead == 0) /* Wrapped */
+ dmap->byte_counter += dmap->bytes_in_use;
dmap->flags &= ~DMA_ACTIVE;
if (event_type == 1 && dmap->qlen < 1)
{
dmap->underrun_count++;
- if ((!(dmap->flags & DMA_CLEAN) &&
- (audio_devs[dev]->dmap_out->flags & DMA_SYNCING ||
- dmap->underrun_count > 5 || dmap->flags & DMA_EMPTY)) ||
- audio_devs[dev]->flags & DMA_HARDSTOP)
-
- {
- dmap->qlen = 0;
- force_restart (dev, dmap);
- }
- else
- /* Ignore underrun. Just move the tail pointer forward and go */
- if (dmap->closing)
- {
- polish_buffers (dmap);
- audio_devs[dev]->d->halt_xfer (dev);
- }
- else
- {
- dmap->qlen++;
- dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
-
- if (!(dmap->flags & DMA_EMPTY))
- polish_buffers (dmap);
-
- dmap->cfrag = -1;
- dmap->flags |= DMA_EMPTY;
- dmap->counts[dmap->qtail] = dmap->fragment_size;
- }
+ dmap->qlen = 0;
+ force_restart (dev, dmap);
}
if (dmap->qlen)
}
dmap->flags |= DMA_ACTIVE;
}
+
+ restore_flags (flags);
} /* event_type != 2 */
save_flags (flags);
cli ();
- if ((out_sleep_flag[dev].flags & WK_SLEEP))
+ if ((out_sleep_flag[dev].opts & WK_SLEEP))
{
{
- out_sleep_flag[dev].flags = WK_WAKEUP;
- module_wake_up (&out_sleeper[dev]);
+ out_sleep_flag[dev].opts = WK_WAKEUP;
+ wake_up (&out_sleeper[dev]);
};
}
restore_flags (flags);
unsigned long flags;
struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
- dmap->byte_counter += dmap->fragment_size;
-
#ifdef OS_DMA_INTR
- sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
+ if (audio_devs[dev]->dmachan2 >= 0)
+ sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
#endif
if (dmap->raw_buf == NULL)
if (dmap->mapping_flags & DMA_MAP_MAPPED)
{
dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ if (dmap->qtail == 0) /* Wrapped */
+ dmap->byte_counter += dmap->bytes_in_use;
dmap->qlen++;
if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
}
else if (dmap->qlen == (dmap->nbufs - 1))
{
- printk ("Sound: Recording overrun\n");
+ /* printk ("Sound: Recording overrun\n"); */
dmap->underrun_count++;
if (audio_devs[dev]->flags & DMA_AUTOMODE)
printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n",
dev, dmap->qlen, dmap->nbufs);
dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ if (dmap->qtail == 0) /* Wrapped */
+ dmap->byte_counter += dmap->bytes_in_use;
}
if (!(audio_devs[dev]->flags & DMA_AUTOMODE))
save_flags (flags);
cli ();
- if ((in_sleep_flag[dev].flags & WK_SLEEP))
+ if ((in_sleep_flag[dev].opts & WK_SLEEP))
{
{
- in_sleep_flag[dev].flags = WK_WAKEUP;
- module_wake_up (&in_sleeper[dev]);
+ in_sleep_flag[dev].opts = WK_WAKEUP;
+ wake_up (&in_sleeper[dev]);
};
}
restore_flags (flags);
int err;
unsigned long flags;
- if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1)) < 0)
+ if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, chan)) < 0)
{
- return -(EBUSY);
+ return -EBUSY;
}
dma_init_buffers (dev, audio_devs[dev]->dmap_out);
audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE;
audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->buffsize;
- save_flags (flags);
- cli ();
- disable_dma (chan);
- clear_dma_ff (chan);
- restore_flags (flags);
+ if (chan >= 0)
+ {
+ save_flags (flags);
+ cli ();
+ disable_dma (chan);
+ clear_dma_ff (chan);
+ restore_flags (flags);
+ }
return 0;
}
}
int
-DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait)
+DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
{
struct dma_buffparms *dmap;
unsigned long flags;
switch (sel_type)
{
case SEL_IN:
+ if (!(audio_devs[dev]->open_mode))
+ return 0;
+
dmap = audio_devs[dev]->dmap_in;
if (dmap->mapping_flags & DMA_MAP_MAPPED)
save_flags (flags);
cli ();
- in_sleep_flag[dev].flags = WK_SLEEP;
- module_select_wait (&in_sleeper[dev], wait);
+ in_sleep_flag[dev].opts = WK_SLEEP;
+ select_wait (&in_sleeper[dev], wait);
restore_flags (flags);
return 0;
}
if (dmap->dma_mode != DMODE_INPUT)
{
- if ((audio_devs[dev]->flags & DMA_DUPLEX) && !dmap->qlen &&
+ if (dmap->dma_mode == DMODE_NONE &&
audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT &&
+ !dmap->qlen &&
audio_devs[dev]->go)
{
unsigned long flags;
save_flags (flags);
cli ();
- in_sleep_flag[dev].flags = WK_SLEEP;
- module_select_wait (&in_sleeper[dev], wait);
+ in_sleep_flag[dev].opts = WK_SLEEP;
+ select_wait (&in_sleeper[dev], wait);
restore_flags (flags);
return 0;
}
save_flags (flags);
cli ();
- out_sleep_flag[dev].flags = WK_SLEEP;
- module_select_wait (&out_sleeper[dev], wait);
+ out_sleep_flag[dev].opts = WK_SLEEP;
+ select_wait (&out_sleeper[dev], wait);
restore_flags (flags);
return 0;
}
save_flags (flags);
cli ();
- out_sleep_flag[dev].flags = WK_SLEEP;
- module_select_wait (&out_sleeper[dev], wait);
+ out_sleep_flag[dev].opts = WK_SLEEP;
+ select_wait (&out_sleeper[dev], wait);
restore_flags (flags);
return 0;
}
int
DMAbuf_open (int dev, int mode)
{
- return -(ENXIO);
+ return -ENXIO;
}
int
int
DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
{
- return -(EIO);
+ return -EIO;
}
int
DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
{
- return -(EIO);
+ return -EIO;
}
int
DMAbuf_rmchars (int dev, int buff_no, int c)
{
- return -(EIO);
+ return -EIO;
}
int
DMAbuf_start_output (int dev, int buff_no, int l)
{
- return -(EIO);
+ return -EIO;
}
int
DMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
{
- return -(EIO);
+ return -EIO;
}
void
int
DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
{
- return -(EIO);
+ return -EIO;
}
int
DMAbuf_open_dma (int dev)
{
- return -(ENXIO);
+ return -ENXIO;
}
void
+++ /dev/null
-
-/* linux/drivers/sound/dmasound.c */
-
-/*
-
-VoxWare compatible Atari TT DMA sound driver for 680x0 Linux
-
-(c) 1995 by Michael Schlueter & Michael Marte
-
-Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS
-interface and the u-law to signed byte conversion.
-
-Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue,
-/dev/mixer, /dev/sndstat and complemented the VFS interface. He would like
-to thank:
-Michael Schlueter for initial ideas and documentation on the MFP and
-the DMA sound hardware.
-Therapy? for their CD 'Troublegum' which really made me rock.
-
-/dev/sndstat is based on code by Hannu Savolainen, the author of the
-VoxWare family of drivers.
-
-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.
-
-History:
-1995/8/25 first release
-
-1995/9/02 ++roman: fixed atari_stram_alloc() call, the timer programming
- and several race conditions
-
-1995/9/14 ++roman: After some discussion with Michael Schlueter, revised
- the interrupt disabling
- Slightly speeded up U8->S8 translation by using long
- operations where possible
- Added 4:3 interpolation for /dev/audio
-
-1995/9/20 ++TeSche: Fixed a bug in sq_write and changed /dev/audio
- converting to play at 12517Hz instead of 6258Hz.
-
-1995/9/23 ++TeSche: Changed sq_interrupt() and sq_play() to pre-program
- the DMA for another frame while there's still one
- running. This allows the IRQ response to be
- arbitrarily delayed and playing will still continue.
-
-1995/10/14 ++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for
- Falcon audio (the Falcon doesn't raise an IRQ at the
- end of a frame, but at the beginning instead!). uses
- 'if (codec_dma)' in lots of places to simply switch
- between Falcon and TT code.
-
-1995/11/06 ++TeSche: started introducing a hardware abstraction scheme
- (may perhaps also serve for Amigas?), can now play
- samples at almost all frequencies by means of a more
- generalized expand routine, takes a good deal of care
- to cut data only at sample sizes, buffer size is now
- a kernel runtime option, implemented fsync() & several
- minor improvements
- ++Guenther: useful hints and bug fixes, cross-checked it for
- Falcons
-
-1996/3/9 ++geert: support added for Amiga, A-law, 16-bit little endian.
- Unification to drivers/sound/dmasound.c.
-1996/4/6 ++Martin Mitchell: updated to 1.3 kernel.
-*/
-
-
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/major.h>
-#include <linux/config.h>
-#include <linux/fcntl.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/bootinfo.h>
-
-#ifdef CONFIG_ATARI
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#endif /* CONFIG_AMIGA */
-
-#include "dmasound.h"
-#include <linux/soundcard.h>
-
-
-#ifdef CONFIG_ATARI
-extern void atari_microwire_cmd(int cmd);
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
- /*
- * The minimum period for audio depends on total (for OCS/ECS/AGA)
- * (Imported from arch/m68k/amiga/amisound.c)
- */
-
-extern volatile u_short amiga_audio_min_period;
-
-
- /*
- * amiga_mksound() should be able to restore the period after beeping
- * (Imported from arch/m68k/amiga/amisound.c)
- */
-
-extern u_short amiga_audio_period;
-
-
- /*
- * Audio DMA masks
- */
-
-#define AMI_AUDIO_OFF (DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3)
-#define AMI_AUDIO_8 (DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1)
-#define AMI_AUDIO_14 (AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3)
-
-#endif /* CONFIG_AMIGA */
-
-
-/*** Some declarations *******************************************************/
-
-
-#define DMASND_TT 1
-#define DMASND_FALCON 2
-#define DMASND_AMIGA 3
-
-#define MAX_CATCH_RADIUS 10
-#define MIN_BUFFERS 4
-#define MIN_BUFSIZE 4
-#define MAX_BUFSIZE 128 /* Limit for Amiga */
-
-static int catchRadius = 0, numBufs = 4, bufSize = 32;
-
-
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-#define min(x, y) ((x) < (y) ? (x) : (y))
-#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
-#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
-
-#define IOCTL_IN(arg) get_user((int *)(arg))
-#define IOCTL_OUT(arg, ret) ioctl_return((int *)arg, ret)
-
-
-/*** Some low level helpers **************************************************/
-
-
-/* 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
-};
-
-/* 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
-};
-
-
-#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,
-};
-
-/* 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,
-};
-#endif /* HAS_16BIT_TABLES */
-
-
-#ifdef HAS_14BIT_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
-};
-
-/* 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
-};
-#endif /* HAS_14BIT_TABLES */
-
-
-/*** Translations ************************************************************/
-
-
-#ifdef CONFIG_ATARI
-static long ata_ct_law(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ata_ct_s8(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ata_ct_u8(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ata_ct_s16be(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ata_ct_u16be(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ata_ct_s16le(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ata_ct_u16le(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ata_ctx_law(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ata_ctx_s8(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ata_ctx_u8(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ata_ctx_s16be(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ata_ctx_u16be(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ata_ctx_s16le(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ata_ctx_u16le(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static long ami_ct_law(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ami_ct_s8(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ami_ct_u8(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ami_ct_s16be(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ami_ct_u16be(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ami_ct_s16le(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-static long ami_ct_u16le(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft);
-#endif /* CONFIG_AMIGA */
-
-
-/*** Machine definitions *****************************************************/
-
-
-typedef struct {
- int type;
- void *(*dma_alloc)(unsigned int, int);
- void (*dma_free)(void *, unsigned int);
- int (*irqinit)(void);
- void (*init)(void);
- void (*silence)(void);
- int (*setFormat)(int);
- int (*setVolume)(int);
- int (*setBass)(int);
- int (*setTreble)(int);
- void (*play)(void);
-} MACHINE;
-
-
-/*** Low level stuff *********************************************************/
-
-
-typedef struct {
- 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 *, long, u_char *, long *, long);
- long (*ct_alaw)(const u_char *, long, u_char *, long *, long);
- long (*ct_s8)(const u_char *, long, u_char *, long *, long);
- long (*ct_u8)(const u_char *, long, u_char *, long *, long);
- long (*ct_s16be)(const u_char *, long, u_char *, long *, long);
- long (*ct_u16be)(const u_char *, long, u_char *, long *, long);
- long (*ct_s16le)(const u_char *, long, u_char *, long *, long);
- long (*ct_u16le)(const u_char *, 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 minDev; /* minor device number currently open */
-#ifdef CONFIG_ATARI
- int bal; /* balance factor for expanding (not volume!) */
- u_long data; /* data for expanding */
-#endif /* CONFIG_ATARI */
-};
-
-static struct sound_settings sound;
-
-
-#ifdef CONFIG_ATARI
-static void *AtaAlloc(unsigned int size, int flags);
-static void AtaFree(void *, unsigned int size);
-static int AtaIrqInit(void);
-static int AtaSetBass(int bass);
-static int AtaSetTreble(int treble);
-static void TTSilence(void);
-static void TTInit(void);
-static int TTSetFormat(int format);
-static int TTSetVolume(int volume);
-static void FalconSilence(void);
-static void FalconInit(void);
-static int FalconSetFormat(int format);
-static int FalconSetVolume(int volume);
-static void ata_sq_play_next_frame(int index);
-static void AtaPlay(void);
-static void ata_sq_interrupt(int irq, struct pt_regs *fp, void *dummy);
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static void *AmiAlloc(unsigned int size, int flags);
-static void AmiFree(void *, unsigned int);
-static int AmiIrqInit(void);
-static void AmiSilence(void);
-static void AmiInit(void);
-static int AmiSetFormat(int format);
-static int AmiSetVolume(int volume);
-static int AmiSetTreble(int treble);
-static void ami_sq_play_next_frame(int index);
-static void AmiPlay(void);
-static void ami_sq_interrupt(int irq, struct pt_regs *fp, void *dummy);
-#endif /* CONFIG_AMIGA */
-
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void);
-static void sound_init(void);
-static int sound_set_format(int format);
-static int sound_set_speed(int speed);
-static int sound_set_stereo(int stereo);
-static int sound_set_volume(int volume);
-#ifdef CONFIG_ATARI
-static int sound_set_bass(int bass);
-#endif /* CONFIG_ATARI */
-static int sound_set_treble(int treble);
-static long sound_copy_translate(const u_char *userPtr, long userCount,
- u_char frame[], long *frameUsed,
- long frameLeft);
-
-
-/*
- * /dev/mixer abstraction
- */
-
-struct sound_mixer {
- int busy;
-};
-
-static struct sound_mixer mixer;
-
-static void mixer_init(void);
-static int mixer_open(int open_mode);
-static int mixer_release(void);
-static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg);
-
-
-/*
- * Sound queue stuff, the heart of the driver
- */
-
-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;
-#ifdef CONFIG_ATARI
- int ignore_int; /* ++TeSche: used for Falcon */
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- int block_size_half, block_size_quarter;
-#endif /* CONFIG_AMIGA */
-};
-
-static struct sound_queue sq;
-
-#define sq_block_address(i) (sq.buffers[i])
-#define SIGNAL_RECEIVED (current->signal & ~current->blocked)
-#define NON_BLOCKING(open_mode) (open_mode & O_NONBLOCK)
-#define ONE_SECOND HZ /* in jiffies (100ths of a second) */
-#define NO_TIME_LIMIT 0xffffffff
-#define SLEEP(queue, time_limit) \
- current->timeout = jiffies+(time_limit); \
- interruptible_sleep_on(&queue);
-#define WAKE_UP(queue) (wake_up_interruptible(&queue))
-
-static void sq_init(int numBufs, int bufSize, char **buffers);
-static void sq_play(void);
-static int sq_write(const char *src, int uLeft);
-static int sq_open(int open_mode);
-static void sq_reset(void);
-static int sq_sync(void);
-static int sq_release(void);
-
-
-/*
- * /dev/sndstat
- */
-
-struct sound_state {
- int busy;
- char buf[512];
- int len, ptr;
-};
-
-static struct sound_state state;
-
-static void state_init(void);
-static int state_open(int open_mode);
-static int state_release(void);
-static int state_read(char *dest, int count);
-
-
-/*** High level stuff ********************************************************/
-
-
-static int sound_open(struct inode *inode, struct file *file);
-static int sound_fsync(struct inode *inode, struct file *filp);
-static void sound_release(struct inode *inode, struct file *file);
-static int sound_lseek(struct inode *inode, struct file *file, off_t offset,
- int orig);
-static int sound_read(struct inode *inode, struct file *file, char *buf,
- int count);
-static int sound_write(struct inode *inode, struct file *file, const char *buf,
- int count);
-static int ioctl_return(int *addr, int value);
-static int unknown_minor_dev(char *fname, int dev);
-static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg);
-
-
-/*** Config & Setup **********************************************************/
-
-
-void soundcard_init(void);
-void dmasound_setup(char *str, int *ints);
-void sound_setup(char *str, int *ints); /* ++Martin: stub for now */
-
-
-/*** Translations ************************************************************/
-
-
-/* ++TeSche: radically changed for new expanding purposes...
- *
- * These two routines now deal with copying/expanding/translating the samples
- * from user space into our buffer at the right frequency. They take care about
- * how much data there's actually to read, how much buffer space there is and
- * to convert samples into the right frequency/encoding. They will only work on
- * complete samples so it may happen they leave some bytes in the input stream
- * if the user didn't write a multiple of the current sample size. They both
- * return the number of bytes they've used from both streams so you may detect
- * such a situation. Luckily all programs should be able to cope with that.
- *
- * I think I've optimized anything as far as one can do in plain C, all
- * variables should fit in registers and the loops are really short. There's
- * one loop for every possible situation. Writing a more generalized and thus
- * parameterized loop would only produce slower code. Feel free to optimize
- * this in assembler if you like. :)
- *
- * I think these routines belong here because they're not yet really hardware
- * independent, especially the fact that the Falcon can play 16bit samples
- * only in stereo is hardcoded in both of them!
- *
- * ++geert: split in even more functions (one per format)
- */
-
-#ifdef CONFIG_ATARI
-static long ata_ct_law(const u_char *userPtr, 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];
-
- count = min(userCount, frameLeft);
- if (sound.soft.stereo)
- count &= ~1;
- used = count;
- while (count > 0) {
- *p++ = table[get_user(userPtr++)];
- count--;
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static long ata_ct_s8(const u_char *userPtr, long userCount, u_char frame[],
- long *frameUsed, long frameLeft)
-{
- 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);
-}
-
-
-static long ata_ct_u8(const u_char *userPtr, 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) {
- *p++ = get_user(userPtr++) ^ 0x80;
- count--;
- }
- } else {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- *p++ = get_user(((u_short *)userPtr)++) ^ 0x8080;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static long ata_ct_s16be(const u_char *userPtr, 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) {
- data = get_user(((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);
-}
-
-
-static long ata_ct_u16be(const u_char *userPtr, 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) {
- data = get_user(((u_short *)userPtr)++) ^ 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) {
- *p++ = get_user(((u_int *)userPtr)++) ^ 0x80008000;
- count--;
- }
- *frameUsed += used;
- }
- return(used);
-}
-
-
-static long ata_ct_s16le(const u_char *userPtr, 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) {
- data = get_user(((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) {
- data = get_user(((u_int *)userPtr)++);
- data = le2be16dbl(data);
- *p++ = data;
- count--;
- }
- *frameUsed += used;
- }
- return(used);
-}
-
-
-static long ata_ct_u16le(const u_char *userPtr, 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) {
- data = get_user(((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) {
- data = get_user(((u_int *)userPtr)++);
- data = le2be16dbl(data) ^ 0x80008000;
- *p++ = data;
- count--;
- }
- *frameUsed += used;
- }
- return(used);
-}
-
-
-static long ata_ctx_law(const u_char *userPtr, 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) {
- if (bal < 0) {
- if (!userCount)
- break;
- data = table[get_user(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;
- data = table[get_user(userPtr++)] << 8;
- data |= table[get_user(userPtr++)];
- 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, 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;
- data = get_user(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;
- data = get_user(((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);
-}
-
-
-static long ata_ctx_u8(const u_char *userPtr, 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;
- data = get_user(userPtr++) ^ 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;
- data = get_user(((u_short *)userPtr)++) ^ 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, 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;
- data = get_user(((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;
- data = get_user(((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);
-}
-
-
-static long ata_ctx_u16be(const u_char *userPtr, 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;
- data = get_user(((u_short *)userPtr)++) ^ 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;
- data = get_user(((u_int *)userPtr)++) ^ 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, 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;
- data = get_user(((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;
- data = get_user(((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);
-}
-
-
-static long ata_ctx_u16le(const u_char *userPtr, 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;
- data = get_user(((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;
- data = get_user(((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);
-}
-#endif /* CONFIG_ATARI */
-
-
-#ifdef CONFIG_AMIGA
-static long ami_ct_law(const u_char *userPtr, 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) {
- *p++ = table[get_user(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) {
- *left++ = table[get_user(userPtr++)];
- *right++ = table[get_user(userPtr++)];
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static long ami_ct_s8(const u_char *userPtr, 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) {
- *left++ = get_user(userPtr++);
- *right++ = get_user(userPtr++);
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static long ami_ct_u8(const u_char *userPtr, 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) {
- *p++ = get_user(userPtr++) ^ 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) {
- *left++ = get_user(userPtr++) ^ 0x80;
- *right++ = get_user(userPtr++) ^ 0x80;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static long ami_ct_s16be(const u_char *userPtr, 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) {
- data = get_user(((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) {
- data = get_user(((u_short *)userPtr)++);
- *lefth = data>>8;
- *leftl = (data>>2) & 0x3f;
- data = get_user(((u_short *)userPtr)++);
- *righth = data>>8;
- *rightl = (data>>2) & 0x3f;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static long ami_ct_u16be(const u_char *userPtr, 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) {
- data = get_user(((u_short *)userPtr)++) ^ 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) {
- data = get_user(((u_short *)userPtr)++) ^ 0x8000;
- *lefth = data>>8;
- *leftl = (data>>2) & 0x3f;
- data = get_user(((u_short *)userPtr)++) ^ 0x8000;
- *righth = data>>8;
- *rightl = (data>>2) & 0x3f;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static long ami_ct_s16le(const u_char *userPtr, 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) {
- data = get_user(((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) {
- data = get_user(((u_short *)userPtr)++);
- data = le2be16(data);
- *lefth = data>>8;
- *leftl = (data>>2) & 0x3f;
- data = get_user(((u_short *)userPtr)++);
- data = le2be16(data);
- *righth = data>>8;
- *rightl = (data>>2) & 0x3f;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static long ami_ct_u16le(const u_char *userPtr, 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) {
- data = get_user(((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;
- while (count > 0) {
- data = get_user(((u_short *)userPtr)++);
- data = le2be16(data) ^ 0x8000;
- *lefth = data>>8;
- *leftl = (data>>2) & 0x3f;
- data = get_user(((u_short *)userPtr)++);
- data = le2be16(data) ^ 0x8000;
- *righth = data>>8;
- *rightl = (data>>2) & 0x3f;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-#endif /* CONFIG_AMIGA */
-
-
-#ifdef CONFIG_ATARI
-static TRANS transTTNormal = {
- 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
-};
-
-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
-};
-
-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
-};
-#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
-};
-#endif /* CONFIG_AMIGA */
-
-
-/*** Low level stuff *********************************************************/
-
-
-#ifdef CONFIG_ATARI
-
-/*
- * Atari (TT/Falcon)
- */
-
-static void *AtaAlloc(unsigned int size, int flags)
-{
- int order;
- unsigned int a_size;
- order = 0;
- a_size = PAGE_SIZE;
- while (a_size < size) {
- order++;
- a_size <<= 1;
- }
- return (void *) __get_dma_pages(flags, order);
-}
-
-static void AtaFree(void *obj, unsigned int size)
-{
- int order;
- unsigned int a_size;
- order = 0;
- a_size = PAGE_SIZE;
- while (a_size < size) {
- order++;
- a_size <<= 1;
- }
- free_pages ((unsigned long) obj, order);
-}
-
-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. */
- add_isr(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW, NULL, "DMA sound");
- mfp.int_en_a |= 0x20; /* Turn interrupt on. */
- mfp.int_mk_a |= 0x20;
- return(1);
-}
-
-
-#define TONE_VOXWARE_TO_DB(v) \
- (((v) < 0) ? -12 : ((v) > 100) ? 12 : ((v) - 50) * 6 / 25)
-#define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50)
-
-
-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));
-}
-
-
-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));
-}
-
-
-
-/*
- * TT
- */
-
-
-static void TTSilence(void)
-{
- 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};
-
- /* 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;
-}
-
-
-static int TTSetFormat(int format)
-{
- /* TT sound DMA supports only 8bit modes */
-
- switch (format) {
- case AFMT_QUERY:
- return(sound.soft.format);
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_S8:
- case AFMT_U8:
- break;
- default:
- 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();
-
- return(format);
-}
-
-
-#define VOLUME_VOXWARE_TO_DB(v) \
- (((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40)
-#define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2)
-
-
-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));
-}
-
-
-
-/*
- * Falcon
- */
-
-
-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 */
-}
-
-
-static void FalconInit(void)
-{
- 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 */
-
- 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 */
-
- 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: /* :-) */
- 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;
- }
-
- FalconInit();
-
- return(format);
-}
-
-
-/* This is for the Falcon output *attenuation* in 1.5dB steps,
- * i.e. output level from 0 to -22.5dB in -1.5dB steps.
- */
-#define VOLUME_VOXWARE_TO_ATT(v) \
- ((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20)
-#define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3)
-
-
-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);
-}
-
-
-static void ata_sq_play_next_frame(int index)
-{
- 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));
- /* 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;
-}
-
-
-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).
- */
- 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, struct pt_regs *fp, void *dummy)
-{
-#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;
- }
-#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.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.
- */
- sq.count--;
- sq.playing--;
-
- if (!sq.playing) {
- tt_dmasnd.ctrl = DMASND_CTRL_OFF;
- sq.ignore_int = 1;
- }
-
- 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();
-
- 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. */
-}
-#endif /* CONFIG_ATARI */
-
-
-#ifdef CONFIG_AMIGA
-
-/*
- * Amiga
- */
-
-
-static void *AmiAlloc(unsigned int size, int flags)
-{
- return(amiga_chip_alloc((long)size));
-}
-
-static void AmiFree(void *obj, unsigned int size)
-{
- amiga_chip_free (obj);
-}
-
-static int AmiIrqInit(void)
-{
- /* turn off DMA for audio channels */
- custom.dmacon = AMI_AUDIO_OFF;
-
- /* Register interrupt handler. */
- if (!add_isr(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0, NULL, "DMA sound"))
- panic("Couldn't add audio interrupt");
- return(1);
-}
-
-
-static void AmiSilence(void)
-{
- /* 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;
- sound.hard.speed = amiga_colorclock/(period+1);
- } 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;
-}
-
-
-static int AmiSetFormat(int format)
-{
- int size;
-
- /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
-
- 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: /* :-) */
- 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();
-
- return(format);
-}
-
-
-#define VOLUME_VOXWARE_TO_AMI(v) \
- (((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100)
-#define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64)
-
-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));
-}
-
-static int AmiSetTreble(int treble)
-{
- sound.treble = treble;
- if (treble > 50)
- ciaa.pra |= 0x02;
- else
- ciaa.pra &= ~0x02;
- return(treble);
-}
-
-
-#define AMI_PLAY_LOADED 1
-#define AMI_PLAY_PLAYING 2
-#define AMI_PLAY_MASK 3
-
-
-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].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;
-
- 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_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 && 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);
-
- custom.intena = IF_SETCLR | IF_AUD0;
-}
-
-
-static void ami_sq_interrupt(int irq, struct pt_regs *fp, void *dummy)
-{
- 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 & 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;
-
- /* 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.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);
-}
-#endif /* CONFIG_AMIGA */
-
-
-/*** Machine definitions *****************************************************/
-
-
-#ifdef CONFIG_ATARI
-static MACHINE machTT = {
- DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit, TTInit, TTSilence, TTSetFormat,
- TTSetVolume, AtaSetBass, AtaSetTreble, AtaPlay
-};
-
-static MACHINE machFalcon = {
- DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit, FalconInit, FalconSilence,
- FalconSetFormat, FalconSetVolume, AtaSetBass, AtaSetTreble, AtaPlay
-};
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static MACHINE machAmiga = {
- DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit, AmiInit, AmiSilence,
- AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble, AmiPlay
-};
-#endif /* CONFIG_AMIGA */
-
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void)
-{
- /* update hardware settings one more */
- (*sound.mach.init)();
-
- (*sound.mach.silence)();
-}
-
-
-static void sound_init(void)
-{
- (*sound.mach.init)();
-}
-
-
-static int sound_set_format(int format)
-{
- return(*sound.mach.setFormat)(format);
-}
-
-
-static int sound_set_speed(int 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;
-
- return(sound.soft.speed);
-}
-
-
-static int sound_set_stereo(int stereo)
-{
- if (stereo < 0)
- return(sound.soft.stereo);
-
- 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)();
-
- return(stereo);
-}
-
-
-static int sound_set_volume(int 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);
-}
-#endif /* CONFIG_ATARI */
-
-
-static int sound_set_treble(int treble)
-{
- return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50);
-}
-
-
-static long sound_copy_translate(const u_char *userPtr, long userCount,
- u_char frame[], long *frameUsed,
- long frameLeft)
-{
- long (*ct_func)(const u_char *, long, u_char *, long *, long) = NULL;
-
- switch (sound.soft.format) {
- case AFMT_MU_LAW:
- ct_func = sound.trans->ct_ulaw;
- break;
- case AFMT_A_LAW:
- ct_func = sound.trans->ct_alaw;
- break;
- case AFMT_S8:
- ct_func = sound.trans->ct_s8;
- break;
- case AFMT_U8:
- ct_func = sound.trans->ct_u8;
- break;
- case AFMT_S16_BE:
- ct_func = sound.trans->ct_s16be;
- break;
- case AFMT_U16_BE:
- ct_func = sound.trans->ct_u16be;
- break;
- case AFMT_S16_LE:
- 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);
-}
-
-
-/*
- * /dev/mixer abstraction
- */
-
-
-#define RECLEVEL_VOXWARE_TO_GAIN(v) \
- ((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)
-#define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3)
-
-
-static void mixer_init(void)
-{
- 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;
- case DMASND_FALCON:
- 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;
-#endif /* CONFIG_AMIGA */
- }
-}
-
-
-static int mixer_open(int open_mode)
-{
- if (mixer.busy)
- return(-EBUSY);
- mixer.busy = 1;
- return(0);
-}
-
-
-static int mixer_release(void)
-{
- mixer.busy = 0;
- return(0);
-}
-
-
-static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg)
-{
- switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
- case DMASND_FALCON:
- switch (cmd) {
- case SOUND_MIXER_READ_DEVMASK:
- 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));
- case SOUND_MIXER_READ_STEREODEVS:
- return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC));
- case SOUND_MIXER_READ_CAPS:
- 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));
- case SOUND_MIXER_WRITE_MIC:
- tt_dmasnd.input_gain =
- RECLEVEL_VOXWARE_TO_GAIN(IOCTL_IN(arg) & 0xff) << 4 |
- RECLEVEL_VOXWARE_TO_GAIN(IOCTL_IN(arg) >> 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));
- 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));
- }
- case SOUND_MIXER_WRITE_VOLUME:
- return(IOCTL_OUT(arg, sound_set_volume(IOCTL_IN(arg))));
- case SOUND_MIXER_WRITE_SPEAKER:
- {
- int porta;
- cli();
- sound_ym.rd_data_reg_sel = 14;
- porta = (sound_ym.rd_data_reg_sel & ~0x40) |
- (IOCTL_IN(arg) < 50 ? 0x40 : 0);
- sound_ym.wd_data = porta;
- sti();
- return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100));
- }
- }
- break;
-
- case DMASND_TT:
- switch (cmd) {
- case SOUND_MIXER_READ_DEVMASK:
- return(IOCTL_OUT(arg,
- SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
- ((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_TT ?
- SOUND_MASK_SPEAKER : 0)));
- case SOUND_MIXER_READ_RECMASK:
- return(IOCTL_OUT(arg, 0));
- case SOUND_MIXER_READ_STEREODEVS:
- 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)));
- case SOUND_MIXER_READ_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)));
- case SOUND_MIXER_READ_SPEAKER:
- {
- int porta;
- if ((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_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:
- return(IOCTL_OUT(arg, sound_set_volume(IOCTL_IN(arg))));
- case SOUND_MIXER_WRITE_BASS:
- return(IOCTL_OUT(arg, sound_set_bass(IOCTL_IN(arg))));
- case SOUND_MIXER_WRITE_TREBLE:
- return(IOCTL_OUT(arg, sound_set_treble(IOCTL_IN(arg))));
- case SOUND_MIXER_WRITE_SPEAKER:
- if ((boot_info.bi_atari.mch_cookie >> 16) == ATARI_MCH_TT) {
- int porta;
- cli();
- sound_ym.rd_data_reg_sel = 14;
- porta = (sound_ym.rd_data_reg_sel & ~0x40) |
- (IOCTL_IN(arg) < 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) {
- case SOUND_MIXER_READ_DEVMASK:
- return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE));
- case SOUND_MIXER_READ_RECMASK:
- return(IOCTL_OUT(arg, 0));
- case SOUND_MIXER_READ_STEREODEVS:
- 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));
- case SOUND_MIXER_WRITE_VOLUME:
- return(IOCTL_OUT(arg, sound_set_volume(IOCTL_IN(arg))));
- case SOUND_MIXER_READ_TREBLE:
- return(IOCTL_OUT(arg, sound.treble));
- case SOUND_MIXER_WRITE_TREBLE:
- return(IOCTL_OUT(arg, sound_set_treble(IOCTL_IN(arg))));
- }
- break;
-#endif /* CONFIG_AMIGA */
- }
-
- return(-EINVAL);
-}
-
-
-
-/*
- * Sound queue stuff, the heart of the driver
- */
-
-
-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;
-
- sq.playing = 0;
-
-#ifdef CONFIG_ATARI
- 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;
-#endif /* CONFIG_AMIGA */
-
- 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;
-
- /* set minimum rate possible without expanding */
- switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
- case DMASND_TT:
- sound.dsp.speed = 6258;
- break;
- case DMASND_FALCON:
- sound.dsp.speed = 8195;
- break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- case DMASND_AMIGA:
- sound.dsp.speed = 8000;
- break;
-#endif /* CONFIG_AMIGA */
- }
-
- /* before the first open to /dev/dsp this wouldn't be set */
- sound.soft = sound.dsp;
-}
-
-
-static void sq_play(void)
-{
- (*sound.mach.play)();
-}
-
-
-/* ++TeSche: radically changed this one too */
-
-static int sq_write(const char *src, int uLeft)
-{
- int 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 < 1)
- 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 {
- if (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.
- */
-
- 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++;
- }
- } while (bUsed); /* uUsed may have been 0 */
-
- sq_play();
-
- return(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;
-#ifdef CONFIG_ATARI
- sq.ignore_int = 1;
-#endif /* CONFIG_ATARI */
- return(0);
-}
-
-
-static void sq_reset(void)
-{
- 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;
- }
- }
-
- 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);
-}
-
-
-
-/*
- * /dev/sndstat
- */
-
-
-static void state_init(void)
-{
- state.busy = 0;
-}
-
-
-/* state.buf should not overflow! */
-
-static int state_open(int open_mode)
-{
- char *buffer = state.buf, *mach = "";
- int len = 0;
-
- if (state.busy)
- return(-EBUSY);
-
- state.ptr = 0;
- state.busy = 1;
-
- switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
- case DMASND_TT:
- case DMASND_FALCON:
- mach = "Atari ";
- break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- case DMASND_AMIGA:
- mach = "Amiga ";
- break;
-#endif /* CONFIG_AMIGA */
- }
- len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
-
- 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;
- case AFMT_A_LAW:
- len += sprintf(buffer+len, " (A-law)");
- break;
- case AFMT_U8:
- len += sprintf(buffer+len, " (unsigned 8 bit)");
- break;
- case AFMT_S8:
- len += sprintf(buffer+len, " (signed 8 bit)");
- break;
- case AFMT_S16_BE:
- len += sprintf(buffer+len, " (signed 16 bit big)");
- break;
- case AFMT_U16_BE:
- len += sprintf(buffer+len, " (unsigned 16 bit big)");
- break;
- case AFMT_S16_LE:
- 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) {
-#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;
- 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;
-#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;
-#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);
-}
-
-
-static int state_release(void)
-{
- state.busy = 0;
- return(0);
-}
-
-
-static int state_read(char *dest, int 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);
-}
-
-
-
-/*** High level stuff ********************************************************/
-
-
-static int sound_open(struct inode *inode, struct file *file)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch (dev) {
- case SND_DEV_STATUS:
- return(state_open(file->f_flags));
- case SND_DEV_CTL:
- return(mixer_open(file->f_flags));
- case SND_DEV_DSP:
- case SND_DEV_AUDIO:
- {
- int rc = sq_open(file->f_flags);
- if (rc == 0) {
- sound.minDev = dev;
- sound.soft = sound.dsp;
- sound_init();
- if (dev == SND_DEV_AUDIO) {
- sound_set_speed(8000);
- sound_set_stereo(0);
- sound_set_format(AFMT_MU_LAW);
- }
- }
- return(rc);
- }
- default:
- return(-ENXIO);
- }
-}
-
-
-static int sound_fsync(struct inode *inode, struct file *filp)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch (dev) {
- case SND_DEV_STATUS:
- case SND_DEV_CTL:
- return(0);
- case SND_DEV_DSP:
- case SND_DEV_AUDIO:
- return(sq_sync());
- default:
- return(unknown_minor_dev("sound_fsync", dev));
- }
-}
-
-
-static void sound_release(struct inode *inode, struct file *file)
-{
- int dev = MINOR(inode->i_rdev);
-
- switch (dev & 0x0f) {
- case SND_DEV_STATUS: state_release(); return;
- case SND_DEV_CTL: mixer_release(); return;
- case SND_DEV_DSP:
- case SND_DEV_AUDIO:
- sq_release(); sound.soft = sound.dsp; sound_silence();
- return;
- default:
- unknown_minor_dev("sound_release", dev);
- }
-}
-
-
-static int sound_lseek(struct inode *inode, struct file *file, off_t offset,
- int orig)
-{
- return(-EPERM);
-}
-
-
-static int sound_read(struct inode *inode, struct file *file, char *buf,
- int count)
-{
- int dev = MINOR(inode->i_rdev);
-
- switch (dev & 0x0f) {
- case SND_DEV_STATUS:
- return(state_read(buf, count));
- case SND_DEV_CTL:
- case SND_DEV_DSP:
- case SND_DEV_AUDIO:
- return(-EPERM);
- default:
- return(unknown_minor_dev("sound_read", dev));
- }
-}
-
-
-static int sound_write(struct inode *inode, struct file *file, const char *buf,
- int count)
-{
- int dev = MINOR(inode->i_rdev);
-
- switch (dev & 0x0f) {
- case SND_DEV_STATUS:
- case SND_DEV_CTL:
- return(-EPERM);
- case SND_DEV_DSP:
- case SND_DEV_AUDIO:
- return(sq_write(buf, count));
- default:
- return(unknown_minor_dev("sound_write", dev));
- }
-}
-
-
-static int ioctl_return(int *addr, int value)
-{
- int error;
-
- if (value < 0)
- return(value);
-
- error = verify_area(VERIFY_WRITE, addr, sizeof(int));
- if (error)
- return(error);
-
- put_user(value, addr);
- return(0);
-}
-
-
-static int unknown_minor_dev(char *fname, int dev)
-{
- /* 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;
-
- switch (dev & 0x0f) {
- case SND_DEV_STATUS:
- return(-EPERM);
- case SND_DEV_CTL:
- return(mixer_ioctl(inode, file, cmd, arg));
- case SND_DEV_AUDIO:
- case SND_DEV_DSP:
- switch (cmd) {
- case SNDCTL_DSP_RESET:
- sq_reset();
- return(0);
- case SNDCTL_DSP_POST:
- case SNDCTL_DSP_SYNC:
- return(sound_fsync(inode, file));
-
- /* ++TeSche: before changing any of these it's probably wise to
- * wait until sound playing has settled down
- */
- case SNDCTL_DSP_SPEED:
- sound_fsync(inode, file);
- return(IOCTL_OUT(arg, sound_set_speed(IOCTL_IN(arg))));
- case SNDCTL_DSP_STEREO:
- sound_fsync(inode, file);
- return(IOCTL_OUT(arg, sound_set_stereo(IOCTL_IN(arg))));
- case SOUND_PCM_WRITE_CHANNELS:
- sound_fsync(inode, file);
- return(IOCTL_OUT(arg, sound_set_stereo(IOCTL_IN(arg)-1)+1));
- case SNDCTL_DSP_SETFMT:
- sound_fsync(inode, file);
- return(IOCTL_OUT(arg, sound_set_format(IOCTL_IN(arg))));
- 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));
- case SNDCTL_DSP_GETBLKSIZE:
- return(IOCTL_OUT(arg, 10240));
- case SNDCTL_DSP_SUBDIVIDE:
- case SNDCTL_DSP_SETFRAGMENT:
- break;
-
- default:
- return(mixer_ioctl(inode, file, cmd, arg));
- }
- break;
-
- default:
- 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
-};
-
-
-
-/*** Config & Setup **********************************************************/
-
-
-void soundcard_init(void)
-{
- int has_sound = 0;
- char **buffers;
- int i;
-
- switch (boot_info.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;
-
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- case MACH_AMIGA:
- if (AMIGAHW_PRESENT(AMI_AUDIO)) {
- sound.mach = machAmiga;
- has_sound = 1;
- }
- break;
-#endif /* CONFIG_AMIGA */
- }
- if (!has_sound)
- return;
-
- /* Set up sound queue, /dev/audio and /dev/dsp. */
- buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
- if (!buffers) {
- out_of_memory:
- printk("DMA sound driver: Not enough buffer memory, driver disabled!\n");
- return;
- }
- for (i = 0; i < numBufs; i++) {
- buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
- if (!buffers[i]) {
- while (i--)
- sound.mach.dma_free (buffers[i], bufSize << 10);
- kfree (buffers);
- goto out_of_memory;
- }
- }
-
- /* Register driver with the VFS. */
- register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
-
- sq_init(numBufs, bufSize << 10, buffers);
-
- /* Set up /dev/sndstat. */
- state_init();
-
- /* Set up /dev/mixer. */
- mixer_init();
-
- if (!sound.mach.irqinit()) {
- printk("DMA sound driver: Interrupt initialization failed\n");
- return;
- }
-
- printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs,
- bufSize);
-
- return;
-}
-
-void sound_setup(char *str, int *ints)
-{
- /* ++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=" */
-
- 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 */
- 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;
- case 0:
- break;
- default:
- printk("dmasound_setup: illegal number of arguments\n");
- }
-}
+++ /dev/null
-
-/* linux/drivers/sound/dmasound.h */
-
-/*
- * Minor numbers for the sound driver.
- *
- * Unfortunately Creative called the codec chip of SB as a DSP. For this
- * reason the /dev/dsp is reserved for digitized audio use. There is a
- * device for true DSP processors but it will be called something else.
- * In v3.0 it's /dev/sndproc but this could be a temporary solution.
- */
-
-#define SND_NDEVS 256 /* Number of supported devices */
-#define SND_DEV_CTL 0 /* Control port /dev/mixer */
-#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
- synthesizer and MIDI output) */
-#define SND_DEV_MIDIN 2 /* Raw midi access */
-#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */
-#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */
-#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */
-#define SND_DEV_STATUS 6 /* /dev/sndstat */
-/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
-#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */
-#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */
-#define SND_DEV_PSS SND_DEV_SNDPROC
-
-#define DSP_DEFAULT_SPEED 8000
-
-#define ON 1
-#define OFF 0
-
-#define MAX_AUDIO_DEV 5
-#define MAX_MIXER_DEV 2
-#define MAX_SYNTH_DEV 3
-#define MAX_MIDI_DEV 6
-#define MAX_TIMER_DEV 3
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#include "sound_config.h"
-#if defined(CONFIG_GUS)
+#if defined(CONFIG_GUSHW)
#include "gus_hw.h"
extern int have_gus_max;
int gus_pnp_flag = 0;
-int *gus_osp;
-
void
attach_gus_card (struct address_info *hw_config)
{
- int io_addr;
-
- gus_osp = hw_config->osp;
snd_set_irq_handler (hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp);
- if (gus_wave_detect (hw_config->io_base)) /*
- * Try first the default
- */
- {
- gus_wave_init (hw_config);
+ gus_wave_init (hw_config);
- request_region (hw_config->io_base, 16, "GUS");
- request_region (hw_config->io_base + 0x100, 12, "GUS"); /* 0x10c-> is MAX */
-
- if (sound_alloc_dma (hw_config->dma, "GUS"))
- printk ("gus_card.c: Can't allocate DMA channel\n");
- if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
- if (sound_alloc_dma (hw_config->dma2, "GUS(2)"))
- printk ("gus_card.c: Can't allocate DMA channel2\n");
-#ifdef CONFIG_MIDI
- gus_midi_init ();
-#endif
- return;
- }
-
-#ifndef EXCLUDE_GUS_IODETECT
-
- /*
- * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
- */
+ request_region (hw_config->io_base, 16, "GUS");
+ request_region (hw_config->io_base + 0x100, 12, "GUS"); /* 0x10c-> is MAX */
- for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
- if (io_addr != hw_config->io_base) /*
- * Already tested
- */
- if (gus_wave_detect (io_addr))
- {
- hw_config->io_base = io_addr;
-
- printk (" WARNING! GUS found at %x, config was %x ", io_addr, hw_config->io_base);
- gus_wave_init (hw_config);
- request_region (io_addr, 16, "GUS");
- request_region (io_addr + 0x100, 12, "GUS"); /* 0x10c-> is MAX */
- if (sound_alloc_dma (hw_config->dma, "GUS"))
- printk ("gus_card.c: Can't allocate DMA channel\n");
- if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
- if (sound_alloc_dma (hw_config->dma2, "GUS"))
- printk ("gus_card.c: Can't allocate DMA channel2\n");
+ if (sound_alloc_dma (hw_config->dma, "GUS"))
+ printk ("gus_card.c: Can't allocate DMA channel\n");
+ if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
+ if (sound_alloc_dma (hw_config->dma2, "GUS(2)"))
+ printk ("gus_card.c: Can't allocate DMA channel2\n");
#ifdef CONFIG_MIDI
- gus_midi_init ();
+ gus_midi_init ();
#endif
- return;
- }
-
-#endif
-
}
int
probe_gus (struct address_info *hw_config)
{
- int io_addr, irq;
-
- gus_osp = hw_config->osp;
+ int irq;
+ int io_addr;
if (hw_config->card_subtype == 1)
gus_pnp_flag = 1;
void
attach_gus_db16 (struct address_info *hw_config)
{
-#ifdef CONFIG_GUS
+#ifdef CONFIG_GUSHW
gus_pcm_volume = 100;
gus_wave_volume = 90;
#endif
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#include "gus_hw.h"
-#if defined(CONFIG_GUS) && defined(CONFIG_MIDI)
+#if defined(CONFIG_GUSHW) && defined(CONFIG_MIDI)
static int midi_busy = 0, input_opened = 0;
static int my_dev;
if (midi_busy)
{
printk ("GUS: Midi busy\n");
- return -(EBUSY);
+ return -EBUSY;
}
- outb (MIDI_RESET, u_MidiControl);
+ outb ((MIDI_RESET), u_MidiControl);
gus_delay ();
gus_midi_control = 0;
}
- outb (gus_midi_control, u_MidiControl); /* Enable */
+ outb ((gus_midi_control), u_MidiControl); /* Enable */
midi_busy = 1;
qlen = qhead = qtail = output_used = 0;
if (GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY)
{
ok = 1;
- outb (midi_byte, u_MidiData);
+ outb ((midi_byte), u_MidiData);
}
else
{
* Enable Midi xmit interrupts (again)
*/
gus_midi_control |= MIDI_ENABLE_XMIT;
- outb (gus_midi_control, u_MidiControl);
+ outb ((gus_midi_control), u_MidiControl);
}
restore_flags (flags);
* Reset FIFO pointers, disable intrs
*/
- outb (MIDI_RESET, u_MidiControl);
+ outb ((MIDI_RESET), u_MidiControl);
midi_busy = 0;
}
static int
gus_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
{
- return -(EINVAL);
+ return -EINVAL;
}
static void
return;
}
- outb (MIDI_RESET, u_MidiControl);
+ outb ((MIDI_RESET), u_MidiControl);
std_midi_synth.midi_dev = my_dev = num_midis;
midi_devs[num_midis++] = &gus_midi_operations;
* Disable Midi output interrupts, since no data in the buffer
*/
gus_midi_control &= ~MIDI_ENABLE_XMIT;
- outb (gus_midi_control, u_MidiControl);
- outb (gus_midi_control, u_MidiControl);
+ outb ((gus_midi_control), u_MidiControl);
+ outb ((gus_midi_control), u_MidiControl);
}
}
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#include <linux/config.h>
#include "sound_config.h"
-#ifdef CONFIG_GUS
+#ifdef CONFIG_GUSHW
#include "gus_linearvol.h"
#define GUS_VOLUME gus_wave_volume
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#include <linux/ultrasound.h>
#include "gus_hw.h"
-#if defined(CONFIG_GUS)
+#if defined(CONFIG_GUSHW)
+
+#define GUS_BANK_SIZE (256*1024)
#define MAX_SAMPLE 150
#define MAX_PATCH 256
static int gus_audio_channels;
static int gus_audio_bits;
-static wait_handle *dram_sleeper = NULL;
+static struct wait_queue *dram_sleeper = NULL;
static volatile struct snd_wait dram_sleep_flag =
{0};
static int freq_div_table[] =
{
+ 44100,
44100, /* 14 */
41160, /* 15 */
38587, /* 16 */
save_flags (flags);
cli ();
- outb (0x43, u_Command);
- outb (addr & 0xff, u_DataLo);
- outb ((addr >> 8) & 0xff, u_DataHi);
+ outb ((0x43), u_Command);
+ outb ((addr & 0xff), u_DataLo);
+ outb (((addr >> 8) & 0xff), u_DataHi);
- outb (0x44, u_Command);
- outb ((addr >> 16) & 0xff, u_DataHi);
- outb (data, u_DRAMIO);
+ outb ((0x44), u_Command);
+ outb (((addr >> 16) & 0xff), u_DataHi);
+ outb ((data), u_DRAMIO);
restore_flags (flags);
}
save_flags (flags);
cli ();
- outb (0x43, u_Command);
- outb (addr & 0xff, u_DataLo);
- outb ((addr >> 8) & 0xff, u_DataHi);
+ outb ((0x43), u_Command);
+ outb ((addr & 0xff), u_DataLo);
+ outb (((addr >> 8) & 0xff), u_DataHi);
- outb (0x44, u_Command);
- outb ((addr >> 16) & 0xff, u_DataHi);
+ outb ((0x44), u_Command);
+ outb (((addr >> 16) & 0xff), u_DataHi);
tmp = inb (u_DRAMIO);
restore_flags (flags);
save_flags (flags);
cli ();
- outb (reg, u_Command);
- outb ((unsigned char) (data & 0xff), u_DataHi);
+ outb ((reg), u_Command);
+ outb (((unsigned char) (data & 0xff)), u_DataHi);
restore_flags (flags);
}
save_flags (flags);
cli ();
- outb (reg | 0x80, u_Command);
+ outb ((reg | 0x80), u_Command);
val = inb (u_DataHi);
restore_flags (flags);
save_flags (flags);
cli ();
- outb (reg, u_Command);
+ outb ((reg), u_Command);
val = inb (u_DataHi);
restore_flags (flags);
save_flags (flags);
cli ();
- outb (reg, u_Command);
+ outb ((reg), u_Command);
- outb ((unsigned char) (data & 0xff), u_DataLo);
- outb ((unsigned char) ((data >> 8) & 0xff), u_DataHi);
+ outb (((unsigned char) (data & 0xff)), u_DataLo);
+ outb (((unsigned char) ((data >> 8) & 0xff)), u_DataHi);
restore_flags (flags);
}
save_flags (flags);
cli ();
- outb (reg | 0x80, u_Command);
+ outb ((reg | 0x80), u_Command);
lo = inb (u_DataLo);
hi = inb (u_DataHi);
save_flags (flags);
cli ();
- outb (reg, u_Command);
+ outb ((reg), u_Command);
lo = inb (u_DataLo);
hi = inb (u_DataHi);
if (voice < 0 || voice > 31)
return;
- outb (voice, u_Voice);
+ outb ((voice), u_Voice);
}
static void
* Set up for Digital ASIC
*/
- outb (0x05, gus_base + 0x0f);
+ outb ((0x05), gus_base + 0x0f);
mix_image |= 0x02; /* Disable line out (for a moment) */
- outb (mix_image, u_Mixer);
+ outb ((mix_image), u_Mixer);
- outb (0x00, u_IRQDMAControl);
+ outb ((0x00), u_IRQDMAControl);
- outb (0x00, gus_base + 0x0f);
+ outb ((0x00), gus_base + 0x0f);
/*
* Now set up the DMA and IRQ interface
* Doing it first time
*/
- outb (mix_image, u_Mixer); /* Select DMA control */
- outb (dma_image | 0x80, u_IRQDMAControl); /* Set DMA address */
+ outb ((mix_image), u_Mixer); /* Select DMA control */
+ outb ((dma_image | 0x80), u_IRQDMAControl); /* Set DMA address */
- outb (mix_image | 0x40, u_Mixer); /* Select IRQ control */
- outb (irq_image, u_IRQDMAControl); /* Set IRQ address */
+ outb ((mix_image | 0x40), u_Mixer); /* Select IRQ control */
+ outb ((irq_image), u_IRQDMAControl); /* Set IRQ address */
/*
* Doing it second time
*/
- outb (mix_image, u_Mixer); /* Select DMA control */
- outb (dma_image, u_IRQDMAControl); /* Set DMA address */
+ outb ((mix_image), u_Mixer); /* Select DMA control */
+ outb ((dma_image), u_IRQDMAControl); /* Set DMA address */
- outb (mix_image | 0x40, u_Mixer); /* Select IRQ control */
- outb (irq_image, u_IRQDMAControl); /* Set IRQ address */
+ outb ((mix_image | 0x40), u_Mixer); /* Select IRQ control */
+ outb ((irq_image), u_IRQDMAControl); /* Set IRQ address */
gus_select_voice (0); /* This disables writes to IRQ/DMA reg */
mix_image &= ~0x02; /* Enable line out */
mix_image |= 0x08; /* Enable IRQ */
- outb (mix_image, u_Mixer); /*
+ outb ((mix_image), u_Mixer); /*
* Turn mixer channels on
* Note! Mic in is left off.
*/
restore_flags (flags);
}
+
static void
pnp_mem_init (void)
{
printk ("Sound: An Interwave audio chip detected but no DRAM\n");
printk ("Sound: Unable to work with this card.\n");
gus_write8 (0x19, gus_read8 (0x19) & ~0x01);
+ gus_mem_size = 0;
return;
}
/*
{
unsigned long i, max_mem = 1024L;
unsigned long loc;
+ unsigned char val;
gus_base = baseaddr;
gus_delay ();
gus_delay ();
+#ifdef GUSPNP_AUTODETECT
+ val = gus_look8 (0x5b); /* Version number register */
+ gus_write8 (0x5b, ~val); /* Invert all bits */
+
+ if ((gus_look8 (0x5b) & 0xf0) == (val & 0xf0)) /* No change */
+ if ((gus_look8 (0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */
+ {
+ DDB (printk ("Interwave chip version %d detected\n", (val & 0xf0) >> 4));
+ gus_pnp_flag = 1;
+ }
+ else
+ {
+ DDB (printk ("Not an Interwave chip (%x)\n", gus_look8 (0x5b)));
+ gus_pnp_flag = 0;
+ }
+ gus_write8 (0x5b, val); /* Restore all bits */
+#endif
+
if (gus_pnp_flag)
pnp_mem_init ();
{
case SNDCTL_SYNTH_INFO:
gus_info.nr_voices = nr_voices;
- copy_to_user (&((char *) arg)[0], &gus_info, sizeof (gus_info));
+ {
+ char *fixit = (char *) &gus_info;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (gus_info));
+ };
return 0;
break;
break;
case SNDCTL_SYNTH_MEMAVL:
- return gus_mem_size - free_mem_ptr - 32;
+ return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32;
default:
- return -(EINVAL);
+ return -EINVAL;
}
}
int sample_no;
if (instr_no < 0 || instr_no > MAX_PATCH)
- return -(EINVAL);
+ instr_no = 0; /* Default to acoustic piano */
if (voice < 0 || voice > 31)
- return -(EINVAL);
+ return -EINVAL;
if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
{
if (sample_no == NOT_SAMPLE)
{
printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
- return -(EINVAL); /* Patch not defined */
+ return -EINVAL; /* Patch not defined */
}
if (sample_ptrs[sample_no] == -1) /* Sample not loaded */
{
printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n",
sample_no, instr_no, voice);
- return -(EINVAL);
+ return -EINVAL;
}
sample_map[voice] = sample_no;
if (voice < 0 || voice > 31)
{
printk ("GUS: Invalid voice\n");
- return -(EINVAL);
+ return -EINVAL;
}
if (note_num == 255)
if ((patch = patch_map[voice]) == -1)
{
- return -(EINVAL);
+ return -EINVAL;
}
if ((samplep = patch_table[patch]) == NOT_SAMPLE)
{
- return -(EINVAL);
+ return -EINVAL;
}
note_freq = note_to_freq (note_num);
if (samples[sample].mode & WAVE_16_BITS)
{
mode |= 0x04; /* 16 bits */
- if ((sample_ptrs[sample] >> 18) !=
- ((sample_ptrs[sample] + samples[sample].len) >> 18))
+ if ((sample_ptrs[sample] / GUS_BANK_SIZE) !=
+ ((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE))
printk ("GUS: Sample address error\n");
}
int err;
if (gus_busy)
- return -(EBUSY);
+ return -EBUSY;
voice_alloc->timestamp = 0;
else
gus_no_dma = 0;
- dram_sleep_flag.flags = WK_NONE;
+ dram_sleep_flag.opts = WK_NONE;
gus_busy = 1;
active_device = GUS_DEV_WAVE;
if (format != GUS_PATCH)
{
printk ("GUS Error: Invalid patch format (key) 0x%x\n", format);
- return -(EINVAL);
+ return -EINVAL;
}
if (count < sizeof_patch)
{
printk ("GUS Error: Patch header too short\n");
- return -(EINVAL);
+ return -EINVAL;
}
count -= sizeof_patch;
+ if (gus_mem_size == 0)
+ return -ENOSPC;
+
if (free_sample >= MAX_SAMPLE)
{
printk ("GUS: Sample table full\n");
- return -(ENOSPC);
+ return -ENOSPC;
}
/*
if (instr < 0 || instr > MAX_PATCH)
{
printk ("GUS: Invalid patch number %d\n", instr);
- return -(EINVAL);
+ return -EINVAL;
}
if (count < patch.len)
if (patch.len <= 0 || patch.len > gus_mem_size)
{
printk ("GUS: Invalid sample length %d\n", (int) patch.len);
- return -(EINVAL);
+ return -EINVAL;
}
if (patch.mode & WAVE_LOOPING)
if (patch.loop_start < 0 || patch.loop_start >= patch.len)
{
printk ("GUS: Invalid loop start\n");
- return -(EINVAL);
+ return -EINVAL;
}
if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)
{
printk ("GUS: Invalid loop end\n");
- return -(EINVAL);
+ return -EINVAL;
}
}
free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */
-#define GUS_BANK_SIZE (256*1024)
-
if (patch.mode & WAVE_16_BITS)
{
/*
if (patch.len >= GUS_BANK_SIZE)
{
printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len);
- return -(ENOSPC);
+ return -ENOSPC;
}
if ((free_mem_ptr / GUS_BANK_SIZE) !=
((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
if ((tmp_mem + patch.len) > gus_mem_size)
- return -(ENOSPC);
+ return -ENOSPC;
free_mem_ptr = tmp_mem; /* This leaves unusable memory */
}
}
if ((free_mem_ptr + patch.len) > gus_mem_size)
- return -(ENOSPC);
+ return -ENOSPC;
sample_ptrs[free_sample] = free_mem_ptr;
blk_sz = left;
/*
- * DMA cannot cross 256k bank boundaries. Check for that.
+ * DMA cannot cross bank (256k) boundaries. Check for that.
*/
blk_end = target + blk_sz;
- if ((target >> 18) != (blk_end >> 18))
+ if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE))
{ /* Split the block */
- blk_end &= ~(256 * 1024 - 1);
+ blk_end &= ~(GUS_BANK_SIZE - 1);
blk_sz = blk_end - target;
}
long i;
unsigned char data;
-
for (i = 0; i < blk_sz; i++)
{
- data = get_fs_byte (&((addr)[sizeof_patch + i]));
+ get_user (data, (unsigned char *) &((addr)[sizeof_patch + i]));
if (patch.mode & WAVE_UNSIGNED)
if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL)
{
printk ("GUS: DMA buffer == NULL\n");
- return -(EINVAL);
+ return -ENOSPC;
}
/*
if (audio_devs[gus_devnum]->dmachan1 > 3)
dma_command |= 0x04; /* 16 bit DMA _channel_ */
- gus_write8 (0x41, dma_command); /* Lets bo luteet (=bugs) */
+ gus_write8 (0x41, dma_command); /* Lets go luteet (=bugs) */
/*
* Sleep here until the DRAM DMA done interrupt is served
unsigned long tlimit;
if (HZ)
- current_set_timeout (tlimit = jiffies + (HZ));
+ current->timeout = tlimit = jiffies + (HZ);
else
tlimit = (unsigned long) -1;
- dram_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&dram_sleeper);
- if (!(dram_sleep_flag.flags & WK_WAKEUP))
+ dram_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&dram_sleeper);
+ if (!(dram_sleep_flag.opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- dram_sleep_flag.flags |= WK_TIMEOUT;
+ dram_sleep_flag.opts |= WK_TIMEOUT;
}
- dram_sleep_flag.flags &= ~WK_SLEEP;
+ dram_sleep_flag.opts &= ~WK_SLEEP;
};
- if ((dram_sleep_flag.flags & WK_TIMEOUT))
+ if ((dram_sleep_flag.opts & WK_TIMEOUT))
printk ("GUS: DMA Transfer timed out\n");
restore_flags (flags);
}
static int
gus_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
{
+ int val;
+
switch (cmd)
{
case SOUND_PCM_WRITE_RATE:
if (local)
return gus_audio_set_speed ((int) arg);
- return snd_ioctl_return ((int *) arg, gus_audio_set_speed (get_user ((int *) arg)));
+ get_user (val, (int *) arg);
+ return ioctl_out (arg, gus_audio_set_speed (val));
break;
case SOUND_PCM_READ_RATE:
if (local)
return gus_audio_speed;
- return snd_ioctl_return ((int *) arg, gus_audio_speed);
+ return ioctl_out (arg, gus_audio_speed);
break;
case SNDCTL_DSP_STEREO:
if (local)
return gus_audio_set_channels ((int) arg + 1) - 1;
- return snd_ioctl_return ((int *) arg, gus_audio_set_channels (get_user ((int *) arg) + 1) - 1);
+ get_user (val, (int *) arg);
+ return ioctl_out (arg, gus_audio_set_channels (val + 1) - 1);
break;
case SOUND_PCM_WRITE_CHANNELS:
if (local)
return gus_audio_set_channels ((int) arg);
- return snd_ioctl_return ((int *) arg, gus_audio_set_channels (get_user ((int *) arg)));
+ get_user (val, (int *) arg);
+ return ioctl_out (arg, gus_audio_set_channels (val));
break;
case SOUND_PCM_READ_CHANNELS:
if (local)
return gus_audio_channels;
- return snd_ioctl_return ((int *) arg, gus_audio_channels);
+ return ioctl_out (arg, gus_audio_channels);
break;
case SNDCTL_DSP_SETFMT:
if (local)
return gus_audio_set_bits ((int) arg);
- return snd_ioctl_return ((int *) arg, gus_audio_set_bits (get_user ((int *) arg)));
+ get_user (val, (int *) arg);
+ return ioctl_out (arg, gus_audio_set_bits (val));
break;
case SOUND_PCM_READ_BITS:
if (local)
return gus_audio_bits;
- return snd_ioctl_return ((int *) arg, gus_audio_bits);
+ return ioctl_out (arg, gus_audio_bits);
case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */
- return snd_ioctl_return ((int *) arg, -(EINVAL));
+ return ioctl_out (arg, -EINVAL);
break;
case SOUND_PCM_READ_FILTER:
- return snd_ioctl_return ((int *) arg, -(EINVAL));
+ return ioctl_out (arg, -EINVAL);
+ break;
+
+/* This is just a temporary hack used for reading the ROM patch set. */
+
+ case SNDCTL_PMGR_ACCESS:
+ {
+ copr_msg *buf;
+ int i, pos;
+
+ buf = (copr_msg *) vmalloc (sizeof (copr_msg));
+ if (buf == NULL)
+ return -ENOSPC;
+
+ copy_from_user ((char *) buf, &((char *) arg)[0], sizeof (*buf));
+
+ pos = buf->len;
+
+ gus_write8 (0x53, gus_look8 (0x53) | 0x02); /* Select ROM I/O access */
+
+ for (i = 0; i < 2048; i++)
+ {
+ buf->data[i] = gus_peek (pos + i);
+ }
+ gus_write8 (0x53, gus_look8 (0x53) & ~0x02); /* Select DRAM I/O access */
+ buf->len = 2048; /* feed back number of WORDs sent */
+ {
+ char *fixit = (char *) buf;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (*buf));
+ };
+ vfree (buf);
+
+ return 0;
+ }
break;
}
- return -(EINVAL);
+ return -EINVAL;
}
static void
}
}
+
static int
gus_audio_open (int dev, int mode)
{
if (gus_busy)
- return -(EBUSY);
+ return -EBUSY;
if (gus_pnp_flag && mode & OPEN_READ)
{
printk ("Sound: This audio device doesn't have recording capability\n");
- return -(EIO);
+ return -EIO;
}
gus_initialize ();
if (gus_audio_bits != 8)
{
printk ("GUS Error: 16 bit recording not supported\n");
- return -(EINVAL);
+ return -EINVAL;
}
return 0;
for (i = 0; i < len; i++)
{
- *out_left++ = get_fs_byte (&((userbuf)[in_left]));
+ get_user (*out_left++, (unsigned char *) &((userbuf)[in_left]));
in_left += 2;
- *out_right++ = get_fs_byte (&((userbuf)[in_right]));
+ get_user (*out_right++, (unsigned char *) &((userbuf)[in_right]));
in_right += 2;
}
}
for (i = 0; i < len; i++)
{
- *out_left++ = get_fs_word (&((userbuf)[in_left]));
+ get_user (*out_left++, (unsigned short *) &((userbuf)[in_left]));
in_left += 4;
- *out_right++ = get_fs_word (&((userbuf)[in_right]));
+ get_user (*out_right++, (unsigned short *) &((userbuf)[in_right]));
in_right += 4;
}
}
struct patch_info *pat;
if (ptr < 0 || ptr >= free_sample)
- return -(EINVAL);
+ return -EINVAL;
memcpy (rec->data.data8, (char *) &samples[ptr],
sizeof (struct patch_info));
struct patch_info *pat;
if (ptr < 0 || ptr >= free_sample)
- return -(EINVAL);
+ return -EINVAL;
pat = (struct patch_info *) rec->data.data8;
if (pat->len > samples[ptr].len) /* Cannot expand sample */
- return -(EINVAL);
+ return -EINVAL;
pat->key = samples[ptr].key; /* Ensure the link is correct */
int l = rec->parm3;
if (sample < 0 || sample >= free_sample)
- return -(EINVAL);
+ return -EINVAL;
if (offs < 0 || offs >= samples[sample].len)
- return -(EINVAL); /* Invalid offset */
+ return -EINVAL; /* Invalid offset */
n = samples[sample].len - offs; /* Num of bytes left */
l = sizeof (rec->data.data8);
if (l <= 0)
- return -(EINVAL); /*
+ return -EINVAL; /*
* Was there a bug?
*/
offs += sample_ptrs[sample]; /*
- * Begin offsets + offset to DRAM
+ * Begin offset + offset to DRAM
*/
for (n = 0; n < l; n++)
int l = rec->parm3;
if (sample < 0 || sample >= free_sample)
- return -(EINVAL);
+ return -EINVAL;
if (offs < 0 || offs >= samples[sample].len)
- return -(EINVAL); /*
+ return -EINVAL; /*
* Invalid offset
*/
l = sizeof (rec->data.data8);
if (l <= 0)
- return -(EINVAL); /*
+ return -EINVAL; /*
* Was there a bug?
*/
break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
}
mix_image &= ~0x07;
mix_image |= mask & 0x07;
- outb (mix_image, u_Mixer);
+ outb ((mix_image), u_Mixer);
restore_flags (flags);
}
switch (cmd & 0xff)
{
case SOUND_MIXER_RECSRC:
- gus_recmask = get_user ((int *) arg) & MIX_DEVS;
+ get_user (gus_recmask, (int *) arg);
+ gus_recmask &= MIX_DEVS;
if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
gus_recmask = SOUND_MASK_MIC;
/* Note! Input volumes are updated during next open for recording */
- return snd_ioctl_return ((int *) arg, gus_recmask);
+ return ioctl_out (arg, gus_recmask);
break;
case SOUND_MIXER_MIC:
{
- int vol = get_user ((int *) arg) & 0xff;
+ int vol;
+
+ get_user (vol, (int *) arg);
+ vol &= 0xff;
if (vol < 0)
vol = 0;
vol = 100;
gus_mic_vol = vol;
set_input_volumes ();
- return snd_ioctl_return ((int *) arg, vol | (vol << 8));
+ return ioctl_out (arg, vol | (vol << 8));
}
break;
case SOUND_MIXER_LINE:
{
- int vol = get_user ((int *) arg) & 0xff;
+ int vol;
+
+ get_user (vol, (int *) arg);
+ vol &= 0xff;
if (vol < 0)
vol = 0;
vol = 100;
gus_line_vol = vol;
set_input_volumes ();
- return snd_ioctl_return ((int *) arg, vol | (vol << 8));
+ return ioctl_out (arg, vol | (vol << 8));
}
break;
case SOUND_MIXER_PCM:
- gus_pcm_volume = get_user ((int *) arg) & 0xff;
+ get_user (gus_pcm_volume, (int *) arg);
+ gus_pcm_volume &= 0xff;
if (gus_pcm_volume < 0)
gus_pcm_volume = 0;
if (gus_pcm_volume > 100)
gus_pcm_volume = 100;
gus_audio_update_volume ();
- return snd_ioctl_return ((int *) arg, gus_pcm_volume | (gus_pcm_volume << 8));
+ return ioctl_out (arg, gus_pcm_volume | (gus_pcm_volume << 8));
break;
case SOUND_MIXER_SYNTH:
{
int voice;
- gus_wave_volume = get_user ((int *) arg) & 0xff;
+ get_user (gus_wave_volume, (int *) arg);
+ gus_wave_volume &= 0xff;
if (gus_wave_volume < 0)
gus_wave_volume = 0;
for (voice = 0; voice < nr_voices; voice++)
dynamic_volume_change (voice); /* Apply the new vol */
- return snd_ioctl_return ((int *) arg, gus_wave_volume | (gus_wave_volume << 8));
+ return ioctl_out (arg, gus_wave_volume | (gus_wave_volume << 8));
}
break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
else
switch (cmd & 0xff) /*
{
case SOUND_MIXER_RECSRC:
- return snd_ioctl_return ((int *) arg, gus_recmask);
+ return ioctl_out (arg, gus_recmask);
break;
case SOUND_MIXER_DEVMASK:
- return snd_ioctl_return ((int *) arg, MIX_DEVS);
+ return ioctl_out (arg, MIX_DEVS);
break;
case SOUND_MIXER_STEREODEVS:
- return snd_ioctl_return ((int *) arg, 0);
+ return ioctl_out (arg, 0);
break;
case SOUND_MIXER_RECMASK:
- return snd_ioctl_return ((int *) arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
+ return ioctl_out (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
break;
case SOUND_MIXER_CAPS:
- return snd_ioctl_return ((int *) arg, 0);
+ return ioctl_out (arg, 0);
break;
case SOUND_MIXER_MIC:
- return snd_ioctl_return ((int *) arg, gus_mic_vol | (gus_mic_vol << 8));
+ return ioctl_out (arg, gus_mic_vol | (gus_mic_vol << 8));
break;
case SOUND_MIXER_LINE:
- return snd_ioctl_return ((int *) arg, gus_line_vol | (gus_line_vol << 8));
+ return ioctl_out (arg, gus_line_vol | (gus_line_vol << 8));
break;
case SOUND_MIXER_PCM:
- return snd_ioctl_return ((int *) arg, gus_pcm_volume | (gus_pcm_volume << 8));
+ return ioctl_out (arg, gus_pcm_volume | (gus_pcm_volume << 8));
break;
case SOUND_MIXER_SYNTH:
- return snd_ioctl_return ((int *) arg, gus_wave_volume | (gus_wave_volume << 8));
+ return ioctl_out (arg, gus_wave_volume | (gus_wave_volume << 8));
break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
}
else
- return -(EINVAL);
+ return -EINVAL;
}
static struct mixer_operations gus_mixer_operations =
*/
mix_image &= ~0x07;
mix_image |= 0x04; /* All channels enabled */
- outb (mix_image, u_Mixer);
+ outb ((mix_image), u_Mixer);
}
}
unsigned long flags;
unsigned char val;
char *model_num = "2.4";
+ char tmp[64], tmp2[64];
int gus_type = 0x24; /* 2.4 */
int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2;
* Versions < 3.6 don't have the digital ASIC. Try to probe it first.
*/
-#ifdef GUSPNP_AUTODETECT
- val = gus_look8 (0x5b); /* Version number register */
- gus_write8 (0x5b, ~val); /* Invert all bits */
-
- if ((gus_look8 (0x5b) & 0xf0) == (val & 0xf0)) /* No change */
- if ((gus_look8 (0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */
- {
- DDB (printk ("Interwave chip version %d detected\n", (val & 0xf0) >> 4));
- gus_pnp_flag = 1;
- }
- else
- {
- DDB (printk ("Not an Interwave chip\n"));
- gus_pnp_flag = 0;
- }
- gus_write8 (0x5b, val); /* Restore all bits */
-#endif
-
save_flags (flags);
cli ();
- outb (0x20, gus_base + 0x0f);
+ outb ((0x20), gus_base + 0x0f);
val = inb (gus_base + 0x0f);
restore_flags (flags);
max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */
- outb (max_config, gus_base + 0x106); /* UltraMax control */
+ outb ((max_config), gus_base + 0x106); /* UltraMax control */
}
if (ad1848_detect (gus_base + 0x10c, &ad_flags, hw_config->osp))
{
char *name = "GUS MAX";
+ int old_num_mixers = num_mixers;
+
+ if (gus_pnp_flag)
+ name = "GUS PnP";
gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
gus_wave_volume = 90;
gus_dma, /* Capture DMA */
1, /* Share DMA channels with GF1 */
hw_config->osp);
+
+ if (num_mixers > old_num_mixers)
+ { /* GUS has it's own mixer map */
+ AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH);
+ AD1848_REROUTE (SOUND_MIXER_LINE2, SOUND_MIXER_CD);
+ AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
+ }
}
else
printk ("[Where's the CS4231?]");
if (hw_config->name)
{
- char tmp[20];
- strncpy (tmp, hw_config->name, 20);
- tmp[19] = 0;
- sprintf (gus_info.name, "%s (%dk)", tmp, (int) gus_mem_size / 1024);
- gus_info.name[sizeof (gus_info.name) - 1] = 0;
+ strncpy (tmp, hw_config->name, 45);
+ tmp[45] = 0;
+ sprintf (tmp2, "%s (%dk)", tmp, (int) gus_mem_size / 1024);
+ tmp2[sizeof (tmp2) - 1] = 0;
+ }
+ else if (gus_pnp_flag)
+ {
+ sprintf (tmp2, "Gravis UltraSound PnP (%dk)",
+ (int) gus_mem_size / 1024);
}
else
- sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
+ sprintf (tmp2, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
samples = (struct patch_info *) (sound_mem_blocks[sound_nblocks] = vmalloc ((MAX_SAMPLE + 1) * sizeof (*samples)));
return;
}
- conf_printf (gus_info.name, hw_config);
+ conf_printf (tmp2, hw_config);
+ strncpy (gus_info.name, tmp2, sizeof (tmp2));
+ gus_info.name[sizeof (tmp2) - 1] = 0;
if (num_synths >= MAX_SYNTH_DEV)
printk ("GUS Error: Too many synthesizers\n");
gus_initialize ();
- if (num_audiodevs < MAX_AUDIO_DEV)
- {
- audio_devs[gus_devnum = num_audiodevs++] = &gus_audio_operations;
- audio_devs[gus_devnum]->dmachan1 = dma;
- audio_devs[gus_devnum]->dmachan2 = dma2;
- audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE;
- audio_devs[gus_devnum]->min_fragment = 9;
- audio_devs[gus_devnum]->mixer_dev = num_mixers; /* Next mixer# */
- audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
- if (dma2 != dma && dma2 != -1)
- audio_devs[gus_devnum]->flags |= DMA_DUPLEX;
- }
- else
- printk ("GUS: Too many PCM devices available\n");
+ if (gus_mem_size > 0)
+ if (num_audiodevs < MAX_AUDIO_DEV)
+ {
+ audio_devs[gus_devnum = num_audiodevs++] = &gus_audio_operations;
+ audio_devs[gus_devnum]->dmachan1 = dma;
+ audio_devs[gus_devnum]->dmachan2 = dma2;
+ audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE;
+ audio_devs[gus_devnum]->min_fragment = 9;
+ audio_devs[gus_devnum]->mixer_dev = num_mixers; /* Next mixer# */
+ audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
+ if (dma2 != dma && dma2 != -1)
+ audio_devs[gus_devnum]->flags |= DMA_DUPLEX;
+ }
+ else
+ printk ("GUS: Too many audio devices available\n");
/*
* Mixer dependent initialization.
switch (active_device)
{
case GUS_DEV_WAVE:
- if ((dram_sleep_flag.flags & WK_SLEEP))
+ if ((dram_sleep_flag.opts & WK_SLEEP))
{
- dram_sleep_flag.flags = WK_WAKEUP;
- module_wake_up (&dram_sleeper);
+ dram_sleep_flag.opts = WK_WAKEUP;
+ wake_up (&dram_sleeper);
};
break;
{
int i;
- outb ((unsigned char) (addr & 0xff), select_addr);
+ outb (((unsigned char) (addr & 0xff)), select_addr);
for (i = 0; i < 2; i++)
inb (select_addr);
- outb ((unsigned char) (val & 0xff), data_addr);
+ outb (((unsigned char) (val & 0xff)), data_addr);
for (i = 0; i < 2; i++)
inb (select_addr);
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#include "sound_config.h"
-#if defined(CONFIG_GUS)
+#if defined(CONFIG_GUSHW)
#include <linux/ultrasound.h>
#include "gus_hw.h"
save_flags (flags);
cli ();
- outb (ctrl_addr, u_MixSelect);
- outb (selector[dev], u_MixData);
- outb (attn_addr, u_MixSelect);
- outb ((unsigned char) vol, u_MixData);
+ outb ((ctrl_addr), u_MixSelect);
+ outb ((selector[dev]), u_MixData);
+ outb ((attn_addr), u_MixSelect);
+ outb (((unsigned char) vol), u_MixData);
restore_flags (flags);
}
break;
case SOUND_MIXER_MIC:
- return snd_ioctl_return ((int *) arg, set_volumes (DEV_MIC, get_user ((int *) arg)));
+ return ioctl_out (arg, set_volumes (DEV_MIC, ioctl_in (arg)));
break;
case SOUND_MIXER_CD:
- return snd_ioctl_return ((int *) arg, set_volumes (DEV_CD, get_user ((int *) arg)));
+ return ioctl_out (arg, set_volumes (DEV_CD, ioctl_in (arg)));
break;
case SOUND_MIXER_LINE:
- return snd_ioctl_return ((int *) arg, set_volumes (DEV_LINE, get_user ((int *) arg)));
+ return ioctl_out (arg, set_volumes (DEV_LINE, ioctl_in (arg)));
break;
case SOUND_MIXER_SYNTH:
- return snd_ioctl_return ((int *) arg, set_volumes (DEV_GF1, get_user ((int *) arg)));
+ return ioctl_out (arg, set_volumes (DEV_GF1, ioctl_in (arg)));
break;
case SOUND_MIXER_VOLUME:
- return snd_ioctl_return ((int *) arg, set_volumes (DEV_VOL, get_user ((int *) arg)));
+ return ioctl_out (arg, set_volumes (DEV_VOL, ioctl_in (arg)));
break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
else
switch (cmd & 0xff) /*
break;
case SOUND_MIXER_DEVMASK:
- return snd_ioctl_return ((int *) arg, MIX_DEVS);
+ return ioctl_out (arg, MIX_DEVS);
break;
case SOUND_MIXER_STEREODEVS:
- return snd_ioctl_return ((int *) arg, SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC);
+ return ioctl_out (arg, SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC);
break;
case SOUND_MIXER_RECMASK:
- return snd_ioctl_return ((int *) arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
+ return ioctl_out (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
break;
case SOUND_MIXER_CAPS:
- return snd_ioctl_return ((int *) arg, 0);
+ return ioctl_out (arg, 0);
break;
case SOUND_MIXER_MIC:
- return snd_ioctl_return ((int *) arg, volumes[DEV_MIC]);
+ return ioctl_out (arg, volumes[DEV_MIC]);
break;
case SOUND_MIXER_LINE:
- return snd_ioctl_return ((int *) arg, volumes[DEV_LINE]);
+ return ioctl_out (arg, volumes[DEV_LINE]);
break;
case SOUND_MIXER_CD:
- return snd_ioctl_return ((int *) arg, volumes[DEV_CD]);
+ return ioctl_out (arg, volumes[DEV_CD]);
break;
case SOUND_MIXER_VOLUME:
- return snd_ioctl_return ((int *) arg, volumes[DEV_VOL]);
+ return ioctl_out (arg, volumes[DEV_VOL]);
break;
case SOUND_MIXER_SYNTH:
- return snd_ioctl_return ((int *) arg, volumes[DEV_GF1]);
+ return ioctl_out (arg, volumes[DEV_GF1]);
break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
}
- return -(EINVAL);
+ return -EINVAL;
}
static struct mixer_operations ics2101_mixer_operations =
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
--- /dev/null
+ver.0.2.0
+ - Includes FreeBSD port
+ - Can load GUS compatible patches
+ - Change values of hardware control parameters for compatibility
+ with GUS driver
+ - Accept 8bit or unsigned wave data
+ - Accept no blank loop data
+ - Add sample mode flags in sample_info
+
+ver.0.1.6
+ - Add voice effects control
+ - Fix awe_voice.h for word alignment
+
+ver.0.1.5c
+ - Fix FM(OPL) playback problem
+
+ver.0.1.5b
+ - Fix pitch calculation for fixed midi key
+
+ver.0.1.5a
+ - Fix bugs in removing samples from linked list.
+
+ver.0.1.5
+ - Add checksum verification for sample uploading
+ (not compatible from older sample_info structure)
+ - Fix sample offset pointers to (actual value - 1)
+ - Add sequencer command to initialize awe32
+
+ver.0.1.4c
+ - Fix card detection and memory check function to avoid system crash
+ at booting
+
+ver.0.1.4b
+ - Add release sustain mode
+ - Initialize FM each time after loading samples
+
+ver.0.1.4a
+ - Fix AWE card detection code
+ - Correct FM initialize position
+ - Add non-releasing mode on voice info
+
+ver.0.1.4
+ - Add AWE card and DRAM detection codes
+ - Add FM initialization code
+ - Modify volume control
+ - Remove linear volume mode
+ - Change memory management; not using malloc dynamically
+ - Add remove-samples command
+ - Use internal id implicitly at loading samples
+
+ver.0.1.3
+ - Fix a bug on patch uploading to RAM
+
+ver.0.1.2
+ - Divide to separated packages
+ - Fix disagreed macro conditions
+ - Fix unresolved function bugs
+ - Integrate VoxWare and USS-Lite driver source (awe_voice.c)
+ and remove awe_card.c
+
+ver.0.1.1
+ - Fix wrong sample numbers in sbktext
+ - Fix txt2sfx bug
+ - Fix pan parameter calculation
+ - Append USS-Lite/Linux2.0 driver
+
if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER
+ bool 'AWE32 synth' CONFIG_AWE32_SYNTH
fi
all: lowlevel.o
+ALLOBJS = init.o aci.o awe_wave.o
OBJS = init.o
ifdef CONFIG_LOWLEVEL_SOUND
ifdef CONFIG_ACI_MIXER
OBJS := $(OBJS) aci.o
endif
+ifdef CONFIG_AWE32_SYNTH
+OBJS := $(OBJS) awe_wave.o
+endif
endif
lowlevel.o: $(OBJS)
$(LD) -r -o lowlevel.o $(OBJS)
+module: manual_config.h
+ rm -f lowlevel.o
+ make CFLAGS="$(CFLAGS) -DLOWLEVEL_MODULE" $(ALLOBJS)
+ $(LD) -r -o lowlevel.o $(ALLOBJS)
+ touch module
+
+manual_config.h:
+ @echo You should create `pwd`/manual_config.h.
+ @echo See `pwd`/README for more info.
+ @exit 1
+
clean:
- rm -f core x y z *~ *.o
+ rm -f core x y z *~ *.o module
ifdef HOSTCC
include $(TOPDIR)/Rules.make
Additional low level sound drivers for Linux
---------------------------------------------
+============================================
This directory contains additional low level sound drivers which
-are not part of USS/Lite (UNIX Sound System). These drivers are
-maintained by their authors.
+are not part of USS/Lite (Open Sound System). These drivers are
+maintained by their authors (not by Hannu Savolainen).
-If you like to write a low level sound driver, please contact
+If you like to write a new low level sound driver, please contact
Hannu Savolainen (hannu@voxware.pp.fi) for more info.
The following low level drivers are included:
-- ACI MIXER for miroPCM12 by Markus Kuhn. See aci.readme for more info.
+- ACI MIXER for miroPCM12 by Markus Kuhn
+(mskuhn@cip.informatik.uni-erlangen.de).
+- SB32/AWE synthesizer driver (Emu8000) by Takashi Iwai
+(iwai@dragon.mm.t.u-tokyo.ac.jp). See README.awe for more
+info.
--- /dev/null
+================================================================
+ AWE32 Sound Driver for Linux / FreeBSD
+ version 0.2.0; Oct. 16, 1996
+================================================================
+
+* GENERAL NOTES
+
+This is a sound driver extension for SB-AWE32 cards to enable the
+wave synth operations. The driver is provided for both Linux 1.2.x
+and 2.0.x kernels, and also FreeBSD. Follow the corresponding
+instruction in the installation document if you use old sound drivers.
+
+This driver was written by Takashi Iwai (iwai@dragon.mm.t.u-tokyo.ac.jp)
+who also maintains the code. Please forward any questions, bug fixes
+and suggestions directly to me (_NOT_ to Linus Torvalds or Hannu
+Savolainen).
+
+
+* CAUTION
+
+- In the v0.2.0, parameters of hardware control are changed to have a
+compatibility with GUS driver. If you have older awesfx and drvmidi
+utilities, please get new versions and install them again.
+
+- The SFX file after v0.1.5 is no more compatible from 0.1.4x.
+Please remake the obsolete SFX files again by txt2sfx utility.
+
+
+* USING THE DRIVER
+
+To load SoundFont files, sfxload utility is required.
+All AWE32 driver and utilities can be downloaded from:
+ http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/
+
+Follow the instruction in awesfx package to make patched GM and
+GS presets. Then, load the SFX file on driver by sfxload utility.
+
+ % sfxload -i gm.sfx
+
+Now you can hear midi musics by supported midi players
+(awemidi-0.1.x.tar.gz or patch file to playmidi-2.3).
+
+ % drvmidi foo.mid
+
+Enjoy.
+
+
+* ACKNOWLEDGMENTS
+
+Thanks to Witold Jachimczyk (witek@xfactor.wpi.edu) for many advices
+to programming of AWE32. Many codes are brought from his AWE32-native
+MOD player, ALMP.
+The port of awedrv0.1.6 to FreeBSD is done by Randall Hopper
+(rhh@ct.picker.com).
+I also thank linux-awe-ml members for their efforts
+to reboot their system many times :-)
+
+
+* BUGS & TODO'S
+
+- Some instruments are inaudible, eg. glockenspiel and sinewaves.
+- No stereo sample can be used.
+- More smart patch management
+- More smart DRAM memory control
+- Dynamic buffer allocation
+- etc, etc, etc.
+
+
+Takashi Iwai <iwai@dragon.mm.t.u-tokyo.ac.jp>
* This mixer driver identifies itself to applications as "ACI" in
* mixer_info.id as retrieved by ioctl(fd, SOUND_MIXER_INFO, &mixer_info).
*
- * Proprietary mixer features that go beyond the standard USS mixer
+ * Proprietary mixer features that go beyond the standard OSS mixer
* interface are:
*
* Full duplex solo configuration:
*
*/
+#include "lowlevel.h"
#include "../sound_config.h"
+#include "lowlevel.h"
#ifdef CONFIG_ACI_MIXER
#undef DEBUG /* if defined, produce a verbose report via syslog */
--- /dev/null
+/*================================================================
+ * AWE32 access routines
+ *================================================================*/
+
+#ifndef AWE_HW_H_DEF
+#define AWE_HW_H_DEF
+
+/*
+ * user configuration:
+ * if auto detection can't work properly, define the following values
+ * for your machine.
+ */
+/*#define AWE_DEFAULT_BASE_ADDR 0x620*/ /* base port address */
+/*#define AWE_DEFAULT_MEM_SIZE 512*/ /* kbytes */
+
+
+/*
+ * maximum size of sample table:
+ * if your data overflow, increase the following values.
+ */
+#define AWE_MAX_SAMPLES 400
+#define AWE_MAX_INFOS 900 /* GS presets has 801 infos! */
+
+
+/*
+ * Emu-8000 control registers
+ * name(channel) reg, port
+ */
+
+#define awe_cmd_idx(reg,ch) (((reg)<< 5) | (ch))
+
+#define Data0 0x620 /* doubleword r/w */
+#define Data1 0xA20 /* doubleword r/w */
+#define Data2 0xA22 /* word r/w */
+#define Data3 0xE20 /* word r/w */
+#define Pointer 0xE22 /* register pointer r/w */
+
+#define AWE_CPF(ch) awe_cmd_idx(0,ch), Data0 /* DW: current pitch and fractional address */
+#define AWE_PTRX(ch) awe_cmd_idx(1,ch), Data0 /* DW: pitch target and reverb send */
+#define AWE_CVCF(ch) awe_cmd_idx(2,ch), Data0 /* DW: current volume and filter cutoff */
+#define AWE_VTFT(ch) awe_cmd_idx(3,ch), Data0 /* DW: volume and filter cutoff targets */
+#define AWE_PSST(ch) awe_cmd_idx(6,ch), Data0 /* DW: pan send and loop start address */
+#define AWE_CSL(ch) awe_cmd_idx(7,ch), Data0 /* DW: chorus send and loop end address */
+#define AWE_CCCA(ch) awe_cmd_idx(0,ch), Data1 /* DW: Q, control bits, and current address */
+#define AWE_HWCF4 awe_cmd_idx(1,9), Data1 /* DW: config dw 4 */
+#define AWE_HWCF5 awe_cmd_idx(1,10), Data1 /* DW: config dw 5 */
+#define AWE_HWCF6 awe_cmd_idx(1,13), Data1 /* DW: config dw 6 */
+#define AWE_SMALR awe_cmd_idx(1,20), Data1 /* DW: sound memory address for left read */
+#define AWE_SMARR awe_cmd_idx(1,21), Data1 /* DW: for right read */
+#define AWE_SMALW awe_cmd_idx(1,22), Data1 /* DW: sound memory address for left write */
+#define AWE_SMARW awe_cmd_idx(1,23), Data1 /* DW: for right write */
+#define AWE_SMLD awe_cmd_idx(1,26), Data1 /* W: sound memory left data */
+#define AWE_SMRD awe_cmd_idx(1,26), Data2 /* W: right data */
+#define AWE_WC awe_cmd_idx(1,27), Data2 /* W: sample counter */
+#define AWE_WC_Cmd awe_cmd_idx(1,27)
+#define AWE_WC_Port Data2
+#define AWE_HWCF1 awe_cmd_idx(1,29), Data1 /* W: config w 1 */
+#define AWE_HWCF2 awe_cmd_idx(1,30), Data1 /* W: config w 2 */
+#define AWE_HWCF3 awe_cmd_idx(1,31), Data1 /* W: config w 3 */
+#define AWE_INIT1(ch) awe_cmd_idx(2,ch), Data1 /* W: init array 1 */
+#define AWE_INIT2(ch) awe_cmd_idx(2,ch), Data2 /* W: init array 2 */
+#define AWE_INIT3(ch) awe_cmd_idx(3,ch), Data1 /* W: init array 3 */
+#define AWE_INIT4(ch) awe_cmd_idx(3,ch), Data2 /* W: init array 4 */
+#define AWE_ENVVOL(ch) awe_cmd_idx(4,ch), Data1 /* W: volume envelope delay */
+#define AWE_DCYSUSV(ch) awe_cmd_idx(5,ch), Data1 /* W: volume envelope sustain and decay */
+#define AWE_ENVVAL(ch) awe_cmd_idx(6,ch), Data1 /* W: modulation envelope delay */
+#define AWE_DCYSUS(ch) awe_cmd_idx(7,ch), Data1 /* W: modulation envelope sustain and decay */
+#define AWE_ATKHLDV(ch) awe_cmd_idx(4,ch), Data2 /* W: volume envelope attack and hold */
+#define AWE_LFO1VAL(ch) awe_cmd_idx(5,ch), Data2 /* W: LFO#1 Delay */
+#define AWE_ATKHLD(ch) awe_cmd_idx(6,ch), Data2 /* W: modulation envelope attack and hold */
+#define AWE_LFO2VAL(ch) awe_cmd_idx(7,ch), Data2 /* W: LFO#2 Delay */
+#define AWE_IP(ch) awe_cmd_idx(0,ch), Data3 /* W: initial pitch */
+#define AWE_IFATN(ch) awe_cmd_idx(1,ch), Data3 /* W: initial filter cutoff and attenuation */
+#define AWE_PEFE(ch) awe_cmd_idx(2,ch), Data3 /* W: pitch and filter envelope heights */
+#define AWE_FMMOD(ch) awe_cmd_idx(3,ch), Data3 /* W: vibrato and filter modulation freq */
+#define AWE_TREMFRQ(ch) awe_cmd_idx(4,ch), Data3 /* W: LFO#1 tremolo amount and freq */
+#define AWE_FM2FRQ2(ch) awe_cmd_idx(5,ch), Data3 /* W: LFO#2 vibrato amount and freq */
+
+/* used during detection (returns ROM version ?) */
+#define AWE_U1 0xE0, Data3 /* (R)(W) used in initialization */
+#define AWE_U2(ch) 0xC0+(ch), Data3 /* (W)(W) used in init envelope */
+
+
+#define AWE_MAX_VOICES 32
+#define AWE_NORMAL_VOICES 30 /*30&31 are reserved for DRAM refresh*/
+
+#define AWE_DRAM_OFFSET 0x200000
+
+#endif
--- /dev/null
+#ifndef AWE_VOICE_H
+#define AWE_VOICE_H
+/*================================================================
+ * awe_voice.h -- voice information for AWE32 wave table synth
+ * ver.0.2.0; Oct. 16, 1996
+ * copyright (c) 1996 by Takashi Iwai
+ *================================================================*/
+
+#ifndef SAMPLE_TYPE_AWE32
+#define SAMPLE_TYPE_AWE32 0x20
+#endif
+
+#ifndef _PATCHKEY
+#define _PATCHKEY(id) ((id<<8)|0xfd)
+#endif
+
+/*----------------------------------------------------------------
+ * patch information record
+ *----------------------------------------------------------------*/
+
+/* patch interface header: 16 bytes */
+typedef struct awe_patch_info {
+ short key; /* use AWE_PATCH here */
+#define AWE_PATCH _PATCHKEY(0x07)
+
+ short device_no; /* synthesizer number */
+ unsigned short sf_id; /* file id (should be zero) */
+ short sf_version; /* patch version (not referred) */
+ long len; /* data length (without this header) */
+
+ short type; /* following data type */
+#define AWE_LOAD_INFO 0
+#define AWE_LOAD_DATA 1
+
+ short reserved; /* word alignment data */
+ char data[0]; /* patch data follows here */
+} awe_patch_info;
+
+
+/*----------------------------------------------------------------
+ * raw voice information record
+ *----------------------------------------------------------------*/
+
+/* wave table envelope & effect parameters to control EMU8000 */
+typedef struct _awe_voice_parm {
+ unsigned short moddelay; /* modulation delay (0x8000) */
+ unsigned short modatkhld; /* modulation attack & hold time (0x7f7f) */
+ unsigned short moddcysus; /* modulation decay & sustain (0x7f7f) */
+ unsigned short modrelease; /* modulation release time (0x807f) */
+ short modkeyhold, modkeydecay; /* envelope change per key (not used) */
+ unsigned short voldelay; /* volume delay (0x8000) */
+ unsigned short volatkhld; /* volume attack & hold time (0x7f7f) */
+ unsigned short voldcysus; /* volume decay & sustain (0x7f7f) */
+ unsigned short volrelease; /* volume release time (0x807f) */
+ short volkeyhold, volkeydecay; /* envelope change per key (not used) */
+ unsigned short lfo1delay; /* LFO1 delay (0x8000) */
+ unsigned short lfo2delay; /* LFO2 delay (0x8000) */
+ unsigned short pefe; /* modulation pitch & cutoff (0x0000) */
+ unsigned short fmmod; /* LFO1 pitch & cutoff (0x0000) */
+ unsigned short tremfrq; /* LFO1 volume & freq (0x0000) */
+ unsigned short fm2frq2; /* LFO2 pitch & freq (0x0000) */
+ unsigned char cutoff; /* initial cutoff (0xff) */
+ unsigned char filterQ; /* initial filter Q [0-15] (0x0) */
+ unsigned char chorus; /* chorus send (0x00) */
+ unsigned char reverb; /* reverb send (0x00) */
+ unsigned short reserved[4]; /* not used */
+} awe_voice_parm;
+
+/* wave table parameters: 92 bytes */
+typedef struct _awe_voice_info {
+ unsigned short sf_id; /* file id (should be zero) */
+ unsigned short sample; /* sample id */
+ long start, end; /* sample offset correction */
+ long loopstart, loopend; /* loop offset correction */
+ short rate_offset; /* sample rate pitch offset */
+ unsigned short mode; /* sample mode */
+#define AWE_MODE_ROMSOUND 0x8000
+#define AWE_MODE_STEREO 1
+#define AWE_MODE_LOOPING 2
+#define AWE_MODE_NORELEASE 4 /* obsolete */
+#define AWE_MODE_INIT_PARM 8
+
+ short root; /* midi root key */
+ short tune; /* pitch tuning (in cents) */
+ char low, high; /* key note range */
+ char vellow, velhigh; /* velocity range */
+ char fixkey, fixvel; /* fixed key, velocity */
+ char pan, fixpan; /* panning, fixed panning */
+ short exclusiveClass; /* exclusive class (0 = none) */
+ unsigned char amplitude; /* sample volume (127 max) */
+ unsigned char attenuation; /* attenuation (0.375dB) */
+ short scaleTuning; /* pitch scale tuning(%), normally 100 */
+ awe_voice_parm parm; /* voice envelope parameters */
+ short index; /* internal index (set by driver) */
+} awe_voice_info;
+
+/* instrument info header: 4 bytes */
+typedef struct _awe_voice_rec {
+ unsigned char bank; /* midi bank number */
+ unsigned char instr; /* midi preset number */
+ short nvoices; /* number of voices */
+ awe_voice_info info[0]; /* voice information follows here */
+} awe_voice_rec;
+
+
+/*----------------------------------------------------------------
+ * sample wave information
+ *----------------------------------------------------------------*/
+
+/* wave table sample header: 32 bytes */
+typedef struct awe_sample_info {
+ unsigned short sf_id; /* file id (should be zero) */
+ unsigned short sample; /* sample id */
+ long start, end; /* start & end offset */
+ long loopstart, loopend; /* loop start & end offset */
+ long size; /* size (0 = ROM) */
+ short checksum_flag; /* use check sum = 1 */
+ unsigned short mode_flags; /* mode flags */
+#define AWE_SAMPLE_8BITS 1 /* wave data is 8bits */
+#define AWE_SAMPLE_UNSIGNED 2 /* wave data is unsigned */
+#define AWE_SAMPLE_NO_BLANK 4 /* no blank loop is attached */
+#define AWE_SAMPLE_SINGLESHOT 8 /* single-shot w/o loop */
+#define AWE_SAMPLE_BIDIR_LOOP 16 /* bidirectional looping */
+#define AWE_SAMPLE_STEREO_LEFT 32 /* stereo left sound */
+#define AWE_SAMPLE_STEREO_RIGHT 64 /* stereo right sound */
+ unsigned long checksum; /* check sum */
+ unsigned short data[0]; /* sample data follows here */
+} awe_sample_info;
+
+
+/*----------------------------------------------------------------
+ * awe hardware controls
+ *----------------------------------------------------------------*/
+
+#define _AWE_DEBUG_MODE 0x00
+#define _AWE_REVERB_MODE 0x01
+#define _AWE_CHORUS_MODE 0x02
+#define _AWE_REMOVE_LAST_SAMPLES 0x03
+#define _AWE_INITIALIZE_CHIP 0x04
+#define _AWE_SEND_EFFECT 0x05
+#define _AWE_TERMINATE_CHANNEL 0x06
+#define _AWE_TERMINATE_ALL 0x07
+#define _AWE_INITIAL_VOLUME 0x08
+#define _AWE_SET_GUS_BANK 0x09
+
+#define _AWE_MODE_FLAG 0x80
+#define _AWE_COOKED_FLAG 0x40 /* not supported */
+#define _AWE_MODE_VALUE_MASK 0x3F
+
+#define _AWE_CMD(chn, voice, cmd, p1, p2) \
+{_SEQ_NEEDBUF(8); _seqbuf[_seqbufptr] = SEQ_PRIVATE;\
+ _seqbuf[_seqbufptr+1] = chn;\
+ _seqbuf[_seqbufptr+2] = _AWE_MODE_FLAG|(cmd);\
+ _seqbuf[_seqbufptr+3] = voice;\
+ *(unsigned short*)&_seqbuf[_seqbufptr+4] = p1;\
+ *(unsigned short*)&_seqbuf[_seqbufptr+6] = p2;\
+ _SEQ_ADVBUF(8);}
+
+#define AWE_DEBUG_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_DEBUG_MODE, p1, 0)
+#define AWE_REVERB_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_REVERB_MODE, p1, 0)
+#define AWE_CHORUS_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_CHORUS_MODE, p1, 0)
+#define AWE_REMOVE_LAST_SAMPLES(dev) _AWE_CMD(dev, 0, _AWE_REMOVE_LAST_SAMPLES, 0, 0)
+#define AWE_INITIALIZE_CHIP(dev) _AWE_CMD(dev, 0, _AWE_INITIALIZE_CHIP, 0, 0)
+#define AWE_SEND_EFFECT(dev,voice,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,type,value)
+#define AWE_TERMINATE_CHANNEL(dev,voice) _AWE_CMD(dev,voice,_AWE_TERMINATE_CHANNEL,0,0)
+#define AWE_TERMINATE_ALL(dev) _AWE_CMD(dev, 0, _AWE_TERMINATE_ALL, 0, 0)
+#define AWE_INITIAL_VOLUME(dev,atten) _AWE_CMD(dev, 0, _AWE_INITIAL_VOLUME, atten, 0)
+#define AWE_SET_GUS_BANK(dev,bank) _AWE_CMD(dev, 0, _AWE_SET_GUS_BANK, bank, 0)
+
+/* reverb mode */
+#define AWE_REVERB_ROOM1 0
+#define AWE_REVERB_ROOM2 1
+#define AWE_REVERB_ROOM3 2
+#define AWE_REVERB_HALL1 3
+#define AWE_REVERB_HALL2 4
+#define AWE_REVERB_PLATE 5
+#define AWE_REVERB_DELAY 6
+#define AWE_REVERB_PANNINGDELAY 7
+
+/* chorus mode */
+#define AWE_CHORUS_1 0
+#define AWE_CHORUS_2 1
+#define AWE_CHORUS_3 2
+#define AWE_CHORUS_4 3
+#define AWE_CHORUS_FEEDBACK 4
+#define AWE_CHORUS_FLANGER 5
+#define AWE_CHORUS_SHORTDELAY 6
+#define AWE_CHORUS_SHORTDELAY2 7
+
+/* effects */
+enum {
+
+/* modulation envelope parameters */
+/* 0*/ AWE_FX_ENV1_DELAY, /* WORD: ENVVAL */
+/* 1*/ AWE_FX_ENV1_ATTACK, /* BYTE: up ATKHLD */
+/* 2*/ AWE_FX_ENV1_HOLD, /* BYTE: lw ATKHLD */
+/* 3*/ AWE_FX_ENV1_DECAY, /* BYTE: lw DCYSUS */
+/* 4*/ AWE_FX_ENV1_RELEASE, /* BYTE: lw DCYSUS */
+/* 5*/ AWE_FX_ENV1_SUSTAIN, /* BYTE: up DCYSUS */
+/* 6*/ AWE_FX_ENV1_PITCH, /* BYTE: up PEFE */
+/* 7*/ AWE_FX_ENV1_CUTOFF, /* BYTE: lw PEFE */
+
+/* volume envelope parameters */
+/* 8*/ AWE_FX_ENV2_DELAY, /* WORD: ENVVOL */
+/* 9*/ AWE_FX_ENV2_ATTACK, /* BYTE: up ATKHLDV */
+/*10*/ AWE_FX_ENV2_HOLD, /* BYTE: lw ATKHLDV */
+/*11*/ AWE_FX_ENV2_DECAY, /* BYTE: lw DCYSUSV */
+/*12*/ AWE_FX_ENV2_RELEASE, /* BYTE: lw DCYSUSV */
+/*13*/ AWE_FX_ENV2_SUSTAIN, /* BYTE: up DCYSUSV */
+
+/* LFO1 (tremolo & vibrato) parameters */
+/*14*/ AWE_FX_LFO1_DELAY, /* WORD: LFO1VAL */
+/*15*/ AWE_FX_LFO1_FREQ, /* BYTE: lo TREMFRQ */
+/*16*/ AWE_FX_LFO1_VOLUME, /* BYTE: up TREMFRQ */
+/*17*/ AWE_FX_LFO1_PITCH, /* BYTE: up FMMOD */
+/*18*/ AWE_FX_LFO1_CUTOFF, /* BYTE: lo FMMOD */
+
+/* LFO2 (vibrato) parameters */
+/*19*/ AWE_FX_LFO2_DELAY, /* WORD: LFO2VAL */
+/*20*/ AWE_FX_LFO2_FREQ, /* BYTE: lo FM2FRQ2 */
+/*21*/ AWE_FX_LFO2_PITCH, /* BYTE: up FM2FRQ2 */
+
+/* Other overall effect parameters */
+/*22*/ AWE_FX_INIT_PITCH, /* SHORT: pitch offset */
+/*23*/ AWE_FX_CHORUS, /* BYTE: chorus effects send (0-255) */
+/*24*/ AWE_FX_REVERB, /* BYTE: reverb effects send (0-255) */
+/*25*/ AWE_FX_CUTOFF, /* BYTE: up IFATN */
+/*26*/ AWE_FX_FILTERQ, /* BYTE: up CCCA */
+
+/* Sample / loop offset changes */
+/*27*/ AWE_FX_SAMPLE_START, /* SHORT: offset */
+/*28*/ AWE_FX_LOOP_START, /* SHORT: offset */
+/*29*/ AWE_FX_LOOP_END, /* SHORT: offset */
+/*30*/ AWE_FX_COARSE_SAMPLE_START, /* SHORT: upper word offset */
+/*31*/ AWE_FX_COARSE_LOOP_START, /* SHORT: upper word offset */
+/*32*/ AWE_FX_COARSE_LOOP_END, /* SHORT: upper word offset */
+
+ AWE_FX_END,
+};
+
+
+#endif /* AWE_VOICE_H */
--- /dev/null
+/*================================================================
+ * awe_wave.c -- driver for AWE32 wave table synth
+ * version 0.2.0; Oct. 16, 1996
+ * copyright (c) 1996 by Takashi Iwai
+ *================================================================*/
+
+/* if you're using obsolete VoxWare 3.0.x on Linux 1.2.x (or FreeBSD),
+ * uncomment the following line
+ */
+/* #define AWE_OBSOLETE_VOXWARE */
+
+#include "lowlevel.h"
+
+#ifdef AWE_OBSOLETE_VOXWARE
+
+#include "sound_config.h"
+#if !defined(EXCLUDE_AWE32)
+#define CONFIG_AWE32_SYNTH
+#endif
+
+#else /* AWE_OBSOLETE_VOXWARE */
+
+#include "../sound_config.h"
+
+#endif /* AWE_OBSOLETE_VOXWARE */
+
+
+/*----------------------------------------------------------------*
+ * compile condition
+ *----------------------------------------------------------------*/
+
+/* initialize FM passthrough even without extended RAM */
+/*#define AWE_ALWAYS_INIT_FM*/
+
+/* debug on */
+#define AWE_DEBUG_ON
+
+/* verify checksum for uploading samples */
+#define AWE_CHECKSUM_DATA
+#define AWE_CHECKSUM_MEMORY
+
+/* disable interruption during sequencer operation */
+/*#define AWE_NEED_DISABLE_INTR*/
+
+/*----------------------------------------------------------------*/
+
+#ifdef CONFIG_AWE32_SYNTH
+
+#include "awe_hw.h"
+#include "awe_voice.h"
+
+#ifdef AWE_OBSOLETE_VOXWARE
+#include "tuning.h"
+#else
+#include "../tuning.h"
+#endif
+
+#ifdef linux
+# include <linux/ultrasound.h>
+#elif defined(__FreeBSD__)
+# include <machine/ultrasound.h>
+#endif
+
+
+/*----------------------------------------------------------------
+ * debug message
+ *----------------------------------------------------------------*/
+
+#ifdef AWE_DEBUG_ON
+static int debug_mode = 0;
+#define DEBUG(LVL,XXX) {if (debug_mode > LVL) { XXX; }}
+#define ERRMSG(XXX) {if (debug_mode) { XXX; }}
+#define FATALERR(XXX) XXX
+#else
+#define DEBUG(LVL,XXX) /**/
+#define ERRMSG(XXX) XXX
+#define FATALERR(XXX) XXX
+#endif
+
+/*----------------------------------------------------------------
+ * bank and voice record
+ *----------------------------------------------------------------*/
+
+/* bank record */
+typedef struct _awe_voice_list {
+ unsigned char bank, instr;
+ awe_voice_info v;
+ struct _awe_voice_list *next_instr;
+ struct _awe_voice_list *next_bank;
+} awe_voice_list;
+
+/* sample and information table */
+static awe_sample_info *samples;
+static awe_voice_list *infos;
+
+#define AWE_MAX_PRESETS 256
+#define AWE_DEFAULT_BANK 0
+
+/* preset table index */
+static awe_voice_list *preset_table[AWE_MAX_PRESETS];
+
+/*----------------------------------------------------------------
+ * voice table
+ *----------------------------------------------------------------*/
+
+#define AWE_FX_BYTES ((AWE_FX_END+7)/8)
+
+typedef struct _voice_info {
+ int state; /* status (on = 1, off = 0) */
+ int note; /* midi key (0-127) */
+ int velocity; /* midi velocity (0-127) */
+ int bender; /* midi pitchbend (-8192 - 8192) */
+ int bender_range; /* midi bender range (x100) */
+ int panning; /* panning (0-127) */
+ int main_vol; /* channel volume (0-127) */
+ int expression_vol; /* midi expression (0-127) */
+
+ /* EMU8000 parameters */
+ int apitch; /* pitch parameter */
+ int avol; /* volume parameter */
+
+ /* instrument parameters */
+ int bank; /* current tone bank */
+ int instr; /* current program */
+ awe_voice_list *vrec;
+ awe_voice_info *sample;
+
+ /* channel effects */
+ unsigned char fx_flags[AWE_FX_BYTES];
+ short fx[AWE_FX_END];
+} voice_info;
+
+static voice_info voices[AWE_MAX_VOICES];
+
+
+/*----------------------------------------------------------------
+ * global variables
+ *----------------------------------------------------------------*/
+
+/* awe32 base address (overwritten at initialization) */
+static int awe_base = 0;
+/* memory byte size (overwritten at initialization) */
+static long awe_mem_size = 0;
+
+/* maximum channels for playing */
+static int awe_max_voices = AWE_MAX_VOICES;
+
+static long free_mem_ptr = 0; /* free word byte size */
+static int free_info = 0; /* free info tables */
+static int last_info = 0; /* last loaded info index */
+static int free_sample = 0; /* free sample tables */
+static int last_sample = 0; /* last loaded sample index */
+static int loaded_once = 0; /* samples are loaded after init? */
+static unsigned short current_sf_id = 0; /* internal id */
+
+static int reverb_mode = 0; /* reverb mode */
+static int chorus_mode = 0; /* chorus mode */
+static unsigned short init_atten = 32; /* 12dB */
+
+static int awe_present = 0; /* awe device present? */
+static int awe_busy = 0; /* awe device opened? */
+
+static int awe_gus_bank = AWE_DEFAULT_BANK; /* GUS default bank number */
+
+
+static struct synth_info awe_info = {
+ "AWE32 Synth", /* name */
+ 0, /* device */
+ SYNTH_TYPE_SAMPLE, /* synth_type */
+ SAMPLE_TYPE_AWE32, /* synth_subtype */
+ 0, /* perc_mode (obsolete) */
+ AWE_MAX_VOICES, /* nr_voices */
+ 0, /* nr_drums (obsolete) */
+ AWE_MAX_INFOS /* instr_bank_size */
+};
+
+
+static struct voice_alloc_info *voice_alloc; /* set at initialization */
+
+
+/*----------------------------------------------------------------
+ * function prototypes
+ *----------------------------------------------------------------*/
+
+#ifndef AWE_OBSOLETE_VOXWARE
+static int awe_check_port(void);
+static void awe_request_region(void);
+static void awe_release_region(void);
+#endif
+
+static void awe_reset_samples(void);
+/* emu8000 chip i/o access */
+static void awe_poke(unsigned short cmd, unsigned short port, unsigned short data);
+static void awe_poke_dw(unsigned short cmd, unsigned short port, unsigned long data);
+static unsigned short awe_peek(unsigned short cmd, unsigned short port);
+static unsigned long awe_peek_dw(unsigned short cmd, unsigned short port);
+static void awe_wait(unsigned short delay);
+
+/* initialize emu8000 chip */
+static void awe_initialize(void);
+
+/* set voice parameters */
+static void awe_init_voice_info(awe_voice_info *vp);
+static void awe_init_voice_parm(awe_voice_parm *pp);
+static int freq_to_note(int freq);
+static int calc_rate_offset(int Hz);
+/*static int calc_parm_delay(int msec);*/
+static int calc_parm_hold(int msec);
+static int calc_parm_attack(int msec);
+static int calc_parm_decay(int msec);
+static int calc_parm_search(int msec, short *table);
+
+/* turn on/off note */
+static void awe_note_on(int voice);
+static void awe_note_off(int voice);
+static void awe_terminate(int voice);
+static void awe_exclusive_off(int voice);
+
+/* calculate voice parameters */
+static void awe_set_pitch(int voice);
+static void awe_set_volume(int voice);
+static void awe_set_pan(int voice, int forced);
+static void awe_fx_fmmod(int voice);
+static void awe_fx_tremfrq(int voice);
+static void awe_fx_fm2frq2(int voice);
+static void awe_fx_cutoff(int voice);
+static void awe_fx_initpitch(int voice);
+static void awe_calc_pitch(int voice);
+static void awe_calc_pitch_from_freq(int voice, int freq);
+static void awe_calc_volume(int voice);
+static void awe_voice_init(int voice, int inst_only);
+
+/* sequencer interface */
+static int awe_open(int dev, int mode);
+static void awe_close(int dev);
+static int awe_ioctl(int dev, unsigned int cmd, caddr_t arg);
+static int awe_kill_note(int dev, int voice, int note, int velocity);
+static int awe_start_note(int dev, int v, int note_num, int volume);
+static int awe_set_instr(int dev, int voice, int instr_no);
+static void awe_reset(int dev);
+static void awe_hw_control(int dev, unsigned char *event);
+static int awe_load_patch(int dev, int format, const char *addr,
+ int offs, int count, int pmgr_flag);
+static void awe_aftertouch(int dev, int voice, int pressure);
+static void awe_controller(int dev, int voice, int ctrl_num, int value);
+static void awe_panning(int dev, int voice, int value);
+static void awe_volume_method(int dev, int mode);
+static int awe_patchmgr(int dev, struct patmgr_info *rec);
+static void awe_bender(int dev, int voice, int value);
+static int awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc);
+static void awe_setup_voice(int dev, int voice, int chn);
+
+/* hardware controls */
+static void awe_hw_gus_control(int dev, int cmd, unsigned char *event);
+static void awe_hw_awe_control(int dev, int cmd, unsigned char *event);
+
+/* voice search */
+static awe_voice_info *awe_search_voice(int voice, int note);
+static awe_voice_list *awe_search_instr(int bank, int preset);
+
+/* load / remove patches */
+static void awe_check_loaded(void);
+static int awe_load_info(awe_patch_info *patch, const char *addr);
+static int awe_load_data(awe_patch_info *patch, const char *addr);
+static int awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag);
+static int awe_write_wave_data(const char *addr, long offset, int size);
+static awe_voice_list *awe_get_removed_list(awe_voice_list *curp);
+static void awe_remove_samples(void);
+static short awe_set_sample(awe_voice_info *vp);
+
+/* lowlevel functions */
+static void awe_init_audio(void);
+static void awe_init_dma(void);
+static void awe_init_array(void);
+static void awe_send_array(unsigned short *data);
+static void awe_tweak(void);
+static void awe_init_fm(void);
+static int awe_open_dram_for_write(int offset);
+static int awe_open_dram_for_read(int offset);
+static void awe_open_dram_for_check(void);
+static void awe_close_dram(void);
+static void awe_close_dram_for_read(void);
+static void awe_write_dram(unsigned short c);
+static int awe_detect(void);
+static int awe_check_dram(void);
+static void awe_set_chorus_mode(int mode);
+static void awe_set_reverb_mode(int mode);
+
+#ifdef AWE_OBSOLETE_VOXWARE
+
+#define awe_check_port() 0 /* always false */
+#define awe_request_region() /* nothing */
+#define awe_release_region() /* nothing */
+
+#else /* AWE_OBSOLETE_VOXWARE */
+
+/* the following macros are osbolete */
+
+#define PERMANENT_MALLOC(type,var,size,memptr) \
+ var = (type)(sound_mem_blocks[sound_nblocks++] = vmalloc(size))
+#define RET_ERROR(err) -err
+
+#endif /* AWE_OBSOLETE_VOXWARE */
+
+
+#ifdef AWE_NEED_DISABLE_INTR
+#define DECL_INTR_FLAGS(x) unsigned long x
+#else
+#undef DISABLE_INTR
+#undef RESTORE_INTR
+#define DECL_INTR_FLAGS(x) /**/
+#define DISABLE_INTR(x) /**/
+#define RESTORE_INTR(x) /**/
+#endif
+
+
+/* macros for Linux and FreeBSD compatibility */
+
+#undef OUTW
+#undef COPY_FROM_USER
+#undef GET_BYTE_FROM_USER
+#undef GET_SHORT_FROM_USER
+#undef IOCTL_TO_USER
+
+#ifdef linux
+# define NO_DATA_ERR ENODATA
+# define OUTW(data, addr) outw(data, addr)
+# define COPY_FROM_USER(target, source, offs, count) \
+ copy_from_user( ((caddr_t)(target)),(source)+(offs),(count) )
+# define GET_BYTE_FROM_USER(target, addr, offs) \
+ get_user(target, (unsigned char*)&((addr)[offs]))
+# define GET_SHORT_FROM_USER(target, addr, offs) \
+ get_user(target, (unsigned short*)&((addr)[offs]))
+# define IOCTL_TO_USER(target, offs, source, count) \
+ copy_to_user ( ((caddr_t)(target)),(source)+(offs),(count) )
+# define BZERO(target,len) \
+ memset( (caddr_t)target, '\0', len )
+#elif defined(__FreeBSD__)
+# define NO_DATA_ERR EINVAL
+# define OUTW(data, addr) outw(addr, data)
+# define COPY_FROM_USER(target, source, offs, count) \
+ uiomove( ((caddr_t)(target)),(count),((struct uio *)(source)) )
+# define GET_BYTE_FROM_USER(target, addr, offs) \
+ uiomove( ((char*)&(target)), 1, ((struct uio *)(addr)) )
+# define GET_SHORT_FROM_USER(target, addr, offs) \
+ uiomove( ((char*)&(target)), 2, ((struct uio *)(addr)) )
+# define IOCTL_TO_USER(target, offs, source, count) \
+ memcpy( &((target)[offs]), (source), (count) )
+# define BZERO(target,len) \
+ bzero( (caddr_t)target, len )
+#endif
+
+
+/*----------------------------------------------------------------
+ * synth operation table
+ *----------------------------------------------------------------*/
+
+static struct synth_operations awe_operations =
+{
+ &awe_info,
+ 0,
+ SYNTH_TYPE_SAMPLE,
+ SAMPLE_TYPE_AWE32,
+ awe_open,
+ awe_close,
+ awe_ioctl,
+ awe_kill_note,
+ awe_start_note,
+ awe_set_instr,
+ awe_reset,
+ awe_hw_control,
+ awe_load_patch,
+ awe_aftertouch,
+ awe_controller,
+ awe_panning,
+ awe_volume_method,
+ awe_patchmgr,
+ awe_bender,
+ awe_alloc,
+ awe_setup_voice
+};
+
+
+
+/*================================================================
+ * attach / unload interface
+ *================================================================*/
+
+#ifdef AWE_OBSOLETE_VOXWARE
+long attach_awe_obsolete(long mem_start, struct address_info *hw_config)
+#else
+int attach_awe(void)
+#endif
+{
+ /* check presence of AWE32 card */
+ if (! awe_detect()) {
+ printk("AWE32: not detected\n");
+ return 0;
+ }
+
+ /* check AWE32 ports are available */
+ if (awe_check_port()) {
+ printk("AWE32: I/O area already used.\n");
+ return 0;
+ }
+
+ /* allocate sample tables */
+ PERMANENT_MALLOC(awe_sample_info *, samples,
+ AWE_MAX_SAMPLES * sizeof(awe_sample_info), mem_start);
+ PERMANENT_MALLOC(awe_voice_list *, infos,
+ AWE_MAX_INFOS * sizeof(awe_voice_list), mem_start);
+ if (samples == NULL || infos == NULL) {
+ printk("AWE32: can't allocate sample tables\n");
+ return 0;
+ }
+
+ if (num_synths >= MAX_SYNTH_DEV)
+ printk("AWE32 Error: too many synthesizers\n");
+ else {
+ voice_alloc = &awe_operations.alloc;
+ voice_alloc->max_voice = awe_max_voices;
+ synth_devs[num_synths++] = &awe_operations;
+ }
+
+ /* reserve I/O ports for awedrv */
+ awe_request_region();
+
+ /* clear all samples */
+ awe_reset_samples();
+
+ /* intialize AWE32 hardware */
+ awe_initialize();
+
+ printk("<AWE32 SynthCard (%dk)>\n", (int)awe_mem_size/1024);
+ sprintf(awe_info.name, "AWE32 Synth (%dk)", (int)awe_mem_size/1024);
+
+ /* set reverb & chorus modes */
+ awe_set_reverb_mode(reverb_mode);
+ awe_set_chorus_mode(chorus_mode);
+
+ awe_present = 1;
+
+#ifdef AWE_OBSOLETE_VOXWARE
+ return mem_start;
+#else
+ return 1;
+#endif
+}
+
+
+void unload_awe(void)
+{
+ if (awe_present) {
+ awe_reset_samples();
+ awe_release_region();
+ }
+}
+
+
+#ifdef AWE_OBSOLETE_VOXWARE
+int probe_awe_obsolete(struct address_info *hw_config)
+{
+ return 1;
+ /*return awe_detect();*/
+}
+
+#endif
+
+/*================================================================
+ * clear sample tables
+ *================================================================*/
+
+static void
+awe_reset_samples(void)
+{
+ int i;
+
+ /* free all bank tables */
+ for (i = 0; i < AWE_MAX_PRESETS; i++) {
+ preset_table[i] = NULL;
+ }
+
+ free_mem_ptr = 0;
+ last_sample = free_sample = 0;
+ last_info = free_info = 0;
+ current_sf_id = 0;
+ loaded_once = 0;
+}
+
+
+/*================================================================
+ * EMU register access
+ *================================================================*/
+
+/* select a given AWE32 pointer */
+#define awe_set_cmd(cmd) OUTW(cmd, awe_base + 0x802)
+#define awe_port(port) (awe_base - 0x620 + port)
+
+/* write 16bit data */
+static void
+awe_poke(unsigned short cmd, unsigned short port, unsigned short data)
+{
+ awe_set_cmd(cmd);
+ OUTW(data, awe_port(port));
+}
+
+/* write 32bit data */
+static void
+awe_poke_dw(unsigned short cmd, unsigned short port, unsigned long data)
+{
+ awe_set_cmd(cmd);
+ OUTW(data, awe_port(port)); /* write lower 16 bits */
+ OUTW(data >> 16, awe_port(port)+2); /* write higher 16 bits */
+}
+
+/* read 16bit data */
+static unsigned short
+awe_peek(unsigned short cmd, unsigned short port)
+{
+ unsigned short k;
+ awe_set_cmd(cmd);
+ k = inw(awe_port(port));
+ return k;
+}
+
+/* read 32bit data */
+static unsigned long
+awe_peek_dw(unsigned short cmd, unsigned short port)
+{
+ unsigned long k1, k2;
+ awe_set_cmd(cmd);
+ k1 = inw(awe_port(port));
+ k2 = inw(awe_port(port)+2);
+ k1 |= k2 << 16;
+ return k1;
+}
+
+/* wait delay number of AWE32 44100Hz clocks */
+static void
+awe_wait(unsigned short delay)
+{
+ unsigned short clock, target;
+ unsigned short port = awe_port(AWE_WC_Port);
+ int counter;
+
+ /* sample counter */
+ awe_set_cmd(AWE_WC_Cmd);
+ clock = (unsigned short)inw(port);
+ target = clock + delay;
+ counter = 0;
+ if (target < clock) {
+ for (; (unsigned short)inw(port) > target; counter++)
+ if (counter > 65536)
+ break;
+ }
+ for (; (unsigned short)inw(port) < target; counter++)
+ if (counter > 65536)
+ break;
+}
+
+
+#ifndef AWE_OBSOLETE_VOXWARE
+
+/*================================================================
+ * port check / request
+ * 0x620-622, 0xA20-A22, 0xE20-E22
+ *================================================================*/
+
+static int
+awe_check_port(void)
+{
+ return (check_region(awe_port(Data0), 3) ||
+ check_region(awe_port(Data1), 3) ||
+ check_region(awe_port(Data3), 3));
+}
+
+static void
+awe_request_region(void)
+{
+ request_region(awe_port(Data0), 3, "sound driver (AWE32)");
+ request_region(awe_port(Data1), 3, "sound driver (AWE32)");
+ request_region(awe_port(Data3), 3, "sound driver (AWE32)");
+}
+
+static void
+awe_release_region(void)
+{
+ release_region(awe_port(Data0), 3);
+ release_region(awe_port(Data1), 3);
+ release_region(awe_port(Data3), 3);
+}
+
+#endif /* !AWE_OBSOLETE_VOXWARE */
+
+
+/*================================================================
+ * AWE32 initialization
+ *================================================================*/
+static void
+awe_initialize(void)
+{
+ unsigned short data;
+ DECL_INTR_FLAGS(flags);
+
+ DEBUG(0,printk("AWE32: initializing..\n"));
+ DISABLE_INTR(flags);
+
+ /* check for an error condition */
+ data = awe_peek(AWE_U1);
+ if (!(data & 0x000F) == 0x000C) {
+ FATALERR(printk("AWE32: can't initialize AWE32\n"));
+ }
+
+ /* initialize hardware configuration */
+ awe_poke(AWE_HWCF1, 0x0059);
+ awe_poke(AWE_HWCF2, 0x0020);
+
+ /* disable audio output */
+ awe_poke(AWE_HWCF3, 0x0000);
+
+ /* initialize audio channels */
+ awe_init_audio();
+
+ /* initialize init array */
+ awe_init_dma();
+ awe_init_array();
+
+ /* check DRAM memory size */
+ awe_mem_size = awe_check_dram();
+
+ /* initialize the FM section of the AWE32 */
+ awe_init_fm();
+
+ /* set up voice envelopes */
+ awe_tweak();
+
+ /* enable audio */
+ awe_poke(AWE_HWCF3, 0x0004);
+
+ data = awe_peek(AWE_HWCF2);
+ if (~data & 0x40) {
+ FATALERR(printk("AWE32: Unable to initialize AWE32.\n"));
+ }
+
+ RESTORE_INTR(flags);
+}
+
+
+/*================================================================
+ * AWE32 voice parameters
+ *================================================================*/
+
+/* initialize voice_info record */
+static void
+awe_init_voice_info(awe_voice_info *vp)
+{
+ vp->sf_id = 0;
+ vp->sample = 0;
+ vp->rate_offset = 0;
+
+ vp->start = 0;
+ vp->end = 0;
+ vp->loopstart = 0;
+ vp->loopend = 0;
+ vp->mode = 0;
+ vp->root = 60;
+ vp->tune = 0;
+ vp->low = 0;
+ vp->high = 127;
+ vp->vellow = 0;
+ vp->velhigh = 127;
+
+ vp->fixkey = -1;
+ vp->fixvel = -1;
+ vp->fixpan = -1;
+ vp->pan = -1;
+
+ vp->exclusiveClass = 0;
+ vp->amplitude = 127;
+ vp->attenuation = 0;
+ vp->scaleTuning = 100;
+
+ awe_init_voice_parm(&vp->parm);
+}
+
+/* initialize voice_parm record:
+ * Env1/2: delay=0, attack=0, hold=0, sustain=0, decay=0, release=0.
+ * Vibrato and Tremolo effects are zero.
+ * Cutoff is maximum.
+ * Chorus and Reverb effects are zero.
+ */
+static void
+awe_init_voice_parm(awe_voice_parm *pp)
+{
+ pp->moddelay = 0x8000;
+ pp->modatkhld = 0x7f7f;
+ pp->moddcysus = 0x7f7f;
+ pp->modrelease = 0x807f;
+ pp->modkeyhold = 0;
+ pp->modkeydecay = 0;
+
+ pp->voldelay = 0x8000;
+ pp->volatkhld = 0x7f7f;
+ pp->voldcysus = 0x7f7f;
+ pp->volrelease = 0x807f;
+ pp->volkeyhold = 0;
+ pp->volkeydecay = 0;
+
+ pp->lfo1delay = 0x8000;
+ pp->lfo2delay = 0x8000;
+ pp->pefe = 0;
+
+ pp->fmmod = 0;
+ pp->tremfrq = 0;
+ pp->fm2frq2 = 0;
+
+ pp->cutoff = 0xff;
+ pp->filterQ = 0;
+
+ pp->chorus = 0;
+ pp->reverb = 0;
+}
+
+
+/* convert frequency mHz to abstract cents (= midi key * 100) */
+static int
+freq_to_note(int mHz)
+{
+ /* abscents = log(mHz/8176) / log(2) * 1200 */
+ unsigned long max_val = (unsigned long)0xffffffff / 10000;
+ int i, times;
+ unsigned long base;
+ unsigned long freq;
+ int note, tune;
+
+ if (mHz == 0)
+ return 0;
+ if (mHz < 0)
+ return 12799; /* maximum */
+
+ freq = mHz;
+ note = 0;
+ for (base = 8176 * 2; freq >= base; base *= 2) {
+ note += 12;
+ if (note >= 128) /* over maximum */
+ return 12799;
+ }
+ base /= 2;
+
+ /* to avoid overflow... */
+ times = 10000;
+ while (freq > max_val) {
+ max_val *= 10;
+ times /= 10;
+ base /= 10;
+ }
+
+ freq = freq * times / base;
+ for (i = 0; i < 12; i++) {
+ if (freq < semitone_tuning[i+1])
+ break;
+ note++;
+ }
+
+ tune = 0;
+ freq = freq * 10000 / semitone_tuning[i];
+ for (i = 0; i < 100; i++) {
+ if (freq < cent_tuning[i+1])
+ break;
+ tune++;
+ }
+
+ return note * 100 + tune;
+}
+
+
+/* convert Hz to AWE32 rate offset:
+ * sample pitch offset for the specified sample rate
+ * rate=44100 is no offset, each 4096 is 1 octave (twice).
+ * eg, when rate is 22050, this offset becomes -4096.
+ */
+static int
+calc_rate_offset(int Hz)
+{
+ /* offset = log(Hz / 44100) / log(2) * 4096 */
+ int freq, base, i;
+
+ /* maybe smaller than max (44100Hz) */
+ if (Hz <= 0 || Hz >= 44100) return 0;
+
+ base = 0;
+ for (freq = Hz * 2; freq < 44100; freq *= 2)
+ base++;
+ base *= 1200;
+
+ freq = 44100 * 10000 / (freq/2);
+ for (i = 0; i < 12; i++) {
+ if (freq < semitone_tuning[i+1])
+ break;
+ base += 100;
+ }
+ freq = freq * 10000 / semitone_tuning[i];
+ for (i = 0; i < 100; i++) {
+ if (freq < cent_tuning[i+1])
+ break;
+ base++;
+ }
+ return -base * 4096 / 1200;
+}
+
+
+/*----------------------------------------------------------------
+ * convert envelope time parameter to AWE32 raw parameter
+ *----------------------------------------------------------------*/
+
+/* attack & decay/release time table (mHz) */
+static short attack_time_tbl[128] = {
+32767, 5939, 3959, 2969, 2375, 1979, 1696, 1484, 1319, 1187, 1079, 989, 913, 848, 791, 742,
+ 698, 659, 625, 593, 565, 539, 516, 494, 475, 456, 439, 424, 409, 395, 383, 371,
+ 359, 344, 330, 316, 302, 290, 277, 266, 255, 244, 233, 224, 214, 205, 196, 188,
+ 180, 173, 165, 158, 152, 145, 139, 133, 127, 122, 117, 112, 107, 103, 98, 94,
+ 90, 86, 83, 79, 76, 73, 69, 67, 64, 61, 58, 56, 54, 51, 49, 47,
+ 45, 43, 41, 39, 38, 36, 35, 33, 32, 30, 29, 28, 27, 25, 24, 23,
+ 22, 21, 20, 20, 19, 18, 17, 16, 16, 15, 14, 14, 13, 13, 12, 11,
+ 11, 10, 10, 10, 9, 9, 8, 8, 8, 7, 7, 7, 6, 6, 6, 0,
+};
+
+static short decay_time_tbl[128] = {
+32767, 3651, 3508, 3371, 3239, 3113, 2991, 2874, 2761, 2653, 2550, 2450, 2354, 2262, 2174, 2089,
+ 2007, 1928, 1853, 1781, 1711, 1644, 1580, 1518, 1459, 1401, 1347, 1294, 1243, 1195, 1148, 1103,
+ 1060, 1018, 979, 940, 904, 868, 834, 802, 770, 740, 711, 683, 657, 631, 606, 582,
+ 560, 538, 517, 496, 477, 458, 440, 423, 407, 391, 375, 361, 347, 333, 320, 307,
+ 295, 284, 273, 262, 252, 242, 232, 223, 215, 206, 198, 190, 183, 176, 169, 162,
+ 156, 150, 144, 138, 133, 128, 123, 118, 113, 109, 104, 100, 96, 93, 89, 85,
+ 82, 79, 76, 73, 70, 67, 64, 62, 60, 57, 55, 53, 51, 49, 47, 45,
+ 43, 41, 40, 38, 37, 35, 34, 32, 31, 30, 29, 28, 27, 25, 24, 0,
+};
+
+/*
+static int
+calc_parm_delay(int msec)
+{
+ return (0x8000 - msec * 1000 / 725);
+}
+*/
+
+static int
+calc_parm_hold(int msec)
+{
+ int val = 0x7f - (unsigned char)(msec / 92);
+ if (val < 1) val = 1;
+ if (val > 127) val = 127;
+ return val;
+}
+
+static int
+calc_parm_attack(int msec)
+{
+ return calc_parm_search(msec, attack_time_tbl);
+}
+
+static int
+calc_parm_decay(int msec)
+{
+ return calc_parm_search(msec, decay_time_tbl);
+}
+
+static int
+calc_parm_search(int msec, short *table)
+{
+ int left = 0, right = 127, mid;
+ while (left < right) {
+ mid = (left + right) / 2;
+ if (msec < (int)table[mid])
+ left = mid + 1;
+ else
+ right = mid;
+ }
+ return left;
+}
+
+
+/*================================================================
+ * effects table
+ *================================================================*/
+
+/* set an effect value */
+#define FX_SET(v,type,value) \
+(voices[v].fx_flags[(type)/8] |= (1<<((type)%8)),\
+ voices[v].fx[type] = (value))
+/* check the effect value is set */
+#define FX_ON(v,type) (voices[v].fx_flags[(type)/8] & (1<<((type)%8)))
+
+#if 0
+#define FX_BYTE(v,type,value)\
+ (FX_ON(v,type) ? (unsigned char)voices[v].fx[type] :\
+ (unsigned char)(value))
+#define FX_WORD(v,type,value)\
+ (FX_ON(v,type) ? (unsigned short)voices[v].fx[type] :\
+ (unsigned short)(value))
+
+#else
+
+/* get byte effect value */
+static unsigned char FX_BYTE(int v, int type, unsigned char value)
+{
+ unsigned char tmp;
+ if (FX_ON(v,type))
+ tmp = (unsigned char)voices[v].fx[type];
+ else
+ tmp = value;
+ DEBUG(4,printk("AWE32: [-- byte(%d) = %x]\n", type, tmp));
+ return tmp;
+}
+
+/* get word effect value */
+static unsigned short FX_WORD(int v, int type, unsigned short value)
+{
+ unsigned short tmp;
+ if (FX_ON(v,type))
+ tmp = (unsigned short)voices[v].fx[type];
+ else
+ tmp = value;
+ DEBUG(4,printk("AWE32: [-- word(%d) = %x]\n", type, tmp));
+ return tmp;
+}
+
+#endif
+
+/* get word (upper=type1/lower=type2) effect value */
+static unsigned short FX_COMB(int v, int type1, int type2, unsigned short value)
+{
+ unsigned short tmp;
+ if (FX_ON(v, type1))
+ tmp = (unsigned short)(voices[v].fx[type1]) << 8;
+ else
+ tmp = value & 0xff00;
+ if (FX_ON(v, type2))
+ tmp |= (unsigned short)(voices[v].fx[type2]) & 0xff;
+ else
+ tmp |= value & 0xff;
+ DEBUG(4,printk("AWE32: [-- comb(%d/%d) = %x]\n", type1, type2, tmp));
+ return tmp;
+}
+
+/* address offset */
+static long
+FX_OFFSET(int voice, int lo, int hi)
+{
+ awe_voice_info *vp;
+ long addr;
+ if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ return 0;
+
+ addr = 0;
+ if (FX_ON(voice, hi)) {
+ addr = (short)voices[voice].fx[hi];
+ addr = addr << 15;
+ }
+ if (FX_ON(voice, lo))
+ addr += (short)voices[voice].fx[lo];
+ if (!(vp->mode & (AWE_SAMPLE_8BITS<<6)))
+ addr /= 2;
+ return addr;
+}
+
+
+typedef void (*fx_affect_func)(int voice);
+static fx_affect_func fx_realtime[] = {
+ /* env1: delay, attack, hold, decay, release, sustain, pitch, cutoff*/
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ /* env2: delay, attack, hold, decay, release, sustain */
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ /* lfo1: delay, freq, volume, pitch, cutoff */
+ NULL, awe_fx_tremfrq, awe_fx_tremfrq, awe_fx_fmmod, awe_fx_fmmod,
+ /* lfo2: delay, freq, pitch */
+ NULL, awe_fx_fm2frq2, awe_fx_fm2frq2,
+ /* global: initpitch, chorus, reverb, cutoff, filterQ */
+ awe_fx_initpitch, NULL, NULL, awe_fx_cutoff, NULL,
+ /* sample: start, loopstart, loopend */
+ NULL, NULL, NULL,
+};
+
+
+/*================================================================
+ * turn on/off sample
+ *================================================================*/
+
+static void
+awe_note_on(int voice)
+{
+ unsigned long temp;
+ long addr;
+ unsigned short tmp2;
+ awe_voice_info *vp;
+
+ /* A voice sample must assigned before calling */
+ if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ return;
+
+ /* channel to be silent and idle */
+ awe_poke(AWE_DCYSUSV(voice), 0x0080);
+ awe_poke(AWE_VTFT(voice), 0);
+ awe_poke(AWE_CVCF(voice), 0);
+ awe_poke(AWE_PTRX(voice), 0);
+ awe_poke(AWE_CPF(voice), 0);
+
+ /* modulation & volume envelope */
+ awe_poke(AWE_ENVVAL(voice),
+ FX_WORD(voice, AWE_FX_ENV1_DELAY, vp->parm.moddelay));
+ awe_poke(AWE_ATKHLD(voice),
+ FX_COMB(voice, AWE_FX_ENV1_ATTACK, AWE_FX_ENV1_HOLD,
+ vp->parm.modatkhld));
+ awe_poke(AWE_DCYSUS(voice),
+ FX_COMB(voice, AWE_FX_ENV1_SUSTAIN, AWE_FX_ENV1_DECAY,
+ vp->parm.moddcysus));
+ awe_poke(AWE_ENVVOL(voice),
+ FX_WORD(voice, AWE_FX_ENV2_DELAY, vp->parm.voldelay));
+ awe_poke(AWE_ATKHLDV(voice),
+ FX_COMB(voice, AWE_FX_ENV2_ATTACK, AWE_FX_ENV2_HOLD,
+ vp->parm.volatkhld));
+ /* decay/sustain parameter for volume envelope must be set at last */
+
+ /* pitch offset */
+ awe_poke(AWE_IP(voice), voices[voice].apitch);
+ DEBUG(3,printk("AWE32: [-- pitch=%x]\n", voices[voice].apitch));
+
+ /* cutoff and volume */
+ tmp2 = FX_BYTE(voice, AWE_FX_CUTOFF, vp->parm.cutoff);
+ tmp2 = (tmp2 << 8) | voices[voice].avol;
+ awe_poke(AWE_IFATN(voice), tmp2);
+
+ /* modulation envelope heights */
+ awe_poke(AWE_PEFE(voice),
+ FX_COMB(voice, AWE_FX_ENV1_PITCH, AWE_FX_ENV1_CUTOFF,
+ vp->parm.pefe));
+
+ /* lfo1/2 delay */
+ awe_poke(AWE_LFO1VAL(voice),
+ FX_WORD(voice, AWE_FX_LFO1_DELAY, vp->parm.lfo1delay));
+ awe_poke(AWE_LFO2VAL(voice),
+ FX_WORD(voice, AWE_FX_LFO2_DELAY, vp->parm.lfo2delay));
+
+ /* lfo1 pitch & cutoff shift */
+ awe_poke(AWE_FMMOD(voice),
+ FX_COMB(voice, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF,
+ vp->parm.fmmod));
+ /* lfo1 volume & freq */
+ awe_poke(AWE_TREMFRQ(voice),
+ FX_COMB(voice, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ,
+ vp->parm.tremfrq));
+ /* lfo2 pitch & freq */
+ awe_poke(AWE_FM2FRQ2(voice),
+ FX_COMB(voice, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ,
+ vp->parm.fm2frq2));
+
+ /* pan & loop start */
+ awe_set_pan(voice, 1);
+
+ /* chorus & loop end (chorus 8bit, MSB) */
+ addr = vp->loopend - 1;
+ addr += FX_OFFSET(voice, AWE_FX_LOOP_END,
+ AWE_FX_COARSE_LOOP_END);
+ temp = FX_BYTE(voice, AWE_FX_CHORUS, vp->parm.chorus);
+ temp = (temp <<24) | (unsigned long)addr;
+ awe_poke_dw(AWE_CSL(voice), temp);
+
+ /* Q & current address (Q 4bit value, MSB) */
+ addr = vp->start - 1;
+ addr += FX_OFFSET(voice, AWE_FX_SAMPLE_START,
+ AWE_FX_COARSE_SAMPLE_START);
+ temp = FX_BYTE(voice, AWE_FX_FILTERQ, vp->parm.filterQ);
+ temp = (temp<<28) | (unsigned long)addr;
+ awe_poke_dw(AWE_CCCA(voice), temp);
+
+ /* reset volume */
+ awe_poke_dw(AWE_VTFT(voice), 0x0000FFFF);
+ awe_poke_dw(AWE_CVCF(voice), 0x0000FFFF);
+
+ /* turn on envelope */
+ awe_poke(AWE_DCYSUSV(voice),
+ FX_COMB(voice, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY,
+ vp->parm.voldcysus));
+ /* set chorus */
+ temp = FX_BYTE(voice, AWE_FX_REVERB, vp->parm.reverb);
+ temp = (awe_peek_dw(AWE_PTRX(voice)) & 0xffff0000) | (temp<<8);
+ awe_poke_dw(AWE_PTRX(voice), temp);
+ awe_poke_dw(AWE_CPF(voice), 0x40000000);
+
+ DEBUG(3,printk("AWE32: [-- start=%x loop=%x]\n",
+ (int)vp->start, (int)vp->loopstart));
+}
+
+/* turn off the voice */
+static void
+awe_note_off(int voice)
+{
+ awe_voice_info *vp;
+ unsigned short tmp;
+ if ((vp = voices[voice].sample) == NULL || !voices[voice].state)
+ return;
+ if (FX_ON(voice, AWE_FX_ENV1_RELEASE))
+ tmp = 0x8000 | voices[voice].fx[AWE_FX_ENV1_RELEASE];
+ else
+ tmp = vp->parm.modrelease;
+ awe_poke(AWE_DCYSUS(voice), tmp);
+ if (FX_ON(voice, AWE_FX_ENV2_RELEASE))
+ tmp = 0x8000 | voices[voice].fx[AWE_FX_ENV2_RELEASE];
+ else
+ tmp = vp->parm.volrelease;
+ awe_poke(AWE_DCYSUSV(voice), tmp);
+}
+
+/* force to terminate the voice (no releasing echo) */
+static void
+awe_terminate(int voice)
+{
+ awe_poke(AWE_DCYSUSV(voice), 0x807F);
+}
+
+
+/* turn off other voices with the same exclusive class (for drums) */
+static void
+awe_exclusive_off(int voice)
+{
+ int i, excls;
+
+ if (voices[voice].sample == NULL) /* no sample */
+ return;
+ excls = voices[voice].sample->exclusiveClass;
+ if (excls == 0) /* not exclusive */
+ return;
+
+ /* turn off voices with the same class */
+ for (i = 0; i < awe_max_voices; i++) {
+ if (i != voice && voices[voice].state &&
+ voices[i].sample &&
+ voices[i].sample->exclusiveClass == excls) {
+ DEBUG(4,printk("AWE32: [exoff(%d)]\n", i));
+ awe_note_off(i);
+ awe_voice_init(i, 1);
+ }
+ }
+}
+
+
+/*================================================================
+ * change the parameters of an audible voice
+ *================================================================*/
+
+/* change pitch */
+static void
+awe_set_pitch(int voice)
+{
+ if (!voices[voice].state) return;
+ awe_poke(AWE_IP(voice), voices[voice].apitch);
+}
+
+/* change volume */
+static void
+awe_set_volume(int voice)
+{
+ awe_voice_info *vp;
+ unsigned short tmp2;
+ if (!voices[voice].state) return;
+ if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ return;
+ tmp2 = FX_BYTE(voice, AWE_FX_CUTOFF, vp->parm.cutoff);
+ tmp2 = (tmp2 << 8) | voices[voice].avol;
+ awe_poke(AWE_IFATN(voice), tmp2);
+}
+
+/* change pan; this could make a click noise.. */
+static void
+awe_set_pan(int voice, int forced)
+{
+ unsigned long temp;
+ long addr;
+ awe_voice_info *vp;
+
+ if (!voices[voice].state && !forced) return;
+ if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ return;
+
+ /* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */
+ if (vp->fixpan > 0) /* 0-127 */
+ temp = 255 - (int)vp->fixpan * 2;
+ else {
+ int pos = 0;
+ if (vp->pan >= 0) /* 0-127 */
+ pos = (int)vp->pan * 2 - 128;
+ pos += voices[voice].panning; /* -128 - 127 */
+ pos = 127 - pos;
+ if (pos < 0)
+ temp = 0;
+ else if (pos > 255)
+ temp = 255;
+ else
+ temp = pos;
+ }
+ addr = vp->loopstart - 1;
+ addr += FX_OFFSET(voice, AWE_FX_LOOP_START,
+ AWE_FX_COARSE_LOOP_START);
+ temp = (temp<<24) | (unsigned long)addr;
+ awe_poke_dw(AWE_PSST(voice), temp);
+}
+
+/* effects change during playing */
+static void
+awe_fx_fmmod(int voice)
+{
+ awe_voice_info *vp;
+ if (!voices[voice].state) return;
+ if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ return;
+ awe_poke(AWE_FMMOD(voice),
+ FX_COMB(voice, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF,
+ vp->parm.fmmod));
+}
+
+static void
+awe_fx_tremfrq(int voice)
+{
+ awe_voice_info *vp;
+ if (!voices[voice].state) return;
+ if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ return;
+ awe_poke(AWE_TREMFRQ(voice),
+ FX_COMB(voice, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ,
+ vp->parm.tremfrq));
+}
+
+static void
+awe_fx_fm2frq2(int voice)
+{
+ awe_voice_info *vp;
+ if (!voices[voice].state) return;
+ if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ return;
+ awe_poke(AWE_FM2FRQ2(voice),
+ FX_COMB(voice, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ,
+ vp->parm.fm2frq2));
+}
+
+static void
+awe_fx_cutoff(int voice)
+{
+ unsigned short tmp2;
+ awe_voice_info *vp;
+ if (!voices[voice].state) return;
+ if ((vp = voices[voice].sample) == NULL || vp->index < 0)
+ return;
+ tmp2 = FX_BYTE(voice, AWE_FX_CUTOFF, vp->parm.cutoff);
+ tmp2 = (tmp2 << 8) | voices[voice].avol;
+ awe_poke(AWE_IFATN(voice), tmp2);
+}
+
+static void
+awe_fx_initpitch(int voice)
+{
+ if (!voices[voice].state) return;
+ if (FX_ON(voice, AWE_FX_INIT_PITCH)) {
+ DEBUG(3,printk("AWE32: initpitch ok\n"));
+ } else {
+ DEBUG(3,printk("AWE32: BAD initpitch %d\n", AWE_FX_INIT_PITCH));
+ }
+ awe_calc_pitch(voice);
+ awe_poke(AWE_IP(voice), voices[voice].apitch);
+}
+
+
+/*================================================================
+ * calculate pitch offset
+ *----------------------------------------------------------------
+ * 0xE000 is no pitch offset at 44100Hz sample.
+ * Every 4096 is one octave.
+ *================================================================*/
+
+static void
+awe_calc_pitch(int voice)
+{
+ voice_info *vp = &voices[voice];
+ awe_voice_info *ap;
+ int offset;
+
+ /* search voice information */
+ if ((ap = vp->sample) == NULL)
+ return;
+ if (ap->index < 0) {
+ if (awe_set_sample(ap) < 0)
+ return;
+ }
+
+ /* calculate offset */
+ if (ap->fixkey >= 0) {
+ DEBUG(3,printk("AWE32: p-> fixkey(%d) tune(%d)\n", ap->fixkey, ap->tune));
+ offset = (ap->fixkey - ap->root) * 4096 / 12;
+ } else {
+ DEBUG(3,printk("AWE32: p(%d)-> root(%d) tune(%d)\n", vp->note, ap->root, ap->tune));
+ offset = (vp->note - ap->root) * 4096 / 12;
+ DEBUG(4,printk("AWE32: p-> ofs=%d\n", offset));
+ }
+ offset += ap->tune * 4096 / 1200;
+ DEBUG(4,printk("AWE32: p-> tune+ ofs=%d\n", offset));
+ if (vp->bender != 0) {
+ DEBUG(3,printk("AWE32: p-> bend(%d) %d\n", voice, vp->bender));
+ /* (819200: 1 semitone) ==> (4096: 12 semitones) */
+ offset += vp->bender * vp->bender_range / 2400;
+ }
+ offset = (offset * ap->scaleTuning) / 100;
+ DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset));
+
+ /* add initial pitch correction */
+ if (FX_ON(voice, AWE_FX_INIT_PITCH)) {
+ DEBUG(3,printk("AWE32: fx_pitch(%d) %d\n", voice, vp->fx[AWE_FX_INIT_PITCH]));
+ offset += vp->fx[AWE_FX_INIT_PITCH];
+ }
+
+ /* 0xe000: root pitch */
+ vp->apitch = 0xe000 + ap->rate_offset + offset;
+ DEBUG(4,printk("AWE32: p-> sum aofs=%x, rate_ofs=%d\n", vp->apitch, ap->rate_offset));
+ if (vp->apitch > 0xffff)
+ vp->apitch = 0xffff;
+ if (vp->apitch < 0)
+ vp->apitch = 0;
+}
+
+
+static void
+awe_calc_pitch_from_freq(int voice, int freq)
+{
+ voice_info *vp = &voices[voice];
+ awe_voice_info *ap;
+ int offset;
+ int note;
+
+ /* search voice information */
+ if ((ap = vp->sample) == NULL)
+ return;
+ if (ap->index < 0) {
+ if (awe_set_sample(ap) < 0)
+ return;
+ }
+ note = freq_to_note(freq);
+ offset = (note - ap->root * 100 + ap->tune) * 4096 / 1200;
+ offset = (offset * ap->scaleTuning) / 100;
+ if (FX_ON(voice, AWE_FX_INIT_PITCH))
+ offset += vp->fx[AWE_FX_INIT_PITCH];
+ vp->apitch = 0xe000 + ap->rate_offset + offset;
+ if (vp->apitch > 0xffff)
+ vp->apitch = 0xffff;
+ if (vp->apitch < 0)
+ vp->apitch = 0;
+}
+
+/*================================================================
+ * calculate volume attenuation
+ *----------------------------------------------------------------
+ * Voice volume is controlled by volume attenuation parameter.
+ * So volume becomes maximum when avol is 0 (no attenuation), and
+ * minimum when 255 (-96dB or silence).
+ *================================================================*/
+
+static int vol_table[128] = {
+ 255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49,
+ 47,46,45,43,42,41,40,39,38,37,36,35,34,34,33,32,
+ 31,31,30,29,29,28,27,27,26,26,25,24,24,23,23,22,
+ 22,21,21,21,20,20,19,19,18,18,18,17,17,16,16,16,
+ 15,15,15,14,14,14,13,13,13,12,12,12,11,11,11,10,
+ 10,10,10,9,9,9,8,8,8,8,7,7,7,7,6,6,
+ 6,6,5,5,5,5,5,4,4,4,4,3,3,3,3,3,
+ 2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,
+};
+
+static void
+awe_calc_volume(int voice)
+{
+ voice_info *vp = &voices[voice];
+ awe_voice_info *ap;
+ int vol;
+
+ /* search voice information */
+ if ((ap = vp->sample) == NULL)
+ return;
+
+ ap = vp->sample;
+ if (ap->index < 0) {
+ if (awe_set_sample(ap) < 0)
+ return;
+ }
+
+ if (vp->velocity < ap->vellow)
+ vp->velocity = ap->vellow;
+ else if (vp->velocity > ap->velhigh)
+ vp->velocity = ap->velhigh;
+
+ /* 0 - 127 */
+ vol = (vp->velocity * vp->main_vol * vp->expression_vol) / (127*127);
+ vol = vol * ap->amplitude / 127;
+ if (vol < 0) vol = 0;
+ if (vol > 127) vol = 127;
+
+ /* calc to attenuation */
+ vol = vol_table[vol];
+ vol = vol + (int)ap->attenuation + init_atten;
+ if (vol > 255) vol = 255;
+
+ vp->avol = vol;
+ DEBUG(3,printk("AWE32: [-- voice(%d) vol=%x]\n", voice, vol));
+}
+
+
+/*================================================================
+ * synth operation routines
+ *================================================================*/
+
+/* initialize the voice */
+static void
+awe_voice_init(int voice, int inst_only)
+{
+ if (! inst_only) {
+ /* clear voice parameters */
+ voices[voice].note = -1;
+ voices[voice].velocity = 0;
+ voices[voice].panning = 0; /* zero center */
+ voices[voice].bender = 0; /* zero tune skew */
+ voices[voice].bender_range = 200; /* sense * 100 */
+ voices[voice].main_vol = 127;
+ voices[voice].expression_vol = 127;
+ voices[voice].bank = AWE_DEFAULT_BANK;
+ voices[voice].instr = -1;
+ voices[voice].vrec = NULL;
+ voices[voice].sample = NULL;
+ }
+
+ /* clear voice mapping */
+ voices[voice].state = 0;
+ voice_alloc->map[voice] = 0;
+
+ /* emu8000 parameters */
+ voices[voice].apitch = 0;
+ voices[voice].avol = 255;
+
+ /* clear effects */
+ BZERO(voices[voice].fx_flags, sizeof(voices[voice].fx_flags));
+}
+
+
+/*----------------------------------------------------------------
+ * device open / close
+ *----------------------------------------------------------------*/
+
+/* open device:
+ * reset status of all voices, and clear sample position flag
+ */
+static int
+awe_open(int dev, int mode)
+{
+ if (awe_busy)
+ return RET_ERROR(EBUSY);
+
+ awe_busy = 1;
+ awe_reset(dev);
+
+ /* clear sample position flag */
+ loaded_once = 0;
+
+ /* set GUS bank to default */
+ awe_gus_bank = AWE_DEFAULT_BANK;
+ return 0;
+}
+
+
+/* close device:
+ * reset all voices again (terminate sounds)
+ */
+static void
+awe_close(int dev)
+{
+ awe_reset(dev);
+ awe_busy = 0;
+}
+
+
+/* sequencer I/O control:
+ */
+static int
+awe_ioctl(int dev, unsigned int cmd, caddr_t arg)
+{
+ switch (cmd) {
+ case SNDCTL_SYNTH_INFO:
+ awe_info.nr_voices = awe_max_voices;
+ IOCTL_TO_USER((char*)arg, 0, &awe_info, sizeof(awe_info));
+ return 0;
+ break;
+
+ case SNDCTL_SEQ_RESETSAMPLES:
+ awe_reset_samples();
+ awe_reset(dev); /* better to reset emu8k chip... */
+ return 0;
+ break;
+
+ case SNDCTL_SEQ_PERCMODE:
+ /* what's this? */
+ return 0;
+ break;
+
+ case SNDCTL_SYNTH_MEMAVL:
+ DEBUG(0,printk("AWE32: [ioctl memavl = %d]\n", (int)free_mem_ptr));
+ return awe_mem_size - free_mem_ptr*2;
+
+ default:
+ ERRMSG(printk("AWE32: unsupported ioctl %d\n", cmd));
+ return RET_ERROR(EINVAL);
+ }
+}
+
+
+/* kill a voice:
+ * not terminate, just release the voice.
+ */
+static int
+awe_kill_note(int dev, int voice, int note, int velocity)
+{
+ awe_voice_info *vp;
+ DECL_INTR_FLAGS(flags);
+
+ DEBUG(2,printk("AWE32: [off(%d)]\n", voice));
+ if (voice < 0 || voice >= awe_max_voices)
+ return RET_ERROR(EINVAL);
+ if ((vp = voices[voice].sample) == NULL)
+ return 0;
+
+ if (!(vp->mode & AWE_MODE_NORELEASE)) {
+ DISABLE_INTR(flags);
+ awe_note_off(voice);
+ RESTORE_INTR(flags);
+ }
+ awe_voice_init(voice, 1);
+ return 0;
+}
+
+
+/* search the note with the specified key range */
+static awe_voice_info *
+awe_search_voice(int voice, int note)
+{
+ awe_voice_list *rec;
+ int maxc;
+
+ for (rec = voices[voice].vrec, maxc = AWE_MAX_INFOS;
+ rec && maxc; rec = rec->next_instr, maxc--) {
+ if (rec->v.low <= note && note <= rec->v.high)
+ return &rec->v;
+ }
+ return NULL;
+}
+
+/* start a voice:
+ * if note is 255, identical with aftertouch function.
+ * Otherwise, start a voice with specified not and volume.
+ */
+static int
+awe_start_note(int dev, int v, int note_num, int volume)
+{
+ DECL_INTR_FLAGS(flags);
+
+ DEBUG(2,printk("AWE32: [on(%d) nt=%d vl=%d]\n", v, note_num, volume));
+ if (v < 0 || v >= awe_max_voices)
+ return RET_ERROR(EINVAL);
+ /* an instrument must be set before starting a note */
+ if (voices[v].vrec == NULL) {
+ DEBUG(1,printk("AWE32: [-- vrec is null]\n"));
+ return 0;
+ }
+
+ if (note_num == 255) {
+ /* dynamic volume change; sample is already assigned */
+ if (! voices[v].state || voices[v].sample == NULL)
+ return 0;
+ /* calculate volume parameter */
+ voices[v].velocity = volume;
+ awe_calc_volume(v);
+ DISABLE_INTR(flags);
+ awe_set_volume(v);
+ RESTORE_INTR(flags);
+ return 0;
+ }
+ /* assign a sample with the corresponding note */
+ if ((voices[v].sample = awe_search_voice(v, note_num)) == NULL) {
+ DEBUG(1,printk("AWE32: [-- sample is null]\n"));
+ return 0;
+ }
+ /* calculate pitch & volume parameters */
+ voices[v].note = note_num;
+ voices[v].velocity = volume;
+ awe_calc_pitch(v);
+ awe_calc_volume(v);
+
+ DISABLE_INTR(flags);
+ /* turn off other voices (for drums) */
+ awe_exclusive_off(v);
+ /* turn on the voice */
+ awe_note_on(v);
+ voices[v].state = 1; /* flag up */
+ RESTORE_INTR(flags);
+
+ return 0;
+}
+
+
+/* search instrument from preset table with the specified bank */
+static awe_voice_list *
+awe_search_instr(int bank, int preset)
+{
+ awe_voice_list *p;
+ int maxc;
+
+ for (maxc = AWE_MAX_INFOS, p = preset_table[preset];
+ p && maxc; p = p->next_bank, maxc--) {
+ if (p->bank == bank)
+ return p;
+ }
+ return NULL;
+}
+
+
+/* assign the instrument to a voice */
+static int
+awe_set_instr(int dev, int voice, int instr_no)
+{
+ awe_voice_list *rec;
+
+ if (voice < 0 || voice >= awe_max_voices)
+ return RET_ERROR(EINVAL);
+
+ if (instr_no < 0 || instr_no >= AWE_MAX_PRESETS)
+ return RET_ERROR(EINVAL);
+
+ if ((rec = awe_search_instr(voices[voice].bank, instr_no)) == NULL) {
+ /* if bank is not defined, use the default bank 0 */
+ if (voices[voice].bank != AWE_DEFAULT_BANK &&
+ (rec = awe_search_instr(AWE_DEFAULT_BANK, instr_no)) == NULL) {
+ DEBUG(1,printk("AWE32 Warning: can't find instrument %d\n", instr_no));
+ return 0;
+ }
+ }
+
+ voices[voice].instr = instr_no;
+ voices[voice].vrec = rec;
+ voices[voice].sample = NULL; /* not set yet */
+
+ return 0;
+}
+
+
+/* reset all voices; terminate sounds and initialize parameters */
+static void
+awe_reset(int dev)
+{
+ int i;
+ /* don't turn off voice 31 and 32. they are used also for FM voices */
+ for (i = 0; i < AWE_NORMAL_VOICES; i++) {
+ awe_terminate(i);
+ awe_voice_init(i, 0);
+ }
+ awe_init_fm();
+ awe_tweak();
+}
+
+
+/* hardware specific control:
+ * GUS specific and AWE32 specific controls are available.
+ */
+static void
+awe_hw_control(int dev, unsigned char *event)
+{
+ int cmd = event[2];
+ if (cmd & _AWE_MODE_FLAG)
+ awe_hw_awe_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);
+ else
+ awe_hw_gus_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);
+}
+
+/* GUS compatible controls */
+static void
+awe_hw_gus_control(int dev, int cmd, unsigned char *event)
+{
+ int voice;
+ unsigned short p1;
+ short p2;
+ int plong;
+ DECL_INTR_FLAGS(flags);
+
+ voice = event[3];
+ p1 = *(unsigned short *) &event[4];
+ p2 = *(short *) &event[6];
+ plong = *(int*) &event[4];
+
+ switch (cmd) {
+ case _GUS_NUMVOICES:
+ if (p1 >= awe_max_voices)
+ printk("AWE32: num_voices: voices out of range %d\n", p1);
+ break;
+ case _GUS_VOICESAMPLE:
+ if (voice < awe_max_voices)
+ awe_set_instr(dev, voice, p1);
+ break;
+
+ case _GUS_VOICEON:
+ if (voice < awe_max_voices) {
+ DISABLE_INTR(flags);
+ awe_note_on(voice);
+ RESTORE_INTR(flags);
+ }
+ break;
+
+ case _GUS_VOICEOFF:
+ if (voice < awe_max_voices) {
+ DISABLE_INTR(flags);
+ awe_note_off(voice);
+ RESTORE_INTR(flags);
+ }
+ break;
+
+ case _GUS_VOICEMODE:
+ /* not supported */
+ break;
+
+ case _GUS_VOICEBALA:
+ /* -128 to 127 */
+ if (voice < awe_max_voices)
+ awe_panning(dev, voice, (short)p1);
+ break;
+
+ case _GUS_VOICEFREQ:
+ if (voice < awe_max_voices)
+ awe_calc_pitch_from_freq(voice, plong);
+ break;
+
+ case _GUS_VOICEVOL:
+ case _GUS_VOICEVOL2:
+ /* not supported yet */
+ break;
+
+ case _GUS_RAMPRANGE:
+ case _GUS_RAMPRATE:
+ case _GUS_RAMPMODE:
+ case _GUS_RAMPON:
+ case _GUS_RAMPOFF:
+ /* volume ramping not supported */
+ break;
+
+ case _GUS_VOLUME_SCALE:
+ break;
+
+ case _GUS_VOICE_POS:
+ if (voice < awe_max_voices) {
+ FX_SET(voice, AWE_FX_SAMPLE_START, (short)(plong & 0x7fff));
+ FX_SET(voice, AWE_FX_COARSE_SAMPLE_START, (plong >> 15) & 0xffff);
+ }
+ break;
+ }
+}
+
+
+/* AWE32 specific controls */
+static void
+awe_hw_awe_control(int dev, int cmd, unsigned char *event)
+{
+ int voice;
+ unsigned short p1;
+ short p2;
+ int chn;
+
+ chn = event[1];
+ voice = event[3];
+ p1 = *(unsigned short *) &event[4];
+ p2 = *(short *) &event[6];
+
+
+#ifdef AWE_DEBUG_ON
+ switch (cmd) {
+ case _AWE_DEBUG_MODE:
+ debug_mode = p1;
+ printk("AWE32: debug mode = %d\n", debug_mode);
+ break;
+#endif
+ case _AWE_REVERB_MODE:
+ if (p1 <= 7) {
+ reverb_mode = p1;
+ DEBUG(0,printk("AWE32: reverb mode %d\n", reverb_mode));
+ awe_set_reverb_mode(reverb_mode);
+ }
+ break;
+
+ case _AWE_CHORUS_MODE:
+ if (p1 <= 7) {
+ chorus_mode = p1;
+ DEBUG(0,printk("AWE32: chorus mode %d\n", chorus_mode));
+ awe_set_chorus_mode(chorus_mode);
+ }
+ break;
+
+ case _AWE_REMOVE_LAST_SAMPLES:
+ DEBUG(0,printk("AWE32: remove last samples\n"));
+ awe_remove_samples();
+ break;
+
+ case _AWE_INITIALIZE_CHIP:
+ awe_initialize();
+ break;
+
+ case _AWE_SEND_EFFECT:
+ if (voice < awe_max_voices && p1 < AWE_FX_END) {
+ FX_SET(voice, p1, p2);
+ DEBUG(0,printk("AWE32: effects (%d) %d %d\n", voice, p1, voices[voice].fx[p1]));
+ if (fx_realtime[p1]) {
+ DEBUG(0,printk("AWE32: fx_realtime (%d)\n", voice));
+ fx_realtime[p1](voice);
+ }
+ }
+ break;
+
+ case _AWE_TERMINATE_CHANNEL:
+ if (voice < awe_max_voices) {
+ DEBUG(0,printk("AWE32: terminate (%d)\n", voice));
+ awe_terminate(voice);
+ awe_voice_init(voice, 1);
+ }
+ break;
+
+ case _AWE_TERMINATE_ALL:
+ DEBUG(0,printk("AWE32: terminate all\n"));
+ awe_reset(0);
+ break;
+
+ case _AWE_INITIAL_VOLUME:
+ DEBUG(0,printk("AWE32: init attenuation %d\n", p1));
+ init_atten = p1;
+ break;
+
+ case _AWE_SET_GUS_BANK:
+ DEBUG(0,printk("AWE32: set gus bank %d\n", p1));
+ awe_gus_bank = p1;
+ break;
+
+ default:
+ DEBUG(0,printk("AWE32: hw control cmd=%d voice=%d\n", cmd, voice));
+ break;
+ }
+}
+
+
+/*----------------------------------------------------------------
+ * load a sound patch:
+ * three types of patches are accepted: AWE, GUS, and SYSEX.
+ *----------------------------------------------------------------*/
+
+static int
+awe_load_patch(int dev, int format, const char *addr,
+ int offs, int count, int pmgr_flag)
+{
+ awe_patch_info patch;
+ int rc = 0;
+
+ if (format == GUS_PATCH) {
+ return awe_load_guspatch(addr, offs, count, pmgr_flag);
+ } else if (format == SYSEX_PATCH) {
+ /* no system exclusive message supported yet */
+ return 0;
+ } else if (format != AWE_PATCH) {
+ FATALERR(printk("AWE32 Error: Invalid patch format (key) 0x%x\n", format));
+ return RET_ERROR(EINVAL);
+ }
+
+ if (count < sizeof(awe_patch_info)) {
+ FATALERR(printk("AWE32 Error: Patch header too short\n"));
+ return RET_ERROR(EINVAL);
+ }
+ COPY_FROM_USER(((char*)&patch) + offs, addr, offs,
+ sizeof(awe_patch_info) - offs);
+
+ count -= sizeof(awe_patch_info);
+ if (count < patch.len) {
+ FATALERR(printk("AWE32 Warning: Patch record too short (%d<%d)\n",
+ count, (int)patch.len));
+ patch.len = count;
+ }
+
+ switch (patch.type) {
+ case AWE_LOAD_INFO:
+ rc = awe_load_info(&patch, addr);
+ break;
+
+ case AWE_LOAD_DATA:
+ rc = awe_load_data(&patch, addr);
+ /*
+ if (!pmgr_flag && rc == 0)
+ pmgr_inform(dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0);
+ */
+ break;
+
+ default:
+ FATALERR(printk("AWE32 Error: unknown patch format type %d\n",
+ patch.type));
+ rc = RET_ERROR(EINVAL);
+ }
+
+ return rc;
+}
+
+
+/* load voice information data */
+static int
+awe_load_info(awe_patch_info *patch, const char *addr)
+{
+ awe_voice_list *rec, *curp;
+ long offset;
+ short i, nvoices;
+ unsigned char bank, instr;
+ int total_size;
+
+ if (patch->len < sizeof(awe_voice_rec)) {
+ FATALERR(printk("AWE32 Error: invalid patch info length\n"));
+ return RET_ERROR(EINVAL);
+ }
+
+ offset = sizeof(awe_patch_info);
+ GET_BYTE_FROM_USER(bank, addr, offset); offset++;
+ GET_BYTE_FROM_USER(instr, addr, offset); offset++;
+ GET_SHORT_FROM_USER(nvoices, addr, offset); offset+=2;
+
+ if (nvoices <= 0 || nvoices >= 100) {
+ FATALERR(printk("AWE32 Error: Illegal voice number %d\n", nvoices));
+ return RET_ERROR(EINVAL);
+ }
+ if (free_info + nvoices > AWE_MAX_INFOS) {
+ ERRMSG(printk("AWE32 Error: Too many voice informations\n"));
+ return RET_ERROR(ENOSPC);
+ }
+
+ total_size = sizeof(awe_voice_rec) + sizeof(awe_voice_info) * nvoices;
+ if (patch->len < total_size) {
+ ERRMSG(printk("AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n",
+ (int)patch->len, nvoices));
+ return RET_ERROR(EINVAL);
+ }
+
+ curp = awe_search_instr(bank, instr);
+ for (i = 0; i < nvoices; i++) {
+ rec = &infos[free_info + i];
+
+ rec->bank = bank;
+ rec->instr = instr;
+ if (i < nvoices - 1)
+ rec->next_instr = rec + 1;
+ else
+ rec->next_instr = curp;
+ rec->next_bank = NULL;
+
+ /* copy awe_voice_info parameters */
+ COPY_FROM_USER(&rec->v, addr, offset, sizeof(awe_voice_info));
+ offset += sizeof(awe_voice_info);
+ rec->v.sf_id = current_sf_id;
+ if (rec->v.mode & AWE_MODE_INIT_PARM)
+ awe_init_voice_parm(&rec->v.parm);
+ awe_set_sample(&rec->v);
+ }
+
+ /* prepend to top of the list */
+ infos[free_info].next_bank = preset_table[instr];
+ preset_table[instr] = &infos[free_info];
+ free_info += nvoices;
+
+ return 0;
+}
+
+
+/* load wave sample data */
+static int
+awe_load_data(awe_patch_info *patch, const char *addr)
+{
+ long offset;
+ int size;
+ int rc;
+
+ if (free_sample >= AWE_MAX_SAMPLES) {
+ ERRMSG(printk("AWE32 Error: Sample table full\n"));
+ return RET_ERROR(ENOSPC);
+ }
+
+ size = (patch->len - sizeof(awe_sample_info)) / 2;
+ offset = sizeof(awe_patch_info);
+ COPY_FROM_USER(&samples[free_sample], addr, offset,
+ sizeof(awe_sample_info));
+ offset += sizeof(awe_sample_info);
+ if (size != samples[free_sample].size) {
+ ERRMSG(printk("AWE32 Warning: sample size differed (%d != %d)\n",
+ (int)samples[free_sample].size, (int)size));
+ samples[free_sample].size = size;
+ }
+ if (samples[free_sample].size > 0)
+ if ((rc = awe_write_wave_data(addr, offset, size)) != 0)
+ return rc;
+
+ awe_check_loaded();
+ samples[free_sample].sf_id = current_sf_id;
+
+ free_sample++;
+ return 0;
+}
+
+/* check the other samples are already loaded */
+static void
+awe_check_loaded(void)
+{
+ if (!loaded_once) {
+ /* it's the first time */
+ last_sample = free_sample;
+ last_info = free_info;
+ current_sf_id++;
+ loaded_once = 1;
+ }
+}
+
+
+#define BLANK_LOOP_START 8
+#define BLANK_LOOP_END 40
+#define BLANK_LOOP_SIZE 48
+
+/* loading onto memory */
+static int
+awe_write_wave_data(const char *addr, long offset, int size)
+{
+ awe_sample_info *sp = &samples[free_sample];
+ int i, truesize;
+ int rc;
+ unsigned long csum1, csum2;
+ DECL_INTR_FLAGS(flags);
+
+ /* be sure loop points start < end */
+ if (sp->loopstart > sp->loopend) {
+ long tmp = sp->loopstart;
+ sp->loopstart = sp->loopend;
+ sp->loopend = tmp;
+ }
+
+ /* compute true data size to be loaded */
+ truesize = size;
+ if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP)
+ truesize += sp->loopend - sp->loopstart;
+ if (sp->mode_flags & AWE_SAMPLE_NO_BLANK)
+ truesize += BLANK_LOOP_SIZE;
+ if (size > 0 && free_mem_ptr + truesize >= awe_mem_size/2) {
+ ERRMSG(printk("AWE32 Error: Sample memory full\n"));
+ return RET_ERROR(ENOSPC);
+ }
+
+ /* recalculate address offset */
+ sp->end -= sp->start;
+ sp->loopstart -= sp->start;
+ sp->loopend -= sp->start;
+ sp->size = truesize;
+
+ sp->start = free_mem_ptr + AWE_DRAM_OFFSET;
+ sp->end += free_mem_ptr + AWE_DRAM_OFFSET;
+ sp->loopstart += free_mem_ptr + AWE_DRAM_OFFSET;
+ sp->loopend += free_mem_ptr + AWE_DRAM_OFFSET;
+
+ DISABLE_INTR(flags);
+ if ((rc = awe_open_dram_for_write(free_mem_ptr)) != 0) {
+ RESTORE_INTR(flags);
+ return rc;
+ }
+
+ csum1 = 0;
+ for (i = 0; i < size; i++) {
+ unsigned char cc;
+ unsigned short c;
+ if (sp->mode_flags & AWE_SAMPLE_8BITS) {
+ GET_BYTE_FROM_USER(cc, addr, offset); offset++;
+ c = cc << 8; /* convert 8bit -> 16bit */
+ } else {
+ GET_SHORT_FROM_USER(c, addr, offset); offset += 2;
+ }
+ if (sp->mode_flags & AWE_SAMPLE_UNSIGNED)
+ c ^= 0x8000; /* unsigned -> signed */
+ csum1 += c;
+ awe_write_dram(c);
+ if (i == sp->loopend &&
+ (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP)) {
+ int looplen = sp->loopend - sp->loopstart;
+ /* copy reverse loop */
+ int k;
+ for (k = 0; k < looplen; k++) {
+ if (sp->mode_flags & AWE_SAMPLE_8BITS) {
+ GET_BYTE_FROM_USER(cc, addr, offset-k);
+ c = cc << 8;
+ } else {
+ GET_SHORT_FROM_USER(c, addr, offset-k*2);
+ }
+ if (sp->mode_flags & AWE_SAMPLE_UNSIGNED)
+ c ^= 0x8000;
+ awe_write_dram(c);
+ }
+ }
+ }
+
+ /* if no blank loop is attached in the sample, add it */
+ if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) {
+ for (i = 0; i < BLANK_LOOP_SIZE; i++)
+ awe_write_dram(0);
+ if (sp->mode_flags & AWE_SAMPLE_SINGLESHOT) {
+ sp->loopstart = sp->end + BLANK_LOOP_START;
+ sp->loopend = sp->end + BLANK_LOOP_END;
+ }
+ sp->size += BLANK_LOOP_SIZE;
+ }
+
+ awe_close_dram();
+ RESTORE_INTR(flags);
+ if (sp->checksum_flag) {
+#ifdef AWE_CHECKSUM_DATA
+ if (sp->checksum_flag != 2 && csum1 != sp->checksum) {
+ ERRMSG(printk("AWE32: [%d] checksum mismatch on data %x:%x\n",
+ free_sample,
+ (int)samples[free_sample].checksum,
+ (int)csum1));
+ return RET_ERROR(NO_DATA_ERR);
+ }
+#endif /* AWE_CHECKSUM_DATA */
+#ifdef AWE_CHECKSUM_MEMORY
+ DISABLE_INTR(flags);
+ if (awe_open_dram_for_read(free_mem_ptr) == 0) {
+ csum2 = 0;
+ for (i = 0; i < size; i++) {
+ unsigned short c;
+ c = awe_peek(AWE_SMLD);
+ csum2 += c;
+ }
+ awe_close_dram_for_read();
+ if (csum2 != samples[free_sample].checksum) {
+ RESTORE_INTR(flags);
+ ERRMSG(printk("AWE32: [%d] checksum mismatch on DRAM %x:%x\n",
+ free_sample,
+ (int)samples[free_sample].checksum,
+ (int)csum2));
+ return RET_ERROR(NO_DATA_ERR);
+ }
+ }
+ RESTORE_INTR(flags);
+#endif /* AWE_CHECKSUM_MEMORY */
+ }
+ free_mem_ptr += sp->size;
+
+ /* re-initialize FM passthrough */
+ DISABLE_INTR(flags);
+ awe_init_fm();
+ awe_tweak();
+ RESTORE_INTR(flags);
+
+ return 0;
+}
+
+
+/* calculate GUS envelope time:
+ * is this correct? i have no idea..
+ */
+static int
+calc_gus_envelope_time(int rate, int start, int end)
+{
+ int r, p, t;
+ r = (3 - ((rate >> 6) & 3)) * 3;
+ p = rate & 0x3f;
+ t = end - start;
+ if (t < 0) t = -t;
+ if (13 > r)
+ t = t << (13 - r);
+ else
+ t = t >> (r - 13);
+ return (t * 10) / (p * 441);
+}
+
+#define calc_gus_sustain(val) (0x7f - vol_table[(val)/2])
+#define calc_gus_attenuation(val) vol_table[(val)/2]
+
+/* load GUS patch */
+static int
+awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
+{
+ struct patch_info patch;
+ awe_voice_list *rec, *curp;
+ long sizeof_patch;
+ int note;
+ int rc;
+
+ sizeof_patch = (long)&patch.data[0] - (long)&patch; /* header size */
+ if (free_sample >= AWE_MAX_SAMPLES) {
+ ERRMSG(printk("AWE32 Error: Sample table full\n"));
+ return RET_ERROR(ENOSPC);
+ }
+ if (free_info >= AWE_MAX_INFOS) {
+ ERRMSG(printk("AWE32 Error: Too many voice informations\n"));
+ return RET_ERROR(ENOSPC);
+ }
+ if (size < sizeof_patch) {
+ ERRMSG(printk("AWE32 Error: Patch header too short\n"));
+ return RET_ERROR(EINVAL);
+ }
+ COPY_FROM_USER(((char*)&patch) + offs, addr, offs, sizeof_patch - offs);
+ size -= sizeof_patch;
+ if (size < patch.len) {
+ FATALERR(printk("AWE32 Warning: Patch record too short (%d<%d)\n",
+ size, (int)patch.len));
+ patch.len = size;
+ }
+
+ samples[free_sample].sf_id = 0;
+ samples[free_sample].sample = free_sample;
+ samples[free_sample].start = 0;
+ samples[free_sample].end = patch.len;
+ samples[free_sample].loopstart = patch.loop_start;
+ samples[free_sample].loopend = patch.loop_end;
+ samples[free_sample].size = patch.len;
+
+ /* set up mode flags */
+ samples[free_sample].mode_flags = 0;
+ if (!(patch.mode & WAVE_16_BITS))
+ samples[free_sample].mode_flags |= AWE_SAMPLE_8BITS;
+ if (patch.mode & WAVE_UNSIGNED)
+ samples[free_sample].mode_flags |= AWE_SAMPLE_UNSIGNED;
+ samples[free_sample].mode_flags |= AWE_SAMPLE_NO_BLANK;
+ if (!(patch.mode & (WAVE_LOOPING|WAVE_BIDIR_LOOP)))
+ samples[free_sample].mode_flags |= AWE_SAMPLE_SINGLESHOT;
+ if (patch.mode & WAVE_BIDIR_LOOP)
+ samples[free_sample].mode_flags |= AWE_SAMPLE_BIDIR_LOOP;
+
+ DEBUG(0,printk("AWE32: [sample %d mode %x]\n", patch.instr_no,
+ samples[free_sample].mode_flags));
+ if (patch.mode & WAVE_16_BITS) {
+ /* convert to word offsets */
+ samples[free_sample].size /= 2;
+ samples[free_sample].end /= 2;
+ samples[free_sample].loopstart /= 2;
+ samples[free_sample].loopend /= 2;
+ }
+ samples[free_sample].checksum_flag = 0;
+ samples[free_sample].checksum = 0;
+
+ if ((rc = awe_write_wave_data(addr, sizeof_patch,
+ samples[free_sample].size)) != 0)
+ return rc;
+
+ awe_check_loaded();
+ samples[free_sample].sf_id = current_sf_id;
+ free_sample++;
+
+ /* set up voice info */
+ rec = &infos[free_info];
+ awe_init_voice_info(&rec->v);
+ rec->v.sf_id = current_sf_id;
+ rec->v.sample = free_sample - 1; /* the last sample */
+ rec->v.rate_offset = calc_rate_offset(patch.base_freq);
+ note = freq_to_note(patch.base_note);
+ rec->v.root = note / 100;
+ rec->v.tune = -(note % 100);
+ rec->v.low = freq_to_note(patch.low_note) / 100;
+ rec->v.high = freq_to_note(patch.high_note) / 100;
+ DEBUG(1,printk("AWE32: [gus base offset=%d, note=%d, range=%d-%d(%d-%d)]\n",
+ rec->v.rate_offset, note,
+ rec->v.low, rec->v.high,
+ patch.low_note, patch.high_note));
+ /* panning position; -128 - 127 => 0-127 */
+ rec->v.pan = (patch.panning + 128) / 2;
+
+ /* detuning is ignored */
+ /* 6points volume envelope */
+ if (patch.mode & WAVE_ENVELOPES) {
+ int attack, hold, decay, release;
+ attack = calc_gus_envelope_time
+ (patch.env_rate[0], 0, patch.env_offset[0]);
+ hold = calc_gus_envelope_time
+ (patch.env_rate[1], patch.env_offset[0],
+ patch.env_offset[1]);
+ decay = calc_gus_envelope_time
+ (patch.env_rate[2], patch.env_offset[1],
+ patch.env_offset[2]);
+ release = calc_gus_envelope_time
+ (patch.env_rate[3], patch.env_offset[1],
+ patch.env_offset[4]);
+ release += calc_gus_envelope_time
+ (patch.env_rate[4], patch.env_offset[3],
+ patch.env_offset[4]);
+ release += calc_gus_envelope_time
+ (patch.env_rate[5], patch.env_offset[4],
+ patch.env_offset[5]);
+ rec->v.parm.volatkhld = (calc_parm_attack(attack) << 8) |
+ calc_parm_hold(hold);
+ rec->v.parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) |
+ calc_parm_decay(decay);
+ rec->v.parm.volrelease = 0x8000 | calc_parm_decay(release);
+ DEBUG(2,printk("AWE32: [gusenv atk=%d, hld=%d, dcy=%d, rel=%d]\n", attack, hold, decay, release));
+ rec->v.attenuation = calc_gus_attenuation(patch.env_offset[0]);
+ }
+
+ /* tremolo effect */
+ if (patch.mode & WAVE_TREMOLO) {
+ int rate = (patch.tremolo_rate * 1000 / 38) / 42;
+ rec->v.parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate;
+ DEBUG(2,printk("AWE32: [gusenv tremolo rate=%d, dep=%d, tremfrq=%x]\n",
+ patch.tremolo_rate, patch.tremolo_depth,
+ rec->v.parm.tremfrq));
+ }
+ /* vibrato effect */
+ if (patch.mode & WAVE_VIBRATO) {
+ int rate = (patch.vibrato_rate * 1000 / 38) / 42;
+ rec->v.parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate;
+ DEBUG(2,printk("AWE32: [gusenv vibrato rate=%d, dep=%d, tremfrq=%x]\n",
+ patch.tremolo_rate, patch.tremolo_depth,
+ rec->v.parm.tremfrq));
+ }
+
+ /* scale_freq, scale_factor, volume, and fractions not implemented */
+
+ /* set the voice index */
+ awe_set_sample(&rec->v);
+
+ /* prepend to top of the list */
+ curp = awe_search_instr(awe_gus_bank, patch.instr_no);
+ rec->bank = awe_gus_bank;
+ rec->instr = patch.instr_no;
+ rec->next_instr = curp;
+ rec->next_bank = preset_table[rec->instr];
+ preset_table[rec->instr] = rec;
+ free_info++;
+
+ return 0;
+}
+
+
+/* remove samples with current sf_id from instrument list */
+static awe_voice_list *
+awe_get_removed_list(awe_voice_list *curp)
+{
+ awe_voice_list *lastp, **prevp;
+ int maxc;
+ lastp = curp;
+ prevp = &lastp;
+ for (maxc = AWE_MAX_INFOS;
+ curp && maxc; curp = curp->next_instr, maxc--) {
+ if (curp->v.sf_id == current_sf_id)
+ *prevp = curp->next_instr;
+ else
+ prevp = &curp->next_instr;
+ }
+ return lastp;
+}
+
+
+/* remove last loaded samples */
+static void
+awe_remove_samples(void)
+{
+ awe_voice_list **prevp, *p, *nextp;
+ int maxc;
+ int i;
+
+ if (last_sample == free_sample && last_info == free_info)
+ return;
+
+ /* remove the records from preset table */
+ for (i = 0; i < AWE_MAX_PRESETS; i++) {
+ prevp = &preset_table[i];
+ for (maxc = AWE_MAX_INFOS, p = preset_table[i];
+ p && maxc; p = nextp, maxc--) {
+ nextp = p->next_bank;
+ p = awe_get_removed_list(p);
+ if (p == NULL)
+ *prevp = nextp;
+ else {
+ *prevp = p;
+ prevp = &p->next_bank;
+ }
+ }
+ }
+
+ for (i = last_sample; i < free_sample; i++)
+ free_mem_ptr -= samples[i].size;
+
+ free_sample = last_sample;
+ free_info = last_info;
+ current_sf_id--;
+ loaded_once = 0;
+}
+
+
+/* search the specified sample */
+static short
+awe_set_sample(awe_voice_info *vp)
+{
+ int i;
+ for (i = 0; i < free_sample; i++) {
+ if (samples[i].sf_id == vp->sf_id &&
+ samples[i].sample == vp->sample) {
+ /* set the actual sample offsets */
+ vp->start += samples[i].start;
+ vp->end += samples[i].end;
+ vp->loopstart += samples[i].loopstart;
+ vp->loopend += samples[i].loopend;
+ /* copy mode flags */
+ vp->mode |= (samples[i].mode_flags << 6);
+ /* set index */
+ vp->index = i;
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+/* voice pressure change */
+static void
+awe_aftertouch(int dev, int voice, int pressure)
+{
+ DECL_INTR_FLAGS(flags);
+
+ DEBUG(2,printk("AWE32: [after(%d) %d]\n", voice, pressure));
+ if (voice < 0 || voice >= awe_max_voices)
+ return;
+ voices[voice].velocity = pressure;
+ awe_calc_volume(voice);
+ DISABLE_INTR(flags);
+ awe_set_volume(voice);
+ RESTORE_INTR(flags);
+}
+
+
+/* voice control change */
+static void
+awe_controller(int dev, int voice, int ctrl_num, int value)
+{
+ DECL_INTR_FLAGS(flags);
+
+ if (voice < 0 || voice >= awe_max_voices)
+ return;
+
+ switch (ctrl_num) {
+ case CTL_BANK_SELECT:
+ DEBUG(2,printk("AWE32: [bank(%d) %d]\n", voice, value));
+ voices[voice].bank = value;
+ break;
+
+ case CTRL_PITCH_BENDER:
+ DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, value));
+ /* zero centered */
+ voices[voice].bender = value;
+ awe_calc_pitch(voice);
+ DISABLE_INTR(flags);
+ awe_set_pitch(voice);
+ RESTORE_INTR(flags);
+ break;
+
+ case CTRL_PITCH_BENDER_RANGE:
+ DEBUG(2,printk("AWE32: [range(%d) %d]\n", voice, value));
+ /* sense x 100 */
+ voices[voice].bender_range = value;
+ /* no audible pitch change yet.. */
+ break;
+
+ case CTL_EXPRESSION:
+ value /= 128;
+ case CTRL_EXPRESSION:
+ DEBUG(2,printk("AWE32: [expr(%d) %d]\n", voice, value));
+ /* 0 - 127 */
+ voices[voice].expression_vol = value;
+ awe_calc_volume(voice);
+ DISABLE_INTR(flags);
+ awe_set_volume(voice);
+ RESTORE_INTR(flags);
+ break;
+
+ case CTL_PAN:
+ DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, value));
+ /* (0-127) -> signed 8bit */
+ voices[voice].panning = value * 2 - 128;
+ DISABLE_INTR(flags);
+ awe_set_pan(voice, 0);
+ RESTORE_INTR(flags);
+ break;
+
+ case CTL_MAIN_VOLUME:
+ value = (value * 127) / 16383;
+ case CTRL_MAIN_VOLUME:
+ DEBUG(2,printk("AWE32: [mainvol(%d) %d]\n", voice, value));
+ /* 0 - 127 */
+ voices[voice].main_vol = value;
+ awe_calc_volume(voice);
+ DISABLE_INTR(flags);
+ awe_set_volume(voice);
+ RESTORE_INTR(flags);
+ break;
+
+ case CTL_EXT_EFF_DEPTH: /* reverb effects: 0-127 */
+ DEBUG(2,printk("AWE32: [reverb(%d) %d]\n", voice, value));
+ FX_SET(voice, AWE_FX_REVERB, value * 2);
+ break;
+
+ case CTL_CHORUS_DEPTH: /* chorus effects: 0-127 */
+ DEBUG(2,printk("AWE32: [chorus(%d) %d]\n", voice, value));
+ FX_SET(voice, AWE_FX_CHORUS, value * 2);
+ break;
+
+
+ default:
+ DEBUG(0,printk("AWE32: [control(%d) ctrl=%d val=%d]\n",
+ voice, ctrl_num, value));
+ break;
+ }
+}
+
+
+/* voice pan change (value = -128 - 127) */
+static void
+awe_panning(int dev, int voice, int value)
+{
+ DECL_INTR_FLAGS(flags);
+ if (voice >= 0 || voice < awe_max_voices) {
+ voices[voice].panning = value;
+ DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, voices[voice].panning));
+ DISABLE_INTR(flags);
+ awe_set_pan(voice, 0);
+ RESTORE_INTR(flags);
+ }
+}
+
+
+/* volume mode change */
+static void
+awe_volume_method(int dev, int mode)
+{
+ /* not impremented */
+ DEBUG(0,printk("AWE32: [volmethod mode=%d]\n", mode));
+}
+
+
+/* patch manager */
+static int
+awe_patchmgr(int dev, struct patmgr_info *rec)
+{
+ FATALERR(printk("AWE32 Warning: patch manager control not supported\n"));
+ return 0;
+}
+
+
+/* pitch wheel change: 0-16384 */
+static void
+awe_bender(int dev, int voice, int value)
+{
+ DECL_INTR_FLAGS(flags);
+
+ if (voice < 0 || voice >= awe_max_voices)
+ return;
+ /* convert to zero centered value */
+ voices[voice].bender = value - 8192;
+ DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, voices[voice].bender));
+ awe_calc_pitch(voice);
+ DISABLE_INTR(flags);
+ awe_set_pitch(voice);
+ RESTORE_INTR(flags);
+}
+
+
+/* search an empty voice; used by sequencer2 */
+static int
+awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc)
+{
+ int i, p, best = -1, best_time = 0x7fffffff;
+
+ p = alloc->ptr;
+ /* First look for a completely stopped voice */
+
+ for (i = 0; i < alloc->max_voice; i++) {
+ if (alloc->map[p] == 0) {
+ alloc->ptr = p;
+ return p;
+ }
+ if (alloc->alloc_times[p] < best_time) {
+ best = p;
+ best_time = alloc->alloc_times[p];
+ }
+ p = (p + 1) % alloc->max_voice;
+ }
+
+ /* Then look for a releasing voice */
+ for (i = 0; i < alloc->max_voice; i++) {
+ if (alloc->map[p] == 0xffff) {
+ alloc->ptr = p;
+ return p;
+ }
+ p = (p + 1) % alloc->max_voice;
+ }
+
+ if (best >= 0)
+ p = best;
+
+ /* terminate the voice */
+ if (voices[p].state)
+ awe_terminate(p);
+
+ alloc->ptr = p;
+ return p;
+}
+
+
+/* set up voice; used by sequencer2 */
+static void
+awe_setup_voice(int dev, int voice, int chn)
+{
+ struct channel_info *info;
+ if (synth_devs[dev] == NULL ||
+ (info = &synth_devs[dev]->chn_info[chn]) == NULL)
+ return;
+ if (voice < 0 || voice >= awe_max_voices)
+ return;
+
+ DEBUG(2,printk("AWE32: [setup(%d) ch=%d]\n", voice, chn));
+ voices[voice].expression_vol = info->controllers[CTL_EXPRESSION];
+ voices[voice].main_vol =
+ (info->controllers[CTL_MAIN_VOLUME] * 100) / 128; /* 0 - 127 */
+ voices[voice].panning =
+ info->controllers[CTL_PAN] * 2 - 128; /* signed 8bit */
+ voices[voice].bender = info->bender_value; /* zero center */
+ voices[voice].bank = info->controllers[CTL_BANK_SELECT];
+ awe_set_instr(dev, voice, info->pgm_num);
+}
+
+
+/*================================================================
+ * initialization of AWE32
+ *================================================================*/
+
+/* intiailize audio channels */
+static void
+awe_init_audio(void)
+{
+ int ch;
+
+ /* turn off envelope engines */
+ for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
+ awe_poke(AWE_DCYSUSV(ch), 0x0080);
+ }
+
+ for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
+ awe_poke(AWE_ENVVOL(ch), 0);
+ awe_poke(AWE_ENVVAL(ch), 0);
+ awe_poke(AWE_DCYSUS(ch), 0);
+ awe_poke(AWE_ATKHLDV(ch), 0);
+ awe_poke(AWE_LFO1VAL(ch), 0);
+ awe_poke(AWE_ATKHLD(ch), 0);
+ awe_poke(AWE_LFO2VAL(ch), 0);
+ awe_poke(AWE_IP(ch), 0);
+ awe_poke(AWE_IFATN(ch), 0);
+ awe_poke(AWE_PEFE(ch), 0);
+ awe_poke(AWE_FMMOD(ch), 0);
+ awe_poke(AWE_TREMFRQ(ch), 0);
+ awe_poke(AWE_FM2FRQ2(ch), 0);
+ awe_poke_dw(AWE_PTRX(ch), 0);
+ awe_poke_dw(AWE_VTFT(ch), 0);
+ awe_poke_dw(AWE_PSST(ch), 0);
+ awe_poke_dw(AWE_CSL(ch), 0);
+ awe_poke_dw(AWE_CCCA(ch), 0);
+ }
+
+ for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
+ awe_poke_dw(AWE_CPF(ch), 0);
+ awe_poke_dw(AWE_CVCF(ch), 0);
+ }
+}
+
+
+/* initialize DMA address */
+static void
+awe_init_dma(void)
+{
+ awe_poke_dw(AWE_SMALR, 0x00000000);
+ awe_poke_dw(AWE_SMARR, 0x00000000);
+ awe_poke_dw(AWE_SMALW, 0x00000000);
+ awe_poke_dw(AWE_SMARW, 0x00000000);
+}
+
+
+/* initialization arrays */
+
+static unsigned short init1[128] = {
+ 0x03ff, 0x0030, 0x07ff, 0x0130, 0x0bff, 0x0230, 0x0fff, 0x0330,
+ 0x13ff, 0x0430, 0x17ff, 0x0530, 0x1bff, 0x0630, 0x1fff, 0x0730,
+ 0x23ff, 0x0830, 0x27ff, 0x0930, 0x2bff, 0x0a30, 0x2fff, 0x0b30,
+ 0x33ff, 0x0c30, 0x37ff, 0x0d30, 0x3bff, 0x0e30, 0x3fff, 0x0f30,
+
+ 0x43ff, 0x0030, 0x47ff, 0x0130, 0x4bff, 0x0230, 0x4fff, 0x0330,
+ 0x53ff, 0x0430, 0x57ff, 0x0530, 0x5bff, 0x0630, 0x5fff, 0x0730,
+ 0x63ff, 0x0830, 0x67ff, 0x0930, 0x6bff, 0x0a30, 0x6fff, 0x0b30,
+ 0x73ff, 0x0c30, 0x77ff, 0x0d30, 0x7bff, 0x0e30, 0x7fff, 0x0f30,
+
+ 0x83ff, 0x0030, 0x87ff, 0x0130, 0x8bff, 0x0230, 0x8fff, 0x0330,
+ 0x93ff, 0x0430, 0x97ff, 0x0530, 0x9bff, 0x0630, 0x9fff, 0x0730,
+ 0xa3ff, 0x0830, 0xa7ff, 0x0930, 0xabff, 0x0a30, 0xafff, 0x0b30,
+ 0xb3ff, 0x0c30, 0xb7ff, 0x0d30, 0xbbff, 0x0e30, 0xbfff, 0x0f30,
+
+ 0xc3ff, 0x0030, 0xc7ff, 0x0130, 0xcbff, 0x0230, 0xcfff, 0x0330,
+ 0xd3ff, 0x0430, 0xd7ff, 0x0530, 0xdbff, 0x0630, 0xdfff, 0x0730,
+ 0xe3ff, 0x0830, 0xe7ff, 0x0930, 0xebff, 0x0a30, 0xefff, 0x0b30,
+ 0xf3ff, 0x0c30, 0xf7ff, 0x0d30, 0xfbff, 0x0e30, 0xffff, 0x0f30,
+};
+
+static unsigned short init2[128] = {
+ 0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330,
+ 0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730,
+ 0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30,
+ 0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30,
+
+ 0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330,
+ 0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730,
+ 0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30,
+ 0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30,
+
+ 0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330,
+ 0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730,
+ 0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30,
+ 0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30,
+ 0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330,
+ 0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730,
+ 0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30,
+ 0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30,
+};
+
+static unsigned short init3[128] = {
+ 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
+ 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254,
+ 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234,
+ 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224,
+
+ 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254,
+ 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264,
+ 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294,
+ 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3,
+
+ 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287,
+ 0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7,
+ 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386,
+ 0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55,
+
+ 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308,
+ 0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F,
+ 0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319,
+ 0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570,
+};
+
+static unsigned short init4[128] = {
+ 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
+ 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
+ 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
+ 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,
+
+ 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,
+ 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,
+ 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,
+ 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,
+
+ 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,
+ 0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,
+ 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,
+ 0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,
+
+ 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,
+ 0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,
+ 0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,
+ 0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570,
+};
+
+
+/* send initialization arrays to start up */
+static void
+awe_init_array(void)
+{
+ awe_send_array(init1);
+ awe_wait(1024);
+ awe_send_array(init2);
+ awe_send_array(init3);
+ awe_poke_dw(AWE_HWCF4, 0);
+ awe_poke_dw(AWE_HWCF5, 0x83);
+ awe_poke_dw(AWE_HWCF6, 0x8000);
+ awe_send_array(init4);
+}
+
+/* send an initialization array */
+static void
+awe_send_array(unsigned short *data)
+{
+ int i;
+ unsigned short *p;
+
+ p = data;
+ for (i = 0; i < AWE_MAX_VOICES; i++, p++)
+ awe_poke(AWE_INIT1(i), *p);
+ for (i = 0; i < AWE_MAX_VOICES; i++, p++)
+ awe_poke(AWE_INIT2(i), *p);
+ for (i = 0; i < AWE_MAX_VOICES; i++, p++)
+ awe_poke(AWE_INIT3(i), *p);
+ for (i = 0; i < AWE_MAX_VOICES; i++, p++)
+ awe_poke(AWE_INIT4(i), *p);
+}
+
+
+/*
+ * set up awe32 channels to some known state.
+ */
+
+static void
+awe_tweak(void)
+{
+ int i;
+
+ /* Set the envelope engine parameters to the "default" values for
+ simply playing back unarticulated audio at 44.1kHz. Set all
+ of the channels: */
+
+ for (i = 0; i < AWE_MAX_VOICES; i++) {
+ awe_poke(AWE_ENVVOL(i) , 0x8000);
+ awe_poke(AWE_ENVVAL(i) , 0x8000);
+ awe_poke(AWE_DCYSUS(i) , 0x7F7F);
+ awe_poke(AWE_ATKHLDV(i) , 0x7F7F);
+ awe_poke(AWE_LFO1VAL(i) , 0x8000);
+ awe_poke(AWE_ATKHLD(i) , 0x7F7F);
+ awe_poke(AWE_LFO2VAL(i) , 0x8000);
+ awe_poke(AWE_IP(i) , 0xE000);
+ awe_poke(AWE_IFATN(i) , 0xFF00);
+ awe_poke(AWE_PEFE(i) , 0x0000);
+ awe_poke(AWE_FMMOD(i) , 0x0000);
+ awe_poke(AWE_TREMFRQ(i) , 0x0010);
+ awe_poke(AWE_FM2FRQ2(i) , 0x0010);
+ }
+}
+
+
+/*
+ * initializes the FM section of AWE32
+ */
+
+static void
+awe_init_fm(void)
+{
+#ifndef AWE_ALWAYS_INIT_FM
+ /* if no extended memory is on board.. */
+ if (awe_mem_size <= 0)
+ return;
+#endif
+ DEBUG(0,printk("AWE32: initializing FM\n"));
+
+ /* Initialize the last two channels for DRAM refresh and producing
+ the reverb and chorus effects for Yamaha OPL-3 synthesizer */
+
+ awe_poke( AWE_DCYSUSV(30) , 0x0080);
+ awe_poke_dw(AWE_PSST(30) , 0xFFFFFFE0);
+ awe_poke_dw(AWE_CSL(30) , 0xFFFFFFE8);
+ awe_poke_dw(AWE_PTRX(30) , 0x00FFFF00);
+ awe_poke_dw(AWE_CPF(30) , 0x00000000);
+ awe_poke_dw(AWE_CCCA(30) , 0x00FFFFE3);
+
+ awe_poke( AWE_DCYSUSV(31) , 0x0080);
+ awe_poke_dw(AWE_PSST(31) , 0x00FFFFE0);
+ awe_poke_dw(AWE_CSL(31) , 0xFFFFFFE8);
+ awe_poke_dw(AWE_PTRX(31) , 0x00FFFF00);
+ awe_poke_dw(AWE_CPF(31) , 0x00000000);
+ awe_poke_dw(AWE_CCCA(31) , 0x00FFFFE3);
+
+ /* Timing loop */
+
+ /* PTRX is 32 bit long but do not write to the MS byte */
+ awe_poke(AWE_PTRX(30) , 0x0000);
+
+ while(! (inw(awe_base-0x620+Pointer) & 0x1000));
+ while( inw(awe_base-0x620+Pointer) & 0x1000);
+
+ /* now write the MS byte of PTRX */
+ OUTW(0x4828, awe_base-0x620+Data0+0x002);
+
+ awe_poke( AWE_IFATN(28) , 0x0000);
+ awe_poke_dw(AWE_VTFT(30) , 0x8000FFFF);
+ awe_poke_dw(AWE_VTFT(31) , 0x8000FFFF);
+
+ /* change maximum channels to 30 */
+ awe_max_voices = AWE_NORMAL_VOICES;
+ awe_info.nr_voices = awe_max_voices;
+ voice_alloc->max_voice = awe_max_voices;
+}
+
+/*
+ * AWE32 DRAM access routines
+ */
+
+/* open DRAM write accessing mode */
+static int
+awe_open_dram_for_write(int offset)
+{
+ int i;
+
+ /* use all channels for DMA transfer */
+ for (i = 0; i < AWE_NORMAL_VOICES; i++) {
+ awe_poke(AWE_DCYSUSV(i), 0x80);
+ awe_poke_dw(AWE_VTFT(i), 0);
+ awe_poke_dw(AWE_CVCF(i), 0);
+ awe_poke_dw(AWE_PTRX(i), 0x40000000);
+ awe_poke_dw(AWE_CPF(i), 0x40000000);
+ awe_poke_dw(AWE_PSST(i), 0);
+ awe_poke_dw(AWE_CSL(i), 0);
+ awe_poke_dw(AWE_CCCA(i), 0x06000000);
+ }
+ /* point channels 31 & 32 to ROM samples for DRAM refresh */
+ awe_poke_dw(AWE_VTFT(30), 0);
+ awe_poke_dw(AWE_PSST(30), 0x1d8);
+ awe_poke_dw(AWE_CSL(30), 0x1e0);
+ awe_poke_dw(AWE_CCCA(30), 0x1d8);
+ awe_poke_dw(AWE_VTFT(31), 0);
+ awe_poke_dw(AWE_PSST(31), 0x1d8);
+ awe_poke_dw(AWE_CSL(31), 0x1e0);
+ awe_poke_dw(AWE_CCCA(31), 0x1d8);
+
+ /* if full bit is on, not ready to write on */
+ if (awe_peek_dw(AWE_SMALW) & 0x80000000) {
+ for (i = 0; i < AWE_NORMAL_VOICES; i++)
+ awe_poke_dw(AWE_CCCA(i), 0);
+ return RET_ERROR(ENOSPC);
+ }
+
+ /* set address to write */
+ awe_poke_dw(AWE_SMALW, offset + AWE_DRAM_OFFSET);
+
+ return 0;
+}
+
+/* open DRAM for RAM size detection */
+static void
+awe_open_dram_for_check(void)
+{
+ int k;
+ unsigned long scratch;
+
+ awe_poke(AWE_HWCF2 , 0x0020);
+
+ for (k = 0; k < AWE_NORMAL_VOICES; k++) {
+ awe_poke(AWE_DCYSUSV(k), 0x0080);
+ awe_poke_dw(AWE_VTFT(k), 0x00000000);
+ awe_poke_dw(AWE_CVCF(k), 0x00000000);
+ awe_poke_dw(AWE_PTRX(k), 0x40000000);
+ awe_poke_dw(AWE_CPF(k), 0x40000000);
+ awe_poke_dw(AWE_PSST(k), 0x00000000);
+ awe_poke_dw(AWE_CSL(k), 0x00000000);
+ scratch = (((k&1) << 9) + 0x400);
+ scratch = scratch << 16;
+ awe_poke_dw(AWE_CCCA(k), scratch);
+ }
+}
+
+
+/* close dram access */
+static void
+awe_close_dram(void)
+{
+ int i;
+ /* wait until FULL bit in SMAxW register be false */
+ for (i = 0; i < 10000; i++) {
+ if (!(awe_peek_dw(AWE_SMALW) & 0x80000000))
+ break;
+ awe_wait(10);
+ }
+
+ for (i = 0; i < AWE_NORMAL_VOICES; i++) {
+ awe_poke_dw(AWE_CCCA(i), 0);
+ awe_poke(AWE_DCYSUSV(i), 0x807F);
+ }
+}
+
+
+#ifdef AWE_CHECKSUM_MEMORY
+/* open DRAM read accessing mode */
+static int
+awe_open_dram_for_read(int offset)
+{
+ int i;
+
+ /* use all channels for DMA transfer */
+ for (i = 0; i < AWE_NORMAL_VOICES; i++) {
+ awe_poke(AWE_DCYSUSV(i), 0x80);
+ awe_poke_dw(AWE_VTFT(i), 0);
+ awe_poke_dw(AWE_CVCF(i), 0);
+ awe_poke_dw(AWE_PTRX(i), 0x40000000);
+ awe_poke_dw(AWE_CPF(i), 0x40000000);
+ awe_poke_dw(AWE_PSST(i), 0);
+ awe_poke_dw(AWE_CSL(i), 0);
+ awe_poke_dw(AWE_CCCA(i), 0x04000000);
+ }
+ /* point channels 31 & 32 to ROM samples for DRAM refresh */
+ awe_poke_dw(AWE_VTFT(30), 0);
+ awe_poke_dw(AWE_PSST(30), 0x1d8);
+ awe_poke_dw(AWE_CSL(30), 0x1e0);
+ awe_poke_dw(AWE_CCCA(30), 0x1d8);
+ awe_poke_dw(AWE_VTFT(31), 0);
+ awe_poke_dw(AWE_PSST(31), 0x1d8);
+ awe_poke_dw(AWE_CSL(31), 0x1e0);
+ awe_poke_dw(AWE_CCCA(31), 0x1d8);
+
+ /* if empty flag is on, not ready to read */
+ if (awe_peek_dw(AWE_SMALR) & 0x80000000) {
+ for (i = 0; i < AWE_NORMAL_VOICES; i++)
+ awe_poke_dw(AWE_CCCA(i), 0);
+ return RET_ERROR(ENOSPC);
+ }
+
+ /* set address to read */
+ awe_poke_dw(AWE_SMALR, offset + AWE_DRAM_OFFSET);
+ /* drop stale data */
+ awe_peek(AWE_SMLD);
+ return 0;
+}
+
+/* close dram access for read */
+static void
+awe_close_dram_for_read(void)
+{
+ int i;
+ /* wait until FULL bit in SMAxW register be false */
+ for (i = 0; i < 10000; i++) {
+ if (!(awe_peek_dw(AWE_SMALR) & 0x80000000))
+ break;
+ awe_wait(10);
+ }
+ for (i = 0; i < AWE_NORMAL_VOICES; i++) {
+ awe_poke_dw(AWE_CCCA(i), 0);
+ awe_poke(AWE_DCYSUSV(i), 0x807F);
+ }
+}
+#endif /* AWE_CHECKSUM_MEMORY */
+
+
+/* write a word data */
+static void
+awe_write_dram(unsigned short c)
+{
+ int k;
+ /* wait until FULL bit in SMAxW register be false */
+ for (k = 0; k < 10000; k++) {
+ if (!(awe_peek_dw(AWE_SMALW) & 0x80000000))
+ break;
+ awe_wait(10);
+ }
+ awe_poke(AWE_SMLD, c);
+}
+
+/*================================================================
+ * detect presence of AWE32 and check memory size
+ *================================================================*/
+
+static int
+awe_detect(void)
+{
+#ifdef AWE_DEFAULT_BASE_ADDR
+ awe_base = AWE_DEFAULT_BASE_ADDR;
+ if (((awe_peek(AWE_U1) & 0x000F) == 0x000C) &&
+ ((awe_peek(AWE_HWCF1) & 0x007E) == 0x0058) &&
+ ((awe_peek(AWE_HWCF2) & 0x0003) == 0x0003))
+ return 1;
+#endif
+ if (awe_base == 0) {
+ for (awe_base = 0x620; awe_base <= 0x680; awe_base += 0x20) {
+ if ((awe_peek(AWE_U1) & 0x000F) != 0x000C)
+ continue;
+ if ((awe_peek(AWE_HWCF1) & 0x007E) != 0x0058)
+ continue;
+ if ((awe_peek(AWE_HWCF2) & 0x0003) != 0x0003)
+ continue;
+ DEBUG(0,printk("AWE32 found at %x\n", awe_base));
+ return 1;
+ }
+ }
+ FATALERR(printk("AWE32 not found\n"));
+ awe_base = 0;
+ return 0;
+}
+
+
+/*================================================================
+ * check dram size on AWE board
+ *================================================================*/
+static int
+awe_check_dram(void)
+{
+ awe_open_dram_for_check();
+
+ awe_poke_dw(AWE_SMALW , 0x00200000); /* DRAM start address */
+ awe_poke( AWE_SMLD , 0x1234);
+ awe_poke( AWE_SMLD , 0x7777);
+
+ awe_mem_size = 0;
+ while (awe_mem_size < 28*1024) { /* 28 MB is max onboard memory */
+ awe_wait(2);
+ awe_poke_dw(AWE_SMALR, 0x00200000); /* Address for reading */
+ awe_peek(AWE_SMLD); /* Discard stale data */
+ if (awe_peek(AWE_SMLD) != 0x1234)
+ break;
+ if (awe_peek(AWE_SMLD) != 0x7777)
+ break;
+ awe_mem_size += 32;
+ /* Address for writing */
+ awe_poke_dw(AWE_SMALW, 0x00200000+awe_mem_size*512L);
+ awe_poke(AWE_SMLD, 0xFFFF);
+ }
+ awe_close_dram();
+
+ DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", (int)awe_mem_size));
+#ifdef AWE_DEFAULT_MEM_SIZE
+ if (awe_mem_size == 0)
+ awe_mem_size = AWE_DEFAULT_MEM_SIZE;
+#endif
+ /* convert to Kbytes */
+ awe_mem_size *= 1024;
+ return awe_mem_size;
+}
+
+
+/*================================================================
+ * chorus and reverb controls
+ *================================================================*/
+
+static unsigned short ChorusEffects[24] =
+{
+ 0xE600,0x03F6,0xBC2C,0xE608,0x031A,0xBC6E,0xE610,0x031A,
+ 0xBC84,0xE620,0x0269,0xBC6E,0xE680,0x04D3,0xBCA6,0xE6E0,
+ 0x044E,0xBC37,0xE600,0x0B06,0xBC00,0xE6C0,0x0B06,0xBC00
+};
+
+static unsigned long ChorusEffects2[] =
+{
+ 0x0000 ,0x006D,0x8000,0x0000,0x0000 ,0x017C,0x8000,0x0000,
+ 0x0000 ,0x0083,0x8000,0x0000,0x0000 ,0x017C,0x8000,0x0000,
+ 0x0000 ,0x005B,0x8000,0x0000,0x0000 ,0x0026,0x8000,0x0000,
+ 0x6E000,0x0083,0x8000,0x0000,0x6E000,0x0083,0x8000,0x0000
+};
+
+static unsigned short ChorusCommand[14] =
+{
+ 0x69,0xA20,0x6C,0xA20,0x63,0xA22,0x29,
+ 0xA20,0x2A,0xA20,0x2D,0xA20,0x2E,0xA20
+};
+
+static unsigned short ReverbEffects[224] =
+{
+ /* Room 1 */
+ 0xB488,0xA450,0x9550,0x84B5,0x383A,0x3EB5,0x72F4,
+ 0x72A4,0x7254,0x7204,0x7204,0x7204,0x4416,0x4516,
+ 0xA490,0xA590,0x842A,0x852A,0x842A,0x852A,0x8429,
+ 0x8529,0x8429,0x8529,0x8428,0x8528,0x8428,0x8528,
+ /* Room 2 */
+ 0xB488,0xA458,0x9558,0x84B5,0x383A,0x3EB5,0x7284,
+ 0x7254,0x7224,0x7224,0x7254,0x7284,0x4448,0x4548,
+ 0xA440,0xA540,0x842A,0x852A,0x842A,0x852A,0x8429,
+ 0x8529,0x8429,0x8529,0x8428,0x8528,0x8428,0x8528,
+ /* Room 3 */
+ 0xB488,0xA460,0x9560,0x84B5,0x383A,0x3EB5,0x7284,
+ 0x7254,0x7224,0x7224,0x7254,0x7284,0x4416,0x4516,
+ 0xA490,0xA590,0x842C,0x852C,0x842C,0x852C,0x842B,
+ 0x852B,0x842B,0x852B,0x842A,0x852A,0x842A,0x852A,
+ /* Hall 1 */
+ 0xB488,0xA470,0x9570,0x84B5,0x383A,0x3EB5,0x7284,
+ 0x7254,0x7224,0x7224,0x7254,0x7284,0x4448,0x4548,
+ 0xA440,0xA540,0x842B,0x852B,0x842B,0x852B,0x842A,
+ 0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529,
+ /* Hall 2 */
+ 0xB488,0xA470,0x9570,0x84B5,0x383A,0x3EB5,0x7254,
+ 0x7234,0x7224,0x7254,0x7264,0x7294,0x44C3,0x45C3,
+ 0xA404,0xA504,0x842A,0x852A,0x842A,0x852A,0x8429,
+ 0x8529,0x8429,0x8529,0x8428,0x8528,0x8428,0x8528,
+ /* Plate */
+ 0xB4FF,0xA470,0x9570,0x84B5,0x383A,0x3EB5,0x7234,
+ 0x7234,0x7234,0x7234,0x7234,0x7234,0x4448,0x4548,
+ 0xA440,0xA540,0x842A,0x852A,0x842A,0x852A,0x8429,
+ 0x8529,0x8429,0x8529,0x8428,0x8528,0x8428,0x8528,
+ /* Delay */
+ 0xB4FF,0xA470,0x9500,0x84B5,0x333A,0x39B5,0x7204,
+ 0x7204,0x7204,0x7204,0x7204,0x72F4,0x4400,0x4500,
+ 0xA4FF,0xA5FF,0x8420,0x8520,0x8420,0x8520,0x8420,
+ 0x8520,0x8420,0x8520,0x8420,0x8520,0x8420,0x8520,
+ /* Panning Delay */
+ 0xB4FF,0xA490,0x9590,0x8474,0x333A,0x39B5,0x7204,
+ 0x7204,0x7204,0x7204,0x7204,0x72F4,0x4400,0x4500,
+ 0xA4FF,0xA5FF,0x8420,0x8520,0x8420,0x8520,0x8420,
+ 0x8520,0x8420,0x8520,0x8420,0x8520,0x8420,0x8520
+};
+
+static unsigned short ReverbCommand[56] =
+{
+ 0x43,0xA20,0x45,0xA20,0x7F,0xA22,0x47,0xA20,
+ 0x54,0xA22,0x56,0xA22,0x4F,0xA20,0x57,0xA20,
+ 0x5F,0xA20,0x47,0xA22,0x4F,0xA22,0x57,0xA22,
+ 0x5D,0xA22,0x5F,0xA22,0x61,0xA20,0x63,0xA20,
+ 0x49,0xA20,0x4B,0xA20,0x51,0xA20,0x53,0xA20,
+ 0x59,0xA20,0x5B,0xA20,0x41,0xA22,0x43,0xA22,
+ 0x49,0xA22,0x4B,0xA22,0x51,0xA22,0x53,0xA22
+};
+
+static void awe_set_chorus_mode(int effect)
+{
+ int k;
+ DECL_INTR_FLAGS(flags);
+
+ DISABLE_INTR(flags);
+ for (k = 0; k < 3; k++)
+ awe_poke(ChorusCommand[k*2],
+ ChorusCommand[k*2+1],
+ ChorusEffects[k+effect*3]);
+ for (k = 0; k < 4; k++)
+ awe_poke_dw(ChorusCommand[6+k*2],
+ ChorusCommand[6+k*2+1],
+ ChorusEffects2[k+effect*4]);
+ RESTORE_INTR(flags);
+}
+
+static void awe_set_reverb_mode(int effect)
+{
+ int k;
+ DECL_INTR_FLAGS(flags);
+
+ DISABLE_INTR(flags);
+ for (k = 0; k < 28; k++)
+ awe_poke(ReverbCommand[k*2],
+ ReverbCommand[k*2+1],
+ ReverbEffects[k+effect*28]);
+ RESTORE_INTR(flags);
+}
+
+#endif /* CONFIG_AWE32_SYNTH */
* lowlevel/init.c - Calls initialization code for configured drivers.
*/
+#include "lowlevel.h"
#include <linux/config.h>
+#include "../soundvers.h"
#ifdef CONFIG_LOWLEVEL_SOUND
+
+#ifdef LOWLEVEL_MODULE
+char *lowlevel_version = SOUND_VERSION_STRING;
+#endif
+
extern int attach_aci(void);
extern void unload_aci(void);
+extern int attach_awe(void);
+extern void unload_awe(void);
+
+/*
+ * There are two places where you can insert initialization calls of
+ * low level drivers. sound_init_lowlevel_drivers() is called after
+ * the sound driver has been initialized (the normal case)
+ * while sound_preinit_lowlevel_drivers() is called before that.
+ */
+void
+sound_preinit_lowlevel_drivers(void)
+{
+}
void
sound_init_lowlevel_drivers(void)
#ifdef CONFIG_ACI_MIXER
attach_aci();
#endif
+
+#ifdef CONFIG_AWE32_SYNTH
+ attach_awe();
+#endif
}
void
#ifdef CONFIG_ACI_MIXER
unload_aci();
#endif
+
+#ifdef CONFIG_AWE32_SYNTH
+ unload_awe();
+#endif
}
#endif
--- /dev/null
+#ifdef LOWLEVEL_MODULE
+#define MODVERSIONS
+#include <linux/modversions.h>
+#include "manual_config.h"
+#endif
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
* OAK OTI-601D Mozart
* OPTi 82C929 MAD16 Pro
* OPTi 82C930
+ * OPTi 82C924 (in non PnP mode)
*
* These audio interface chips don't produce sound themselves. They just
* connect some other components (OPL-[234] and a WSS compatible codec)
*
* CD-ROM port: 0x00=340, 0x40=330, 0x80=360 or 0xc0=320
* OPL4 select: 0x20=OPL4, 0x00=OPL3
- * CD-ROM irq: 0x00=disabled, 0x04=IRQ5, 0x08=IRQ7, 0x0a=IRQ3, 0x10=IRQ9,
+ * CD-ROM irq: 0x00=disabled, 0x04=IRQ5, 0x08=IRQ7, 0x0c=IRQ3, 0x10=IRQ9,
* 0x14=IRQ10 and 0x18=IRQ11.
*
* CD-ROM DMA (Sony or Panasonic): 0x00=DMA3, 0x01=DMA2, 0x02=DMA1 or 0x03=disabled
#define MOZART 2
#define C929 3
#define C930 4
+#define C924 5
/*
* Registers
{
case C928:
case MOZART:
- outb (0xE2, PASSWD_REG);
+ outb ((0xE2), PASSWD_REG);
break;
case C929:
- outb (0xE3, PASSWD_REG);
+ outb ((0xE3), PASSWD_REG);
break;
case C930:
- /* outb( 0xE4, PASSWD_REG); */
+ /* outb(( 0xE4), PASSWD_REG); */
+ break;
+
+ case C924:
+ outb ((0xE5), PASSWD_REG);
break;
}
if (board_type == C930)
{
- outb (port - MC0_PORT, 0xe0e); /* Write to index reg */
+ outb ((port - MC0_PORT), 0xe0e); /* Write to index reg */
tmp = inb (0xe0f); /* Read from data reg */
}
else
{
case C928:
case MOZART:
- outb (0xE2, PASSWD_REG);
+ outb ((0xE2), PASSWD_REG);
break;
case C929:
- outb (0xE3, PASSWD_REG);
+ outb ((0xE3), PASSWD_REG);
break;
case C930:
- /* outb( 0xE4, PASSWD_REG); */
+ /* outb(( 0xE4), PASSWD_REG); */
+ break;
+
+ case C924:
+ outb ((0xE5), PASSWD_REG);
break;
}
if (board_type == C930)
{
- outb (port - MC0_PORT, 0xe0e); /* Write to index reg */
- outb ((unsigned char) (value & 0xff), 0xe0f);
+ outb ((port - MC0_PORT), 0xe0e); /* Write to index reg */
+ outb (((unsigned char) (value & 0xff)), 0xe0f);
}
else
- outb ((unsigned char) (value & 0xff), port);
+ outb (((unsigned char) (value & 0xff)), port);
restore_flags (flags);
}
/* MC2 is CD configuration. Don't touch it. */
mad_write (MC3_PORT, 0); /* Disable SB mode IRQ and DMA */
-
mad_write (MC4_PORT, 0x52); /* ??? */
- mad_write (MC5_PORT, 0x3D); /* Init it into mode2 */
+ mad_write (MC5_PORT, 0x3C); /* Init it into mode2 */
mad_write (MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */
mad_write (MC7_PORT, 0xCB);
mad_write (MC10_PORT, 0x11);
- if (!wss_init (hw_config))
- return 0;
-
-/*
- * A temporary kludge which drops the device back to mode1.
- * This removes problems with interrupts but disables full duplex.
- * A better solution should be introduced later.
- */
- mad_write (MC5_PORT, 0x1D); /* Disable mode2 */
return wss_init (hw_config);
}
-int
-probe_mad16 (struct address_info *hw_config)
+static int
+chip_detect (void)
{
int i;
- static int valid_ports[] =
- {0x530, 0xe80, 0xf40, 0x604};
- unsigned char tmp;
- unsigned char cs4231_mode = 0;
-
- int ad_flags = 0;
-
- if (already_initialized)
- return 0;
-
- mad16_osp = hw_config->osp;
-/*
- * Check that all ports return 0xff (bus float) when no password
- * is written to the password register.
- */
-
- DDB (printk ("--- Detecting MAD16 / Mozart ---\n"));
-
/*
* Then try to detect with the old password
*/
- board_type = C928;
+ board_type = C924;
- DDB (printk ("Detect using password = 0xE2\n"));
+ DDB (printk ("Detect using password = 0xE5\n"));
if (!detect_mad16 ()) /* No luck. Try different model */
{
- board_type = C929;
+ board_type = C928;
- DDB (printk ("Detect using password = 0xE3\n"));
+ DDB (printk ("Detect using password = 0xE2\n"));
if (!detect_mad16 ())
{
- if (inb (PASSWD_REG) != 0xff)
- return 0;
+ board_type = C929;
+
+ DDB (printk ("Detect using password = 0xE3\n"));
+
+ if (!detect_mad16 ())
+ {
+ if (inb (PASSWD_REG) != 0xff)
+ return 0;
/*
* First relocate MC# registers to 0xe0e/0xe0f, disable password
*/
- outb (0xE4, PASSWD_REG);
- outb (0x80, PASSWD_REG);
+ outb ((0xE4), PASSWD_REG);
+ outb ((0x80), PASSWD_REG);
- board_type = C930;
+ board_type = C930;
- DDB (printk ("Detect using password = 0xE4\n"));
+ DDB (printk ("Detect using password = 0xE4\n"));
- for (i = 0xf8d; i <= 0xf93; i++)
- DDB (printk ("port %03x = %02x\n", i, mad_read (i)));
+ for (i = 0xf8d; i <= 0xf93; i++)
+ DDB (printk ("port %03x = %02x\n", i, mad_read (i)));
- if (!detect_mad16 ())
- return 0;
+ if (!detect_mad16 ())
+ return 0;
- DDB (printk ("mad16.c: 82C930 detected\n"));
- return init_c930 (hw_config);
+ DDB (printk ("mad16.c: 82C930 detected\n"));
+ }
+ else
+ {
+ DDB (printk ("mad16.c: 82C929 detected\n"));
+ }
}
else
{
- DDB (printk ("mad16.c: 82C929 detected\n"));
+ unsigned char model;
+
+ if (((model = mad_read (MC3_PORT)) & 0x03) == 0x03)
+ {
+ DDB (printk ("mad16.c: Mozart detected\n"));
+ board_type = MOZART;
+ }
+ else
+ {
+ DDB (printk ("mad16.c: 82C928 detected???\n"));
+ board_type = C928;
+ }
}
}
- else
- {
- unsigned char model;
- if (((model = mad_read (MC3_PORT)) & 0x03) == 0x03)
- {
- DDB (printk ("mad16.c: Mozart detected\n"));
- board_type = MOZART;
- }
- else
- {
- DDB (printk ("mad16.c: 82C928 detected???\n"));
- board_type = C928;
- }
- }
+ return 1;
+}
+
+int
+probe_mad16 (struct address_info *hw_config)
+{
+ int i;
+ static int valid_ports[] =
+ {0x530, 0xe80, 0xf40, 0x604};
+ unsigned char tmp;
+ unsigned char cs4231_mode = 0;
+
+ int ad_flags = 0;
+
+ if (already_initialized)
+ return 0;
+
+ mad16_osp = hw_config->osp;
+/*
+ * Check that all ports return 0xff (bus float) when no password
+ * is written to the password register.
+ */
+
+ DDB (printk ("--- Detecting MAD16 / Mozart ---\n"));
+ if (!chip_detect ())
+ return 0;
+
+ if (board_type == C930)
+ return init_c930 (hw_config);
+
for (i = 0xf8d; i <= 0xf93; i++)
DDB (printk ("port %03x = %02x\n", i, mad_read (i)));
* Set the WSS address
*/
- tmp = 0x80; /* Enable WSS, Disable SB */
+ tmp = (mad_read (MC1_PORT) & 0x0f) | 0x80; /* Enable WSS, Disable SB */
for (i = 0; i < 5; i++)
{
*/
#ifdef MAD16_CONF
+ tmp &= ~0x0f;
tmp |= ((MAD16_CONF) & 0x0f); /* CD-ROM and joystick bits */
#endif
mad_write (MC1_PORT, tmp);
#if defined(MAD16_CONF) && defined(MAD16_CDSEL)
tmp = MAD16_CDSEL;
#else
- tmp = 0x03;
+ tmp = mad_read (MC2_PORT);
#endif
#ifdef MAD16_OPL4
mad_write (MC2_PORT, tmp);
mad_write (MC3_PORT, 0xf0); /* Disable SB */
+ if (board_type == C924) /* Specific C924 init values */
+ {
+ mad_write (MC4_PORT, 0xA0);
+ mad_write (MC5_PORT, 0x05);
+ mad_write (MC6_PORT, 0x03);
+ }
+
if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, mad16_osp))
return 0;
/*
* Set the IRQ and DMA addresses.
*/
+ if (board_type == C930)
+ interrupt_bits[5] = 0x28; /* Also IRQ5 is possible on C930 */
bits = interrupt_bits[hw_config->irq];
if (bits == -1)
return;
- outb (bits | 0x40, config_port);
+ outb ((bits | 0x40), config_port);
if ((inb (version_port) & 0x40) == 0)
printk ("[IRQ Conflict?]");
else
dma2 = dma;
- outb (bits | dma_bits[dma] | dma2_bit, config_port); /* Write IRQ+DMA setup */
+ outb ((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */
ad1848_init ("MAD16 WSS", hw_config->io_base + 4,
hw_config->irq,
}
#endif
-#if (defined(CONFIG_UART401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
unload_uart401 (hw_config);
#endif
}
+
+
/* That's all folks */
#endif
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#endif
-static wait_handle *maui_sleeper = NULL;
+static struct wait_queue *maui_sleeper = NULL;
static volatile struct snd_wait maui_sleep_flag =
{0};
unsigned long tlimit;
if (HZ / 10)
- current_set_timeout (tlimit = jiffies + (HZ / 10));
+ current->timeout = tlimit = jiffies + (HZ / 10);
else
tlimit = (unsigned long) -1;
- maui_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&maui_sleeper);
- if (!(maui_sleep_flag.flags & WK_WAKEUP))
+ maui_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&maui_sleeper);
+ if (!(maui_sleep_flag.opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- maui_sleep_flag.flags |= WK_TIMEOUT;
+ maui_sleep_flag.opts |= WK_TIMEOUT;
}
- maui_sleep_flag.flags &= ~WK_SLEEP;
+ maui_sleep_flag.opts &= ~WK_SLEEP;
};
- if (current_got_fatal_signal ())
- return 0;
+ if ((current->signal & ~current->blocked))
+ {
+ return 0;
+ }
}
return 0;
{
if (maui_wait (STAT_TX_AVAIL))
{
- outb (data, HOST_DATA_PORT);
+ outb ((data), HOST_DATA_PORT);
return 1;
}
printk ("Maui: Write timeout\n");
return 0;
}
- outb (0x00, HOST_CTRL_PORT); /* Reset */
+ outb ((0x00), HOST_CTRL_PORT); /* Reset */
- outb (bits, HOST_DATA_PORT); /* Set the IRQ bits */
- outb (bits | 0x80, HOST_DATA_PORT); /* Set the IRQ bits again? */
+ outb ((bits), HOST_DATA_PORT); /* Set the IRQ bits */
+ outb ((bits | 0x80), HOST_DATA_PORT); /* Set the IRQ bits again? */
- outb (0x80, HOST_CTRL_PORT); /* Leave reset */
- outb (0x80, HOST_CTRL_PORT); /* Leave reset */
+ outb ((0x80), HOST_CTRL_PORT); /* Leave reset */
+ outb ((0x80), HOST_CTRL_PORT); /* Leave reset */
- outb (0xD0, HOST_CTRL_PORT); /* Cause interrupt */
+ outb ((0xD0), HOST_CTRL_PORT); /* Cause interrupt */
for (i = 0; i < 1000000 && !irq_ok; i++);
if (!irq_ok)
return 0;
- outb (0x80, HOST_CTRL_PORT); /* Leave reset */
+ outb ((0x80), HOST_CTRL_PORT); /* Leave reset */
printk ("Turtle Beach Maui initialization\n");
if (!download_code ())
return 0;
- outb (0xE0, HOST_CTRL_PORT); /* Normal operation */
+ outb ((0xE0), HOST_CTRL_PORT); /* Normal operation */
/* Select mpu401 mode */
if (count < hdr_size)
{
printk ("Maui error: Patch header too short\n");
- return -(EINVAL);
+ return -EINVAL;
}
count -= hdr_size;
{
unsigned char data;
- data = get_fs_byte (&((addr)[hdr_size + i]));
+ get_user (data, (unsigned char *) &((addr)[hdr_size + i]));
if (i == 0 && !(data & 0x80))
- return -(EINVAL);
+ return -EINVAL;
if (maui_write (data) == -1)
- return -(EIO);
+ return -EIO;
}
if ((i = maui_read ()) != 0x80)
if (i != -1)
printk ("Maui: Error status %02x\n", i);
- return -(EIO);
+ return -EIO;
}
return 0;
if (snd_set_irq_handler (hw_config->irq, mauiintr, "Maui", maui_osp) < 0)
return 0;
- maui_sleep_flag.flags = WK_NONE;
+ maui_sleep_flag.opts = WK_NONE;
/*
* Initialize the processor if necessary
*/
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#define _MIDI_SYNTH_C_
-static wait_handle *sysex_sleeper = NULL;
+static struct wait_queue *sysex_sleeper = NULL;
static volatile struct snd_wait sysex_sleep_flag =
{0};
{
int timeout;
- for (timeout = 0; timeout < 32000; timeout++)
- if (midi_devs[midi_dev]->putc (midi_dev, (unsigned char) (data & 0xff)))
+ for (timeout = 0; timeout < 3200; timeout++)
+ if (midi_devs[midi_dev]->outputc (midi_dev, (unsigned char) (data & 0xff)))
{
if (data & 0x80) /*
* Status byte
sysex_state[dev] = 0;
- while (!midi_devs[orig_dev]->putc (orig_dev, 0xf7) &&
+ while (!midi_devs[orig_dev]->outputc (orig_dev, 0xf7) &&
timeout < 1000)
timeout++;
{
case SNDCTL_SYNTH_INFO:
- copy_to_user (&((char *) arg)[0], synth_devs[dev]->info, sizeof (struct synth_info));
+ {
+ char *fixit = (char *) synth_devs[dev]->info;
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (struct synth_info));
+ };
return 0;
break;
break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
}
int orig_dev = synth_devs[dev]->midi_dev;
if (instr_no < 0 || instr_no > 127)
- return 0;
+ instr_no = 0;
if (channel < 0 || channel > 15)
return 0;
struct midi_input_info *inc;
if (orig_dev < 0 || orig_dev > num_midis)
- return -(ENXIO);
+ return -ENXIO;
midi2synth[orig_dev] = dev;
sysex_state[dev] = 0;
inc->m_prev_status = 0x00;
restore_flags (flags);
- sysex_sleep_flag.flags = WK_NONE;
+ sysex_sleep_flag.opts = WK_NONE;
return 1;
}
/*
* Shut up the synths by sending just single active sensing message.
*/
- midi_devs[orig_dev]->putc (orig_dev, 0xfe);
+ midi_devs[orig_dev]->outputc (orig_dev, 0xfe);
midi_devs[orig_dev]->close (orig_dev);
}
if (format != SYSEX_PATCH)
{
printk ("MIDI Error: Invalid patch format (key) 0x%x\n", format);
- return -(EINVAL);
+ return -EINVAL;
}
if (count < hdr_size)
{
printk ("MIDI Error: Patch header too short\n");
- return -(EINVAL);
+ return -EINVAL;
}
count -= hdr_size;
left = sysex.len;
src_offs = 0;
- sysex_sleep_flag.flags = WK_NONE;
+ sysex_sleep_flag.opts = WK_NONE;
- for (i = 0; i < left && !current_got_fatal_signal (); i++)
+ for (i = 0; i < left && !(current->signal & ~current->blocked); i++)
{
unsigned char data;
- data = get_fs_byte (&((addr)[hdr_size + i]));
+ get_user (data, (unsigned char *) &((addr)[hdr_size + i]));
eox_seen = (i > 0 && data & 0x80); /* End of sysex */
if (data != 0xf0)
{
printk ("Error: Sysex start missing\n");
- return -(EINVAL);
+ return -EINVAL;
}
}
- while (!midi_devs[orig_dev]->putc (orig_dev, (unsigned char) (data & 0xff)) &&
- !current_got_fatal_signal ())
+ while (!midi_devs[orig_dev]->outputc (orig_dev, (unsigned char) (data & 0xff)) &&
+ !(current->signal & ~current->blocked))
{
unsigned long tlimit;
if (1)
- current_set_timeout (tlimit = jiffies + (1));
+ current->timeout = tlimit = jiffies + (1);
else
tlimit = (unsigned long) -1;
- sysex_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&sysex_sleeper);
- if (!(sysex_sleep_flag.flags & WK_WAKEUP))
+ sysex_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&sysex_sleeper);
+ if (!(sysex_sleep_flag.opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- sysex_sleep_flag.flags |= WK_TIMEOUT;
+ sysex_sleep_flag.opts |= WK_TIMEOUT;
}
- sysex_sleep_flag.flags &= ~WK_SLEEP;
+ sysex_sleep_flag.opts &= ~WK_SLEEP;
}; /* Wait for timeout */
if (!first_byte && data & 0x80)
int
midi_synth_patchmgr (int dev, struct patmgr_info *rec)
{
- return -(EINVAL);
+ return -EINVAL;
}
void
}
}
- if (!midi_devs[orig_dev]->putc (orig_dev, bytes[i]))
+ if (!midi_devs[orig_dev]->outputc (orig_dev, bytes[i]))
{
/*
* Hardware level buffer is full. Abort the sysex message.
bytes[i] = 0xf7;
sysex_state[dev] = 0;
- while (!midi_devs[orig_dev]->putc (orig_dev, bytes[i]) &&
+ while (!midi_devs[orig_dev]->outputc (orig_dev, bytes[i]) &&
timeout < 1000)
timeout++;
}
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#define MAX_QUEUE_SIZE 4000
-static wait_handle *midi_sleeper[MAX_MIDI_DEV] =
+static struct wait_queue *midi_sleeper[MAX_MIDI_DEV] =
{NULL};
static volatile struct snd_wait midi_sleep_flag[MAX_MIDI_DEV] =
{
{0}};
-static wait_handle *input_sleeper[MAX_MIDI_DEV] =
+static struct wait_queue *input_sleeper[MAX_MIDI_DEV] =
{NULL};
static volatile struct snd_wait input_sleep_flag[MAX_MIDI_DEV] =
{
if (SPACE_AVAIL(q)) \
{ \
unsigned long flags; \
- save_flags(flags);cli(); \
+ save_flags( flags);cli(); \
q->queue[q->tail] = (data); \
q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \
restore_flags(flags); \
if (DATA_AVAIL(q)) \
{ \
unsigned long flags; \
- save_flags(flags);cli(); \
+ save_flags( flags);cli(); \
data = q->queue[q->head]; \
q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \
restore_flags(flags); \
*/
if (midi_devs[dev]->buffer_status != NULL)
- while (!current_got_fatal_signal () &&
+ while (!(current->signal & ~current->blocked) &&
midi_devs[dev]->buffer_status (dev))
{
unsigned long tlimit;
if (HZ / 10)
- current_set_timeout (tlimit = jiffies + (HZ / 10));
+ current->timeout = tlimit = jiffies + (HZ / 10);
else
tlimit = (unsigned long) -1;
- midi_sleep_flag[dev].flags = WK_SLEEP;
- module_interruptible_sleep_on (&midi_sleeper[dev]);
- if (!(midi_sleep_flag[dev].flags & WK_WAKEUP))
+ midi_sleep_flag[dev].opts = WK_SLEEP;
+ interruptible_sleep_on (&midi_sleeper[dev]);
+ if (!(midi_sleep_flag[dev].opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- midi_sleep_flag[dev].flags |= WK_TIMEOUT;
+ midi_sleep_flag[dev].opts |= WK_TIMEOUT;
}
- midi_sleep_flag[dev].flags &= ~WK_SLEEP;
+ midi_sleep_flag[dev].opts &= ~WK_SLEEP;
};
}
if (SPACE_AVAIL (midi_in_buf[dev]))
{
QUEUE_BYTE (midi_in_buf[dev], data);
- if ((input_sleep_flag[dev].flags & WK_SLEEP))
+ if ((input_sleep_flag[dev].opts & WK_SLEEP))
{
- input_sleep_flag[dev].flags = WK_WAKEUP;
- module_wake_up (&input_sleeper[dev]);
+ input_sleep_flag[dev].opts = WK_WAKEUP;
+ wake_up (&input_sleeper[dev]);
};
}
for (dev = 0; dev < num_midis; dev++)
if (midi_out_buf[dev] != NULL)
{
- while (DATA_AVAIL (midi_out_buf[dev]) &&
- midi_devs[dev]->putc (dev,
- midi_out_buf[dev]->queue[midi_out_buf[dev]->head]))
+ int ok = 1;
+
+ while (DATA_AVAIL (midi_out_buf[dev]) && ok)
{
+ int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head];
+
+ restore_flags (flags); /* Give some time to others */
+ ok = midi_devs[dev]->outputc (dev, c);
+ save_flags (flags);
+ cli ();
midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
midi_out_buf[dev]->len--;
}
if (DATA_AVAIL (midi_out_buf[dev]) < 100 &&
- (midi_sleep_flag[dev].flags & WK_SLEEP))
+ (midi_sleep_flag[dev].opts & WK_SLEEP))
{
- midi_sleep_flag[dev].flags = WK_WAKEUP;
- module_wake_up (&midi_sleeper[dev]);
+ midi_sleep_flag[dev].opts = WK_WAKEUP;
+ wake_up (&midi_sleeper[dev]);
};
}
if (dev < 0 || dev >= num_midis)
{
printk ("Sound: Nonexistent MIDI interface %d\n", dev);
- return -(ENXIO);
+ return -ENXIO;
}
/*
{
printk ("midi: Can't allocate buffer\n");
midi_devs[dev]->close (dev);
- return -(EIO);
+ return -EIO;
}
midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
midi_devs[dev]->close (dev);
vfree (midi_in_buf[dev]);
midi_in_buf[dev] = NULL;
- return -(EIO);
+ return -EIO;
}
midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
open_devs++;
- midi_sleep_flag[dev].flags = WK_NONE;
- input_sleep_flag[dev].flags = WK_NONE;
+ midi_sleep_flag[dev].opts = WK_NONE;
+ input_sleep_flag[dev].opts = WK_NONE;
if (open_devs < 2) /* This was first open */
{
if (mode != OPEN_READ)
{
- midi_devs[dev]->putc (dev, 0xfe); /*
+ midi_devs[dev]->outputc (dev, 0xfe); /*
* Active sensing to shut the
* devices
*/
- while (!current_got_fatal_signal () &&
+ while (!(current->signal & ~current->blocked) &&
DATA_AVAIL (midi_out_buf[dev]))
{
unsigned long tlimit;
if (0)
- current_set_timeout (tlimit = jiffies + (0));
+ current->timeout = tlimit = jiffies + (0);
else
tlimit = (unsigned long) -1;
- midi_sleep_flag[dev].flags = WK_SLEEP;
- module_interruptible_sleep_on (&midi_sleeper[dev]);
- if (!(midi_sleep_flag[dev].flags & WK_WAKEUP))
+ midi_sleep_flag[dev].opts = WK_SLEEP;
+ interruptible_sleep_on (&midi_sleeper[dev]);
+ if (!(midi_sleep_flag[dev].opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- midi_sleep_flag[dev].flags |= WK_TIMEOUT;
+ midi_sleep_flag[dev].opts |= WK_TIMEOUT;
}
- midi_sleep_flag[dev].flags &= ~WK_SLEEP;
+ midi_sleep_flag[dev].opts &= ~WK_SLEEP;
}; /*
* Sync
*/
unsigned long tlimit;
if (0)
- current_set_timeout (tlimit = jiffies + (0));
+ current->timeout = tlimit = jiffies + (0);
else
tlimit = (unsigned long) -1;
- midi_sleep_flag[dev].flags = WK_SLEEP;
- module_interruptible_sleep_on (&midi_sleeper[dev]);
- if (!(midi_sleep_flag[dev].flags & WK_WAKEUP))
+ midi_sleep_flag[dev].opts = WK_SLEEP;
+ interruptible_sleep_on (&midi_sleeper[dev]);
+ if (!(midi_sleep_flag[dev].opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- midi_sleep_flag[dev].flags |= WK_TIMEOUT;
+ midi_sleep_flag[dev].opts |= WK_TIMEOUT;
}
- midi_sleep_flag[dev].flags &= ~WK_SLEEP;
+ midi_sleep_flag[dev].opts &= ~WK_SLEEP;
};
- if (current_got_fatal_signal ())
+ if ((current->signal & ~current->blocked))
{
restore_flags (flags);
- return -(EINTR);
+ return -EINTR;
}
n = SPACE_AVAIL (midi_out_buf[dev]);
unsigned long tlimit;
if (parms[dev].prech_timeout)
- current_set_timeout (tlimit = jiffies + (parms[dev].prech_timeout));
+ current->timeout = tlimit = jiffies + (parms[dev].prech_timeout);
else
tlimit = (unsigned long) -1;
- input_sleep_flag[dev].flags = WK_SLEEP;
- module_interruptible_sleep_on (&input_sleeper[dev]);
- if (!(input_sleep_flag[dev].flags & WK_WAKEUP))
+ input_sleep_flag[dev].opts = WK_SLEEP;
+ interruptible_sleep_on (&input_sleeper[dev]);
+ if (!(input_sleep_flag[dev].opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- input_sleep_flag[dev].flags |= WK_TIMEOUT;
+ input_sleep_flag[dev].opts |= WK_TIMEOUT;
}
- input_sleep_flag[dev].flags &= ~WK_SLEEP;
+ input_sleep_flag[dev].opts &= ~WK_SLEEP;
};
- if (current_got_fatal_signal ())
- c = -(EINTR); /*
+ if ((current->signal & ~current->blocked))
+ c = -EINTR; /*
* The user is getting restless
*/
}
while (c < n)
{
REMOVE_BYTE (midi_in_buf[dev], tmp_data);
- copy_to_user (&(buf)[c], (char *) &tmp_data, 1);
+ {
+ char *fixit = (char *) &tmp_data;
+
+ copy_to_user (&(buf)[c], fixit, 1);
+ };
c++;
}
}
else
printk ("/dev/midi%d: No coprocessor for this device\n", dev);
- return -(ENXIO);
+ return -ENXIO;
}
else
switch (cmd)
{
case SNDCTL_MIDI_PRETIME:
- val = (int) get_user ((int *) arg);
+ get_user (val, (int *) arg);
if (val < 0)
val = 0;
val = (HZ * val) / 10;
parms[dev].prech_timeout = val;
- return snd_ioctl_return ((int *) arg, val);
+ return ioctl_out (arg, val);
break;
default:
}
int
-MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait)
+MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
{
dev = dev >> 4;
if (!DATA_AVAIL (midi_in_buf[dev]))
{
- input_sleep_flag[dev].flags = WK_SLEEP;
- module_select_wait (&input_sleeper[dev], wait);
+ input_sleep_flag[dev].opts = WK_SLEEP;
+ select_wait (&input_sleeper[dev], wait);
return 0;
}
return 1;
if (SPACE_AVAIL (midi_out_buf[dev]))
{
- midi_sleep_flag[dev].flags = WK_SLEEP;
- module_select_wait (&midi_sleeper[dev], wait);
+ midi_sleep_flag[dev].opts = WK_SLEEP;
+ select_wait (&midi_sleeper[dev], wait);
return 0;
}
return 1;
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
static int init_sequence[20]; /* NOTE! pos 0 = len, start pos 1. */
+
#ifdef CONFIG_SEQUENCER
static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL;
static void
write_command (struct mpu_config *devc, unsigned char cmd)
{
- outb (cmd, COMDPORT (devc->base));
+ outb ((cmd), COMDPORT (devc->base));
}
static int
read_data (struct mpu_config *devc)
static void
write_data (struct mpu_config *devc, unsigned char byte)
{
- outb (byte, DATAPORT (devc->base));
+ outb ((byte), DATAPORT (devc->base));
}
#define OUTPUT_READY 0x40
struct mpu_config *devc;
if (dev < 0 || dev >= num_midis)
- return -(ENXIO);
+ return -ENXIO;
devc = &dev_conf[dev];
if (devc->opened)
{
printk ("MPU-401: Midi busy\n");
- return -(EBUSY);
+ return -EBUSY;
}
/*
if (mpu401_status (devc) == 0xff) /* Bus float */
{
printk ("MPU-401: Device not initialized properly\n");
- return -(EIO);
+ return -EIO;
}
reset_mpu401 (devc);
}
*/
{
printk ("MPU-401 commands not possible in the UART mode\n");
- return -(EINVAL);
+ return -EINVAL;
}
/*
if (timeout-- <= 0)
{
printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd);
- return -(EIO);
+ return -EIO;
}
save_flags (flags);
{
restore_flags (flags);
/* printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */
- return -(EIO);
+ return -EIO;
}
if (cmd->nr_args)
{
restore_flags (flags);
printk ("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd);
- return -(EIO);
+ return -EIO;
}
}
{
restore_flags (flags);
/* printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); */
- return -(EIO);
+ return -EIO;
}
}
if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */
{
printk ("MPU-401: Intelligent mode not supported by the HW\n");
- return -(EINVAL);
+ return -EINVAL;
}
- set_uart_mode (dev, devc, !get_user ((int *) arg));
+ set_uart_mode (dev, devc, !ioctl_in (arg));
return 0;
break;
if ((ret = mpu401_command (dev, &rec)) < 0)
return ret;
- copy_to_user (&((char *) arg)[0], (char *) &rec, sizeof (rec));
+ {
+ char *fixit = (char *) &rec;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (rec));
+ };
return 0;
}
break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
}
midi_dev = synth_devs[dev]->midi_dev;
if (midi_dev < 0 || midi_dev > num_midis)
- return -(ENXIO);
+ return -ENXIO;
devc = &dev_conf[midi_dev];
{
case SNDCTL_SYNTH_INFO:
- copy_to_user (&((char *) arg)[0], &mpu_synth_info[midi_dev], sizeof (struct synth_info));
+ {
+ char *fixit = (char *) &mpu_synth_info[midi_dev];
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (struct synth_info));
+ };
return 0;
break;
break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
}
if (midi_dev < 0 || midi_dev > num_midis)
{
- return -(ENXIO);
+ return -ENXIO;
}
devc = &dev_conf[midi_dev];
if (mpu401_status (devc) == 0xff) /* Bus float */
{
printk ("MPU-401: Device not initialized properly\n");
- return -(EIO);
+ return -EIO;
}
reset_mpu401 (devc);
}
if (devc->opened)
{
printk ("MPU-401: Midi busy\n");
- return -(EBUSY);
+ return -EBUSY;
}
devc->mode = MODE_SYNTH;
int midi_dev = sound_timer_devs[dev]->devlink;
if (timer_open)
- return -(EBUSY);
+ return -EBUSY;
tmr_reset ();
curr_tempo = 50;
{
case SNDCTL_TMR_SOURCE:
{
- int parm = (int) get_user ((int *) arg) & timer_caps;
+ int parm;
+
+ get_user (parm, (int *) arg);
+ parm &= timer_caps;
if (parm != 0)
{
mpu_cmd (midi_dev, 0x3d, 0); /* Use SMPTE sync */
}
- return snd_ioctl_return ((int *) arg, timer_mode);
+ return ioctl_out (arg, timer_mode);
}
break;
case SNDCTL_TMR_TIMEBASE:
{
- int val = (int) get_user ((int *) arg);
+ int val = (int) ioctl_in (arg);
if (val)
set_timebase (midi_dev, val);
- return snd_ioctl_return ((int *) arg, curr_timebase);
+ return ioctl_out (arg, curr_timebase);
}
break;
case SNDCTL_TMR_TEMPO:
{
- int val = (int) get_user ((int *) arg);
+ int val = (int) ioctl_in (arg);
int ret;
if (val)
curr_tempo = val;
}
- return snd_ioctl_return ((int *) arg, curr_tempo);
+ return ioctl_out (arg, curr_tempo);
}
break;
case SNDCTL_SEQ_CTRLRATE:
- if (get_user ((int *) arg) != 0) /* Can't change */
- return -(EINVAL);
+ if (ioctl_in (arg) != 0) /* Can't change */
+ return -EINVAL;
+
+ return ioctl_out (arg, ((curr_tempo * curr_timebase) + 30) / 60);
+ break;
- return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60);
+ case SNDCTL_SEQ_GETTIME:
+ return ioctl_out (arg, curr_ticks);
break;
case SNDCTL_TMR_METRONOME:
- metronome_mode = (int) get_user ((int *) arg);
+ metronome_mode = (int) ioctl_in (arg);
setup_metronome (midi_dev);
return 0;
break;
default:;
}
- return -(EINVAL);
+ return -EINVAL;
}
static void
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
unsigned long current_freq;
int volume;
int mode;
+ int panning; /* 0xffff means not set */
};
typedef struct opl_devinfo
if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR)
{
printk ("FM Error: Invalid instrument number %d\n", ins.channel);
- return -(EINVAL);
+ return -EINVAL;
}
pmgr_inform (dev, PM_E_PATCH_LOADED, ins.channel, 0, 0, 0);
case SNDCTL_SYNTH_INFO:
devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice;
- copy_to_user (&((char *) arg)[0], &devc->fm_info, sizeof (devc->fm_info));
+ {
+ char *fixit = (char *) &devc->fm_info;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (devc->fm_info));
+ };
return 0;
break;
break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
}
* Note2! The chip is initialized if detected.
*/
- unsigned char stat1, stat2, signature;
+ unsigned char stat1, signature;
int i;
if (devc != NULL)
signature = stat1 = inb (ioaddr); /* Status register */
- if ((stat1 & 0xE0) != 0x00)
+ if (signature != 0x00 && signature != 0x06 && signature != 0x02)
{
- return 0; /*
- * Should be 0x00
- */
- }
-
- opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* Set timer1 to 0xff */
-
- opl3_command (ioaddr, TIMER_CONTROL_REGISTER,
- TIMER2_MASK | TIMER1_START); /*
- * Unmask and start timer 1
- */
-
- /*
- * Now we have to delay at least 80 usec
- */
-
- for (i = 0; i < 50; i++)
- tenmicrosec (devc->osp);
-
- stat2 = inb (ioaddr); /*
- * Read status after timers have expired
- */
-
- /*
- * Stop the timers
- */
-
- /* Reset timers 1 and 2 */
- opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);
- /* Reset the IRQ of the FM chip */
- opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);
-
- if ((stat2 & 0xE0) != 0xc0)
- {
- return 0; /*
- * There is no YM3812
- */
+ DDB (printk ("OPL3 not detected %x\n", signature));
+ return 0;
}
- /*
- * There is a FM chip in this address. Detect the type (OPL2 to OPL4)
- */
-
if (signature == 0x06 && !force_opl3_mode) /* OPL2 */
{
detected_model = 2;
{
int tmp;
- outb (0x02, ioaddr - 8); /* Select OPL4 ID register */
+ outb ((0x02), ioaddr - 8); /* Select OPL4 ID register */
tenmicrosec (devc->osp);
tmp = inb (ioaddr - 7); /* Read it */
tenmicrosec (devc->osp);
{
detected_model = 4;
- outb (0xF8, ioaddr - 8); /* Select OPL4 FM mixer control */
+ outb ((0xF8), ioaddr - 8); /* Select OPL4 FM mixer control */
tenmicrosec (devc->osp);
- outb (0x1B, ioaddr - 7); /* Write value */
+ outb ((0x1B), ioaddr - 7); /* Write value */
tenmicrosec (devc->osp);
}
else
*/
opl3_command (ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT);
- opl3_command (ioaddr, PERCUSSION_REGISTER, 0x00); /*
+ opl3_command (ioaddr, PERCOSSION_REGISTER, 0x00); /*
* Melodic mode.
*/
devc->voc[voice].keyon_byte = 0;
devc->voc[voice].bender = 0;
devc->voc[voice].volume = 64;
- devc->voc[voice].bender_range = 200; /*
- * 200 cents = 2 semitones
- */
+ devc->voc[voice].panning = 0xffff; /* Not set */
+ devc->voc[voice].bender_range = 200;
devc->voc[voice].orig_freq = 0;
devc->voc[voice].current_freq = 0;
devc->voc[voice].mode = 0;
return 0;
if (instr_no < 0 || instr_no >= SBFM_MAXINSTR)
- return 0;
+ instr_no = 0; /* Acoustic piano (usually) */
devc->act_i[voice] = &devc->i_map[instr_no];
return 0;
opl3_start_note (int dev, int voice, int note, int volume)
{
unsigned char data, fpc;
- int block, fnum, freq, voice_mode;
+ int block, fnum, freq, voice_mode, pan;
struct sbi_instrument *instr;
struct physical_voice_info *map;
return 0;
map = &pv_map[devc->lv_map[voice]];
+ pan = devc->voc[voice].panning;
if (map->voice_mode == 0)
return 0;
* Set Feedback/Connection
*/
fpc = instr->operators[10];
+
+ if (pan != 0xffff)
+ {
+ fpc &= ~STEREO_BITS;
+
+ if (pan < -64)
+ fpc |= VOICE_TO_LEFT;
+ else if (pan > 64)
+ fpc |= VOICE_TO_RIGHT;
+ else
+ fpc |= (VOICE_TO_LEFT | VOICE_TO_RIGHT);
+ }
+
if (!(fpc & 0x30))
fpc |= 0x30; /*
* Ensure that at least one chn is enabled
* register. The OPL-3 survives with just two INBs
*/
- outb ((unsigned char) (addr & 0xff), io_addr);
+ outb (((unsigned char) (addr & 0xff)), io_addr);
if (!devc->model != 2)
tenmicrosec (devc->osp);
for (i = 0; i < 2; i++)
inb (io_addr);
- outb ((unsigned char) (val & 0xff), io_addr + 1);
+ outb (((unsigned char) (val & 0xff)), io_addr + 1);
if (devc->model != 2)
{
int i;
if (devc->busy)
- return -(EBUSY);
+ return -EBUSY;
devc->busy = 1;
devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9;
if (count < sizeof (ins))
{
printk ("FM Error: Patch record too short\n");
- return -(EINVAL);
+ return -EINVAL;
}
copy_from_user (&((char *) &ins)[offs], &(addr)[offs], sizeof (ins) - offs);
if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR)
{
printk ("FM Error: Invalid instrument number %d\n", ins.channel);
- return -(EINVAL);
+ return -EINVAL;
}
ins.key = format;
}
static void
-opl3_panning (int dev, int voice, int pressure)
+opl3_panning (int dev, int voice, int value)
{
+ devc->voc[voice].panning = value;
}
static void
*/
opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data);
- data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); /*
- * *
- * KEYON|OCTAVE|MS
- *
- * * bits * *
- * of * f-num
- *
- */
+ data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);
devc->voc[voice].keyon_byte = data;
opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data);
}
case CTL_MAIN_VOLUME:
devc->voc[voice].volume = value / 128;
break;
+
+ case CTL_PAN:
+ devc->voc[voice].panning = (value * 2) - 128;
+ break;
}
}
static int
opl3_patchmgr (int dev, struct patmgr_info *rec)
{
- return -(EINVAL);
+ return -EINVAL;
}
static void
devc->voc[voice].bender = info->bender_value;
devc->voc[voice].volume =
info->controllers[CTL_MAIN_VOLUME];
+ devc->voc[voice].panning = (info->controllers[CTL_PAN] * 2) - 128;
}
static struct synth_operations opl3_operations =
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#define COMPOSITE_SINE_WAVE_MODE 0x80 /* Don't use with OPL-3? */
#define KEYBOARD_SPLIT 0x40
-#define PERCUSSION_REGISTER 0xbd /* Left side only */
+#define PERCOSSION_REGISTER 0xbd /* Left side only */
#define TREMOLO_DEPTH 0x80
#define VIBRATO_DEPTH 0x40
-#define PERCUSSION_ENABLE 0x20
+#define PERCOSSION_ENABLE 0x20
#define BASSDRUM_ON 0x10
#define SNAREDRUM_ON 0x08
#define TOMTOM_ON 0x04
-
-#define ALLOW_SELECT
-#undef NO_INLINE_ASM
-#define SHORT_BANNERS
-
#ifdef MODULE
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/ctype.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/dma.h>
#include <linux/wait.h>
#define TRUE 1
struct snd_wait {
- int flags;
+ int opts;
};
extern int sound_alloc_dma(int chn, char *deviceID);
extern void sound_free_dma(int chn);
extern void sound_close_dma(int chn);
-#define RUNTIME_DMA_ALLOC
-
extern caddr_t sound_mem_blocks[1024];
extern int sound_nblocks;
-
-#undef PSEUDO_DMA_AUTOINIT
-#define ALLOW_BUFFER_MAPPING
-
*/
#include <linux/config.h>
-
#include "sound_config.h"
#if defined(CONFIG_PAS)
static int pas_irq = 0;
static int pas_sb_base = 0;
-int *pas_osp;
char pas_model;
static char *pas_model_names[] =
void
pas_write (unsigned char data, int ioaddr)
{
- outb (data, ioaddr ^ translate_code);
+ outb ((data), ioaddr ^ translate_code);
}
/******************* Begin of the Interrupt Handler ********************/
* as per Media Vision. Only define this if your PAS doesn't work correctly.
*/
#ifdef SYMPHONY_PAS
- outb (0x05, 0xa8);
- outb (0x60, 0xa9);
+ outb ((0x05), 0xa8);
+ outb ((0x60), 0xa9);
#endif
#ifdef BROKEN_BUS_CLOCK
* you have something on base port 0x388. SO be forewarned.
*/
- outb (0xBC, 0x9A01); /* Activate first board */
- outb (hw_config->io_base >> 2, 0x9A01); /* Set base address */
+ outb ((0xBC), 0x9A01); /* Activate first board */
+ outb ((hw_config->io_base >> 2), 0x9A01); /* Set base address */
translate_code = 0x388 ^ hw_config->io_base;
pas_write (1, 0xBF88); /* Select one wait states */
attach_pas_card (struct address_info *hw_config)
{
pas_irq = hw_config->irq;
- pas_osp = hw_config->osp;
if (detect_pas_hw (hw_config))
{
int
probe_pas (struct address_info *hw_config)
{
- pas_osp = hw_config->osp;
return detect_pas_hw (hw_config);
}
* The low level driver for the PAS Midi Interface.
*/
-#include <linux/config.h>
-
#include "sound_config.h"
+#include <linux/config.h>
#if defined(CONFIG_PAS) && defined(CONFIG_MIDI)
static int midi_busy = 0, input_opened = 0;
static int my_dev;
-static volatile int ofifo_bytes = 0;
static unsigned char tmp_queue[256];
static volatile int qlen;
if (midi_busy)
{
printk ("PAS2: Midi busy\n");
- return -(EBUSY);
+ return -EBUSY;
}
/*
if (mode == OPEN_READ || mode == OPEN_READWRITE)
{
- ctrl |= 0x04; /*
- * Enable input
- */
+ ctrl |= 0x04; /* Enable input */
input_opened = 1;
}
if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
{
- ctrl |= 0x08 | /*
- * Enable output
- */
- 0x10;
+ ctrl |= 0x08 | 0x10; /* Enable output */
}
- pas_write (ctrl,
- 0x178b);
+ pas_write (ctrl, 0x178b);
/*
* Acknowledge any pending interrupts
*/
pas_write (0xff, 0x1B88);
- ofifo_bytes = 0;
restore_flags (flags);
fifo_space = ((x = pas_read (0x1B89)) >> 4) & 0x0f;
- if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /*
- * Fifo
- * full
- */
+/*
+ * The MIDI FIFO space register and it's documentation is nonunderstandable.
+ * There seem to be no way to differentiate between buffer full and buffer
+ * empty situations. For this reason we don't never write the buffer
+ * completely full. In this way we can assume that 0 (or is it 15)
+ * means that the buffer is empty.
+ */
+
+ if (fifo_space < 2 && fifo_space != 0) /* Full (almost) */
{
- return 0; /*
- * Upper layer will call again
- */
+ return 0; /* Ask upper layers to retry after some time */
}
- ofifo_bytes++;
-
pas_write (midi_byte, 0x178A);
return 1;
if (!qlen)
if (dump_to_midi (midi_byte))
- return 1; /*
- * OK
- */
+ return 1;
/*
* Put to the local queue
*/
if (qlen >= 256)
- return 0; /*
- * Local queue full
- */
+ return 0; /* Local queue full */
save_flags (flags);
cli ();
static int
pas_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
{
- return -(EINVAL);
+ return -EINVAL;
}
static void
pas_midi_kick (int dev)
{
- ofifo_bytes = 0;
}
static int
pas_midi_start_read,
pas_midi_end_read,
pas_midi_kick,
- NULL, /*
- * command
- */
+ NULL,
pas_buffer_status,
NULL
};
stat = pas_read (0x1B88);
- if (stat & 0x04) /*
- * Input byte available
- */
+ if (stat & 0x04) /* Input data available */
{
- incount = pas_read (0x1B89) & 0x0f; /*
- * Input FIFO count
- */
+ incount = pas_read (0x1B89) & 0x0f; /* Input FIFO size */
if (!incount)
incount = 16;
midi_input_intr (my_dev, pas_read (0x178A));
}
else
- pas_read (0x178A); /*
- * Flush
- */
+ pas_read (0x178A); /* Flush */
}
if (stat & (0x08 | 0x10))
{
- if (!(stat & 0x08))
- {
- ofifo_bytes = 8;
- }
- else
- {
- ofifo_bytes = 0;
- }
-
save_flags (flags);
cli ();
if (stat & 0x40)
{
- printk ("MIDI output overrun %x,%x,%d \n", pas_read (0x1B89), stat, ofifo_bytes);
- ofifo_bytes = 100;
+ printk ("MIDI output overrun %x,%x\n", pas_read (0x1B89), stat);
}
- pas_write (stat, 0x1B88); /*
- * Acknowledge interrupts
- */
+ pas_write (stat, 0x1B88); /* Acknowledge interrupts */
}
#endif
*
* Mixer routines for the Pro Audio Spectrum cards.
*/
-
-#include <linux/config.h>
+#include <linux/config.h>
#include "sound_config.h"
#if defined(CONFIG_PAS)
SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \
SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV)
+static int *levels;
-static unsigned short levels[SOUND_MIXER_NRDEVICES] =
+static int default_levels[32] =
{
0x3232, /* Master Volume */
0x3232, /* Bass */
if (pas_model == 4)
{
outw (data | (data << 8), (ioaddr ^ translate_code) - 1);
- outb (0x80, 0);
+ outb ((0x80), 0);
}
else
pas_write (data, ioaddr);
break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
return (levels[whichDev]);
if (cmd == SOUND_MIXER_PRIVATE1) /* Set loudness bit */
{
- int level = get_user ((int *) arg);
+ int level;
+
+ get_user (level, (int *) arg);
if (level == -1) /* Return current settings */
{
if (mode_control & 0x04)
- return snd_ioctl_return ((int *) arg, 1);
+ return ioctl_out (arg, 1);
else
- return snd_ioctl_return ((int *) arg, 0);
+ return ioctl_out (arg, 0);
}
else
{
if (level)
mode_control |= 0x04;
set_mode (mode_control);
- return snd_ioctl_return ((int *) arg, !!level); /* 0 or 1 */
+ return ioctl_out (arg, !!level); /* 0 or 1 */
}
}
if (cmd == SOUND_MIXER_PRIVATE2) /* Set enhance bit */
{
- int level = get_user ((int *) arg);
+ int level;
+
+ get_user (level, (int *) arg);
if (level == -1) /* Return current settings */
{
if (!(mode_control & 0x03))
- return snd_ioctl_return ((int *) arg, 0);
- return snd_ioctl_return ((int *) arg, ((mode_control & 0x03) + 1) * 20);
+ return ioctl_out (arg, 0);
+ return ioctl_out (arg, ((mode_control & 0x03) + 1) * 20);
}
else
{
if (cmd == SOUND_MIXER_PRIVATE3) /* Set mute bit */
{
- int level = get_user ((int *) arg);
+ int level;
+
+ get_user (level, (int *) arg);
if (level == -1) /* Return current settings */
{
- return snd_ioctl_return ((int *) arg,
- !(pas_read (0x0B8A) &
- 0x20));
+ return ioctl_out (arg, !(pas_read (0x0B8A) & 0x20));
}
else
{
if (((cmd >> 8) & 0xff) == 'M')
{
if (_IOC_DIR (cmd) & _IOC_WRITE)
- return snd_ioctl_return ((int *) arg, pas_mixer_set (cmd & 0xff, get_user ((int *) arg)));
+ return ioctl_out (arg, pas_mixer_set (cmd & 0xff, ioctl_in (arg)));
else
{ /*
* Read parameters
{
case SOUND_MIXER_RECSRC:
- return snd_ioctl_return ((int *) arg, rec_devices);
+ return ioctl_out (arg, rec_devices);
break;
case SOUND_MIXER_STEREODEVS:
- return snd_ioctl_return ((int *) arg, SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE));
+ return ioctl_out (arg, SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE));
break;
case SOUND_MIXER_DEVMASK:
- return snd_ioctl_return ((int *) arg, SUPPORTED_MIXER_DEVICES);
+ return ioctl_out (arg, SUPPORTED_MIXER_DEVICES);
break;
case SOUND_MIXER_RECMASK:
- return snd_ioctl_return ((int *) arg, POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES);
+ return ioctl_out (arg, POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES);
break;
case SOUND_MIXER_CAPS:
- return snd_ioctl_return ((int *) arg, 0); /* No special capabilities */
+ return ioctl_out (arg, 0); /* No special capabilities */
break;
default:
- return snd_ioctl_return ((int *) arg, levels[cmd & 0xff]);
+ return ioctl_out (arg, levels[cmd & 0xff]);
}
}
}
- return -(EINVAL);
+ return -EINVAL;
}
static struct mixer_operations pas_mixer_operations =
int
pas_init_mixer (void)
{
+ levels = load_mixer_volumes ("PAS16_1", default_levels, 1);
+
pas_mixer_reset ();
if (num_mixers < MAX_MIXER_DEV)
*
* The low level driver for the Pro Audio Spectrum ADC/DAC.
*/
-
-#include <linux/config.h>
+#include <linux/config.h>
#include "sound_config.h"
#if defined(CONFIG_PAS) && defined(CONFIG_AUDIO)
unsigned long flags;
if (arg == 0)
- return pcm_speed;
+ return pcm_speed;
if (arg > 44100)
arg = 44100;
pcm_set_bits (int arg)
{
if (arg == 0)
- return pcm_bits;
+ return pcm_bits;
if ((arg & pcm_bitsok) != arg)
return pcm_bits;
case SOUND_PCM_WRITE_RATE:
if (local)
return pcm_set_speed ((int) arg);
- return snd_ioctl_return ((int *) arg, pcm_set_speed (get_user ((int *) arg)));
+ return ioctl_out (arg, pcm_set_speed (ioctl_in (arg)));
break;
case SOUND_PCM_READ_RATE:
if (local)
return pcm_speed;
- return snd_ioctl_return ((int *) arg, pcm_speed);
+ return ioctl_out (arg, pcm_speed);
break;
case SNDCTL_DSP_STEREO:
if (local)
return pcm_set_channels ((int) arg + 1) - 1;
- return snd_ioctl_return ((int *) arg, pcm_set_channels (get_user ((int *) arg) + 1) - 1);
+ return ioctl_out (arg, pcm_set_channels (ioctl_in (arg) + 1) - 1);
break;
case SOUND_PCM_WRITE_CHANNELS:
if (local)
return pcm_set_channels ((int) arg);
- return snd_ioctl_return ((int *) arg, pcm_set_channels (get_user ((int *) arg)));
+ return ioctl_out (arg, pcm_set_channels (ioctl_in (arg)));
break;
case SOUND_PCM_READ_CHANNELS:
if (local)
return pcm_channels;
- return snd_ioctl_return ((int *) arg, pcm_channels);
+ return ioctl_out (arg, pcm_channels);
break;
case SNDCTL_DSP_SETFMT:
if (local)
return pcm_set_bits ((int) arg);
- return snd_ioctl_return ((int *) arg, pcm_set_bits (get_user ((int *) arg)));
+ return ioctl_out (arg, pcm_set_bits (ioctl_in (arg)));
break;
case SOUND_PCM_READ_BITS:
if (local)
return pcm_bits;
- return snd_ioctl_return ((int *) arg, pcm_bits);
+ return ioctl_out (arg, pcm_bits);
case SOUND_PCM_WRITE_FILTER: /*
* NOT YET IMPLEMENTED
*/
- if (get_user ((int *) arg) > 1)
- return -(EINVAL);
- pcm_filter = get_user ((int *) arg);
+ if (ioctl_in (arg) > 1)
+ return -EINVAL;
+ pcm_filter = ioctl_in (arg);
break;
case SOUND_PCM_READ_FILTER:
- return snd_ioctl_return ((int *) arg, pcm_filter);
+ return ioctl_out (arg, pcm_filter);
break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
- return -(EINVAL);
+ return -EINVAL;
}
static void
if (pcm_busy)
{
restore_flags (flags);
- return -(EBUSY);
+ return -EBUSY;
}
pcm_busy = 1;
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#if defined(CONFIG_SEQUENCER)
-static wait_handle *server_procs[MAX_SYNTH_DEV] =
+static struct wait_queue *server_procs[MAX_SYNTH_DEV] =
{NULL};
static volatile struct snd_wait server_wait_flag[MAX_SYNTH_DEV] =
{
#define A_TO_S 1
#define S_TO_A 2
-static wait_handle *appl_proc = NULL;
+static struct wait_queue *appl_proc = NULL;
static volatile struct snd_wait appl_wait_flag =
{0};
pmgr_open (int dev)
{
if (dev < 0 || dev >= num_synths)
- return -(ENXIO);
+ return -ENXIO;
if (pmgr_opened[dev])
- return -(EBUSY);
+ return -EBUSY;
pmgr_opened[dev] = 1;
- server_wait_flag[dev].flags = WK_NONE;
+ server_wait_flag[dev].opts = WK_NONE;
return 0;
}
{
mbox[dev]->key = PM_ERROR;
- mbox[dev]->parm1 = -(EIO);
+ mbox[dev]->parm1 = -EIO;
- if ((appl_wait_flag.flags & WK_SLEEP))
+ if ((appl_wait_flag.opts & WK_SLEEP))
{
- appl_wait_flag.flags = WK_WAKEUP;
- module_wake_up (&appl_proc);
+ appl_wait_flag.opts = WK_WAKEUP;
+ wake_up (&appl_proc);
};
}
if (count != sizeof (struct patmgr_info))
{
printk ("PATMGR%d: Invalid read count\n", dev);
- return -(EIO);
+ return -EIO;
}
- while (!ok && !current_got_fatal_signal ())
+ while (!ok && !(current->signal & ~current->blocked))
{
save_flags (flags);
cli ();
while (!(mbox[dev] && msg_direction[dev] == A_TO_S) &&
- !current_got_fatal_signal ())
+ !(current->signal & ~current->blocked))
{
- server_wait_flag[dev].flags = WK_SLEEP;
- module_interruptible_sleep_on (&server_procs[dev]);
- server_wait_flag[dev].flags &= ~WK_SLEEP;;
+ server_wait_flag[dev].opts = WK_SLEEP;
+ interruptible_sleep_on (&server_procs[dev]);
+ server_wait_flag[dev].opts &= ~WK_SLEEP;;
}
if (mbox[dev] && msg_direction[dev] == A_TO_S)
{
- copy_to_user (&(buf)[0], (char *) mbox[dev], count);
+ {
+ char *fixit = (char *) mbox[dev];
+
+ copy_to_user (&(buf)[0], fixit, count);
+ };
msg_direction[dev] = 0;
ok = 1;
}
}
if (!ok)
- return -(EINTR);
+ return -EINTR;
return count;
}
if (count < 4)
{
printk ("PATMGR%d: Write count < 4\n", dev);
- return -(EIO);
+ return -EIO;
}
copy_from_user ((char *) mbox[dev], &(buf)[0], 4);
tmp_dev = ((unsigned short *) mbox[dev])[2];
if (tmp_dev != dev)
- return -(ENXIO);
+ return -ENXIO;
return synth_devs[dev]->load_patch (dev, *(unsigned short *) mbox[dev],
buf, 4, count, 1);
if (count != sizeof (struct patmgr_info))
{
printk ("PATMGR%d: Invalid write count\n", dev);
- return -(EIO);
+ return -EIO;
}
/*
copy_from_user (&((char *) mbox[dev])[4], &(buf)[4], count - 4);
msg_direction[dev] = S_TO_A;
- if ((appl_wait_flag.flags & WK_SLEEP))
+ if ((appl_wait_flag.opts & WK_SLEEP))
{
{
- appl_wait_flag.flags = WK_WAKEUP;
- module_wake_up (&appl_proc);
+ appl_wait_flag.opts = WK_WAKEUP;
+ wake_up (&appl_proc);
};
}
}
mbox[dev] = rec;
msg_direction[dev] = A_TO_S;
- if ((server_wait_flag[dev].flags & WK_SLEEP))
+ if ((server_wait_flag[dev].opts & WK_SLEEP))
{
{
- server_wait_flag[dev].flags = WK_WAKEUP;
- module_wake_up (&server_procs[dev]);
+ server_wait_flag[dev].opts = WK_WAKEUP;
+ wake_up (&server_procs[dev]);
};
}
- appl_wait_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&appl_proc);
- appl_wait_flag.flags &= ~WK_SLEEP;;
+ appl_wait_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&appl_proc);
+ appl_wait_flag.opts &= ~WK_SLEEP;;
if (msg_direction[dev] != S_TO_A)
{
rec->key = PM_ERROR;
- rec->parm1 = -(EIO);
+ rec->parm1 = -EIO;
}
else if (rec->key == PM_ERROR)
{
mbox[dev]->parm3 = p3;
msg_direction[dev] = A_TO_S;
- if ((server_wait_flag[dev].flags & WK_SLEEP))
+ if ((server_wait_flag[dev].opts & WK_SLEEP))
{
{
- server_wait_flag[dev].flags = WK_WAKEUP;
- module_wake_up (&server_procs[dev]);
+ server_wait_flag[dev].opts = WK_WAKEUP;
+ wake_up (&server_procs[dev]);
};
}
- appl_wait_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&appl_proc);
- appl_wait_flag.flags &= ~WK_SLEEP;;
+ appl_wait_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&appl_proc);
+ appl_wait_flag.opts &= ~WK_SLEEP;;
mbox[dev] = NULL;
msg_direction[dev] = 0;
}
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
static int pss_initialized = 0;
static int nonstandard_microcode = 0;
+static void
+pss_write (int data)
+{
+ int i, limit;
+
+ limit = jiffies + 10; /* The timeout is 0.1 seconds */
+ /*
+ * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes
+ * called while interrupts are disabled. This means that the timer is
+ * disabled also. However the timeout situation is a abnormal condition.
+ * Normally the DSP should be ready to accept commands after just couple of
+ * loops.
+ */
+
+ for (i = 0; i < 5000000 && jiffies < limit; i++)
+ {
+ if (inw (devc->base + PSS_STATUS) & PSS_WRITE_EMPTY)
+ {
+ outw (devc->base + PSS_DATA, data);
+ return;
+ }
+ }
+ printk ("PSS: DSP Command (%04x) Timeout.\n", data);
+}
+
int
probe_pss (struct address_info *hw_config)
{
conf_printf (tmp, hw_config);
}
+static void
+pss_init_speaker (void)
+{
+/* Don't ask what are these commands. I really don't know */
+ pss_write (0x0010);
+ pss_write (0x0000 | 252); /* Left master volume */
+ pss_write (0x0010);
+ pss_write (0x0100 | 252); /* Right master volume */
+ pss_write (0x0010);
+ pss_write (0x0200 | 246); /* Bass */
+ pss_write (0x0010);
+ pss_write (0x0300 | 246); /* Treble */
+ pss_write (0x0010);
+ pss_write (0x0800 | 0x00ce); /* Stereo switch? */
+}
+
int
probe_pss_mpu (struct address_info *hw_config)
{
return 0;
}
+ pss_init_speaker ();
+
/*
* Finally wait until the DSP algorithm has initialized itself and
* deactivates receive interrupt.
if (pss_synthLen == 0)
{
printk ("PSS: MIDI synth microcode not available.\n");
- return -(EIO);
+ return -EIO;
}
if (nonstandard_microcode)
if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST))
{
printk ("PSS: Unable to load MIDI synth microcode to DSP.\n");
- return -(EIO);
+ return -EIO;
}
nonstandard_microcode = 0;
break;
download_boot_block (void *dev_info, copr_buffer * buf)
{
if (buf->len <= 0 || buf->len > sizeof (buf->data))
- return -(EINVAL);
+ return -EINVAL;
if (!pss_download_boot (devc, buf->data, buf->len, buf->flags))
{
printk ("PSS: Unable to load microcode block to DSP.\n");
- return -(EIO);
+ return -EIO;
}
nonstandard_microcode = 1; /* The MIDI microcode has been overwritten */
buf = (copr_buffer *) vmalloc (sizeof (copr_buffer));
if (buf == NULL)
- return -(ENOSPC);
+ return -ENOSPC;
copy_from_user ((char *) buf, &((char *) arg)[0], sizeof (*buf));
err = download_boot_block (dev_info, buf);
buf = (copr_msg *) vmalloc (sizeof (copr_msg));
if (buf == NULL)
- return -(ENOSPC);
+ return -ENOSPC;
copy_from_user ((char *) buf, &((char *) arg)[0], sizeof (*buf));
{
restore_flags (flags);
buf->len = i; /* feed back number of WORDs sent */
- copy_to_user (&((char *) arg)[0], &buf, sizeof (buf));
+ {
+ char *fixit = (char *) buf;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (*buf));
+ };
vfree (buf);
- return -(EIO);
+ return -EIO;
}
}
buf = (copr_msg *) vmalloc (sizeof (copr_msg));
if (buf == NULL)
- return -(ENOSPC);
+ return -ENOSPC;
data = (unsigned short *) buf->data;
if (!pss_get_dspword (devc, data++))
{
if (i == 0)
- err = -(EIO);
+ err = -EIO;
break;
}
}
restore_flags (flags);
- copy_to_user (&((char *) arg)[0], &buf, sizeof (buf));
+ {
+ char *fixit = (char *) buf;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (*buf));
+ };
vfree (buf);
return err;
if (!pss_put_dspword (devc, 0x00d0))
{
restore_flags (flags);
- return -(EIO);
+ return -EIO;
}
if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff)))
{
restore_flags (flags);
- return -(EIO);
+ return -EIO;
}
if (!pss_get_dspword (devc, &tmp))
{
restore_flags (flags);
- return -(EIO);
+ return -EIO;
}
buf.parm1 = tmp;
restore_flags (flags);
- copy_to_user (&((char *) arg)[0], &buf, sizeof (buf));
+ {
+ char *fixit = (char *) &buf;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (buf));
+ };
return 0;
}
break;
if (!pss_put_dspword (devc, 0x00d1))
{
restore_flags (flags);
- return -(EIO);
+ return -EIO;
}
if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff)))
{
restore_flags (flags);
- return -(EIO);
+ return -EIO;
}
tmp = (unsigned int) buf.parm2 & 0xffff;
if (!pss_put_dspword (devc, tmp))
{
restore_flags (flags);
- return -(EIO);
+ return -EIO;
}
restore_flags (flags);
if (!pss_put_dspword (devc, 0x00d3))
{
restore_flags (flags);
- return -(EIO);
+ return -EIO;
}
if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff)))
{
restore_flags (flags);
- return -(EIO);
+ return -EIO;
}
tmp = (unsigned int) buf.parm2 & 0x00ff;
if (!pss_put_dspword (devc, tmp))
{
restore_flags (flags);
- return -(EIO);
+ return -EIO;
}
tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff;
if (!pss_put_dspword (devc, tmp))
{
restore_flags (flags);
- return -(EIO);
+ return -EIO;
}
restore_flags (flags);
if (!pss_put_dspword (devc, 0x00d2))
{
restore_flags (flags);
- return -(EIO);
+ return -EIO;
}
if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff)))
{
restore_flags (flags);
- return -(EIO);
+ return -EIO;
}
if (!pss_get_dspword (devc, &tmp)) /* Read MSB */
{
restore_flags (flags);
- return -(EIO);
+ return -EIO;
}
buf.parm1 = tmp << 8;
if (!pss_get_dspword (devc, &tmp)) /* Read LSB */
{
restore_flags (flags);
- return -(EIO);
+ return -EIO;
}
buf.parm1 |= tmp & 0x00ff;
restore_flags (flags);
- copy_to_user (&((char *) arg)[0], &buf, sizeof (buf));
+ {
+ char *fixit = (char *) &buf;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (buf));
+ };
return 0;
}
break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
- return -(EINVAL);
+ return -EINVAL;
}
static coproc_operations pss_coproc_operations =
int
probe_pss_mss (struct address_info *hw_config)
{
- int timeout;
+ volatile int timeout;
if (!pss_initialized)
return 0;
timeout < 100000 && (inb (hw_config->io_base + 3) & 0x3f) != 0x04;
timeout++);
- outb (0x0b, hw_config->io_base + 4); /* Required by some cards */
+ outb ((0x0b), hw_config->io_base + 4); /* Required by some cards */
+
+ for (timeout = 0;
+ timeout < 100000;
+ timeout++);
return probe_ms_sound (hw_config);
}
#define MDL_SB201 3 /* SB2.01 */
#define MDL_SBPRO 4 /* SB Pro */
#define MDL_SB16 5 /* SB16/32/AWE */
+#define MDL_SBPNP 6 /* SB16/32/AWE PnP */
#define MDL_JAZZ 10 /* Media Vision Jazz16 */
#define MDL_SMW 11 /* Logitech SoundMan Wave (Jazz16) */
#define MDL_ESS 12 /* ESS ES688 and ES1688 */
volatile int intr_active, irq_mode;
/* Mixer fields */
- unsigned short levels[SOUND_MIXER_NRDEVICES];
+ int *levels;
mixer_tab *iomap;
int mixer_caps, recmask, supported_devices;
int supported_rec_devices;
int my_mixerdev;
+ int sbmixnum;
/* Audio fields */
unsigned long trg_buf;
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
if (devc == NULL)
{
printk ("SB: Incomplete initialization\n");
- return -(ENXIO);
+ return -ENXIO;
}
if (devc->caps & SB_NO_RECORDING && mode & OPEN_READ)
{
printk ("SB: Recording is not possible with this device\n");
- return -(EPERM);
+ return -EPERM;
}
save_flags (flags);
if (devc->opened)
{
restore_flags (flags);
- return -(EBUSY);
+ return -EBUSY;
}
if (devc->dma16 != -1 && devc->dma16 != devc->dma8)
{
if (sound_open_dma (devc->dma16, "Sound Blaster 16 bit"))
{
- return -(EBUSY);
+ return -EBUSY;
}
}
devc->opened = mode;
if (channels != devc->channels)
{
devc->channels = channels;
- sbpro_audio_set_speed (dev, devc->speed);
+ if (devc->model == MDL_SBPRO)
+ sbpro_audio_set_speed (dev, devc->speed);
}
return devc->channels;
}
* ESS specific routines
*/
+static int
+ess_audio_set_speed (int dev, int speed)
+{
+ sb_devc *devc = audio_devs[dev]->devc;
+ int divider;
+
+ if (speed > 0)
+ {
+ if (speed < 5000)
+ speed = 4000;
+
+ if (speed > 48000)
+ speed = 48000;
+
+ if (speed > 22000)
+ {
+ divider = (795500 + speed / 2) / speed;
+ speed = (795500 + divider / 2) / divider;
+ }
+ else
+ {
+ divider = (397700 + speed / 2) / speed;
+ speed = (397700 + divider / 2) / divider;
+ }
+
+ devc->speed = speed;
+ }
+
+ return devc->speed;
+}
+
static void
ess_speed (sb_devc * devc)
{
static int
sb_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local)
{
- return -(EINVAL);
+ return -EINVAL;
}
static void
NULL,
NULL,
ess_audio_trigger,
- sb16_audio_set_speed,
+ ess_audio_set_speed,
sb16_audio_set_bits,
sbpro_audio_set_channels
};
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
static unsigned char jazz16_bits = 0; /* I/O relocation bits */
/*
- * Logitech SoundMan Wave specific initialization code
+ * Logitech Soundman Wave specific initialization code
*/
#ifdef SMW_MIDI0001_INCLUDED
/*
* Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes
* called while interrupts are disabled. This means that the timer is
- * disabled also. However the timeout situation is an abnormal condition.
+ * disabled also. However the timeout situation is a abnormal condition.
* Normally the DSP should be ready to accept commands after just couple of
* loops.
*/
{
if ((inb (DSP_STATUS) & 0x80) == 0)
{
- outb (val, DSP_COMMAND);
+ outb ((val), DSP_COMMAND);
return 1;
}
}
int loopc;
if (devc->model == MDL_ESS)
- outb (3, DSP_RESET); /* Reset FIFO too */
+ outb ((3), DSP_RESET); /* Reset FIFO too */
else
- outb (1, DSP_RESET);
+ outb ((1), DSP_RESET);
tenmicrosec (devc->osp);
- outb (0, DSP_RESET);
+ outb ((0), DSP_RESET);
tenmicrosec (devc->osp);
tenmicrosec (devc->osp);
tenmicrosec (devc->osp);
return 1;
}
+#if defined(CONFIG_MIDI) && defined(CONFIG_UART401)
static void
-sb16_set_mpu_port(sb_devc *devc, struct address_info *hw_config)
+sb16_set_mpu_port (sb_devc * devc, struct address_info *hw_config)
{
/*
- * This routine initializes new MIDI port setup register of SB Vibra.
+ * This routine initializes new MIDI port setup register of SB Vibra (CT2502).
*/
- unsigned char bits = sb_getmixer(devc, 0x84) & ~0x06;
- switch (hw_config->io_base)
- {
- case 0x300:
- sb_setmixer (devc, 0x84, bits | 0x04);
- break;
+ unsigned char bits = sb_getmixer (devc, 0x84) & ~0x06;
- case 0x330:
- sb_setmixer (devc, 0x84, bits | 0x00);
- break;
+ switch (hw_config->io_base)
+ {
+ case 0x300:
+ sb_setmixer (devc, 0x84, bits | 0x04);
+ break;
- default:
- sb_setmixer (devc, 0x84, bits | 0x02); /* Disable MPU */
- printk("SB16: Invalid MIDI I/O port %x\n", hw_config->io_base);
- }
+ case 0x330:
+ sb_setmixer (devc, 0x84, bits | 0x00);
+ break;
+
+ default:
+ sb_setmixer (devc, 0x84, bits | 0x02); /* Disable MPU */
+ printk ("SB16: Invalid MIDI I/O port %x\n", hw_config->io_base);
+ }
}
+#endif
static int
sb16_set_irq_hw (sb_devc * devc, int level)
ival = 8;
break;
default:
+ if (devc->type == MDL_SBPNP)
+ return 1;
printk ("SB16 IRQ%d is not possible\n", level);
return 0;
}
*/
save_flags (flags);
cli ();
- outb (0xAF, 0x201);
- outb (0x50, 0x201);
- outb (bits, 0x201);
+ outb ((0xAF), 0x201);
+ outb ((0x50), 0x201);
+ outb ((bits), 0x201);
restore_flags (flags);
}
return 1;
}
+
static int
ess_init (sb_devc * devc, struct address_info *hw_config)
{
}
else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80)
{
+ char *chip = "ES688";
+
+ if ((ess_minor & 0x0f) >= 8)
+ chip = "ES1688";
+
sprintf (name,
- "ESS ES1688 AudioDrive (rev %d)",
- ess_minor & 0x0f);
+ "ESS %s AudioDrive (rev %d)",
+ chip, ess_minor & 0x0f);
}
else
strcpy (name, "Jazz16");
memset ((char *) &sb_info, 0, sizeof (sb_info)); /* Zero everything */
- devc->osp = hw_config->osp;
devc->type = hw_config->card_subtype;
devc->base = hw_config->io_base;
if (devc->major == 0 || (devc->major == 3 && devc->minor == 1))
relocate_Jazz16 (devc, hw_config);
+
if (!sb_dsp_reset (devc))
{
DDB (printk ("SB reset failed\n"));
sb_dsp_init (struct address_info *hw_config)
{
sb_devc *devc;
- char name[100];
-
-#ifndef NO_SB_IRQ_TEST
int n;
-#endif
+ char name[100];
/*
* Check if we had detected a SB device earlier
*/
DDB (printk ("sb_dsp_init(%x) entered\n", hw_config->io_base));
+ name[0] = 0;
if (detected_devc == NULL)
{
devc->dev = num_audiodevs;
devc->caps = hw_config->driver_use_1;
- if (snd_set_irq_handler (hw_config->irq,
- sbintr, "sound blaster", devc->osp) < 0)
- {
- printk ("SB: Can't allocate IRQ%d\n", hw_config->irq);
- irq2devc[hw_config->irq] = NULL;
- return;
- }
+ if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) &&
+ hw_config->irq > 0)
+ { /* IRQ setup */
+ if (snd_set_irq_handler (hw_config->irq,
+ sbintr, "soundblaster", devc->osp) < 0)
+ {
+ printk ("SB: Can't allocate IRQ%d\n", hw_config->irq);
+ return;
+ }
- irq2devc[hw_config->irq] = devc;
- devc->irq_ok = 0;
+ irq2devc[hw_config->irq] = devc;
+ devc->irq_ok = 0;
- if (devc->major == 4)
- if (!sb16_set_irq_hw (devc, devc->irq)) /* Unsupported IRQ */
- {
- snd_release_irq (devc->irq);
- return;
- }
-
- if ((devc->type == 0 || devc->type == MDL_ESS) &&
- devc->major == 3 && devc->minor == 1)
- { /* Handle various chipsets which claim they are SB Pro compatible */
- if ((devc->type != 0 && devc->type != MDL_ESS) ||
- !ess_init (devc, hw_config))
- if ((devc->type != 0 && devc->type != MDL_JAZZ &&
- devc->type != MDL_SMW) || !init_Jazz16 (devc, hw_config))
+ if (devc->major == 4)
+ if (!sb16_set_irq_hw (devc, devc->irq)) /* Unsupported IRQ */
{
- DDB (printk ("This is a genuine SB Pro\n"));
+ snd_release_irq (devc->irq);
+ irq2devc[hw_config->irq] = NULL;
+ return;
}
- }
-#ifndef NO_SB_IRQ_TEST
- if (devc->major != 4 || devc->minor > 11) /* Not Sb16 v4.5 or v4.11 */
- {
- for (n = 0; n < 3 && devc->irq_ok == 0; n++)
- if (sb_dsp_command (devc, 0xf2)) /* Cause interrupt immediately */
- {
- int i;
+ if ((devc->type == 0 || devc->type == MDL_ESS) &&
+ devc->major == 3 && devc->minor == 1)
+ { /* Handle various chipsets which claim they are SB Pro compatible */
+ if ((devc->type != 0 && devc->type != MDL_ESS) ||
+ !ess_init (devc, hw_config))
+ if ((devc->type != 0 && devc->type != MDL_JAZZ &&
+ devc->type != MDL_SMW) || !init_Jazz16 (devc, hw_config))
+ {
+ DDB (printk ("This is a genuine SB Pro\n"));
+ }
+ }
- for (i = 0; !devc->irq_ok && i < 10000; i++);
- }
+ if (devc->major == 4 && devc->minor <= 11) /* Won't work */
+ devc->irq_ok = 1;
+ else
+ {
+ for (n = 0; n < 3 && devc->irq_ok == 0; n++)
+ if (sb_dsp_command (devc, 0xf2)) /* Cause interrupt immediately */
+ {
+ int i;
- if (!devc->irq_ok)
- {
- printk ("sb: Interrupt test on IRQ%d failed - device disabled\n", devc->irq);
- snd_release_irq (devc->irq);
- return;
- }
- else
- {
- DDB (printk ("IRQ test OK (IRQ%d)\n", devc->irq));
+ for (i = 0; !devc->irq_ok && i < 10000; i++);
+ }
+
+ if (!devc->irq_ok)
+ {
+ printk ("sb: Interrupt test on IRQ%d failed - Propable IRQ conflict\n", devc->irq);
+ }
+ else
+ {
+ DDB (printk ("IRQ test OK (IRQ%d)\n", devc->irq));
+ }
+
+ } /* IRQ setup */
}
- }
-#endif
- request_region (hw_config->io_base, 16, "sound blaster");
+ request_region (hw_config->io_base, 16, "soundblaster");
switch (devc->major)
{
hw_config->card_subtype = devc->model;
last_devc = devc; /* For SB MPU detection */
- if (!(devc->caps & SB_NO_AUDIO))
+ if (!(devc->caps & SB_NO_AUDIO) && devc->dma8 >= 0)
{
- if (sound_alloc_dma (devc->dma8, "Sound Blaster8"))
+ if (sound_alloc_dma (devc->dma8, "SoundBlaster8"))
{
printk ("SB: Can't allocate 8 bit DMA channel %d\n", devc->dma8);
}
if (devc->dma16 >= 0 && devc->dma16 != devc->dma8)
- if (sound_alloc_dma (devc->dma16, "Sound Blaster16"))
+ if (sound_alloc_dma (devc->dma16, "SoundBlaster16"))
{
printk ("SB: Can't allocate 16 bit DMA channel %d\n", devc->dma16);
}
if (irq < 0)
irq *= -1;
- devc = irq2devc[irq];
+ if (irq > 2 && irq < 16)
+ devc = irq2devc[irq];
+ else
+ devc = NULL;
if (devc && devc->base == hw_config->io_base)
{
release_region (devc->base, 16);
+
if (!(devc->caps & SB_NO_AUDIO))
{
sound_free_dma (devc->dma8);
sound_free_dma (devc->dma16);
}
- snd_release_irq (devc->irq);
- irq2devc[devc->irq] = NULL;
+ if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) &&
+ devc->irq > 0)
+ {
+ snd_release_irq (devc->irq);
+ irq2devc[devc->irq] = NULL;
+ }
}
+ else
+ release_region (hw_config->io_base, 16);
}
/*
save_flags (flags);
cli ();
- outb ((unsigned char) (port & 0xff), MIXER_ADDR);
+ outb (((unsigned char) (port & 0xff)), MIXER_ADDR);
tenmicrosec (devc->osp);
- outb ((unsigned char) (value & 0xff), MIXER_DATA);
+ tenmicrosec (devc->osp);
+ outb (((unsigned char) (value & 0xff)), MIXER_DATA);
+ tenmicrosec (devc->osp);
tenmicrosec (devc->osp);
restore_flags (flags);
}
save_flags (flags);
cli ();
- outb ((unsigned char) (port & 0xff), MIXER_ADDR);
+ outb (((unsigned char) (port & 0xff)), MIXER_ADDR);
+ tenmicrosec (devc->osp);
tenmicrosec (devc->osp);
val = inb (MIXER_DATA);
tenmicrosec (devc->osp);
save_flags (flags);
cli ();
- outb (addr & 0xff, base + 1); /* Low address bits */
- outb (addr >> 8, base + 2); /* High address bits */
- outb (val, base); /* Data */
+ outb ((addr & 0xff), base + 1); /* Low address bits */
+ outb ((addr >> 8), base + 2); /* High address bits */
+ outb ((val), base); /* Data */
restore_flags (flags);
}
save_flags (flags);
cli ();
- outb (addr & 0xff, base + 1); /* Low address bits */
- outb (addr >> 8, base + 2); /* High address bits */
+ outb ((addr & 0xff), base + 1); /* Low address bits */
+ outb ((addr >> 8), base + 2); /* High address bits */
val = inb (base); /* Data */
restore_flags (flags);
*/
control = inb (mpu_base + 7);
- outb (control | 3, mpu_base + 7); /* Set last two bits to 1 (?) */
- outb ((control & 0xfe) | 2, mpu_base + 7); /* xxxxxxx0 resets the mc */
+ outb ((control | 3), mpu_base + 7); /* Set last two bits to 1 (?) */
+ outb (((control & 0xfe) | 2), mpu_base + 7); /* xxxxxxx0 resets the mc */
for (i = 0; i < 300; i++) /* Wait at least 1ms */
tenmicrosec (devc->osp);
- outb (control & 0xfc, mpu_base + 7); /* xxxxxx00 enables RAM */
+ outb ((control & 0xfc), mpu_base + 7); /* xxxxxx00 enables RAM */
/*
* Detect microcontroller by probing the 8k RAM area
/* control |= 0x20; Uncomment this if you want to use IRQ7 */
#endif
- outb (control | 0x03, mpu_base + 7); /* xxxxxx11 restarts */
+ outb ((control | 0x03), mpu_base + 7); /* xxxxxx11 restarts */
hw_config->name = "SoundMan Wave";
return 1;
}
*/
save_flags (flags);
cli ();
- outb (0xAF, 0x201);
- outb (0x50, 0x201);
- outb (bits, 0x201);
+ outb ((0xAF), 0x201);
+ outb ((0x50), 0x201);
+ outb ((bits), 0x201);
restore_flags (flags);
hw_config->name = "Jazz16";
last_devc = 0;
if (hw_config->io_base <= 0)
- return 0;
+ return 0;
if (check_region (hw_config->io_base, 4))
{
}
hw_config->name = "Sound Blaster 16";
hw_config->irq = -devc->irq;
- sb16_set_mpu_port(devc, hw_config);
+ if (devc->minor > 12) /* What is Vibra's version??? */
+ sb16_set_mpu_port (devc, hw_config);
break;
case MDL_ESS:
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
unsigned long flags;
if (devc == NULL)
- return -(ENXIO);
+ return -ENXIO;
save_flags (flags);
cli ();
if (devc->opened)
{
restore_flags (flags);
- return -(EBUSY);
+ return -EBUSY;
}
devc->opened = 1;
restore_flags (flags);
if (!sb_dsp_command (devc, 0x35)) /* Start MIDI UART mode */
{
devc->opened = 0;
- return -(EIO);
+ return -EIO;
}
devc->intr_active = 1;
sb_devc *devc = midi_devs[dev]->devc;
if (devc == NULL)
- return -(ENXIO);
+ return -ENXIO;
sb_dsp_command (devc, midi_byte);
sb_devc *devc = midi_devs[dev]->devc;
if (devc == NULL)
- return -(ENXIO);
+ return -ENXIO;
sb_dsp_reset (devc);
devc->intr_active = 0;
static int
sb_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
{
- return -(EPERM);
+ return -EPERM;
}
void
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#include "sb.h"
#include "sb_mixer.h"
+static int sbmixnum = 1;
+
void sb_mixer_reset (sb_devc * devc);
void
sb_mixer_get (sb_devc * devc, int dev)
{
if (!((1 << dev) & devc->supported_devices))
- return -(EINVAL);
+ return -EINVAL;
return devc->levels[dev];
}
right = 100;
if (dev > 31)
- return -(EINVAL);
+ return -EINVAL;
if (!(devc->supported_devices & (1 << dev))) /* Not supported */
- return -(EINVAL);
+ return -EINVAL;
switch (dev)
{
default:
reg = smw_mix_regs[dev];
if (reg == 0)
- return -(EINVAL);
+ return -EINVAL;
sb_setmixer (devc, reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */
sb_setmixer (devc, reg + 1, (24 - (24 * right / 100)) | 0x40);
}
right = 100;
if (dev > 31)
- return -(EINVAL);
+ return -EINVAL;
if (!(devc->supported_devices & (1 << dev))) /*
* Not supported
*/
- return -(EINVAL);
+ return -EINVAL;
regoffs = (*devc->iomap)[dev][LEFT_CHN].regno;
if (regoffs == 0)
- return -(EINVAL);
+ return -EINVAL;
val = sb_getmixer (devc, regoffs);
change_bits (devc, &val, dev, LEFT_CHN, left);
sb_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
{
sb_devc *devc = mixer_devs[dev]->devc;
+ int val;
if (((cmd >> 8) & 0xff) == 'M')
{
switch (cmd & 0xff)
{
case SOUND_MIXER_RECSRC:
- return snd_ioctl_return ((int *) arg, set_recmask (devc, get_user ((int *) arg)));
+ get_user (val, (int *) arg);
+ return ioctl_out (arg, set_recmask (devc, val));
break;
default:
- return snd_ioctl_return ((int *) arg, sb_mixer_set (devc, cmd & 0xff, get_user ((int *) arg)));
+ get_user (val, (int *) arg);
+ return ioctl_out (arg, sb_mixer_set (devc, cmd & 0xff, val));
}
else
switch (cmd & 0xff)
{
case SOUND_MIXER_RECSRC:
- return snd_ioctl_return ((int *) arg, devc->recmask);
+ return ioctl_out (arg, devc->recmask);
break;
case SOUND_MIXER_DEVMASK:
- return snd_ioctl_return ((int *) arg, devc->supported_devices);
+ return ioctl_out (arg, devc->supported_devices);
break;
case SOUND_MIXER_STEREODEVS:
if (devc->model == MDL_JAZZ || devc->model == MDL_SMW)
- return snd_ioctl_return ((int *) arg, devc->supported_devices);
+ return ioctl_out (arg, devc->supported_devices);
else
- return snd_ioctl_return ((int *) arg, devc->supported_devices & ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
+ return ioctl_out (arg, devc->supported_devices & ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX));
break;
case SOUND_MIXER_RECMASK:
- return snd_ioctl_return ((int *) arg, devc->supported_rec_devices);
+ return ioctl_out (arg, devc->supported_rec_devices);
break;
case SOUND_MIXER_CAPS:
- return snd_ioctl_return ((int *) arg, devc->mixer_caps);
+ return ioctl_out (arg, devc->mixer_caps);
break;
default:
- return snd_ioctl_return ((int *) arg, sb_mixer_get (devc, cmd & 0xff));
+ return ioctl_out (arg, sb_mixer_get (devc, cmd & 0xff));
}
}
else
- return -(EINVAL);
+ return -EINVAL;
}
static struct mixer_operations sb_mixer_operations =
void
sb_mixer_reset (sb_devc * devc)
{
+ char name[32];
int i;
+ sprintf (name, "SB_%d", devc->sbmixnum);
+
+ devc->levels = load_mixer_volumes (name, default_levels, 1);
+
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
sb_mixer_set (devc, i, devc->levels[i]);
+
set_recmask (devc, SOUND_MASK_MIC);
}
{
int mixer_type = 0;
+ devc->sbmixnum = sbmixnum++;
+ devc->levels = NULL;
+
sb_setmixer (devc, 0x00, 0); /* Reset mixer */
if (!(mixer_type = detect_mixer (devc)))
sizeof (struct mixer_operations));
mixer_devs[num_mixers]->devc = devc;
- memcpy ((char *) devc->levels, (char *) &default_levels, sizeof (default_levels));
sb_mixer_reset (devc);
devc->my_mixerdev = num_mixers++;
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
SOUND_MASK_CD | \
SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \
- SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE)
+ SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | \
+ SOUND_MASK_IMIX)
/*
* Mixer registers
MIX_ENT(SOUND_MIXER_LINE, 0x38, 7, 5, 0x39, 7, 5),
MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5),
-MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_IMIX, 0x3c, 0, 1, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2), /* Obsolete. Use IGAIN */
MIX_ENT(SOUND_MIXER_IGAIN, 0x3f, 7, 2, 0x40, 7, 2),
higher than with SB Pro. This improves the
sound quality */
-static unsigned short default_levels[SOUND_MIXER_NRDEVICES] =
+static int default_levels[32] =
{
0x2020, /* Master Volume */
0x4b4b, /* Bass */
#else /* If the user selected just plain SB Pro */
-static unsigned short default_levels[SOUND_MIXER_NRDEVICES] =
+static int default_levels[32] =
{
0x5a5a, /* Master Volume */
0x4b4b, /* Bass */
0x4b4b, /* Ext Line */
0x1010, /* Mic */
0x4b4b, /* CD */
- 0x4b4b, /* Recording monitor */
+ 0x0000, /* Recording monitor */
0x4b4b, /* SB PCM */
0x4b4b, /* Recording level */
0x4b4b, /* Input gain */
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#define SEQ_2 2
static int seq_mode = SEQ_1;
-static wait_handle *seq_sleeper = NULL;
+static struct wait_queue *seq_sleeper = NULL;
static volatile struct snd_wait seq_sleep_flag =
{0};
-static wait_handle *midi_sleeper = NULL;
+static struct wait_queue *midi_sleeper = NULL;
static volatile struct snd_wait midi_sleep_flag =
{0};
1 : 0))
{
restore_flags (flags);
- return -(EAGAIN);
+ return -EAGAIN;
}
unsigned long tlimit;
if (pre_event_timeout)
- current_set_timeout (tlimit = jiffies + (pre_event_timeout));
+ current->timeout = tlimit = jiffies + (pre_event_timeout);
else
tlimit = (unsigned long) -1;
- midi_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&midi_sleeper);
- if (!(midi_sleep_flag.flags & WK_WAKEUP))
+ midi_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&midi_sleeper);
+ if (!(midi_sleep_flag.opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- midi_sleep_flag.flags |= WK_TIMEOUT;
+ midi_sleep_flag.opts |= WK_TIMEOUT;
}
- midi_sleep_flag.flags &= ~WK_SLEEP;
+ midi_sleep_flag.opts &= ~WK_SLEEP;
};
if (!iqlen)
while (iqlen && c >= ev_len)
{
- copy_to_user (&(buf)[p], (char *) &iqueue[iqhead * IEV_SZ], ev_len);
+ {
+ char *fixit = (char *) &iqueue[iqhead * IEV_SZ];
+
+ copy_to_user (&(buf)[p], fixit, ev_len);
+ };
p += ev_len;
c -= ev_len;
iqlen++;
iqtail = (iqtail + 1) % SEQ_MAX_QUEUE;
- if ((midi_sleep_flag.flags & WK_SLEEP))
+ if ((midi_sleep_flag.opts & WK_SLEEP))
{
{
- midi_sleep_flag.flags = WK_WAKEUP;
- module_wake_up (&midi_sleeper);
+ midi_sleep_flag.opts = WK_WAKEUP;
+ wake_up (&midi_sleeper);
};
}
restore_flags (flags);
DEB (printk ("sequencer_write(dev=%d, count=%d)\n", dev, count));
if (mode == OPEN_READ)
- return -(EIO);
+ return -EIO;
if (dev)
return pmgr_write (dev - 1, file, buf, count);
dev = *(unsigned short *) &event_rec[2];
if (dev < 0 || dev >= max_synthdev)
- return -(ENXIO);
+ return -ENXIO;
if (!(synth_open_mask & (1 << dev)))
- return -(ENXIO);
+ return -ENXIO;
err = synth_devs[dev]->load_patch (dev, *(short *) &event_rec[0], buf, p + 4, c, 0);
if (err < 0)
if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED)
{
printk ("Sequencer: Invalid level 2 event %x\n", ev_code);
- return -(EINVAL);
+ return -EINVAL;
}
ev_size = 8;
if (seq_mode == SEQ_2)
{
printk ("Sequencer: 4 byte event in level 2 mode\n");
- return -(EINVAL);
+ return -EINVAL;
}
ev_size = 4;
}
if (dev >= max_mididev)
{
printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev);
- return -(ENXIO);
+ return -ENXIO;
}
mode = file->mode & O_ACCMODE;
if (!processed && (file->flags & (O_NONBLOCK) ?
1 : 0))
- return -(EAGAIN);
+ return -EAGAIN;
else
return processed;
}
* Give chance to drain the queue
*/
- if (!nonblock && qlen >= SEQ_MAX_QUEUE && !(seq_sleep_flag.flags & WK_SLEEP))
+ if (!nonblock && qlen >= SEQ_MAX_QUEUE && !(seq_sleep_flag.opts & WK_SLEEP))
{
/*
* Sleep until there is enough space on the queue
*/
- seq_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&seq_sleeper);
- seq_sleep_flag.flags &= ~WK_SLEEP;;
+ seq_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&seq_sleeper);
+ seq_sleep_flag.opts &= ~WK_SLEEP;;
}
if (qlen >= SEQ_MAX_QUEUE)
int dev = q[2];
if (dev < 0 || dev >= max_synthdev)
- return -(ENXIO);
+ return -ENXIO;
if (!(synth_open_mask & (1 << dev)))
- return -(ENXIO);
+ return -ENXIO;
switch (q[1])
{
break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
return 0;
if (chn == 9)
{
synth_devs[dev]->set_instr (dev, voice, 128 + note);
- synth_devs[dev]->chn_info[chn].pgm_num = 128 + note;
+ synth_devs[dev]->chn_info[chn].pgm_num = 128 + note;
note = 60; /* Middle C */
}
save_flags (flags);
cli ();
- if ((seq_sleep_flag.flags & WK_SLEEP))
+ if ((seq_sleep_flag.opts & WK_SLEEP))
{
{
- seq_sleep_flag.flags = WK_WAKEUP;
- module_wake_up (&seq_sleeper);
+ seq_sleep_flag.opts = WK_WAKEUP;
+ wake_up (&seq_sleeper);
};
}
restore_flags (flags);
{
long time;
- seq_playing = 1;
time = parm;
prev_event_time = time;
+ seq_playing = 1;
request_sound_timer (time);
if ((SEQ_MAX_QUEUE - qlen) >= output_threshold)
save_flags (flags);
cli ();
- if ((seq_sleep_flag.flags & WK_SLEEP))
+ if ((seq_sleep_flag.opts & WK_SLEEP))
{
{
- seq_sleep_flag.flags = WK_WAKEUP;
- module_wake_up (&seq_sleeper);
+ seq_sleep_flag.opts = WK_WAKEUP;
+ wake_up (&seq_sleeper);
};
}
restore_flags (flags);
save_flags (flags);
cli ();
- if ((seq_sleep_flag.flags & WK_SLEEP))
+ if ((seq_sleep_flag.opts & WK_SLEEP))
{
{
- seq_sleep_flag.flags = WK_WAKEUP;
- module_wake_up (&seq_sleeper);
+ seq_sleep_flag.opts = WK_WAKEUP;
+ wake_up (&seq_sleeper);
};
}
restore_flags (flags);
if (dev < 0 || dev >= num_midis)
break;
- if (!midi_devs[dev]->putc (dev, q[1]))
+ if (!midi_devs[dev]->outputc (dev, q[1]))
{
/*
* Output FIFO is full. Wait one timer cycle and try again.
save_flags (flags);
cli ();
- if ((seq_sleep_flag.flags & WK_SLEEP))
+ if ((seq_sleep_flag.opts & WK_SLEEP))
{
{
- seq_sleep_flag.flags = WK_WAKEUP;
- module_wake_up (&seq_sleeper);
+ seq_sleep_flag.opts = WK_WAKEUP;
+ wake_up (&seq_sleeper);
};
}
restore_flags (flags);
if (!sequencer_ok)
{
printk ("Soundcard: Sequencer not initialized\n");
- return -(ENXIO);
+ return -ENXIO;
}
if (dev) /* Patch manager device */
{
printk ("Patch manager interface is currently broken. Sorry\n");
- return -(ENXIO);
+ return -ENXIO;
}
save_flags (flags);
cli ();
if (sequencer_busy)
{
- printk ("Sequencer busy\n");
restore_flags (flags);
- return -(EBUSY);
+ return -EBUSY;
}
sequencer_busy = 1;
restore_flags (flags);
{
printk ("sequencer: No timer for level 2\n");
sequencer_busy = 0;
- return -(ENXIO);
+ return -ENXIO;
}
setup_mode2 ();
}
- if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE))
+ if (seq_mode == SEQ_1 && mode == OPEN_READ)
if (!max_mididev)
{
printk ("Sequencer: No Midi devices. Input not possible\n");
sequencer_busy = 0;
- return -(ENXIO);
+ return -ENXIO;
}
if (!max_synthdev && !max_mididev)
- return -(ENXIO);
+ return -ENXIO;
synth_open_mask = 0;
tmr->open (tmr_no, seq_mode);
}
- seq_sleep_flag.flags = WK_NONE;
- midi_sleep_flag.flags = WK_NONE;
+ seq_sleep_flag.opts = WK_NONE;
+ midi_sleep_flag.opts = WK_NONE;
output_threshold = SEQ_MAX_QUEUE / 2;
for (i = 0; i < num_synths; i++)
n = 1;
- while (!current_got_fatal_signal () && n)
+ while (!(current->signal & ~current->blocked) && n)
{
n = 0;
unsigned long tlimit;
if (HZ / 10)
- current_set_timeout (tlimit = jiffies + (HZ / 10));
+ current->timeout = tlimit = jiffies + (HZ / 10);
else
tlimit = (unsigned long) -1;
- seq_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&seq_sleeper);
- if (!(seq_sleep_flag.flags & WK_WAKEUP))
+ seq_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&seq_sleeper);
+ if (!(seq_sleep_flag.opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- seq_sleep_flag.flags |= WK_TIMEOUT;
+ seq_sleep_flag.opts |= WK_TIMEOUT;
}
- seq_sleep_flag.flags &= ~WK_SLEEP;
+ seq_sleep_flag.opts &= ~WK_SLEEP;
};
}
}
if (mode != OPEN_READ && !(file->flags & (O_NONBLOCK) ?
1 : 0))
- while (!current_got_fatal_signal () && qlen)
+ while (!(current->signal & ~current->blocked) && qlen > 0)
{
seq_sync ();
}
*/
for (i = 0; i < max_synthdev; i++)
- if (synth_open_mask & (1 << i)) /*
+ {
+ if (synth_open_mask & (1 << i)) /*
* Actually opened
*/
- if (synth_devs[i])
- {
- synth_devs[i]->close (i);
+ if (synth_devs[i])
+ {
+ synth_devs[i]->close (i);
- if (synth_devs[i]->midi_dev)
- midi_opened[synth_devs[i]->midi_dev] = 0;
- }
+ if (synth_devs[i]->midi_dev)
+ midi_opened[synth_devs[i]->midi_dev] = 0;
+ }
+ }
for (i = 0; i < num_synths; i++)
if (pmgr_present[i])
pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0);
for (i = 0; i < max_mididev; i++)
- if (midi_opened[i])
- midi_devs[i]->close (i);
+ {
+ if (midi_opened[i])
+ midi_devs[i]->close (i);
+ }
if (seq_mode == SEQ_2)
tmr->close (tmr_no);
{
unsigned long flags;
- if (qlen && !seq_playing && !current_got_fatal_signal ())
+ if (qlen && !seq_playing && !(current->signal & ~current->blocked))
seq_startplay ();
save_flags (flags);
cli ();
- if (qlen && !(seq_sleep_flag.flags & WK_SLEEP))
+ if (qlen > 0)
{
{
unsigned long tlimit;
if (HZ)
- current_set_timeout (tlimit = jiffies + (HZ));
+ current->timeout = tlimit = jiffies + (HZ);
else
tlimit = (unsigned long) -1;
- seq_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&seq_sleeper);
- if (!(seq_sleep_flag.flags & WK_WAKEUP))
+ seq_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&seq_sleeper);
+ if (!(seq_sleep_flag.opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- seq_sleep_flag.flags |= WK_TIMEOUT;
+ seq_sleep_flag.opts |= WK_TIMEOUT;
}
- seq_sleep_flag.flags &= ~WK_SLEEP;
+ seq_sleep_flag.opts &= ~WK_SLEEP;
};
}
restore_flags (flags);
save_flags (flags);
cli ();
- while (n && !midi_devs[dev]->putc (dev, data))
+ while (n && !midi_devs[dev]->outputc (dev, data))
{
{
unsigned long tlimit;
if (4)
- current_set_timeout (tlimit = jiffies + (4));
+ current->timeout = tlimit = jiffies + (4);
else
tlimit = (unsigned long) -1;
- seq_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&seq_sleeper);
- if (!(seq_sleep_flag.flags & WK_WAKEUP))
+ seq_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&seq_sleeper);
+ if (!(seq_sleep_flag.opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- seq_sleep_flag.flags |= WK_TIMEOUT;
+ seq_sleep_flag.opts |= WK_TIMEOUT;
}
- seq_sleep_flag.flags &= ~WK_SLEEP;
+ seq_sleep_flag.opts &= ~WK_SLEEP;
};
n--;
}
save_flags (flags);
cli ();
- if ((seq_sleep_flag.flags & WK_SLEEP))
+ if ((seq_sleep_flag.opts & WK_SLEEP))
{
/* printk ("Sequencer Warning: Unexpected sleeping process - Waking up\n"); */
{
- seq_sleep_flag.flags = WK_WAKEUP;
- module_wake_up (&seq_sleeper);
+ seq_sleep_flag.opts = WK_WAKEUP;
+ wake_up (&seq_sleeper);
};
}
restore_flags (flags);
case SNDCTL_TMR_METRONOME:
case SNDCTL_TMR_SOURCE:
if (dev) /* Patch manager */
- return -(EIO);
+ return -EIO;
if (seq_mode != SEQ_2)
- return -(EINVAL);
+ return -EINVAL;
return tmr->ioctl (tmr_no, cmd, arg);
break;
case SNDCTL_TMR_SELECT:
if (dev) /* Patch manager */
- return -(EIO);
+ return -EIO;
if (seq_mode != SEQ_2)
- return -(EINVAL);
- pending_timer = get_user ((int *) arg);
+ return -EINVAL;
+ get_user (pending_timer, (int *) arg);
if (pending_timer < 0 || pending_timer >= num_sound_timers)
{
pending_timer = -1;
- return -(EINVAL);
+ return -EINVAL;
}
- return snd_ioctl_return ((int *) arg, pending_timer);
+ return ioctl_out (arg, pending_timer);
break;
case SNDCTL_SEQ_PANIC:
if (dev) /*
* Patch manager
*/
- return -(EIO);
+ return -EIO;
if (mode == OPEN_READ)
return 0;
- while (qlen && !current_got_fatal_signal ())
+ while (qlen > 0 && !(current->signal & ~current->blocked))
seq_sync ();
if (qlen)
- return -(EINTR);
+ return -EINTR;
else
return 0;
break;
if (dev) /*
* Patch manager
*/
- return -(EIO);
+ return -EIO;
seq_reset ();
return 0;
if (dev) /*
* Patch manager
*/
- return -(EIO);
+ return -EIO;
- midi_dev = get_user ((int *) arg);
+ get_user (midi_dev, (int *) arg);
if (midi_dev >= max_mididev)
- return -(ENXIO);
+ return -ENXIO;
if (!midi_opened[midi_dev])
{
if (dev) /*
* Patch manager
*/
- return -(EIO);
+ return -EIO;
if (mode == OPEN_WRITE)
return 0;
- return snd_ioctl_return ((int *) arg, iqlen);
+ return ioctl_out (arg, iqlen);
break;
case SNDCTL_SEQ_GETOUTCOUNT:
if (mode == OPEN_READ)
return 0;
- return snd_ioctl_return ((int *) arg, SEQ_MAX_QUEUE - qlen);
+ return ioctl_out (arg, SEQ_MAX_QUEUE - qlen);
+ break;
+
+ case SNDCTL_SEQ_GETTIME:
+ if (seq_mode == SEQ_2)
+ return tmr->ioctl (tmr_no, cmd, arg);
+
+ return ioctl_out (arg, jiffies - seq_time);
break;
case SNDCTL_SEQ_CTRLRATE:
if (dev) /* Patch manager */
- return -(EIO);
+ return -EIO;
/*
* If *arg == 0, just return the current rate
if (seq_mode == SEQ_2)
return tmr->ioctl (tmr_no, cmd, arg);
- if (get_user ((int *) arg) != 0)
- return -(EINVAL);
+ if (ioctl_in (arg) != 0)
+ return -EINVAL;
- return snd_ioctl_return ((int *) arg, HZ);
+ return ioctl_out (arg, HZ);
break;
case SNDCTL_SEQ_RESETSAMPLES:
{
int err;
- dev = get_user ((int *) arg);
+ get_user (dev, (int *) arg);
if (dev < 0 || dev >= num_synths)
{
- return -(ENXIO);
+ return -ENXIO;
}
if (!(synth_open_mask & (1 << dev)) && !orig_dev)
{
- return -(EBUSY);
+ return -EBUSY;
}
if (!orig_dev && pmgr_present[dev])
break;
case SNDCTL_SEQ_NRSYNTHS:
- return snd_ioctl_return ((int *) arg, max_synthdev);
+ return ioctl_out (arg, max_synthdev);
break;
case SNDCTL_SEQ_NRMIDIS:
- return snd_ioctl_return ((int *) arg, max_mididev);
+ return ioctl_out (arg, max_mididev);
break;
case SNDCTL_SYNTH_MEMAVL:
{
- int dev = get_user ((int *) arg);
+ int dev;
+
+ get_user (dev, (int *) arg);
if (dev < 0 || dev >= num_synths)
- return -(ENXIO);
+ return -ENXIO;
if (!(synth_open_mask & (1 << dev)) && !orig_dev)
- return -(EBUSY);
+ return -EBUSY;
- return snd_ioctl_return ((int *) arg, synth_devs[dev]->ioctl (dev, cmd, arg));
+ return ioctl_out (arg, synth_devs[dev]->ioctl (dev, cmd, arg));
}
break;
case SNDCTL_FM_4OP_ENABLE:
{
- int dev = get_user ((int *) arg);
+ int dev = ioctl_in (arg);
if (dev < 0 || dev >= num_synths)
- return -(ENXIO);
+ return -ENXIO;
if (!(synth_open_mask & (1 << dev)))
- return -(ENXIO);
+ return -ENXIO;
synth_devs[dev]->ioctl (dev, cmd, arg);
return 0;
dev = inf.device;
if (dev < 0 || dev >= max_synthdev)
- return -(ENXIO);
+ return -ENXIO;
if (!(synth_open_mask & (1 << dev)) && !orig_dev)
- return -(EBUSY);
+ return -EBUSY;
return synth_devs[dev]->ioctl (dev, cmd, arg);
}
{
struct midi_info inf;
int dev;
+ char *pp;
copy_from_user ((char *) &inf, &((char *) arg)[0], sizeof (inf));
dev = inf.device;
if (dev < 0 || dev >= max_mididev)
- return -(ENXIO);
+ return -ENXIO;
+
+ pp = (char *) &midi_devs[dev]->info;
+ {
+ char *fixit = pp;
- copy_to_user (&((char *) arg)[0], (char *) &(midi_devs[dev]->info), sizeof (inf));
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (inf));
+ };
return 0;
}
break;
if ((inf = (struct patmgr_info *) vmalloc (sizeof (*inf))) == NULL)
{
printk ("patmgr: Can't allocate memory for a message\n");
- return -(EIO);
+ return -EIO;
}
copy_from_user ((char *) inf, &((char *) arg)[0], sizeof (*inf));
if (dev < 0 || dev >= num_synths)
{
vfree (inf);
- return -(ENXIO);
+ return -ENXIO;
}
if (!synth_devs[dev]->pmgr_interface)
{
vfree (inf);
- return -(ENXIO);
+ return -ENXIO;
}
if ((err = synth_devs[dev]->pmgr_interface (dev, inf)) == -1)
return err;
}
- copy_to_user (&((char *) arg)[0], (char *) inf, sizeof (*inf));
+ {
+ char *fixit = (char *) inf;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (*inf));
+ };
vfree (inf);
return 0;
}
if ((inf = (struct patmgr_info *) vmalloc (sizeof (*inf))) == NULL)
{
printk ("patmgr: Can't allocate memory for a message\n");
- return -(EIO);
+ return -EIO;
}
copy_from_user ((char *) inf, &((char *) arg)[0], sizeof (*inf));
if (dev < 0 || dev >= num_synths)
{
vfree (inf);
- return -(ENXIO);
+ return -ENXIO;
}
if (!pmgr_present[dev])
{
vfree (inf);
- return -(ESRCH);
+ return -ESRCH;
}
if ((err = pmgr_access (dev, inf)) < 0)
return err;
}
- copy_to_user (&((char *) arg)[0], (char *) inf, sizeof (*inf));
+ {
+ char *fixit = (char *) inf;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (*inf));
+ };
vfree (inf);
return 0;
}
case SNDCTL_SEQ_THRESHOLD:
{
- int tmp = get_user ((int *) arg);
+ int tmp = ioctl_in (arg);
if (dev) /*
* Patch manager
*/
- return -(EIO);
+ return -EIO;
if (tmp < 1)
tmp = 1;
case SNDCTL_MIDI_PRETIME:
{
- int val = get_user ((int *) arg);
+ int val = ioctl_in (arg);
if (val < 0)
val = 0;
val = (HZ * val) / 10;
pre_event_timeout = val;
- return snd_ioctl_return ((int *) arg, val);
+ return ioctl_out (arg, val);
}
break;
if (dev) /*
* Patch manager
*/
- return -(EIO);
+ return -EIO;
if (mode == OPEN_READ)
- return -(EIO);
+ return -EIO;
if (!synth_devs[0])
- return -(ENXIO);
+ return -ENXIO;
if (!(synth_open_mask & (1 << 0)))
- return -(ENXIO);
+ return -ENXIO;
return synth_devs[0]->ioctl (0, cmd, arg);
break;
}
- return -(EINVAL);
+ return -EINVAL;
}
int
-sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table_handle * wait)
+sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
{
unsigned long flags;
if (!iqlen)
{
- midi_sleep_flag.flags = WK_SLEEP;
- module_select_wait (&midi_sleeper, wait);
+ midi_sleep_flag.opts = WK_SLEEP;
+ select_wait (&midi_sleeper, wait);
restore_flags (flags);
return 0;
}
if ((SEQ_MAX_QUEUE - qlen) < output_threshold)
{
- seq_sleep_flag.flags = WK_SLEEP;
- module_select_wait (&seq_sleeper, wait);
+ seq_sleep_flag.opts = WK_SLEEP;
+ select_wait (&seq_sleeper, wait);
restore_flags (flags);
return 0;
}
void DMAbuf_reset_dma (int dev);
void DMAbuf_inputintr(int dev);
void DMAbuf_outputintr(int dev, int underflow_flag);
-int DMAbuf_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait);
+int DMAbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
+void DMAbuf_start_device(int dev);
void DMAbuf_start_devices(unsigned int devmask);
+void DMAbuf_reset (int dev);
+int DMAbuf_sync (int dev);
/*
* System calls for /dev/dsp and /dev/audio
void audio_release (int dev, struct fileinfo *file);
int audio_ioctl (int dev, struct fileinfo *file,
unsigned int cmd, caddr_t arg);
-int audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
-void audio_init (void);
+void audio_init_devices (void);
-int audio_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait);
+int audio_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
/*
* System calls for the /dev/sequencer
void seq_input_event(unsigned char *event, int len);
void seq_copy_to_input (unsigned char *event, int len);
-int sequencer_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait);
+int sequencer_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
/*
* System calls for the /dev/midi
void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count);
void MIDIbuf_init(void);
-int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait);
+int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
/*
*
void sound_dma_free(int dev);
void conf_printf(char *name, struct address_info *hw_config);
void conf_printf2(char *name, int base, int irq, int dma, int dma2);
+int ioctl_in(caddr_t arg);
+int ioctl_out(caddr_t arg, int result);
/* From sound_switch.c */
int sound_read_sw (int dev, struct fileinfo *file, char *buf, int count);
#define AD_F_CS4231 0x0001 /* Returned if a CS4232 (or compatible) detected */
#define AD_F_CS4248 0x0001 /* Returned if a CS4248 (or compatible) detected */
+void ad1848_control(int cmd, int arg);
+#define AD1848_SET_XTAL 1
+#define AD1848_MIXER_REROUTE 2
+#define AD1848_REROUTE(oldctl, newctl) \
+ ad1848_control(AD1848_MIXER_REROUTE, ((oldctl)<<8)|(newctl))
+
void ad1848_interrupt (int irq, void *dev_id, struct pt_regs * dummy);
void attach_ms_sound(struct address_info * hw_config);
int probe_ms_sound(struct address_info *hw_config);
int probe_ss_ms_sound (struct address_info *hw_config);
void attach_ss_ms_sound(struct address_info * hw_config);
-int pss_read (int dev, struct fileinfo *file, char *buf, int count);
-int pss_write (int dev, struct fileinfo *file, char *buf, int count);
-int pss_open (int dev, struct fileinfo *file);
-void pss_release (int dev, struct fileinfo *file);
-int pss_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, caddr_t arg);
-int pss_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
-void pss_init(void);
-
/* From aedsp16.c */
int InitAEDSP16_SBPRO(struct address_info *hw_config);
int InitAEDSP16_MSS(struct address_info *hw_config);
void attach_maui(struct address_info * hw_config);
int probe_maui(struct address_info *hw_config);
-/* From sound_pnp.c */
-void sound_pnp_init(int *osp);
-void sound_pnp_disconnect(void);
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#include "os.h"
#include "soundvers.h"
-#if defined(ISC) || defined(SCO) || defined(SVR42)
-#define GENERIC_SYSV
-#endif
-
#define MAX_REALTIME_FACTOR 4
#endif
-/************* PCM DMA buffer sizes *******************/
-
-/* If you are using high playback or recording speeds, the default buffer size
- is too small. DSP_BUFFSIZE must be 64k or less.
-
- A rule of thumb is 64k for PAS16, 32k for PAS+, 16k for SB Pro and
- 4k for SB.
-
- If you change the DSP_BUFFSIZE, don't modify this file.
- Use the make config command instead. */
-
-#ifndef DSP_BUFFSIZE
-#define DSP_BUFFSIZE (4096)
-#endif
+/*
+ * Use always 64k buffer size. There is no reason to use shorter.
+ */
+#undef DSP_BUFFSIZE
+#define DSP_BUFFSIZE (16*1024)
#ifndef DSP_BUFFCOUNT
#define DSP_BUFFCOUNT 1 /* 1 is recommended. */
int driver_use_1; /* Driver defined field 1 */
int driver_use_2; /* Driver defined field 2 */
int *osp; /* OS specific info */
- int card_subtype; /* Driver specific. Usually 0 */
+ int card_subtype; /* Driver spesific. Usually 0 */
};
#define SYNTH_MAX_VOICES 32
#endif
#ifndef DDB
-#define DDB(x)
+#define DDB(x) {}
#endif
#define TIMER_ARMED 121234
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#include "sound_config.h"
-struct sbc_device
- {
- int usecount;
- };
-
static int in_use = 0; /* Total # of open devices */
+/*
+ * Table for configurable mixer volume handling
+ */
+static mixer_vol_table mixer_vols[MAX_MIXER_DEV];
+static int num_mixer_volumes = 0;
+
/*
* /dev/sndstatus -device
*/
static int status_len, status_ptr;
static int status_busy = 0;
+int
+ *
+load_mixer_volumes (char *name, int *levels, int present)
+{
+ int i, n;
+
+ for (i = 0; i < num_mixer_volumes; i++)
+ if (strcmp (name, mixer_vols[i].name) == 0)
+ {
+ if (present)
+ mixer_vols[i].num = i;
+ return mixer_vols[i].levels;
+ }
+
+ if (num_mixer_volumes >= MAX_MIXER_DEV)
+ {
+ printk ("Sound: Too many mixers (%s)\n", name);
+ return levels;
+ }
+
+ n = num_mixer_volumes++;
+
+ strcpy (mixer_vols[n].name, name);
+
+ if (present)
+ mixer_vols[n].num = n;
+ else
+ mixer_vols[n].num = -1;
+
+ for (i = 0; i < 32; i++)
+ mixer_vols[n].levels[i] = levels[i];
+ return mixer_vols[n].levels;
+}
+
+static int
+set_mixer_levels (caddr_t arg)
+{
+ mixer_vol_table *buf = NULL;
+ int err = 0;
+
+ if ((buf = (mixer_vol_table *) vmalloc (sizeof (mixer_vol_table))) == NULL)
+ return -ENOSPC;
+
+ copy_from_user ((char *) buf, &((char *) arg)[0], sizeof (*buf));
+
+ load_mixer_volumes (buf->name, buf->levels, 0);
+
+ {
+ char *fixit = (char *) buf;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (*buf));
+ };
+ vfree (buf);
+
+ return err;
+}
+
+static int
+get_mixer_levels (caddr_t arg)
+{
+ mixer_vol_table *buf = NULL;
+ int n, err = 0;
+
+ if ((buf = (mixer_vol_table *) vmalloc (sizeof (mixer_vol_table))) == NULL)
+ return -ENOSPC;
+
+ copy_from_user ((char *) buf, &((char *) arg)[0], sizeof (*buf));
+
+ n = buf->num;
+ if (n < 0 || n >= num_mixer_volumes)
+ err = -EINVAL;
+ else
+ {
+ memcpy ((char *) buf, (char *) &mixer_vols[n], sizeof (*buf));
+ }
+
+ {
+ char *fixit = (char *) buf;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (*buf));
+ };
+ vfree (buf);
+
+ return err;
+}
+
static int
put_status (char *s)
{
put_status (system_utsname.machine);
put_status ("\n");
+
if (!put_status ("Config options: "))
return;
if (!put_status_int (SELECTED_SOUND_OPTIONS, 16))
return;
}
+
if (!put_status ("\nCard config: \n"))
return;
}
#endif
+#ifdef CONFIG_MIDI
if (!put_status ("\nTimers:\n"))
return;
if (!put_status ("\n"))
return;
}
+#endif
if (!put_status ("\nMixers:\n"))
return;
if (l <= 0)
return 0;
- copy_to_user (&(buf)[0], &status_buf[status_ptr], l);
+ {
+ char *fixit = &status_buf[status_ptr];
+
+ copy_to_user (&(buf)[0], fixit, l);
+ };
status_ptr += l;
return l;
return MIDIbuf_read (dev, file, buf, count);
#endif
- default:
- printk ("Sound: Undefined minor device %d\n", dev);
+ default:;
}
- return -(EPERM);
+ return -EINVAL;
}
int
DEB (printk ("sound_write_sw(dev=%d, count=%d)\n", dev, count));
+
switch (dev & 0x0f)
{
}
- return -(EPERM);
+ return -EINVAL;
}
int
if ((dev >= SND_NDEVS) || (dev < 0))
{
printk ("Invalid minor device %d\n", dev);
- return -(ENXIO);
+ return -ENXIO;
}
+
switch (dev & 0x0f)
{
case SND_DEV_STATUS:
if (status_busy)
- return -(EBUSY);
+ return -EBUSY;
status_busy = 1;
if ((status_buf = (char *) vmalloc (4000)) == NULL)
- return -(EIO);
+ return -EIO;
status_len = status_ptr = 0;
init_status ();
break;
case SND_DEV_CTL:
if ((dev & 0xf0) && ((dev & 0xf0) >> 4) >= num_mixers)
- return -(ENXIO);
+ return -ENXIO;
return 0;
break;
default:
printk ("Invalid minor device %d\n", dev);
- return -(ENXIO);
+ return -ENXIO;
}
in_use++;
mixer_info info;
if (dev < 0 || dev >= num_mixers)
- return -(ENXIO);
+ return -ENXIO;
+
+ strcpy (info.id, mixer_devs[dev]->id);
+ strcpy (info.name, mixer_devs[dev]->name);
+ info.modify_counter = mixer_devs[dev]->modify_counter;
+
+ {
+ char *fixit = (char *) &info;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (info));
+ };
+ return 0;
+}
+
+static int
+get_old_mixer_info (int dev, caddr_t arg)
+{
+ _old_mixer_info info;
+
+ if (dev < 0 || dev >= num_mixers)
+ return -ENXIO;
strcpy (info.id, mixer_devs[dev]->id);
strcpy (info.name, mixer_devs[dev]->name);
- copy_to_user (&((char *) arg)[0], (char *) &info, sizeof (info));
+ {
+ char *fixit = (char *) &info;
+
+ copy_to_user (&((char *) arg)[0], fixit, sizeof (info));
+ };
return 0;
}
+static int
+sound_mixer_ioctl (int mixdev,
+ unsigned int cmd, caddr_t arg)
+{
+ if (cmd == SOUND_MIXER_INFO)
+ return get_mixer_info (mixdev, arg);
+ if (cmd == SOUND_OLD_MIXER_INFO)
+ return get_old_mixer_info (mixdev, arg);
+
+ if (_IOC_DIR (cmd) & _IOC_WRITE)
+ mixer_devs[mixdev]->modify_counter++;
+
+ return mixer_devs[mixdev]->ioctl (mixdev, cmd, arg);
+}
+
int
sound_ioctl_sw (int dev, struct fileinfo *file,
unsigned int cmd, caddr_t arg)
{
DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
+ if (cmd == OSS_GETVERSION)
+ return ioctl_out (arg, SOUND_VERSION);
+
+
if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0) /* Mixer ioctl */
if ((dev & 0x0f) != SND_DEV_CTL)
{
case SND_DEV_AUDIO:
mixdev = audio_devs[dev >> 4]->mixer_dev;
if (mixdev < 0 || mixdev >= num_mixers)
- return -(ENXIO);
- if (cmd == SOUND_MIXER_INFO)
- return get_mixer_info (mixdev, arg);
- return mixer_devs[mixdev]->ioctl (mixdev, cmd, arg);
+ return -ENXIO;
+ return sound_mixer_ioctl (mixdev, cmd, arg);
break;
#endif
default:
- if (cmd == SOUND_MIXER_INFO)
- return get_mixer_info (0, arg);
- return mixer_devs[0]->ioctl (0, cmd, arg);
+ return sound_mixer_ioctl (dev, cmd, arg);
}
}
{
case SND_DEV_CTL:
+ if (cmd == SOUND_MIXER_GETLEVELS)
+ return get_mixer_levels (arg);
+ if (cmd == SOUND_MIXER_SETLEVELS)
+ return set_mixer_levels (arg);
if (!num_mixers)
- return -(ENXIO);
+ return -ENXIO;
dev = dev >> 4;
if (dev >= num_mixers)
- return -(ENXIO);
+ return -ENXIO;
- if (cmd == SOUND_MIXER_INFO)
- return get_mixer_info (dev, arg);
- return mixer_devs[dev]->ioctl (dev, cmd, arg);
+ return sound_mixer_ioctl (dev, cmd, arg);
break;
#ifdef CONFIG_SEQUENCER
}
- return -(EPERM);
+ return -EINVAL;
}
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
timer_open (int dev, int mode)
{
if (opened)
- return -(EBUSY);
+ return -EBUSY;
tmr_reset ();
curr_tempo = 60;
switch (cmd)
{
case SNDCTL_TMR_SOURCE:
- return snd_ioctl_return ((int *) arg, TMR_INTERNAL);
+ return ioctl_out (arg, TMR_INTERNAL);
break;
case SNDCTL_TMR_START:
case SNDCTL_TMR_TIMEBASE:
{
- int val = get_user ((int *) arg);
+ int val;
+
+ get_user (val, (int *) arg);
if (val)
{
curr_timebase = val;
}
- return snd_ioctl_return ((int *) arg, curr_timebase);
+ return ioctl_out (arg, curr_timebase);
}
break;
case SNDCTL_TMR_TEMPO:
{
- int val = get_user ((int *) arg);
+ int val;
+
+ get_user (val, (int *) arg);
if (val)
{
reprogram_timer ();
}
- return snd_ioctl_return ((int *) arg, curr_tempo);
+ return ioctl_out (arg, curr_tempo);
}
break;
case SNDCTL_SEQ_CTRLRATE:
- if (get_user ((int *) arg) != 0) /* Can't change */
- return -(EINVAL);
+ if (ioctl_in (arg) != 0) /* Can't change */
+ return -EINVAL;
+
+ return ioctl_out (arg, ((curr_tempo * curr_timebase) + 30) / 60);
+ break;
- return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60);
+ case SNDCTL_SEQ_GETTIME:
+ return ioctl_out (arg, curr_ticks);
break;
case SNDCTL_TMR_METRONOME:
default:;
}
- return -(EINVAL);
+ return -EINVAL;
}
static void
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#include <linux/major.h>
-int *sound_global_osp = NULL;
+int *sound_osp = NULL;
static int chrdev_registered = 0;
static int sound_major = SOUND_MAJOR;
#define DMA_MAP_BUSY 2
+int
+ioctl_in (caddr_t arg)
+{
+ int xx;
+
+ get_user (xx, (int *) arg);
+ return xx;
+}
+
+int
+ioctl_out (caddr_t arg, int result)
+{
+ put_user (result, (int *) arg);
+ return 0;
+}
+
int
snd_ioctl_return (int *addr, int value)
{
if (value < 0)
return value;
- put_user (value, addr);
+ put_user (value, (int *) &((addr)[0]));
return 0;
}
static long
-sound_read (inode_handle * inode, file_handle * file, char *buf, unsigned long count)
+sound_read (struct inode *inode, struct file *file, char *buf, unsigned long count)
{
int dev;
- dev = MINOR (inode_get_rdev (inode));
+ dev = MINOR (inode->i_rdev);
- files[dev].flags = file_get_flags (file);
+ files[dev].flags = file->f_flags;
return sound_read_sw (dev, &files[dev], buf, count);
}
static long
-sound_write (inode_handle * inode, file_handle * file, const char *buf, unsigned long count)
+sound_write (struct inode *inode, struct file *file, const char *buf, unsigned long count)
{
int dev;
- dev = MINOR (inode_get_rdev (inode));
+ dev = MINOR (inode->i_rdev);
- files[dev].flags = file_get_flags (file);
+ files[dev].flags = file->f_flags;
return sound_write_sw (dev, &files[dev], buf, count);
}
static long long
-sound_lseek (inode_handle * inode, file_handle * file, long long offset, int orig)
+sound_lseek (struct inode *inode, struct file *file, long long offset, int orig)
{
- return -(EPERM);
+ return -EPERM;
}
static int
-sound_open (inode_handle * inode, file_handle * file)
+sound_open (struct inode *inode, struct file *file)
{
int dev, retval;
struct fileinfo tmp_file;
if (is_unloading)
{
printk ("Sound: Driver partially removed. Can't open device\n");
- return -(EBUSY);
+ return -EBUSY;
}
- dev = MINOR (inode_get_rdev (inode));
+ dev = MINOR (inode->i_rdev);
if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS)
{
- printk ("Sound Card Error: The soundcard system has not been configured\n");
- return -(ENXIO);
+ printk ("SoundCard Error: The soundcard system has not been configured\n");
+ return -ENXIO;
}
tmp_file.mode = 0;
- tmp_file.flags = file_get_flags (file);
+ tmp_file.flags = file->f_flags;
if ((tmp_file.flags & O_ACCMODE) == O_RDWR)
tmp_file.mode = OPEN_READWRITE;
}
static void
-sound_release (inode_handle * inode, file_handle * file)
+sound_release (struct inode *inode, struct file *file)
{
int dev;
- dev = MINOR (inode_get_rdev (inode));
+ dev = MINOR (inode->i_rdev);
- files[dev].flags = file_get_flags (file);
+ files[dev].flags = file->f_flags;
sound_release_sw (dev, &files[dev]);
#ifdef MODULE
}
static int
-sound_ioctl (inode_handle * inode, file_handle * file,
+sound_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int dev, err;
- dev = MINOR (inode_get_rdev (inode));
+ dev = MINOR (inode->i_rdev);
- files[dev].flags = file_get_flags (file);
+ files[dev].flags = file->f_flags;
if (_IOC_DIR (cmd) != _IOC_NONE)
{
}
static int
-sound_select (inode_handle * inode, file_handle * file, int sel_type, select_table_handle * wait)
+sound_select (struct inode *inode, struct file *file, int sel_type, select_table * wait)
{
int dev;
- dev = MINOR (inode_get_rdev (inode));
+ dev = MINOR (inode->i_rdev);
- files[dev].flags = file_get_flags (file);
+ files[dev].flags = file->f_flags;
DEB (printk ("sound_select(dev=%d, type=0x%x)\n", dev, sel_type));
}
static int
-sound_mmap (inode_handle * inode, file_handle * file, vm_area_handle * vma)
+sound_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
{
int dev, dev_class;
unsigned long size;
struct dma_buffparms *dmap = NULL;
- dev = MINOR (inode_get_rdev (inode));
+ dev = MINOR (inode->i_rdev);
- files[dev].flags = file_get_flags (file);
+ files[dev].flags = file->f_flags;
dev_class = dev & 0x0f;
dev >>= 4;
return -EINVAL;
}
- if ((vma_get_flags (vma) & (VM_READ | VM_WRITE)) == (VM_READ | VM_WRITE))
+ if ((vma->vm_flags & (VM_READ | VM_WRITE)) == (VM_READ | VM_WRITE))
{
printk ("Sound: Cannot do read/write mmap()\n");
return -EINVAL;
}
- if (vma_get_flags (vma) & VM_READ)
+ if (vma->vm_flags & VM_READ)
{
dmap = audio_devs[dev]->dmap_in;
}
- else if (vma_get_flags (vma) & VM_WRITE)
+ else if (vma->vm_flags & VM_WRITE)
{
dmap = audio_devs[dev]->dmap_out;
}
return -EIO;
}
- if (vma_get_offset (vma) != 0)
+ if (vma->vm_offset != 0)
{
printk ("Sound: mmap() offset must be 0.\n");
return -EINVAL;
}
- size = vma_get_end (vma) - vma_get_start (vma);
+ size = vma->vm_end - vma->vm_start;
if (size != dmap->bytes_in_use)
{
size, dmap->bytes_in_use);
}
- if (remap_page_range (vma_get_start (vma), virt_to_phys(dmap->raw_buf),
- vma_get_end (vma) - vma_get_start (vma),
- vma_get_page_prot (vma)))
+ if (remap_page_range (vma->vm_start, virt_to_phys (dmap->raw_buf),
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
return -EAGAIN;
- vma_set_inode (vma, inode);
- inode_inc_count (inode);
+ vma->vm_inode = inode;
+ inode->i_count++;
dmap->mapping_flags |= DMA_MAP_MAPPED;
return 0;
}
-static struct file_operation_handle sound_fops =
+static struct file_operations sound_fops =
{
sound_lseek,
sound_read,
soundcard_init (void)
{
#ifndef MODULE
- module_register_chrdev (sound_major, "sound", &sound_fops);
+ register_chrdev (sound_major, "sound", &sound_fops);
chrdev_registered = 1;
#endif
sndtable_init (); /* Initialize call tables and detect cards */
-
-#ifdef CONFIG_LOWLEVEL_SOUND
- {
- extern void sound_init_lowlevel_drivers (void);
-
- sound_init_lowlevel_drivers ();
- }
-#endif
-
if (sndtable_get_cardcount () == 0)
return; /* No cards detected */
if (num_audiodevs) /* Audio devices present */
{
DMAbuf_init ();
- audio_init ();
+ audio_init_devices ();
}
#endif
int ints[21];
int i;
- if (connect_wrapper (WRAPPER_VERSION) < 0)
+ if (0 < 0)
{
printk ("Sound: Incompatible kernel (wrapper) version\n");
return -EINVAL;
if (i)
sound_setup ("sound=", ints);
- err = module_register_chrdev (sound_major, "sound", &sound_fops);
+ err = register_chrdev (sound_major, "sound", &sound_fops);
if (err)
{
printk ("sound: driver already loaded/included in kernel\n");
}
if (chrdev_registered)
- module_unregister_chrdev (sound_major, "sound");
+ unregister_chrdev (sound_major, "sound");
#ifdef CONFIG_SEQUENCER
sound_stop_timer ();
save_flags (flags);
cli ();
-
retcode = request_irq (interrupt_level, iproc, 0 /* SA_INTERRUPT */ , name, NULL);
if (retcode < 0)
{
extern unsigned long seq_time;
if (count < 0)
- count = jiffies + (-count);
- else
- count += seq_time;
+ {
+
+ {
+ seq_timer.expires = (-count) + jiffies;
+ add_timer (&seq_timer);
+ };
+ return;
+ }
+
+ count += seq_time;
+
+ count -= jiffies;
+
+ if (count < 1)
+ count = 1;
- ;
{
- seq_timer.expires = ((count - jiffies)) + jiffies;
+ seq_timer.expires = (count) + jiffies;
add_timer (&seq_timer);
};
}
audio_devs[dev]->buffsize = PAGE_SIZE * (1 << sz);
- if ((start_addr = (char *) __get_dma_pages (GFP_ATOMIC, sz)) == NULL)
+ if ((start_addr = (char *) __get_free_pages (GFP_ATOMIC, sz, MAX_DMA_ADDRESS)) == NULL)
audio_devs[dev]->buffsize /= 2;
}
if (start_addr == NULL)
{
printk ("Sound error: Couldn't allocate DMA buffer\n");
- return -(ENOMEM);
+ return -ENOMEM;
}
else
{
"sound: Got invalid address 0x%lx for %ldb DMA-buffer\n",
(long) start_addr,
audio_devs[dev]->buffsize);
- return -(EFAULT);
+ return -EFAULT;
}
}
dmap->raw_buf = start_addr;
for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
{
- mem_map_reserve (i);
+ set_bit (PG_reserved, &mem_map[i].flags);;
}
return 0;
}
void
-sound_free_dmap (int dev, struct dma_buffparms *dmap)
+sound_free_dmap (int dev, struct dma_buffparms *dmap, int chan)
{
int sz, size, i;
unsigned long start_addr, end_addr;
for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
{
- mem_map_unreserve (i);
+ clear_bit (PG_reserved, &mem_map[i].flags);;
}
free_pages ((unsigned long) dmap->raw_buf, sz);
{
printk ("Entered sound_map_buffer()\n");
printk ("Exited sound_map_buffer()\n");
- return -(EINVAL);
+ return -EINVAL;
}
#endif
-#define SOUND_VERSION_STRING "3.5.4-960630"
-#define SOUND_INTERNAL_VERSION 0x030504
+#define SOUND_VERSION_STRING "3.7-beta6-961029"
+#define SOUND_INTERNAL_VERSION 0x030701
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#include "sound_config.h"
-#if defined(CONFIG_SSCAPE)
+#if defined(CONFIG_SSCAPEHW)
#include "coproc.h"
{0};
static struct sscape_info *devc = &dev_info;
-static wait_handle *sscape_sleeper = NULL;
+static struct wait_queue *sscape_sleeper = NULL;
static volatile struct snd_wait sscape_sleep_flag =
{0};
save_flags (flags);
cli ();
- outb (reg, PORT (ODIE_ADDR));
+ outb ((reg), PORT (ODIE_ADDR));
val = inb (PORT (ODIE_DATA));
restore_flags (flags);
return val;
save_flags (flags);
cli ();
- outb (reg, PORT (ODIE_ADDR));
- outb (data, PORT (ODIE_DATA));
+ outb ((reg), PORT (ODIE_ADDR));
+ outb ((data), PORT (ODIE_DATA));
restore_flags (flags);
}
static void
host_open (struct sscape_info *devc)
{
- outb (0x00, PORT (HOST_CTRL)); /* Put the board to the host mode */
+ outb ((0x00), PORT (HOST_CTRL)); /* Put the board to the host mode */
}
static void
host_close (struct sscape_info *devc)
{
- outb (0x03, PORT (HOST_CTRL)); /* Put the board to the MIDI mode */
+ outb ((0x03), PORT (HOST_CTRL)); /* Put the board to the MIDI mode */
}
static int
return 0;
}
- outb (data[i], PORT (HOST_DATA));
+ outb ((data[i]), PORT (HOST_DATA));
}
static int debug = 0;
bits = sscape_read (devc, GA_INTSTAT_REG);
- if ((sscape_sleep_flag.flags & WK_SLEEP))
+ if ((sscape_sleep_flag.opts & WK_SLEEP))
{
{
- sscape_sleep_flag.flags = WK_WAKEUP;
- module_wake_up (&sscape_sleeper);
+ sscape_sleep_flag.opts = WK_WAKEUP;
+ wake_up (&sscape_sleeper);
};
}
{
set_mt32 (devc, 0);
if (!verify_mpu (devc))
- return -(EIO);
+ return -EIO;
}
- sscape_sleep_flag.flags = WK_NONE;
+ sscape_sleep_flag.opts = WK_NONE;
return 0;
}
sscape_write (devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */
devc->dma_allocated = 0;
}
- sscape_sleep_flag.flags = WK_NONE;
+ sscape_sleep_flag.opts = WK_NONE;
restore_flags (flags);
return;
save_flags (flags);
cli ();
codec_dma_bits = sscape_read (devc, GA_CDCFG_REG);
-#if 0
- sscape_write (devc, GA_CDCFG_REG,
- codec_dma_bits & ~0x08); /* Disable codec DMA */
-#endif
if (devc->dma_allocated == 0)
{
/*
* Wait until transfer completes.
*/
- sscape_sleep_flag.flags = WK_NONE;
+ sscape_sleep_flag.opts = WK_NONE;
done = 0;
timeout_val = 100;
while (!done && timeout_val-- > 0)
unsigned long tlimit;
if (1)
- current_set_timeout (tlimit = jiffies + (1));
+ current->timeout = tlimit = jiffies + (1);
else
tlimit = (unsigned long) -1;
- sscape_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&sscape_sleeper);
- if (!(sscape_sleep_flag.flags & WK_WAKEUP))
+ sscape_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&sscape_sleeper);
+ if (!(sscape_sleep_flag.opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- sscape_sleep_flag.flags |= WK_TIMEOUT;
+ sscape_sleep_flag.opts |= WK_TIMEOUT;
}
- sscape_sleep_flag.flags &= ~WK_SLEEP;
+ sscape_sleep_flag.opts &= ~WK_SLEEP;
};
clear_dma_ff (devc->dma);
if ((resid = get_dma_residue (devc->dma)) == 0)
/*
* Take the board out of reset
*/
- outb (0x00, PORT (HOST_CTRL));
- outb (0x00, PORT (MIDI_CTRL));
+ outb ((0x00), PORT (HOST_CTRL));
+ outb ((0x00), PORT (MIDI_CTRL));
temp = sscape_read (devc, GA_HMCTL_REG);
temp |= 0x40;
timeout_val = 5 * HZ;
while (!done && timeout_val-- > 0)
{
+ unsigned char x;
+
{
unsigned long tlimit;
if (1)
- current_set_timeout (tlimit = jiffies + (1));
+ current->timeout = tlimit = jiffies + (1);
else
tlimit = (unsigned long) -1;
- sscape_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&sscape_sleeper);
- if (!(sscape_sleep_flag.flags & WK_WAKEUP))
+ sscape_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&sscape_sleeper);
+ if (!(sscape_sleep_flag.opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- sscape_sleep_flag.flags |= WK_TIMEOUT;
+ sscape_sleep_flag.opts |= WK_TIMEOUT;
}
- sscape_sleep_flag.flags &= ~WK_SLEEP;
+ sscape_sleep_flag.opts &= ~WK_SLEEP;
};
- if (inb (PORT (HOST_DATA)) == 0xff) /* OBP startup acknowledge */
- done = 1;
+ x = inb (PORT (HOST_DATA));
+ if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */
+ {
+ printk ("Soundscape: Acknowledge = %x\n", x);
+ done = 1;
+ }
}
sscape_write (devc, GA_CDCFG_REG, codec_dma_bits);
unsigned long tlimit;
if (1)
- current_set_timeout (tlimit = jiffies + (1));
+ current->timeout = tlimit = jiffies + (1);
else
tlimit = (unsigned long) -1;
- sscape_sleep_flag.flags = WK_SLEEP;
- module_interruptible_sleep_on (&sscape_sleeper);
- if (!(sscape_sleep_flag.flags & WK_WAKEUP))
+ sscape_sleep_flag.opts = WK_SLEEP;
+ interruptible_sleep_on (&sscape_sleeper);
+ if (!(sscape_sleep_flag.opts & WK_WAKEUP))
{
if (jiffies >= tlimit)
- sscape_sleep_flag.flags |= WK_TIMEOUT;
+ sscape_sleep_flag.opts |= WK_TIMEOUT;
}
- sscape_sleep_flag.flags &= ~WK_SLEEP;
+ sscape_sleep_flag.opts &= ~WK_SLEEP;
};
if (inb (PORT (HOST_DATA)) == 0xfe) /* Host startup acknowledge */
done = 1;
download_boot_block (void *dev_info, copr_buffer * buf)
{
if (buf->len <= 0 || buf->len > sizeof (buf->data))
- return -(EINVAL);
+ return -EINVAL;
if (!sscape_download_boot (devc, buf->data, buf->len, buf->flags))
{
printk ("SSCAPE: Unable to load microcode block to the OBP.\n");
- return -(EIO);
+ return -EIO;
}
return 0;
buf = (copr_buffer *) vmalloc (sizeof (copr_buffer));
if (buf == NULL)
- return -(ENOSPC);
+ return -ENOSPC;
copy_from_user ((char *) buf, &((char *) arg)[0], sizeof (*buf));
err = download_boot_block (dev_info, buf);
vfree (buf);
break;
default:
- return -(EINVAL);
+ return -EINVAL;
}
}
(sscape_read (devc, i) & 0xc0));
break;
- case 6: /* CD-ROM config. Don't touch. */
+ case 6: /* CD-ROM config (WSS codec actually) */
+ sscape_write (devc, i, regs[i]);
break;
case 9: /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */
{
unsigned char save;
- devc->failed = 1;
devc->base = hw_config->io_base;
devc->irq = hw_config->irq;
devc->dma = hw_config->dma;
- devc->osp = hw_config->osp;
+
+ devc->failed = 1;
if (sscape_detected != 0 && sscape_detected != hw_config->io_base)
return 0;
* First 4 bits
*/
if ((save = inb (PORT (ODIE_ADDR))) & 0xf0)
- return 0;
+ {
+ DDB (printk ("soundscape: Detect error A\n"));
+ return 0;
+ }
- outb (0x00, PORT (ODIE_ADDR));
+ outb ((0x00), PORT (ODIE_ADDR));
if (inb (PORT (ODIE_ADDR)) != 0x00)
- return 0;
+ {
+ DDB (printk ("soundscape: Detect error B\n"));
+ return 0;
+ }
- outb (0xff, PORT (ODIE_ADDR));
+ outb ((0xff), PORT (ODIE_ADDR));
if (inb (PORT (ODIE_ADDR)) != 0x0f)
- return 0;
+ {
+ DDB (printk ("soundscape: Detect error C\n"));
+ return 0;
+ }
- outb (save, PORT (ODIE_ADDR));
+ outb ((save), PORT (ODIE_ADDR));
/*
* Now verify that some indirect registers return zero on some bits.
*/
if (sscape_read (devc, 0) & 0x0c)
- return 0;
+ {
+ DDB (printk ("soundscape: Detect error D (%x)\n", sscape_read (devc, 0)));
+ return 0;
+ }
if (sscape_read (devc, 1) & 0x0f)
- return 0;
+ {
+ DDB (printk ("soundscape: Detect error E\n"));
+ return 0;
+ }
if (sscape_read (devc, 5) & 0x0f)
- return 0;
+ {
+ DDB (printk ("soundscape: Detect error F\n"));
+ return 0;
+ }
#ifdef SSCAPE_DEBUG1
/*
int i, irq_bits = 0xff;
if (devc->failed)
- return 0;
+ {
+ printk ("Soundscape: Card not detected\n");
+ return 0;
+ }
if (devc->ok == 0)
{
return 0;
}
+
return ad1848_detect (hw_config->io_base, NULL, hw_config->osp);
}
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
def_tmr_open (int dev, int mode)
{
if (opened)
- return -(EBUSY);
+ return -EBUSY;
tmr_reset ();
curr_tempo = 60;
switch (cmd)
{
case SNDCTL_TMR_SOURCE:
- return snd_ioctl_return ((int *) arg, TMR_INTERNAL);
+ return ioctl_out (arg, TMR_INTERNAL);
break;
case SNDCTL_TMR_START:
case SNDCTL_TMR_TIMEBASE:
{
- int val = get_user ((int *) arg);
+ int val;
+
+ get_user (val, (int *) arg);
if (val)
{
curr_timebase = val;
}
- return snd_ioctl_return ((int *) arg, curr_timebase);
+ return ioctl_out (arg, curr_timebase);
}
break;
case SNDCTL_TMR_TEMPO:
{
- int val = get_user ((int *) arg);
+ int val;
+
+ get_user (val, (int *) arg);
if (val)
{
curr_tempo = val;
}
- return snd_ioctl_return ((int *) arg, curr_tempo);
+ return ioctl_out (arg, curr_tempo);
}
break;
case SNDCTL_SEQ_CTRLRATE:
- if (get_user ((int *) arg) != 0) /* Can't change */
- return -(EINVAL);
+ if (ioctl_in (arg) != 0) /* Can't change */
+ return -EINVAL;
+
+ return ioctl_out (arg, ((curr_tempo * curr_timebase) + 30) / 60);
+ break;
- return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60);
+ case SNDCTL_SEQ_GETTIME:
+ return ioctl_out (arg, curr_ticks);
break;
case SNDCTL_TMR_METRONOME:
default:;
}
- return -(EINVAL);
+ return -EINVAL;
}
static void
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
static unsigned char
trix_read (int addr)
{
- outb ((unsigned char) addr, 0x390); /* MT-0002-PC ASIC address */
+ outb (((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */
return inb (0x391); /* MT-0002-PC ASIC data */
}
static void
trix_write (int addr, int data)
{
- outb ((unsigned char) addr, 0x390); /* MT-0002-PC ASIC address */
- outb ((unsigned char) data, 0x391); /* MT-0002-PC ASIC data */
+ outb (((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */
+ outb (((unsigned char) data), 0x391); /* MT-0002-PC ASIC data */
}
static void
return;
trix_write (0xf8, 0x00); /* ??????? */
- outb (0x01, base + 6); /* Clear the internal data pointer */
- outb (0x00, base + 6); /* Restart */
+ outb ((0x01), base + 6); /* Clear the internal data pointer */
+ outb ((0x00), base + 6); /* Restart */
/*
* Write the boot code to the RAM upload/download register.
* Each write increments the internal data pointer.
*/
- outb (0x01, base + 6); /* Clear the internal data pointer */
- outb (0x1A, 0x390); /* Select RAM download/upload port */
+ outb ((0x01), base + 6); /* Clear the internal data pointer */
+ outb ((0x1A), 0x390); /* Select RAM download/upload port */
for (i = 0; i < n; i++)
- outb (trix_boot[i], 0x391);
+ outb ((trix_boot[i]), 0x391);
for (i = n; i < 10016; i++) /* Clear up to first 16 bytes of data RAM */
- outb (0x00, 0x391);
- outb (0x00, base + 6); /* Reset */
- outb (0x50, 0x390); /* ?????? */
+ outb ((0x00), 0x391);
+ outb ((0x00), base + 6); /* Reset */
+ outb ((0x50), 0x390); /* ?????? */
}
return 0;
}
- if (hw_config->dma2 != -1)
+ if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
if (hw_config->dma2 != 0 && hw_config->dma2 != 1 && hw_config->dma2 != 3)
{
printk ("AudioTrix: Bad capture DMA %d\n", hw_config->dma2);
int config_port = hw_config->io_base + 0;
int dma1 = hw_config->dma, dma2 = hw_config->dma2;
+ int old_num_mixers = num_mixers;
trix_osp = hw_config->osp;
return;
}
- outb (bits | 0x40, config_port);
+ outb ((bits | 0x40), config_port);
if (hw_config->dma2 == -1 || hw_config->dma2 == hw_config->dma)
{
trix_write (0x14, tmp | 0x80 | (dma2 << 4));
}
- outb (bits, config_port); /* Write IRQ+DMA setup */
+ outb ((bits), config_port); /* Write IRQ+DMA setup */
ad1848_init ("AudioTrix Pro", hw_config->io_base + 4,
hw_config->irq,
0,
hw_config->osp);
request_region (hw_config->io_base, 4, "MSS config");
+
+ if (num_mixers > old_num_mixers) /* Mixer got installed */
+ {
+ AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_LINE); /* Line in */
+ AD1848_REROUTE (SOUND_MIXER_LINE2, SOUND_MIXER_CD);
+ AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* OPL4 */
+ AD1848_REROUTE (SOUND_MIXER_SPEAKER, SOUND_MIXER_ALTPCM); /* SB */
+ }
}
int
hw_config->name = "AudioTrix SB";
#ifdef CONFIG_SBDSP
- return probe_sb (hw_config);
+ return sb_dsp_detect (hw_config);
#else
return 0;
#endif
{
#ifdef CONFIG_SBDSP
hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING;
- attach_sb_card (hw_config);
+ sb_dsp_init (hw_config);
#endif
}
unload_trix_sb (struct address_info *hw_config)
{
#ifdef CONFIG_SBDSP
- unload_sb (hw_config);
+ sb_dsp_unload (hw_config);
#endif
}
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
int irq;
int *osp;
void (*midi_input_intr) (int dev, unsigned char data);
- int opened;
+ int opened, disabled;
volatile unsigned char input_byte;
int my_dev;
int share_irq;
static void
uart401_cmd (uart401_devc * devc, unsigned char cmd)
{
- outb (cmd, COMDPORT);
+ outb ((cmd), COMDPORT);
}
static int
uart401_read (uart401_devc * devc)
static void
uart401_write (uart401_devc * devc, unsigned char byte)
{
- outb (byte, DATAPORT);
+ outb ((byte), DATAPORT);
}
#define OUTPUT_READY 0x40
#define UART_MODE_ON 0x3F
static int reset_uart401 (uart401_devc * devc);
+static void enter_uart_mode (uart401_devc * devc);
static void
uart401_input_loop (uart401_devc * devc)
if (devc->opened)
{
- return -(EBUSY);
+ return -EBUSY;
}
while (input_avail (devc))
devc->midi_input_intr = input;
devc->opened = mode;
+ enter_uart_mode (devc);
+ devc->disabled = 0;
return 0;
}
{
uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
+ reset_uart401 (devc);
devc->opened = 0;
}
unsigned long flags;
uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
+ if (devc->disabled)
+ return 1;
/*
* Test for input since pending input seems to block the output.
*/
if (!output_ready (devc))
{
- printk ("MPU-401: Timeout\n");
- return 0;
+ printk ("MPU-401: Timeout - Device not responding\n");
+ devc->disabled = 1;
+ reset_uart401 (devc);
+ enter_uart_mode (devc);
+ return 1;
}
uart401_write (devc, midi_byte);
static int
uart401_ioctl (int dev, unsigned cmd, caddr_t arg)
{
- return -(EINVAL);
+ return -EINVAL;
}
static void
ok = 0;
- /* save_flags(flags);cli(); */
-
for (n = 0; n < 2 && !ok; n++)
{
for (timeout = 30000; timeout < 0 && !output_ready (devc); timeout--);
}
+
+ if (ok)
+ {
+ DDB (printk ("Reset UART401 OK\n"));
+ }
+ else
+ DDB (printk ("Reset UART401 failed - No hardware detected.\n"));
+
if (ok)
uart401_input_loop (devc); /*
* Flush input before enabling interrupts
*/
- /* restore_flags(flags); */
-
return ok;
}
static uart401_devc hw_info;
uart401_devc *devc = &hw_info;
+ DDB (printk ("Entered probe_uart401()\n"));
+
detected_devc = NULL;
if (check_region (hw_config->io_base, 4))
return;
reset_uart401 (devc);
-
release_region (hw_config->io_base, 4);
if (!devc->share_irq)
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
static void
uart6850_cmd (unsigned char cmd)
{
- outb (cmd, COMDPORT);
+ outb ((cmd), COMDPORT);
}
static int
uart6850_read (void)
static void
uart6850_write (unsigned char byte)
{
- outb (byte, DATAPORT);
+ outb ((byte), DATAPORT);
}
#define OUTPUT_READY 0x02 /* Mask for data ready Bit */
if (uart6850_opened)
{
printk ("Midi6850: Midi busy\n");
- return -(EBUSY);
+ return -EBUSY;
}
;
static int
uart6850_ioctl (int dev, unsigned cmd, caddr_t arg)
{
- return -(EINVAL);
+ return -EINVAL;
}
static void
*
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
* affs regular file handling primitives
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/sched.h>
#include <linux/affs_fs.h>
#include <linux/major.h>
#include <linux/blkdev.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
extern int *blk_size[];
extern struct timezone sys_tz;
#include <linux/fcntl.h>
#include <linux/locks.h>
#include <linux/amigaffs.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/affs_fs.h>
#include <linux/amigaffs.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#include <linux/personality.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
#include <linux/personality.h>
#include <linux/elfcore.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <linux/config.h>
unsigned long interp_load_addr, int ibcs)
{
char **argv, **envp;
- unsigned long *dlinfo;
unsigned long *sp;
/*
* Force 16 byte alignment here for generality.
*/
sp = (unsigned long *) (~15UL & (unsigned long) p);
- sp -= exec ? DLINFO_ITEMS*2 : 2;
- dlinfo = sp;
+
+ /*
+ * Put the ELF interpreter info on the stack
+ */
+#define NEW_AUX_ENT(nr, id, val) \
+ __put_user ((id), sp+(nr*2)); \
+ __put_user ((val), sp+(nr*2+1)); \
+
+ sp -= 2;
+ NEW_AUX_ENT(0, AT_NULL, 0);
+
+ if (exec) {
+ sp -= 11*2;
+
+ NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
+ NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr));
+ NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum);
+ NEW_AUX_ENT (3, AT_PAGESZ, PAGE_SIZE);
+ NEW_AUX_ENT (4, AT_BASE, interp_load_addr);
+ NEW_AUX_ENT (5, AT_FLAGS, 0);
+ NEW_AUX_ENT (6, AT_ENTRY, (unsigned long) exec->e_entry);
+ NEW_AUX_ENT (7, AT_UID, (unsigned long) current->uid);
+ NEW_AUX_ENT (8, AT_EUID, (unsigned long) current->euid);
+ NEW_AUX_ENT (9, AT_GID, (unsigned long) current->gid);
+ NEW_AUX_ENT (10, AT_EGID, (unsigned long) current->egid);
+ }
+#undef NEW_AUX_ENT
+
sp -= envc+1;
envp = (char **) sp;
sp -= argc+1;
argv = (char **) sp;
if (!ibcs) {
- put_user((unsigned long) envp,--sp);
- put_user((unsigned long) argv,--sp);
+ __put_user((unsigned long) envp,--sp);
+ __put_user((unsigned long) argv,--sp);
}
-#define NEW_AUX_ENT(id, val) \
- put_user ((id), dlinfo++); \
- put_user ((val), dlinfo++)
-
- if (exec) { /* Put this here for an ELF program interpreter */
- struct elf_phdr * eppnt;
- eppnt = (struct elf_phdr *) exec->e_phoff;
-
- NEW_AUX_ENT (AT_PHDR, load_addr + exec->e_phoff);
- NEW_AUX_ENT (AT_PHENT, sizeof (struct elf_phdr));
- NEW_AUX_ENT (AT_PHNUM, exec->e_phnum);
- NEW_AUX_ENT (AT_PAGESZ, PAGE_SIZE);
- NEW_AUX_ENT (AT_BASE, interp_load_addr);
- NEW_AUX_ENT (AT_FLAGS, 0);
- NEW_AUX_ENT (AT_ENTRY, (unsigned long) exec->e_entry);
- NEW_AUX_ENT (AT_UID, (unsigned long) current->uid);
- NEW_AUX_ENT (AT_EUID, (unsigned long) current->euid);
- NEW_AUX_ENT (AT_GID, (unsigned long) current->gid);
- NEW_AUX_ENT (AT_EGID, (unsigned long) current->egid);
- }
- NEW_AUX_ENT (AT_NULL, 0);
-#undef NEW_AUX_ENT
- put_user((unsigned long)argc,--sp);
+ __put_user((unsigned long)argc,--sp);
current->mm->arg_start = (unsigned long) p;
while (argc-->0) {
char c;
- put_user(p,argv++);
+ __put_user(p,argv++);
do {
get_user(c,p++);
} while (c);
}
- put_user(NULL, argv);
+ __put_user(NULL, argv);
current->mm->arg_end = current->mm->env_start = (unsigned long) p;
while (envc-->0) {
char c;
- put_user(p,envp++);
+ __put_user(p,envp++);
do {
get_user(c,p++);
} while (c);
}
- put_user(NULL, envp);
+ __put_user(NULL, envp);
current->mm->env_end = (unsigned long) p;
return sp;
}
#include <linux/fcntl.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
extern int *blk_size[];
#include <linux/vmalloc.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
#define NR_SIZES 5
#include <linux/malloc.h>
#include <linux/mount.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define __DQUOT_VERSION__ "dquot_5.6.0"
#include <linux/personality.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <linux/config.h>
* ext directory handling functions
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/kernel.h>
* ext regular file handling primitives
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/sched.h>
* extfs fsync primitive
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/locks.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
void ext_put_inode(struct inode *inode)
{
#include <linux/fcntl.h>
#include <linux/errno.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
/*
* comment out this line if you want names > EXT_NAME_LEN chars to be
* ext symlink handling code
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/sched.h>
* ext2 directory handling functions
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/fs.h>
* ext2 fs regular file handling primitives
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/errno.h>
* ext2fs fsync primitive
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/errno.h>
* Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/errno.h>
* Universite Pierre et Marie Curie (Paris VI)
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/fs.h>
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <stdarg.h>
#include <asm/bitops.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/errno.h>
* ext2 symlink handling code
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/dirent.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "msbuffer.h"
#include "tables.h"
#include <linux/string.h>
#include <linux/pagemap.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include "msbuffer.h"
#include "msbuffer.h"
#include "tables.h"
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/unaligned.h>
#include <linux/malloc.h>
#include <linux/msdos_fs.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
/*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <asm/segment.h>
-
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <asm/bitops.h>
+#include <asm/uaccess.h>
extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
#include <linux/stat.h>
#include <linux/string.h>
#include <asm/bitops.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "hpfs.h"
#include "hpfs_caps.h"
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <asm/segment.h>
-
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/termios.h>
#include <linux/fcntl.h> /* for f_flags values */
+#include <asm/uaccess.h>
+
static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
int error;
#include <linux/sched.h>
#include <linux/locks.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
static int isofs_readdir(struct inode *, struct file *, void *, filldir_t);
#include <linux/cdrom.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
/*
* We have no support for "multi volume" CDs, but more and more disks carry
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/malloc.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/malloc.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
static int isofs_readlink(struct inode *, char *, int);
static int isofs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
#include <linux/stat.h>
#include <linux/fcntl.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define OFFSET_MAX ((off_t)0x7fffffff) /* FIXME: move elsewhere? */
#include <linux/minix_fs.h>
#include <linux/stat.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
static long minix_dir_read(struct inode * inode, struct file * filp,
char * buf, unsigned long count)
#include <linux/mm.h>
#include <linux/pagemap.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#define NBUF 32
#include <linux/fs.h>
#include <linux/minix_fs.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#define blocksize BLOCK_SIZE
#include <linux/locks.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
void minix_put_inode(struct inode *inode)
#include <linux/fcntl.h>
#include <linux/errno.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
/*
* comment out this line if you want names > info->s_namelen chars to be
#include <linux/minix_fs.h>
#include <linux/stat.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
static int minix_readlink(struct inode *, char *, int);
static int minix_follow_link(struct inode *, struct inode *, int, int, struct inode **);
#include <linux/string.h>
#include <linux/stat.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "../fat/msbuffer.h"
#include <linux/stat.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/ncp_fs.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/locks.h>
#include "ncplib_kernel.h"
*
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/sched.h>
#include <linux/config.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/ncp_fs.h>
*
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_fs.h>
#include "ncplib_kernel.h"
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
static inline int min(int a, int b)
#include <linux/socket.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/in.h>
#include <linux/net.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/pagemap.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#undef DEBUG_BIO
#include <linux/malloc.h>
#include <linux/mm.h>
-#include <asm/segment.h> /* for fs functions */
+#include <asm/uaccess.h> /* for fs functions */
static int nfs_dir_open(struct inode * inode, struct file * file);
static long nfs_dir_read(struct inode *, struct file *, char *, unsigned long);
#include <linux/malloc.h>
#include <linux/pagemap.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
static int nfs_file_mmap(struct inode *, struct file *, struct vm_area_struct *);
#include <linux/smp_lock.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
/* This is for kernel_thread */
#define __KERNEL_SYSCALLS__
#include <net/route.h>
#include <net/sock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
/* Range of privileged ports */
#define STARTPORT 600
#include <linux/in.h>
#include <linux/pagemap.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#ifdef NFS_PROC_DEBUG
#include <linux/udp.h>
#include <net/sock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define msleep(sec) { current->timeout = sec * HZ / 1000; \
current->state = TASK_INTERRUPTIBLE; \
#include <linux/mm.h>
#include <linux/rpcsock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define _S(nr) (1<<((nr)-1))
#include <linux/malloc.h>
#include <linux/string.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
static int nfs_readlink(struct inode *, char *, int);
static int nfs_follow_link(struct inode *, struct inode *, int, int,
#include <linux/malloc.h>
#include <linux/mount.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#ifndef min
#define min(a,b) ((a) < (b)) ? (a) : (b)
#include <linux/mm.h>
#include <linux/file.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
asmlinkage int sys_statfs(const char * path, struct statfs * buf)
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <asm/segment.h>
-
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/termios.h>
#include <linux/mm.h>
+#include <asm/uaccess.h>
+
/*
* Define this if you want SunOS compatibility wrt braindead
* select behaviour on FIFO's.
#include <linux/pagemap.h>
#include <linux/swap.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
* proc base directory handling functions
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/sched.h>
* proc fd directory handling functions
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/limits.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
static void proc_put_inode(struct inode *inode)
{
#include <linux/sched.h>
#include <linux/kernel.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
extern unsigned long log_size;
* /proc link-file handling code
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/page.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
* proc root directory handling functions
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
/* forward references */
static long proc_readscsi(struct inode * inode, struct file * file,
#include <linux/mm.h>
#include <linux/uio.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
static long long default_llseek(struct inode *inode,
struct file *file,
#include <linux/sched.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
/*
* Traditional linux readdir() handling..
#include <linux/personality.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/smb_fs.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
*
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/smb_fs.h>
*
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/smb_fs.h>
#include <linux/smb_fs.h>
#include <linux/fcntl.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
/*
#include <linux/malloc.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/string.h>
#define ARCH i386
#include <linux/socket.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/in.h>
#include <linux/net.h>
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#ifndef __alpha__
#include <linux/fd.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
#ifdef CONFIG_KERNELD
#include <linux/stat.h>
#include <linux/string.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
static long sysv_dir_read(struct inode * inode, struct file * filp,
char * buf, unsigned long count)
#include <linux/locks.h>
#include <linux/pagemap.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define NBUF 32
#include <linux/string.h>
#include <linux/locks.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
void sysv_put_inode(struct inode *inode)
{
#include <linux/sysv_fs.h>
#include <linux/stat.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
static int sysv_readlink(struct inode *, char *, int);
static int sysv_follow_link(struct inode *, struct inode *, int, int, struct inode **);
#include <linux/ufs_fs.h>
#include <linux/locks.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
int ufs_need_swab = 0;
#include <linux/ufs_fs.h>
#include <linux/sched.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
static int
ufs_readlink(struct inode * inode, char * buffer, int buflen)
#include <linux/umsdos_fs.h>
#include <linux/malloc.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define PRINTK(x)
#define Printk(x) printk x
#include <linux/msdos_fs.h>
#include <linux/umsdos_fs.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define PRINTK(x)
#define Printk(x) printk x
#include <linux/msdos_fs.h>
#include <linux/umsdos_fs.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#define PRINTK(x)
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/umsdos_fs.h>
* Extended MS-DOS ioctl directory handling functions
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/umsdos_fs.h>
#include <linux/malloc.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define PRINTK(x)
#define Printk(x) printk x
#include <linux/umsdos_fs.h>
#include <linux/malloc.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#define PRINTK(x)
#include <linux/stat.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "../fat/msbuffer.h"
#include "../fat/tables.h"
#include <linux/xia_fs.h>
#include <linux/stat.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "xiafs_mac.h"
#include <linux/locks.h>
#include <linux/pagemap.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include "xiafs_mac.h"
#include <linux/fs.h>
#include <linux/xia_fs.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include "xiafs_mac.h"
#include <linux/stat.h>
#include <linux/locks.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "xiafs_mac.h"
#include <linux/fcntl.h>
#include <linux/errno.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include "xiafs_mac.h"
#include <linux/xia_fs.h>
#include <linux/stat.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
static int
xiafs_readlink(struct inode *, char *, int);
-#ifndef _ASM_SEGMENT_H
-#define _ASM_SEGMENT_H
+#ifndef __ALPHA_SEGMENT_H
+#define __ALPHA_SEGMENT_H
-/*
- * The fs value determines whether argument validity checking should be
- * performed or not. If get_fs() == USER_DS, checking is performed, with
- * get_fs() == KERNEL_DS, checking is bypassed.
- *
- * For historical reasons, these macros are grossly misnamed.
- */
+/* Only here because we have some old header files that expect it.. */
-#define KERNEL_DS 0
-#define USER_DS 1
-
-#define get_fs() (current->tss.flags & 0x1)
-#define set_fs(x) (current->tss.flags = (current->tss.flags & ~0x1) | ((x) & 0x1))
-
-static inline unsigned long get_ds(void)
-{
- return 0;
-}
-
-/*
- * Is a address valid? This does a straighforward calculation rather
- * than tests.
- *
- * Address valid if:
- * - "addr" doesn't have any high-bits set
- * - AND "size" doesn't have any high-bits set
- * - AND "addr+size" doesn't have any high-bits set
- * - OR we are in kernel mode.
- */
-#define __access_ok(addr,size,mask) \
- (((mask)&((addr | size | (addr+size)) >> 42))==0)
-#define __access_mask (-(long)get_fs())
-
-#define access_ok(type,addr,size) \
- __access_ok(((unsigned long)(addr)),(size),__access_mask)
-
-/*
- * These are the main single-value transfer routines. They automatically
- * use the right size if we just have the right pointer type.
- *
- * As the alpha uses the same address space for kernel and user
- * data, we can just do these as direct assignments. (Of course, the
- * exception handling means that it's no longer "just"...)
- *
- * Careful to not
- * (a) re-use the arguments for side effects (sizeof/typeof is ok)
- * (b) require any knowledge of processes at this stage
- */
-#define put_user(x,ptr) __put_user((x),(ptr),sizeof(*(ptr)),__access_mask)
-#define get_user(x,ptr) __get_user((x),(ptr),sizeof(*(ptr)),__access_mask)
-
-#define copy_to_user(to,from,n) __copy_tofrom_user((to),(from),(n),__cu_to)
-#define copy_from_user(to,from,n) __copy_tofrom_user((to),(from),(n),__cu_from)
-
-/*
- * Not pretty? What do you mean not "not pretty"?
- */
-extern void __copy_user(void);
-
-#define __copy_tofrom_user(to,from,n,v) \
-({ \
- register void * __cu_to __asm__("$6") = (to); \
- register const void * __cu_from __asm__("$7") = (from); \
- register long __cu_len __asm__("$0") = (n); \
- if (__access_ok(((long)(v)),__cu_len,__access_mask)) { \
- register void * __cu_ex __asm__("$8"); \
- __cu_ex = ¤t->tss.ex; \
- __asm__ __volatile__( \
- "jsr $28,(%7),__copy_user" \
- : "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to) \
- : "0" (__cu_len), "1" (__cu_from), "2" (__cu_to), \
- "r" (__cu_ex), "r" (__copy_user) \
- : "$1","$2","$3","$4","$5","$28","memory"); \
- } \
- __cu_len; \
-})
-
-extern void __get_user_unknown(void);
-
-#define __get_user(x,ptr,size,mask) \
-({ \
- long __gu_err = -EFAULT, __gu_val = 0; \
- const __typeof__(*(ptr)) *__gu_addr = (ptr); \
- if (__access_ok((long)__gu_addr,size,mask)) { \
- long __gu_ex_count = current->tss.ex.count; \
- switch (size) { \
- case 1: __get_user_8; break; \
- case 2: __get_user_16; break; \
- case 4: __get_user_32; break; \
- case 8: __get_user_64; break; \
- default: __get_user_unknown(); break; \
- } \
- } \
- (x) = (__typeof__(*(ptr))) __gu_val; \
- __gu_err; \
-})
-
-#define __get_user_64 \
- __asm__("/* Inline __get_user_64 */\n\t" \
- "br $28,1f\n\t" /* set up exception address */ \
- "br 2f\n" /* exception! */ \
- "1:\t" \
- "stq %5,%3\n\t" /* store inc'ed exception count */ \
- "ldq %1,%2\n\t" /* actual data load */ \
- "stq %4,%3\n\t" /* restore exception count */ \
- "clr %0\n" /* no exception: error = 0 */ \
- "2:\t/* End __get_user_64 */" \
- : "=r"(__gu_err), "=r"(__gu_val) \
- : "m"(*__gu_addr), "m"(current->tss.ex.count), \
- "r"(__gu_ex_count), "r"(__gu_ex_count+1), \
- "0"(__gu_err), "1"(__gu_val) \
- : "$28")
-
-#define __get_user_32 \
- __asm__("/* Inline __get_user_32 */\n\t" \
- "br $28,1f\n\t" /* set up exception address */ \
- "br 2f\n" /* exception! */ \
- "1:\t" \
- "stq %5,%3\n\t" /* store inc'ed exception count */ \
- "ldl %1,%2\n\t" /* actual data load */ \
- "stq %4,%3\n\t" /* restore exception count */ \
- "clr %0\n" /* no exception: error = 0 */ \
- "2:\t/* End __get_user_32 */" \
- : "=r"(__gu_err), "=r"(__gu_val) \
- : "m"(*__gu_addr), "m"(current->tss.ex.count), \
- "r"(__gu_ex_count), "r"(__gu_ex_count+1), \
- "0"(__gu_err), "1"(__gu_val) \
- : "$28")
-
-#define __get_user_16 \
- __asm__("/* Inline __get_user_16 */\n\t" \
- "br $28,1f\n\t" /* set up exception address */ \
- "br 2f\n" /* exception! */ \
- "1:\t" \
- "stq %6,%4\n\t" /* store inc'ed exception count */ \
- "ldq_u %1,%2\n\t" /* actual data load */ \
- "stq %5,%4\n\t" /* restore exception count */ \
- "clr %0\n\t" /* no exception: error = 0 */ \
- "extwl %1,%3,%1\n" /* extract the short */ \
- "2:\t/* End __get_user_16 */" \
- : "=r"(__gu_err), "=r"(__gu_val) \
- : "m"(*__gu_addr), "r"(__gu_addr), \
- "m"(current->tss.ex.count), "r"(__gu_ex_count), \
- "r"(__gu_ex_count+1), "0"(__gu_err), "1"(__gu_val) \
- : "$28")
-
-#define __get_user_8 \
- __asm__("/* Inline __get_user_8 */\n\t" \
- "br $28,1f\n\t" /* set up exception address */ \
- "br 2f\n" /* exception! */ \
- "1:\t" \
- "stq %6,%4\n\t" /* store inc'ed exception count */ \
- "ldq_u %1,%2\n\t" /* actual data load */ \
- "stq %5,%4\n\t" /* restore exception count */ \
- "clr %0\n\t" /* no exception: error = 0 */ \
- "extbl %1,%3,%1\n" /* extract the byte */ \
- "2:\t/* End __get_user_8 */" \
- : "=r"(__gu_err), "=r"(__gu_val) \
- : "m"(*__gu_addr), "r"(__gu_addr), \
- "m"(current->tss.ex.count), "r"(__gu_ex_count), \
- "r"(__gu_ex_count+1), "0"(__gu_err), "1"(__gu_val) \
- : "$28")
-
-extern void __put_user_unknown(void);
-
-#define __put_user(x,ptr,size,mask) \
-({ \
- long __pu_err = -EFAULT; \
- __typeof__(*(ptr)) *__pu_addr = (ptr); \
- __typeof__(*(ptr)) __pu_val = (x); \
- if (__access_ok((long)__pu_addr,size,mask)) { \
- long __pu_ex_count = current->tss.ex.count; \
- switch (size) { \
- case 1: __put_user_8; break; \
- case 2: __put_user_16; break; \
- case 4: __put_user_32; break; \
- case 8: __put_user_64; break; \
- default: __put_user_unknown(); break; \
- } \
- } \
- __pu_err; \
-})
-
-#define __put_user_64 \
- __asm__("/* Inline __put_user_64 */\n\t" \
- "br $28,1f\n\t" /* set up exception address */ \
- "br 2f\n" /* exception! */ \
- "1:\t" \
- "stq %5,%3\n\t" /* store inc'ed exception count */ \
- "stq %2,%1\n\t" /* actual data store */ \
- "stq %4,%3\n\t" /* restore exception count */ \
- "clr %0\n" /* no exception: error = 0 */ \
- "2:\t/* End __put_user_64 */" \
- : "=r"(__pu_err), "=m"(*__pu_addr) \
- : "r"(__pu_val), "m"(current->tss.ex.count), \
- "r"(__pu_ex_count), "r"(__pu_ex_count+1), \
- "0"(__pu_err) \
- : "$28")
-
-#define __put_user_32 \
- __asm__("/* Inline __put_user_32 */\n\t" \
- "br $28,1f\n\t" /* set up exception address */ \
- "br 2f\n" /* exception! */ \
- "1:\t" \
- "stq %5,%3\n\t" /* store inc'ed exception count */ \
- "stl %2,%1\n\t" /* actual data store */ \
- "stq %4,%3\n\t" /* restore exception count */ \
- "clr %0\n" /* no exception: error = 0 */ \
- "2:\t/* End __put_user_32 */" \
- : "=r"(__pu_err), "=m"(*__pu_addr) \
- : "r"(__pu_val), "m"(current->tss.ex.count), \
- "r"(__pu_ex_count), "r"(__pu_ex_count+1), \
- "0"(__pu_err) \
- : "$28")
-
-#define __put_user_16 \
- __asm__("/* Inline __put_user_16 */\n\t" \
- "br $28,1f\n\t" /* set up exception address */ \
- "lda %0,%7\n\t" /* exception! error = -EFAULT */ \
- "br 2f\n" \
- "1:\t" \
- "stq %6,%4\n\t" /* store inc'ed exception count */ \
- "ldq_u %0,%1\n\t" /* masked data store */ \
- "inswl %2,%3,%2\n\t" \
- "mskwl %0,%3,%0\n\t" \
- "or %0,%2,%2\n\t" \
- "stq_u %2,%1\n\t" \
- "stq %5,%4\n\t" /* restore exception count */ \
- "clr %0\n" /* no exception: error = 0 */ \
- "2:\t/* End __put_user_16 */" \
- : "=r"(__pu_err), "=m"(*__pu_addr), "=r"(__pu_val) \
- : "r"(__pu_addr), "m"(current->tss.ex.count), \
- "r"(__pu_ex_count), "r"(__pu_ex_count+1), "i"(-EFAULT), \
- "2"(__pu_val) \
- : "$28")
-
-#define __put_user_8 \
- __asm__("/* Inline __put_user_8 */\n\t" \
- "br $28,1f\n\t" /* set up exception address */ \
- "lda %0,%7\n\t" /* exception! error = -EFAULT */ \
- "br 2f\n" \
- "1:\t" \
- "stq %6,%4\n\t" /* store inc'ed exception count */ \
- "ldq_u %0,%1\n\t" /* masked data store */ \
- "insbl %2,%3,%2\n\t" \
- "mskbl %0,%3,%0\n\t" \
- "or %0,%2,%2\n\t" \
- "stq_u %2,%1\n\t" \
- "stq %5,%4\n\t" /* restore exception count */ \
- "clr %0\n" /* no exception: error = 0 */ \
- "2:\t/* End __put_user_8 */" \
- : "=r"(__pu_err), "=m"(*__pu_addr), "=r"(__pu_val) \
- : "r"(__pu_addr), "m"(current->tss.ex.count), \
- "r"(__pu_ex_count), "r"(__pu_ex_count+1), "i"(-EFAULT), \
- "2"(__pu_val) \
- : "$28")
-
-
-extern void __clear_user(void);
-
-#define clear_user(to,n) \
-({ \
- register void * __cl_to __asm__("$6") = (to); \
- register long __cl_len __asm__("$0") = (n); \
- if (__access_ok(((long)__cl_to),__cl_len,__access_mask)) { \
- register void * __cl_ex __asm__("$7"); \
- __cl_ex = ¤t->tss.ex; \
- __asm__ __volatile__( \
- "jsr $28,(%2),__clear_user" \
- : "=r"(__cl_len), "=r"(__cl_to) \
- : "r"(__clear_user), "r"(__cl_ex), \
- "0"(__cl_len), "1"(__cl_to) \
- : "$1","$2","$3","$4","$5","$28","memory"); \
- } \
- __cl_len; \
-})
-
-
-/* Returns: -EFAULT if exception before terminator, N if the entire
- buffer filled, else strlen. */
-
-struct exception_struct;
-extern long __strncpy_from_user(char *__to, const char *__from,
- long __to_len, struct exception_struct *);
-
-#define strncpy_from_user(to,from,n) \
-({ \
- char * __sfu_to = (to); \
- const char * __sfu_from = (from); \
- long __sfu_len = (n), __sfu_ret = -EFAULT; \
- if (__access_ok(((long)__sfu_from),__sfu_len,__access_mask)) { \
- __sfu_ret = __strncpy_from_user(__sfu_to,__sfu_from, \
- __sfu_len, ¤t->tss.ex); \
- __sfu_ret; \
-})
-
-#endif /* _ASM_SEGMENT_H */
+#endif
--- /dev/null
+#ifndef _ASM_SEGMENT_H
+#define _ASM_SEGMENT_H
+
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not. If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+
+#define KERNEL_DS 0
+#define USER_DS 1
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+#define get_fs() (current->tss.flags & 0x1)
+#define set_fs(x) (current->tss.flags = (current->tss.flags & ~0x1) | ((x) & 0x1))
+
+static inline unsigned long get_ds(void)
+{
+ return 0;
+}
+
+/*
+ * Is a address valid? This does a straighforward calculation rather
+ * than tests.
+ *
+ * Address valid if:
+ * - "addr" doesn't have any high-bits set
+ * - AND "size" doesn't have any high-bits set
+ * - AND "addr+size" doesn't have any high-bits set
+ * - OR we are in kernel mode.
+ */
+#define __access_ok(addr,size,mask) \
+ (((mask)&((addr | size | (addr+size)) >> 42))==0)
+#define __access_mask (-(long)get_fs())
+
+#define access_ok(type,addr,size) \
+ __access_ok(((unsigned long)(addr)),(size),__access_mask)
+
+/*
+ * These are the main single-value transfer routines. They automatically
+ * use the right size if we just have the right pointer type.
+ *
+ * As the alpha uses the same address space for kernel and user
+ * data, we can just do these as direct assignments. (Of course, the
+ * exception handling means that it's no longer "just"...)
+ *
+ * Careful to not
+ * (a) re-use the arguments for side effects (sizeof/typeof is ok)
+ * (b) require any knowledge of processes at this stage
+ */
+#define put_user(x,ptr) __put_user_check((x),(ptr),sizeof(*(ptr)),__access_mask)
+#define get_user(x,ptr) __get_user_check((x),(ptr),sizeof(*(ptr)),__access_mask)
+
+/*
+ * The "__xxx" versions do not do address space checking, useful when
+ * doing multiple accesses to the same area (the user has to do the
+ * checks by hand with "access_ok()")
+ */
+#define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
+#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+
+#define copy_to_user(to,from,n) __copy_tofrom_user((to),(from),(n),__cu_to)
+#define copy_from_user(to,from,n) __copy_tofrom_user((to),(from),(n),__cu_from)
+
+/*
+ * Not pretty? What do you mean not "not pretty"?
+ */
+extern void __copy_user(void);
+
+#define __copy_tofrom_user(to,from,n,v) \
+({ \
+ register void * __cu_to __asm__("$6") = (to); \
+ register const void * __cu_from __asm__("$7") = (from); \
+ register long __cu_len __asm__("$0") = (n); \
+ if (__access_ok(((long)(v)),__cu_len,__access_mask)) { \
+ register void * __cu_ex __asm__("$8"); \
+ __cu_ex = ¤t->tss.ex; \
+ __asm__ __volatile__( \
+ "jsr $28,(%7),__copy_user" \
+ : "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to) \
+ : "0" (__cu_len), "1" (__cu_from), "2" (__cu_to), \
+ "r" (__cu_ex), "r" (__copy_user) \
+ : "$1","$2","$3","$4","$5","$28","memory"); \
+ } \
+ __cu_len; \
+})
+
+extern void __get_user_unknown(void);
+
+#define __get_user_nocheck(x,ptr,size) \
+({ \
+ long __gu_err = -EFAULT, __gu_val = 0; \
+ const __typeof__(*(ptr)) *__gu_addr = (ptr); \
+ long __gu_ex_count = current->tss.ex.count; \
+ switch (size) { \
+ case 1: __get_user_8; break; \
+ case 2: __get_user_16; break; \
+ case 4: __get_user_32; break; \
+ case 8: __get_user_64; break; \
+ default: __get_user_unknown(); break; \
+ } \
+ (x) = (__typeof__(*(ptr))) __gu_val; \
+ __gu_err; \
+})
+
+#define __get_user_check(x,ptr,size,mask) \
+({ \
+ long __gu_err = -EFAULT, __gu_val = 0; \
+ const __typeof__(*(ptr)) *__gu_addr = (ptr); \
+ if (__access_ok((long)__gu_addr,size,mask)) { \
+ long __gu_ex_count = current->tss.ex.count; \
+ switch (size) { \
+ case 1: __get_user_8; break; \
+ case 2: __get_user_16; break; \
+ case 4: __get_user_32; break; \
+ case 8: __get_user_64; break; \
+ default: __get_user_unknown(); break; \
+ } \
+ } \
+ (x) = (__typeof__(*(ptr))) __gu_val; \
+ __gu_err; \
+})
+
+#define __get_user_64 \
+ __asm__("/* Inline __get_user_64 */\n\t" \
+ "br $28,1f\n\t" /* set up exception address */ \
+ "br 2f\n" /* exception! */ \
+ "1:\t" \
+ "stq %5,%3\n\t" /* store inc'ed exception count */ \
+ "ldq %1,%2\n\t" /* actual data load */ \
+ "stq %4,%3\n\t" /* restore exception count */ \
+ "clr %0\n" /* no exception: error = 0 */ \
+ "2:\t/* End __get_user_64 */" \
+ : "=r"(__gu_err), "=r"(__gu_val) \
+ : "m"(*__gu_addr), "m"(current->tss.ex.count), \
+ "r"(__gu_ex_count), "r"(__gu_ex_count+1), \
+ "0"(__gu_err), "1"(__gu_val) \
+ : "$28")
+
+#define __get_user_32 \
+ __asm__("/* Inline __get_user_32 */\n\t" \
+ "br $28,1f\n\t" /* set up exception address */ \
+ "br 2f\n" /* exception! */ \
+ "1:\t" \
+ "stq %5,%3\n\t" /* store inc'ed exception count */ \
+ "ldl %1,%2\n\t" /* actual data load */ \
+ "stq %4,%3\n\t" /* restore exception count */ \
+ "clr %0\n" /* no exception: error = 0 */ \
+ "2:\t/* End __get_user_32 */" \
+ : "=r"(__gu_err), "=r"(__gu_val) \
+ : "m"(*__gu_addr), "m"(current->tss.ex.count), \
+ "r"(__gu_ex_count), "r"(__gu_ex_count+1), \
+ "0"(__gu_err), "1"(__gu_val) \
+ : "$28")
+
+#define __get_user_16 \
+ __asm__("/* Inline __get_user_16 */\n\t" \
+ "br $28,1f\n\t" /* set up exception address */ \
+ "br 2f\n" /* exception! */ \
+ "1:\t" \
+ "stq %6,%4\n\t" /* store inc'ed exception count */ \
+ "ldq_u %1,%2\n\t" /* actual data load */ \
+ "stq %5,%4\n\t" /* restore exception count */ \
+ "clr %0\n\t" /* no exception: error = 0 */ \
+ "extwl %1,%3,%1\n" /* extract the short */ \
+ "2:\t/* End __get_user_16 */" \
+ : "=r"(__gu_err), "=r"(__gu_val) \
+ : "m"(*__gu_addr), "r"(__gu_addr), \
+ "m"(current->tss.ex.count), "r"(__gu_ex_count), \
+ "r"(__gu_ex_count+1), "0"(__gu_err), "1"(__gu_val) \
+ : "$28")
+
+#define __get_user_8 \
+ __asm__("/* Inline __get_user_8 */\n\t" \
+ "br $28,1f\n\t" /* set up exception address */ \
+ "br 2f\n" /* exception! */ \
+ "1:\t" \
+ "stq %6,%4\n\t" /* store inc'ed exception count */ \
+ "ldq_u %1,%2\n\t" /* actual data load */ \
+ "stq %5,%4\n\t" /* restore exception count */ \
+ "clr %0\n\t" /* no exception: error = 0 */ \
+ "extbl %1,%3,%1\n" /* extract the byte */ \
+ "2:\t/* End __get_user_8 */" \
+ : "=r"(__gu_err), "=r"(__gu_val) \
+ : "m"(*__gu_addr), "r"(__gu_addr), \
+ "m"(current->tss.ex.count), "r"(__gu_ex_count), \
+ "r"(__gu_ex_count+1), "0"(__gu_err), "1"(__gu_val) \
+ : "$28")
+
+extern void __put_user_unknown(void);
+
+#define __put_user_nocheck(x,ptr,size) \
+({ \
+ long __pu_err = -EFAULT; \
+ __typeof__(*(ptr)) *__pu_addr = (ptr); \
+ __typeof__(*(ptr)) __pu_val = (x); \
+ long __pu_ex_count = current->tss.ex.count; \
+ switch (size) { \
+ case 1: __put_user_8; break; \
+ case 2: __put_user_16; break; \
+ case 4: __put_user_32; break; \
+ case 8: __put_user_64; break; \
+ default: __put_user_unknown(); break; \
+ } \
+ __pu_err; \
+})
+
+#define __put_user_check(x,ptr,size,mask) \
+({ \
+ long __pu_err = -EFAULT; \
+ __typeof__(*(ptr)) *__pu_addr = (ptr); \
+ __typeof__(*(ptr)) __pu_val = (x); \
+ if (__access_ok((long)__pu_addr,size,mask)) { \
+ long __pu_ex_count = current->tss.ex.count; \
+ switch (size) { \
+ case 1: __put_user_8; break; \
+ case 2: __put_user_16; break; \
+ case 4: __put_user_32; break; \
+ case 8: __put_user_64; break; \
+ default: __put_user_unknown(); break; \
+ } \
+ } \
+ __pu_err; \
+})
+
+#define __put_user_64 \
+ __asm__("/* Inline __put_user_64 */\n\t" \
+ "br $28,1f\n\t" /* set up exception address */ \
+ "br 2f\n" /* exception! */ \
+ "1:\t" \
+ "stq %5,%3\n\t" /* store inc'ed exception count */ \
+ "stq %2,%1\n\t" /* actual data store */ \
+ "stq %4,%3\n\t" /* restore exception count */ \
+ "clr %0\n" /* no exception: error = 0 */ \
+ "2:\t/* End __put_user_64 */" \
+ : "=r"(__pu_err), "=m"(*__pu_addr) \
+ : "r"(__pu_val), "m"(current->tss.ex.count), \
+ "r"(__pu_ex_count), "r"(__pu_ex_count+1), \
+ "0"(__pu_err) \
+ : "$28")
+
+#define __put_user_32 \
+ __asm__("/* Inline __put_user_32 */\n\t" \
+ "br $28,1f\n\t" /* set up exception address */ \
+ "br 2f\n" /* exception! */ \
+ "1:\t" \
+ "stq %5,%3\n\t" /* store inc'ed exception count */ \
+ "stl %2,%1\n\t" /* actual data store */ \
+ "stq %4,%3\n\t" /* restore exception count */ \
+ "clr %0\n" /* no exception: error = 0 */ \
+ "2:\t/* End __put_user_32 */" \
+ : "=r"(__pu_err), "=m"(*__pu_addr) \
+ : "r"(__pu_val), "m"(current->tss.ex.count), \
+ "r"(__pu_ex_count), "r"(__pu_ex_count+1), \
+ "0"(__pu_err) \
+ : "$28")
+
+#define __put_user_16 \
+ __asm__("/* Inline __put_user_16 */\n\t" \
+ "br $28,1f\n\t" /* set up exception address */ \
+ "lda %0,%7\n\t" /* exception! error = -EFAULT */ \
+ "br 2f\n" \
+ "1:\t" \
+ "stq %6,%4\n\t" /* store inc'ed exception count */ \
+ "ldq_u %0,%1\n\t" /* masked data store */ \
+ "inswl %2,%3,%2\n\t" \
+ "mskwl %0,%3,%0\n\t" \
+ "or %0,%2,%2\n\t" \
+ "stq_u %2,%1\n\t" \
+ "stq %5,%4\n\t" /* restore exception count */ \
+ "clr %0\n" /* no exception: error = 0 */ \
+ "2:\t/* End __put_user_16 */" \
+ : "=r"(__pu_err), "=m"(*__pu_addr), "=r"(__pu_val) \
+ : "r"(__pu_addr), "m"(current->tss.ex.count), \
+ "r"(__pu_ex_count), "r"(__pu_ex_count+1), "i"(-EFAULT), \
+ "2"(__pu_val) \
+ : "$28")
+
+#define __put_user_8 \
+ __asm__("/* Inline __put_user_8 */\n\t" \
+ "br $28,1f\n\t" /* set up exception address */ \
+ "lda %0,%7\n\t" /* exception! error = -EFAULT */ \
+ "br 2f\n" \
+ "1:\t" \
+ "stq %6,%4\n\t" /* store inc'ed exception count */ \
+ "ldq_u %0,%1\n\t" /* masked data store */ \
+ "insbl %2,%3,%2\n\t" \
+ "mskbl %0,%3,%0\n\t" \
+ "or %0,%2,%2\n\t" \
+ "stq_u %2,%1\n\t" \
+ "stq %5,%4\n\t" /* restore exception count */ \
+ "clr %0\n" /* no exception: error = 0 */ \
+ "2:\t/* End __put_user_8 */" \
+ : "=r"(__pu_err), "=m"(*__pu_addr), "=r"(__pu_val) \
+ : "r"(__pu_addr), "m"(current->tss.ex.count), \
+ "r"(__pu_ex_count), "r"(__pu_ex_count+1), "i"(-EFAULT), \
+ "2"(__pu_val) \
+ : "$28")
+
+
+extern void __clear_user(void);
+
+#define clear_user(to,n) \
+({ \
+ register void * __cl_to __asm__("$6") = (to); \
+ register long __cl_len __asm__("$0") = (n); \
+ if (__access_ok(((long)__cl_to),__cl_len,__access_mask)) { \
+ register void * __cl_ex __asm__("$7"); \
+ __cl_ex = ¤t->tss.ex; \
+ __asm__ __volatile__( \
+ "jsr $28,(%2),__clear_user" \
+ : "=r"(__cl_len), "=r"(__cl_to) \
+ : "r"(__clear_user), "r"(__cl_ex), \
+ "0"(__cl_len), "1"(__cl_to) \
+ : "$1","$2","$3","$4","$5","$28","memory"); \
+ } \
+ __cl_len; \
+})
+
+
+/* Returns: -EFAULT if exception before terminator, N if the entire
+ buffer filled, else strlen. */
+
+struct exception_struct;
+extern long __strncpy_from_user(char *__to, const char *__from,
+ long __to_len, struct exception_struct *);
+
+#define strncpy_from_user(to,from,n) \
+({ \
+ char * __sfu_to = (to); \
+ const char * __sfu_from = (from); \
+ long __sfu_len = (n), __sfu_ret = -EFAULT; \
+ if (__access_ok(((long)__sfu_from),__sfu_len,__access_mask)) { \
+ __sfu_ret = __strncpy_from_user(__sfu_to,__sfu_from, \
+ __sfu_len, ¤t->tss.ex); \
+ __sfu_ret; \
+})
+
+extern inline int verify_area(int type, const void * addr, unsigned long size)
+{
+ return access_ok(type,addr,size)?0:-EFAULT;
+}
+
+#endif /* _ASM_SEGMENT_H */
*/
#include <asm/ptrace.h>
+#include <asm/user.h>
typedef unsigned long elf_greg_t;
#define USER_CS 0x23
#define USER_DS 0x2B
-#ifndef __ASSEMBLY__
-
-#include <linux/string.h>
-
-/*
- * The fs value determines whether argument validity checking should be
- * performed or not. If get_fs() == USER_DS, checking is performed, with
- * get_fs() == KERNEL_DS, checking is bypassed.
- *
- * For historical reasons, these macros are grossly misnamed.
- */
-
-#define get_fs() (current->tss.segment)
-#define set_fs(x) (current->tss.segment = (x))
-#define get_ds() (KERNEL_DS)
-
-#define __user_ok(addr,size) \
-((size <= 0xC0000000) && (addr <= 0xC0000000 - size))
-#define __kernel_ok \
-(get_fs() == KERNEL_DS)
-
-extern int __verify_write(const void *, unsigned long);
-
-#if CPU > 386
-#define __access_ok(type,addr,size) \
-(__kernel_ok || __user_ok(addr,size))
-#else
-#define __access_ok(type,addr,size) \
-(__kernel_ok || (__user_ok(addr,size) && \
- ((type) == VERIFY_READ || wp_works_ok || __verify_write((void *)(addr),(size)))))
-#endif /* CPU */
-
-#define access_ok(type,addr,size) \
-__access_ok((type),(unsigned long)(addr),(size))
-
-/*
- * Uh, these should become the main single-value transfer routines..
- * They automatically use the right size if we just have the right
- * pointer type..
- *
- * This gets kind of ugly. We want to return _two_ values in "get_user()"
- * and yet we don't want to do any pointers, because that is too much
- * of a performance impact. Thus we have a few rather ugly macros here,
- * and hide all the uglyness from the user.
- */
-#define put_user(x,ptr) ({ \
-unsigned long __pu_addr = (unsigned long)(ptr); \
-__put_user((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr))); })
-
-#define get_user(x,ptr) ({ \
-unsigned long __gu_addr = (unsigned long)(ptr); \
-__get_user((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr))); })
-
-struct __large_struct { unsigned long buf[100]; };
-#define __m(x) (*(struct __large_struct *)(x))
-
-#define __put_user(x,addr,size) ({ \
-int __pu_ret = -EFAULT; \
-if (access_ok(VERIFY_WRITE,addr,size)) { \
-switch (size) { \
-case 1: __put_user_8(x,addr,__pu_ret); break; \
-case 2: __put_user_16(x,addr,__pu_ret); break; \
-case 4: __put_user_32(x,addr,__pu_ret); break; \
-default: __pu_ret = __put_user_bad(); break; \
-} } __pu_ret; })
-
-#define __put_user_asm(x,addr,ret,bwl,reg,rtype) \
-__asm__ __volatile__( \
- "movl $1f,%0\n\t" \
- "incl %3\n\t" \
- "mov" #bwl " %" reg "1,%2\n\t" \
- "xorl %0,%0\n\t" \
- "decl %3\n1:" \
-:"=d" (ret) \
-:#rtype (x), "m" (__m(addr)),"m" (current->tss.ex.count), "0" (ret))
-
-#define __put_user_8(x,addr,ret) \
-__put_user_asm(x,addr,ret,b,"b","iq")
-#define __put_user_16(x,addr,ret) \
-__put_user_asm(x,addr,ret,w,"w","ir")
-#define __put_user_32(x,addr,ret) \
-__put_user_asm(x,addr,ret,l,"","ir")
-
-extern int __put_user_bad(void);
-
-#define __get_user(x,addr,size,type) ({ \
-int __gu_ret = -EFAULT; \
-unsigned long __gu_val = 0; \
-if (access_ok(VERIFY_WRITE,addr,size)) { \
-switch (size) { \
-case 1: __get_user_8(__gu_val,addr,__gu_ret); break; \
-case 2: __get_user_16(__gu_val,addr,__gu_ret); break; \
-case 4: __get_user_32(__gu_val,addr,__gu_ret); break; \
-default: __gu_ret = __get_user_bad(); break; \
-} } x = (type) __gu_val; __gu_ret; })
-
-#define __get_user_asm(x,addr,ret,bwl,reg,rtype) \
-__asm__ __volatile__( \
- "movl $1f,%0\n\t" \
- "incl %3\n\t" \
- "mov" #bwl " %2,%" reg "1\n\t" \
- "xorl %0,%0\n\t" \
- "decl %3\n1:" \
-:"=d" (ret), #rtype (x) \
-:"m" (__m(addr)),"m" (current->tss.ex.count), "0" (ret), "1" (x))
-
-#define __get_user_8(x,addr,ret) \
-__get_user_asm(x,addr,ret,b,"b","=q")
-#define __get_user_16(x,addr,ret) \
-__get_user_asm(x,addr,ret,w,"w","=r")
-#define __get_user_32(x,addr,ret) \
-__get_user_asm(x,addr,ret,l,"","=r")
-
-extern int __get_user_bad(void);
-
-#define __copy_user(to,from,size) \
-__asm__ __volatile__( \
- "movl $3f,%0\n\t" \
- "incl %2\n\t" \
- "rep; movsl\n\t" \
- "testb $2,%b3\n\t" \
- "je 1f\n\t" \
- "movsw\n\t" \
- "subb $2,%b3\n" \
- "1:\t" \
- "testb $1,%b3\n\t" \
- "je 2f\n\t" \
- "movsb\n\t" \
- "decb %b3\n" \
- "2:\t" \
- "decl %2\n" \
- "3:\tlea 0(%3,%1,4),%0" \
- :"=d" (size) \
- :"c" (size >> 2), "m" (current->tss.ex), "q" (size & 3), \
- "D" (to), "S" (from), "0" (size) \
- :"cx","di","si","memory");
-
-#define copy_to_user(to,from,n) ({ \
-unsigned long __cu_to = (unsigned long) (to); \
-unsigned long __cu_size = (unsigned long) (n); \
-if (__cu_size && __access_ok(VERIFY_WRITE, __cu_to, __cu_size)) \
-__copy_user(__cu_to,from,__cu_size); \
-__cu_size; })
-
-#define copy_from_user(to,from,n) ({ \
-unsigned long __cu_from = (unsigned long) (from); \
-unsigned long __cu_size = (unsigned long) (n); \
-if (__cu_size && __access_ok(VERIFY_READ, __cu_from, __cu_size)) \
-__copy_user(to,__cu_from,__cu_size); \
-__cu_size; })
-
-#define __clear_user(addr,size) \
-__asm__ __volatile__( \
- "movl $3f,%0\n\t" \
- "incl %2\n\t" \
- "rep; stosl\n\t" \
- "testl $2,%3\n\t" \
- "je 1f\n\t" \
- "stosw\n\t" \
- "subl $2,%3\n" \
- "1:\t" \
- "testl $1,%3\n\t" \
- "je 2f\n\t" \
- "stosb\n\t" \
- "decl %3\n" \
- "2:\t" \
- "decl %2\n" \
- "3:\tlea 0(%3,%1,4),%0" \
- :"=d" (size) \
- :"c" (size >> 2), "m" (current->tss.ex), "r" (size & 3), \
- "D" (addr), "0" (size), "a" (0) \
- :"cx","di","memory");
-
-#define clear_user(addr,n) ({ \
-void * __cl_addr = (addr); \
-unsigned long __cl_size = (n); \
-if (__cl_size && __access_ok(VERIFY_WRITE, ((unsigned long)(__cl_addr)), __cl_size)) \
-__clear_user(__cl_addr, __cl_size); \
-__cl_size; })
-
-#define __strncpy_from_user(dst,src,count,res) \
-__asm__ __volatile__( \
- "cld\n\t" \
- "movl $3f,%0\n\t" \
- "incl %2\n" \
- "1:\tdecl %1\n\t" \
- "js 2f\n\t" \
- "lodsb\n\t" \
- "stosb\n\t" \
- "testb %%al,%%al\n\t" \
- "jne 1b\n" \
- "2:\t" \
- "incl %1\n\t" \
- "xorl %0,%0\n\t" \
- "decl %2\n" \
- "3:" \
- :"=d" (res), "=r" (count) \
- :"m" (current->tss.ex), "1" (count), "S" (src),"D" (dst),"0" (res) \
- :"si","di","ax","cx","memory")
-
-#define strncpy_from_user(dest,src,count) ({ \
-const void * __sc_src = (src); \
-unsigned long __sc_count = (count); \
-long __sc_res = -EFAULT; \
-if (__access_ok(VERIFY_READ, ((unsigned long)(__sc_src)), __sc_count)) { \
- unsigned long __sc_residue = __sc_count; \
- __strncpy_from_user(dest,__sc_src,__sc_count,__sc_res); \
- if (!__sc_res) __sc_res = __sc_residue - __sc_count; \
-} __sc_res; })
-
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* _ASM_SEGMENT_H */
+#endif
"std\n\t"
"rep\n\t"
"movsb\n\t"
+ "cld"
: /* no output */
:"c" (n), "S" (n-1+(const char *)src), "D" (n-1+(char *)tmp)
:"cx","si","di","memory");
--- /dev/null
+#ifndef __i386_UACCESS_H
+#define __i386_UACCESS_H
+
+/*
+ * User space memory access functions
+ */
+#include <linux/sched.h>
+
+#include <asm/segment.h>
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not. If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+
+#define get_fs() (current->tss.segment)
+#define set_fs(x) (current->tss.segment = (x))
+#define get_ds() (KERNEL_DS)
+
+#define __user_ok(addr,size) \
+((size <= 0xC0000000UL) && (addr <= 0xC0000000UL - size))
+#define __kernel_ok \
+(get_fs() == KERNEL_DS)
+
+extern int __verify_write(const void *, unsigned long);
+
+#if CPU > 386
+#define __access_ok(type,addr,size) \
+(__kernel_ok || __user_ok(addr,size))
+#else
+#define __access_ok(type,addr,size) \
+(__kernel_ok || (__user_ok(addr,size) && \
+ ((type) == VERIFY_READ || wp_works_ok || __verify_write((void *)(addr),(size)))))
+#endif /* CPU */
+
+#define access_ok(type,addr,size) \
+__access_ok((type),(unsigned long)(addr),(size))
+
+/*
+ * Uh, these should become the main single-value transfer routines..
+ * They automatically use the right size if we just have the right
+ * pointer type..
+ *
+ * This gets kind of ugly. We want to return _two_ values in "get_user()"
+ * and yet we don't want to do any pointers, because that is too much
+ * of a performance impact. Thus we have a few rather ugly macros here,
+ * and hide all the uglyness from the user.
+ *
+ * The "__xxx" versions of the user access functions are versions that
+ * do not verify the address space, that must have been done previously
+ * with a separate "access_ok()" call (this is used when we do multiple
+ * accesses to the same area of user memory).
+ */
+#define put_user(x,ptr) \
+__do_put_user((unsigned long)((__typeof__(*(ptr)))(x)),(ptr),(sizeof(*(ptr))))
+#define __put_user(x,ptr) \
+__do_put_user_nocheck((unsigned long)((__typeof__(*(ptr)))(x)),(ptr),(sizeof(*(ptr))))
+
+struct __large_struct { unsigned long buf[100]; };
+#define __m(x) (*(struct __large_struct *)(x))
+
+#define __put_user_asm(x,addr,ret,bwl,reg,rtype) \
+__asm__ __volatile__( \
+ "movl $1f,%0\n\t" \
+ "incl %3\n\t" \
+ "mov" #bwl " %" reg "1,%2\n\t" \
+ "xorl %0,%0\n\t" \
+ "decl %3\n1:" \
+:"=&d" (ret) \
+:#rtype (x), "m" (__m(addr)),"m" (current->tss.ex.count))
+
+extern int __put_user_bad(void);
+
+#define __put_user_size(x,ptr,size,retval) \
+switch (size) { \
+case 1: __put_user_asm(x,ptr,retval,b,"b","iq"); break; \
+case 2: __put_user_asm(x,ptr,retval,w,"w","ir"); break; \
+case 4: __put_user_asm(x,ptr,retval,l,"","ir"); break; \
+default: retval = __put_user_bad(); }
+
+static inline int __do_put_user(unsigned long x, void * ptr, int size)
+{
+ int retval = -EFAULT;
+ if (access_ok(VERIFY_WRITE, ptr, size))
+ __put_user_size(x,ptr,size,retval);
+ return retval;
+}
+
+#define __do_put_user_nocheck(x, ptr, size) \
+({ int retval; __put_user_size(x,ptr,size,retval); retval; })
+
+#define get_user(x,ptr) \
+__do_get_user((x),(unsigned long)(ptr),sizeof(*(ptr)),__typeof__(*(ptr)))
+
+#define __get_user(x,ptr) \
+__do_get_user_nocheck((x),(unsigned long)(ptr),sizeof(*(ptr)),__typeof__(*(ptr)))
+
+#define __do_get_user(x,ptr,size,type) ({ \
+unsigned long __gu_addr = ptr; \
+int __gu_ret = -EFAULT; \
+unsigned long __gu_val = 0; \
+if (access_ok(VERIFY_READ,__gu_addr,size)) { \
+switch (size) { \
+case 1: __do_get_user_8(__gu_val,__gu_addr,__gu_ret); break; \
+case 2: __do_get_user_16(__gu_val,__gu_addr,__gu_ret); break; \
+case 4: __do_get_user_32(__gu_val,__gu_addr,__gu_ret); break; \
+default: __gu_ret = __do_get_user_bad(); break; \
+} } x = (type) __gu_val; __gu_ret; })
+
+#define __do_get_user_nocheck(x,ptr,size,type) ({ \
+int __gu_ret; \
+unsigned long __gu_val; \
+switch (size) { \
+case 1: __do_get_user_8(__gu_val,ptr,__gu_ret); break; \
+case 2: __do_get_user_16(__gu_val,ptr,__gu_ret); break; \
+case 4: __do_get_user_32(__gu_val,ptr,__gu_ret); break; \
+default: __gu_ret = __do_get_user_bad(); __gu_val = 0; break; \
+} x = (type) __gu_val; __gu_ret; })
+
+#define __do_get_user_asm(x,addr,ret,bwl,reg,rtype) \
+__asm__ __volatile__( \
+ "movl $1f,%0\n\t" \
+ "incl %3\n\t" \
+ "mov" #bwl " %2,%" reg "1\n\t" \
+ "xorl %0,%0\n\t" \
+ "decl %3\n1:" \
+:"=&d" (ret), #rtype (x) \
+:"m" (__m(addr)),"m" (current->tss.ex.count))
+
+#define __do_get_user_8(x,addr,ret) \
+__do_get_user_asm(x,addr,ret,b,"b","=&q")
+#define __do_get_user_16(x,addr,ret) \
+__do_get_user_asm(x,addr,ret,w,"w","=&r")
+#define __do_get_user_32(x,addr,ret) \
+__do_get_user_asm(x,addr,ret,l,"","=&r")
+
+extern int __do_get_user_bad(void);
+
+#define __copy_user(to,from,size) \
+__asm__ __volatile__( \
+ "shrl $2,%1\n\t" \
+ "movl $3f,%0\n\t" \
+ "incl %3\n\t" \
+ "rep; movsl\n\t" \
+ "testl $2,%2\n\t" \
+ "je 1f\n\t" \
+ "movsw\n\t" \
+ "subl $2,%2\n" \
+ "1:\t" \
+ "testl $1,%2\n\t" \
+ "je 2f\n\t" \
+ "movsb\n\t" \
+ "decl %2\n" \
+ "2:\t" \
+ "decl %3\n" \
+ "3:\tlea 0(%2,%1,4),%0" \
+ :"=&d" (size) \
+ :"c" (size), "r" (size & 3), "m" (current->tss.ex), \
+ "D" (to), "S" (from) \
+ :"cx","di","si","memory");
+
+static inline unsigned long __constant_copy_user(void * to, const void * from, unsigned long size)
+{
+ unsigned long result;
+
+ switch (size & 3) {
+ default:
+ __asm__ __volatile__(
+ "movl $1f,%0\n\t"
+ "incl %1\n\t"
+ "rep ; movsl\n\t"
+ "decl %1\n"
+ "1:\tlea 0(,%%ecx,4),%0"
+ :"=&d" (result)
+ :"m" (current->tss.ex),
+ "S" (from),"D" (to),"c" (size/4)
+ :"cx","di","si","memory");
+ break;
+ case 1:
+ __asm__ __volatile__(
+ "movl $1f,%0\n\t"
+ "incl %3\n\t"
+ "rep ; movsl\n\t"
+ "movsb\n\t"
+ "decl %1\n\t"
+ "decl %3\n"
+ "1:\tlea 0(%1,%%ecx,4),%0"
+ :"=&d" (result)
+ :"ab" (1),"m" (current->tss.ex),
+ "S" (from),"D" (to), "c" (size/4)
+ :"cx","di","si","memory");
+ break;
+ case 2:
+ __asm__ __volatile__(
+ "movl $1f,%0\n\t"
+ "incl %2\n\t"
+ "rep ; movsl\n\t"
+ "movsw\n\t"
+ "subl $2,%1\n\t"
+ "decl %2\n"
+ "1:\tlea 0(%1,%%ecx,4),%0"
+ :"=&d" (result)
+ :"ab" (2),"m" (current->tss.ex),
+ "S" (from),"D" (to),"c" (size/4)
+ :"cx","di","si","memory");
+ break;
+ case 3:
+ __asm__ __volatile__(
+ "movl $1f,%0\n\t"
+ "incl %2\n\t"
+ "rep ; movsl\n\t"
+ "movsw\n\t"
+ "subl $2,%1\n\t"
+ "movsb\n\t"
+ "decl %1\n\t"
+ "decl %2\n"
+ "1:\tlea 0(%1,%%ecx,4),%0"
+ :"=&d" (result)
+ :"ab" (3),"m" (current->tss.ex),
+ "S" (from),"D" (to),"c" (size/4)
+ :"cx","di","si","memory");
+ break;
+ }
+ return result;
+}
+
+static inline unsigned long __generic_copy_to_user(void *to, const void *from, unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n))
+ __copy_user(to,from,n);
+ return n;
+}
+
+static inline unsigned long __constant_copy_to_user(void *to, const void *from, unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n))
+ n = __constant_copy_user(to,from,n);
+ return n;
+}
+
+static inline unsigned long __generic_copy_from_user(void *to, const void *from, unsigned long n)
+{
+ if (access_ok(VERIFY_READ, from, n))
+ __copy_user(to,from,n);
+ return n;
+}
+
+static inline unsigned long __constant_copy_from_user(void *to, const void *from, unsigned long n)
+{
+ if (access_ok(VERIFY_READ, from, n))
+ n = __constant_copy_user(to,from,n);
+ return n;
+}
+
+#define copy_to_user(to,from,n) \
+(__builtin_constant_p(n) ? \
+ __constant_copy_to_user((to),(from),(n)) : \
+ __generic_copy_to_user((to),(from),(n)))
+
+#define copy_from_user(to,from,n) \
+(__builtin_constant_p(n) ? \
+ __constant_copy_from_user((to),(from),(n)) : \
+ __generic_copy_from_user((to),(from),(n)))
+
+#define __clear_user(addr,size) \
+__asm__ __volatile__( \
+ "movl $3f,%0\n\t" \
+ "incl %2\n\t" \
+ "rep; stosl\n\t" \
+ "testl $2,%3\n\t" \
+ "je 1f\n\t" \
+ "stosw\n\t" \
+ "subl $2,%3\n" \
+ "1:\t" \
+ "testl $1,%3\n\t" \
+ "je 2f\n\t" \
+ "stosb\n\t" \
+ "decl %3\n" \
+ "2:\t" \
+ "decl %2\n" \
+ "3:\tlea 0(%3,%1,4),%0" \
+ :"=&d" (size) \
+ :"c" (size >> 2), "m" (current->tss.ex), "r" (size & 3), \
+ "D" (addr), "a" (0) \
+ :"cx","di","memory");
+
+#define clear_user(addr,n) ({ \
+void * __cl_addr = (addr); \
+unsigned long __cl_size = (n); \
+if (__cl_size && __access_ok(VERIFY_WRITE, ((unsigned long)(__cl_addr)), __cl_size)) \
+__clear_user(__cl_addr, __cl_size); \
+__cl_size; })
+
+#define __strncpy_from_user(dst,src,count,res) \
+__asm__ __volatile__( \
+ "cld\n\t" \
+ "movl $3f,%0\n\t" \
+ "incl %2\n" \
+ "1:\tdecl %1\n\t" \
+ "js 2f\n\t" \
+ "lodsb\n\t" \
+ "stosb\n\t" \
+ "testb %%al,%%al\n\t" \
+ "jne 1b\n" \
+ "2:\t" \
+ "incl %1\n\t" \
+ "xorl %0,%0\n\t" \
+ "decl %2\n" \
+ "3:" \
+ :"=&d" (res), "=r" (count) \
+ :"m" (current->tss.ex), "1" (count), "S" (src),"D" (dst) \
+ :"si","di","ax","memory")
+
+#define strncpy_from_user(dest,src,count) ({ \
+const void * __sc_src = (src); \
+unsigned long __sc_count = (count); \
+long __sc_res = -EFAULT; \
+if (__access_ok(VERIFY_READ, ((unsigned long)(__sc_src)), __sc_count)) { \
+ unsigned long __sc_residue = __sc_count; \
+ __strncpy_from_user(dest,__sc_src,__sc_count,__sc_res); \
+ if (!__sc_res) __sc_res = __sc_residue - __sc_count; \
+} __sc_res; })
+
+
+extern inline int verify_area(int type, const void * addr, unsigned long size)
+{
+ return access_ok(type,addr,size)?0:-EFAULT;
+}
+
+#endif /* __i386_UACCESS_H */
#include <linux/kdev_t.h>
#include <linux/ioctl.h>
-#include <asm/semaphore.h>
-
/*
* It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix
* that later. Anyway, now the file code is no longer dependent
#ifdef __KERNEL__
+#include <asm/semaphore.h>
#include <asm/bitops.h>
extern void buffer_init(void);
#include <asm/page.h>
#include <asm/atomic.h>
-#include <asm/segment.h>
-
-#define VERIFY_READ 0
-#define VERIFY_WRITE 1
-
-extern inline int verify_area(int type, const void * addr, unsigned long size)
-{
- return access_ok(type,addr,size)?0:-EFAULT;
-}
/*
* Linux kernel virtual memory manager primitives.
PROC_NET_IP_MASQ_APP,
PROC_NET_STRIP_STATUS,
PROC_NET_STRIP_TRACE,
+ PROC_NET_Z8530,
PROC_NET_LAST
};
-
-#ifndef _RAID0_H
-#define _RAID0_H
-
-struct strip_zone
-{
- int zone_offset; /* Zone offset in md_dev */
- int dev_offset; /* Zone offset in real dev */
- int size; /* Zone size */
- int nb_dev; /* Number of devices attached to the zone */
- struct real_dev *dev[MAX_REAL]; /* Devices attached to the zone */
-};
-
-struct raid0_hash
-{
- struct strip_zone *zone0, *zone1;
-};
-
-struct raid0_data
-{
- struct raid0_hash *hash_table; /* Dynamically allocated */
- struct strip_zone *strip_zone; /* This one too */
- int nr_strip_zones;
- struct strip_zone *smallest;
- int nr_zones;
-};
-
-#endif
-
#ifndef _RAID0_H
#define _RAID0_H
-/* $Id: scc.h,v 1.15 1995/11/16 20:19:26 jreuter Exp jreuter $ */
+/* $Id: scc.h,v 1.26 1996/10/09 16:35:56 jreuter Exp jreuter $ */
#ifndef _SCC_H
#define _SCC_H
+#include <linux/if_ether.h>
+
/* selection of hardware types */
#define PA0HZP 0x00 /* hardware type for PA0HZP SCC card and compatible */
#define SCC_PARANOIA_CHECK /* tell the user if something is going wrong */
-/* ioctl() commands */
-
-#define TIOCSCCCFG 0x2200 /* set hardware parameters */
-#define TIOCSCCINI 0x2201 /* init driver */
-#define TIOCCHANINI 0x2202 /* init channel */
-
-#define TIOCCHANMEM 0x2210 /* adjust buffer pools */
-
-#define TIOCGKISS 0x2282 /* get kiss parameter */
-#define TIOCSKISS 0x2283 /* set kiss parameter */
-
-#define TIOCSCCSTAT 0x2284 /* get scc status */
+/* DEV ioctl() commands */
+#define SIOCSCCRESERVED (SIOCDEVPRIVATE+0)
+#define SIOCSCCCFG (SIOCDEVPRIVATE+1)
+#define SIOCSCCINI (SIOCDEVPRIVATE+2)
+#define SIOCSCCCHANINI (SIOCDEVPRIVATE+3)
+#define SIOCSCCSMEM (SIOCDEVPRIVATE+4)
+#define SIOCSCCGKISS (SIOCDEVPRIVATE+5)
+#define SIOCSCCSKISS (SIOCDEVPRIVATE+6)
+#define SIOCSCCGSTAT (SIOCDEVPRIVATE+7)
/* magic number */
#define SCC_MAGIC 0x8530 /* ;-) */
-/* KISS protocol flags */
-#define FEND 192
-#define FESC 219
-#define TFEND 220
-#define TFESC 221
-
/* KISS state machine */
#define KISS_IDLE 0
#define PARAM_WAIT 16
#define PARAM_MAXDEFER 17
#define PARAM_TX 18
-#define PARAM_SLIP 19
+#define PARAM_HWEVENT 31
#define PARAM_RETURN 255 /* reset kiss mode */
+/* fulldup parameter */
+
+#define KISS_DUPLEX_HALF 0 /* normal CSMA operation */
+#define KISS_DUPLEX_FULL 1 /* fullduplex, key down trx after transmission */
+#define KISS_DUPLEX_LINK 2 /* fullduplex, key down trx after 'idletime' sec */
+#define KISS_DUPLEX_OPTIMA 3 /* fullduplex, let the protocol layer control the hw */
+
+/* misc. parameters */
+
#define TIMER_OFF 65535U /* to switch off timers */
#define NO_SUCH_PARAM 65534U /* param not implemented */
+/* HWEVENT parameter */
+
+#define HWEV_DCD_ON 0
+#define HWEV_DCD_OFF 1
+#define HWEV_ALL_SENT 2
+
/* channel grouping */
#define RXGROUP 0x100 /* if set, only tx when all channels clear */
#define TXS_BUSY 1 /* waiting for permission to send / tailtime */
#define TXS_ACTIVE 2 /* Transmitter on, sending data */
#define TXS_NEWFRAME 3 /* reset CRC and send (next) frame */
+#define TXS_IDLE2 4 /* Transmitter on, no data pending */
+#define TXS_WAIT 5 /* Waiting for Mintime to expire */
+#define TXS_TIMEOUT 6 /* We had a transmission timeout */
#define TX_ON 1 /* command for scc_key_trx() */
#define TX_OFF 0 /* dto */
-/* Buffer management */
-
-#define BT_RECEIVE 1 /* buffer allocated by receive */
-#define BT_TRANSMIT 2 /* buffer allocated by transmit */
-
-#define NULLBUF (struct mbuf *)0
-#define NULLBUFP (struct mbuf **)0
+/* Vector masks in RR2B */
+#define VECTOR_MASK 0x06
+#define TXINT 0x00
+#define EXINT 0x02
+#define RXINT 0x04
+#define SPINT 0x06
-typedef unsigned short io_port; /* type definition for an 'io port address' */
-typedef unsigned short ioaddr; /* old def */
+typedef unsigned long io_port; /* type definition for an 'io port address' */
#ifdef SCC_DELAY
#define Inb(port) inb_p(port)
#define Outb(port, val) outb(val, port)
#endif
-/* some nasty macros (esp. Expired) */
-
-#define TIMER_STOPPED 65535U
-#define Running(k) (scc->k != TIMER_STOPPED)
-#define Expired(k) (scc->k != TIMER_STOPPED) && (!(scc->k) || (--(scc->k) == 0))
-#define Stop_Timer(k) scc->k = TIMER_STOPPED
-
-
-/* Basic message buffer structure */
+#define TIMER_OFF 65535U
-struct mbuf {
- struct mbuf *next; /* Link to next buffer */
- struct mbuf *prev; /* Link to previous buffer */
-
- int cnt; /* Number of bytes stored in buffer */
- unsigned char *rw_ptr; /* read-write pointer */
- unsigned char data[0]; /* anchor for allocated buffer */
-};
-
/* SCC channel control structure for KISS */
struct scc_kiss {
unsigned char txdelay; /* Transmit Delay 10 ms/cnt */
unsigned char persist; /* Persistence (0-255) as a % */
unsigned char slottime; /* Delay to wait on persistence hit */
- unsigned char tailtime; /* Delay after XMTR OFF */
+ unsigned char tailtime; /* Delay after last byte written */
unsigned char fulldup; /* Full Duplex mode 0=CSMA 1=DUP 2=ALWAYS KEYED */
unsigned char waittime; /* Waittime before any transmit attempt */
unsigned int maxkeyup; /* Maximum time to transmit (seconds) */
- unsigned char mintime; /* Minimal offtime after MAXKEYUP timeout */
+ unsigned char mintime; /* Minimal offtime after MAXKEYUP timeout (seconds) */
unsigned int idletime; /* Maximum idle time in ALWAYS KEYED mode (seconds) */
unsigned int maxdefer; /* Timer for CSMA channel busy limit */
unsigned char tx_inhibit; /* Transmit is not allowed when set */
- unsigned char group; /* group ID for AX.25 TX interlocking */
- unsigned char not_slip; /* set to zero: use SLIP instead of KISS */
- unsigned char softdcd; /* use DPLL instead of DCD pin for carrier detect */
+ unsigned char group; /* Group ID for AX.25 TX interlocking */
+ unsigned char mode; /* 'normal' or 'hwctrl' mode (unused) */
+ unsigned char softdcd; /* Use DPLL instead of DCD pin for carrier detect */
};
unsigned int tx_under; /* Transmitter Underruns */
unsigned int tx_state; /* Transmitter state */
-
- char tx_kiss_state; /* state of the kiss interpreter */
- char rx_kiss_state; /* state of the kiss encoder */
-
int tx_queued; /* tx frames enqueued */
- int rx_queued; /* rx frames enqueued */
-
- unsigned int rxbuffers; /* allocated rx_buffers */
- unsigned int txbuffers; /* allocated tx_buffers */
+
+ unsigned int maxqueue; /* allocated tx_buffers */
unsigned int bufsize; /* used buffersize */
};
char nrz; /* NRZ instead of NRZI */
};
-struct ioctl_command {
+struct scc_kiss_cmd {
int command; /* one of the KISS-Commands defined above */
unsigned param; /* KISS-Param */
};
-/* currently unused */
-
struct scc_hw_config {
io_port data_a; /* data port channel A */
io_port ctrl_a; /* control port channel A */
int irq; /* irq */
long clock; /* clock */
char option; /* command for function port */
-
+
char brand; /* hardware type */
char escc; /* use ext. features of a 8580/85180/85280 */
};
+/* (#) only one INTACK latch allowed. */
+
+
struct scc_mem_config {
- unsigned int rxbuffers;
- unsigned int txbuffers;
+ unsigned int dummy;
unsigned int bufsize;
};
-/* (#) only one INTACK latch allowed. */
-
/* SCC channel structure */
struct scc_channel {
- int magic; /* magic word */
+ int magic; /* magic word */
- int init; /* channel exists? */
- struct tty_struct *tty; /* link to tty control structure */
- char tty_opened; /* No. of open() calls... */
- char throttled; /* driver is throttled */
-
- char brand; /* manufacturer of the board */
- long clock; /* used clock */
+ int init; /* channel exists? */
+
+ struct device *dev; /* link to device control structure */
+ struct enet_statistics dev_stat;/* device statistics */
+
+ char brand; /* manufacturer of the board */
+ long clock; /* used clock */
- io_port ctrl; /* I/O address of CONTROL register */
- io_port data; /* I/O address of DATA register */
- io_port special; /* I/O address of special function port */
+ io_port ctrl; /* I/O address of CONTROL register */
+ io_port data; /* I/O address of DATA register */
+ io_port special; /* I/O address of special function port */
+ int irq; /* Number of Interrupt */
char option;
- char enhanced; /* Enhanced SCC support */
+ char enhanced; /* Enhanced SCC support */
- unsigned char wreg[16]; /* Copy of last written value in WRx */
- unsigned char status; /* Copy of R0 at last external interrupt */
+ unsigned char wreg[16]; /* Copy of last written value in WRx */
+ unsigned char status; /* Copy of R0 at last external interrupt */
- struct scc_kiss kiss; /* control structure for KISS params */
- struct scc_stat stat; /* statistical information */
- struct scc_modem modem; /* modem information */
+ struct scc_kiss kiss; /* control structure for KISS params */
+ struct scc_stat stat; /* statistical information */
+ struct scc_modem modem; /* modem information */
- struct mbuf *rx_buffer_pool; /* free buffers for rx/tx frames are */
- struct mbuf *tx_buffer_pool; /* linked in these ring chains */
-
- struct mbuf *rx_queue; /* chain of received frames */
- struct mbuf *tx_queue; /* chain of frames due to transmit */
- struct mbuf *rx_bp; /* pointer to frame currently received */
- struct mbuf *tx_bp; /* pointer to frame currently transmitted */
-
- struct mbuf *kiss_decode_bp; /* frame we are receiving from tty */
- struct mbuf *kiss_encode_bp; /* frame we are sending to tty */
-
+ struct sk_buff *tx_next_buff; /* next tx buffer */
+ struct sk_buff *rx_buff; /* pointer to frame currently received */
+ struct sk_buff *tx_buff; /* pointer to frame currently transmitted */
+
/* Timer */
-
- struct timer_list tx_t; /* tx timer for this channel */
- struct timer_list rx_t; /* rx timer */
- /* rx timer counters */
-
- unsigned int t_dwait; /* wait time (DWAIT) */
- unsigned int t_slot; /* channel sample frequency */
- unsigned int t_txdel; /* TX delay */
- unsigned int t_tail; /* tail time */
- unsigned int t_maxk; /* max. key up */
- unsigned int t_min; /* minimal key up */
- unsigned int t_idle; /* */
- unsigned int t_mbusy; /* time until defer if channel busy */
+ struct timer_list tx_t; /* tx timer for this channel */
+ struct timer_list tx_wdog; /* tx watchdogs */
};
-
-/* 8530 Serial Communications Controller Register definitions */
-#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 */
-
-/* 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 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 */
-
-/* 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 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 CRC_ERR 0x40 /* CRC/Framing Error */
-#define END_FR 0x80 /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel B only) - Interrupt vector */
-
-#define VECTOR_MASK 0x06
-
-#define TXINT 0x00
-#define EXINT 0x02
-#define RXINT 0x04
-#define SPINT 0x06
-
-
-/* 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) */
-
-
-/* 8536 register definitions */
-
-#define CIO_MICR 0x00 /* Master interrupt control register */
-#define CIO_MCCR 0x01 /* Master configuration control register */
-#define CIO_CTMS1 0x1c /* Counter/timer mode specification #1 */
-#define CIO_CTMS2 0x1d /* Counter/timer mode specification #2 */
-#define CIO_CTMS3 0x1e /* Counter/timer mode specification #3 */
-#define CIO_IVR 0x04 /* Interrupt vector register */
-
-#define CIO_CSR1 0x0a /* Command and status register CTC #1 */
-#define CIO_CSR2 0x0b /* Command and status register CTC #2 */
-#define CIO_CSR3 0x0c /* Command and status register CTC #3 */
-
-#define CIO_CT1MSB 0x16 /* CTC #1 Timer constant - MSB */
-#define CIO_CT1LSB 0x17 /* CTC #1 Timer constant - LSB */
-#define CIO_CT2MSB 0x18 /* CTC #2 Timer constant - MSB */
-#define CIO_CT2LSB 0x19 /* CTC #2 Timer constant - LSB */
-#define CIO_CT3MSB 0x1a /* CTC #3 Timer constant - MSB */
-#define CIO_CT3LSB 0x1b /* CTC #3 Timer constant - LSB */
-#define CIO_PDCA 0x23 /* Port A data direction control */
-#define CIO_PDCB 0x2b /* Port B data direction control */
-
-#define CIO_GCB 0x04 /* CTC Gate command bit */
-#define CIO_TCB 0x02 /* CTC Trigger command bit */
-#define CIO_IE 0xc0 /* CTC Interrupt enable (set) */
-#define CIO_CIP 0x20 /* CTC Clear interrupt pending */
-#define CIO_IP 0x20 /* CTC Interrupt pending */
-
-
-/* 8580/85180/85280 Enhanced SCC register definitions */
-
-/* Write Register 7' (SDLC/HDLC Programmable Enhancements) */
-#define AUTOTXF 0x01 /* Auto Tx Flag */
-#define AUTOEOM 0x02 /* Auto EOM Latch Reset */
-#define AUTORTS 0x04 /* Auto RTS */
-#define TXDNRZI 0x08 /* TxD Pulled High in SDLC NRZI mode */
-#define FASTDTR 0x10 /* Fast DTR/REQ Mode */
-#define CRCCBCR 0x20 /* CRC Check Bytes Completely Received */
-#define EXTRDEN 0x40 /* Extended Read Enabled */
-
-/* Write Register 15 (external/status interrupt control) */
-#define SHDLCE 1 /* SDLC/HDLC Enhancements Enable */
-#define FIFOE 4 /* FIFO Enable */
-
-/* Read Register 6 (frame status FIFO) */
-#define BCLSB 0xff /* LSB of 14 bits count */
-
-/* Read Register 7 (frame status FIFO) */
-#define BCMSB 0x3f /* MSB of 14 bits count */
-#define FDA 0x40 /* FIFO Data Available Status */
-#define FOY 0x80 /* FIFO Overflow Status */
-
-#endif /* _SCC_H */
-
-/* global functions */
-
-#ifdef PREV_LINUX_1_3_33
-extern long scc_init(long kmem_start);
-#else
-extern int scc_init(void);
+int scc_init(void);
#endif
* SUCH DAMAGE.
*/
-#define SOUND_VERSION 350
-#define UNIX_SOUND_SYSTEM
+/*
+ * OSS interface version. With versions earlier than 3.6 this value is
+ * an integer with value less than 361. In versions 3.6 and later
+ * it's a six digit hexadecimal value. For example value
+ * of 0x030600 represents OSS version 3.6.0.
+ * Use ioctl(fd, OSS_GETVERSION, &int) to get the version number of
+ * the currently active driver.
+ */
+#define SOUND_VERSION 0x030700
+#define OPEN_SOUND_SYSTEM
+
+/* In Linux we need to be prepared for cross compiling */
#include <linux/ioctl.h>
/*
* IOCTL Commands for /dev/sequencer
*/
-#ifndef _IOWR
-/* @(#)ioctlp.h */
+#ifndef _SIOWR
+#if defined(_IOWR) && !defined(sun)
+/* Use already defined ioctl defines if they exist (except with Sun) */
+#define SIOCPARM_MASK IOCPARM_MASK
+#define SIOC_VOID IOC_VOID
+#define SIOC_OUT IOC_OUT
+#define SIOC_IN IOC_IN
+#define SIOC_INOUT IOC_INOUT
+#define _SIO _IO
+#define _SIOR _IOR
+#define _SIOW _IOW
+#define _SIOWR _IOWR
+#else
/* Ioctl's have the command encoded in the lower word,
* and the size of any in or out parameters in the upper
* to encode the in/out status of the parameter; for now
* we restrict parameters to at most 128 bytes.
*/
-/* #define IOCTYPE (0xff<<8) */
-#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */
-#define IOC_VOID 0x00000000 /* no parameters */
-#define IOC_OUT 0x20000000 /* copy out parameters */
-#define IOC_IN 0x40000000 /* copy in parameters */
-#define IOC_INOUT (IOC_IN|IOC_OUT)
+/* #define SIOCTYPE (0xff<<8) */
+#define SIOCPARM_MASK 0x1fff /* parameters must be < 8192 bytes */
+#define SIOC_VOID 0x00000000 /* no parameters */
+#define SIOC_OUT 0x20000000 /* copy out parameters */
+#define SIOC_IN 0x40000000 /* copy in parameters */
+#define SIOC_INOUT (SIOC_IN|SIOC_OUT)
/* the 0x20000000 is so we can distinguish new ioctl's from old */
-#define _IO(x,y) ((int)(IOC_VOID|(x<<8)|y))
-#define _IOR(x,y,t) ((int)(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
-#define _IOW(x,y,t) ((int)(IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
-/* this should be _IORW, but stdio got there first */
-#define _IOWR(x,y,t) ((int)(IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
-#endif /* !_IOWR */
-
-#define SNDCTL_SEQ_RESET _IO ('Q', 0)
-#define SNDCTL_SEQ_SYNC _IO ('Q', 1)
-#define SNDCTL_SYNTH_INFO _IOWR('Q', 2, struct synth_info)
-#define SNDCTL_SEQ_CTRLRATE _IOWR('Q', 3, int) /* Set/get timer resolution (HZ) */
-#define SNDCTL_SEQ_GETOUTCOUNT _IOR ('Q', 4, int)
-#define SNDCTL_SEQ_GETINCOUNT _IOR ('Q', 5, int)
-#define SNDCTL_SEQ_PERCMODE _IOW ('Q', 6, int)
-#define SNDCTL_FM_LOAD_INSTR _IOW ('Q', 7, struct sbi_instrument) /* Valid for FM only */
-#define SNDCTL_SEQ_TESTMIDI _IOW ('Q', 8, int)
-#define SNDCTL_SEQ_RESETSAMPLES _IOW ('Q', 9, int)
-#define SNDCTL_SEQ_NRSYNTHS _IOR ('Q',10, int)
-#define SNDCTL_SEQ_NRMIDIS _IOR ('Q',11, int)
-#define SNDCTL_MIDI_INFO _IOWR('Q',12, struct midi_info)
-#define SNDCTL_SEQ_THRESHOLD _IOW ('Q',13, int)
+#define _SIO(x,y) ((int)(SIOC_VOID|(x<<8)|y))
+#define _SIOR(x,y,t) ((int)(SIOC_OUT|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y))
+#define _SIOW(x,y,t) ((int)(SIOC_IN|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y))
+/* this should be _SIORW, but stdio got there first */
+#define _SIOWR(x,y,t) ((int)(SIOC_INOUT|((sizeof(t)&SIOCPARM_MASK)<<16)|(x<<8)|y))
+# endif /* _IOWR */
+#endif /* !_SIOWR */
+
+#define SNDCTL_SEQ_RESET _SIO ('Q', 0)
+#define SNDCTL_SEQ_SYNC _SIO ('Q', 1)
+#define SNDCTL_SYNTH_INFO _SIOWR('Q', 2, struct synth_info)
+#define SNDCTL_SEQ_CTRLRATE _SIOWR('Q', 3, int) /* Set/get timer resolution (HZ) */
+#define SNDCTL_SEQ_GETOUTCOUNT _SIOR ('Q', 4, int)
+#define SNDCTL_SEQ_GETINCOUNT _SIOR ('Q', 5, int)
+#define SNDCTL_SEQ_PERCMODE _SIOW ('Q', 6, int)
+#define SNDCTL_FM_LOAD_INSTR _SIOW ('Q', 7, struct sbi_instrument) /* Valid for FM only */
+#define SNDCTL_SEQ_TESTMIDI _SIOW ('Q', 8, int)
+#define SNDCTL_SEQ_RESETSAMPLES _SIOW ('Q', 9, int)
+#define SNDCTL_SEQ_NRSYNTHS _SIOR ('Q',10, int)
+#define SNDCTL_SEQ_NRMIDIS _SIOR ('Q',11, int)
+#define SNDCTL_MIDI_INFO _SIOWR('Q',12, struct midi_info)
+#define SNDCTL_SEQ_THRESHOLD _SIOW ('Q',13, int)
#define SNDCTL_SEQ_TRESHOLD SNDCTL_SEQ_THRESHOLD /* there was once a typo */
-#define SNDCTL_SYNTH_MEMAVL _IOWR('Q',14, int) /* in=dev#, out=memsize */
-#define SNDCTL_FM_4OP_ENABLE _IOW ('Q',15, int) /* in=dev# */
-#define SNDCTL_PMGR_ACCESS _IOWR('Q',16, struct patmgr_info)
-#define SNDCTL_SEQ_PANIC _IO ('Q',17)
-#define SNDCTL_SEQ_OUTOFBAND _IOW ('Q',18, struct seq_event_rec)
+#define SNDCTL_SYNTH_MEMAVL _SIOWR('Q',14, int) /* in=dev#, out=memsize */
+#define SNDCTL_FM_4OP_ENABLE _SIOW ('Q',15, int) /* in=dev# */
+#define SNDCTL_PMGR_ACCESS _SIOWR('Q',16, struct patmgr_info)
+#define SNDCTL_SEQ_PANIC _SIO ('Q',17)
+#define SNDCTL_SEQ_OUTOFBAND _SIOW ('Q',18, struct seq_event_rec)
+#define SNDCTL_SEQ_GETTIME _SIOR ('Q',19, int)
struct seq_event_rec {
unsigned char arr[8];
};
-#define SNDCTL_TMR_TIMEBASE _IOWR('T', 1, int)
-#define SNDCTL_TMR_START _IO ('T', 2)
-#define SNDCTL_TMR_STOP _IO ('T', 3)
-#define SNDCTL_TMR_CONTINUE _IO ('T', 4)
-#define SNDCTL_TMR_TEMPO _IOWR('T', 5, int)
-#define SNDCTL_TMR_SOURCE _IOWR('T', 6, int)
+#define SNDCTL_TMR_TIMEBASE _SIOWR('T', 1, int)
+#define SNDCTL_TMR_START _SIO ('T', 2)
+#define SNDCTL_TMR_STOP _SIO ('T', 3)
+#define SNDCTL_TMR_CONTINUE _SIO ('T', 4)
+#define SNDCTL_TMR_TEMPO _SIOWR('T', 5, int)
+#define SNDCTL_TMR_SOURCE _SIOWR('T', 6, int)
# define TMR_INTERNAL 0x00000001
# define TMR_EXTERNAL 0x00000002
# define TMR_MODE_MIDI 0x00000010
# define TMR_MODE_FSK 0x00000020
# define TMR_MODE_CLS 0x00000040
# define TMR_MODE_SMPTE 0x00000080
-#define SNDCTL_TMR_METRONOME _IOW ('T', 7, int)
-#define SNDCTL_TMR_SELECT _IOW ('T', 8, int)
+#define SNDCTL_TMR_METRONOME _SIOW ('T', 7, int)
+#define SNDCTL_TMR_SELECT _SIOW ('T', 8, int)
/*
- * Endian aware patch key generation algorithm.
+ * Some big endian/little endian handling macros
*/
-#if defined(_AIX) || defined(AIX)
+#if defined(_AIX) || defined(AIX) || defined(sparc) || defined(HPPA) || defined(PPC)
+/* Big endian machines */
# define _PATCHKEY(id) (0xfd00|id)
+# define AFMT_S16_NE AFMT_S16_BE
#else
# define _PATCHKEY(id) ((id<<8)|0xfd)
+# define AFMT_S16_NE AFMT_S16_LE
#endif
/*
#define PS_MGR_OK 2 /* Patch manager supported */
#define PS_MANAGED 3 /* Patch manager running */
-#define SNDCTL_PMGR_IFACE _IOWR('P', 1, struct patmgr_info)
+#define SNDCTL_PMGR_IFACE _SIOWR('P', 1, struct patmgr_info)
/*
* The patmgr_info is a fixed size structure which is used for two
unsigned char data[30];
} mpu_command_rec;
-#define SNDCTL_MIDI_PRETIME _IOWR('m', 0, int)
-#define SNDCTL_MIDI_MPUMODE _IOWR('m', 1, int)
-#define SNDCTL_MIDI_MPUCMD _IOWR('m', 2, mpu_command_rec)
+#define SNDCTL_MIDI_PRETIME _SIOWR('m', 0, int)
+#define SNDCTL_MIDI_MPUMODE _SIOWR('m', 1, int)
+#define SNDCTL_MIDI_MPUCMD _SIOWR('m', 2, mpu_command_rec)
/********************************************
* IOCTL commands for /dev/dsp and /dev/audio
*/
-#define SNDCTL_DSP_RESET _IO ('P', 0)
-#define SNDCTL_DSP_SYNC _IO ('P', 1)
-#define SNDCTL_DSP_SPEED _IOWR('P', 2, int)
-#define SNDCTL_DSP_STEREO _IOWR('P', 3, int)
-#define SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int)
+#define SNDCTL_DSP_RESET _SIO ('P', 0)
+#define SNDCTL_DSP_SYNC _SIO ('P', 1)
+#define SNDCTL_DSP_SPEED _SIOWR('P', 2, int)
+#define SNDCTL_DSP_STEREO _SIOWR('P', 3, int)
+#define SNDCTL_DSP_GETBLKSIZE _SIOWR('P', 4, int)
#define SNDCTL_DSP_SAMPLESIZE SNDCTL_DSP_SETFMT
-#define SNDCTL_DSP_CHANNELS _IOWR('P', 6, int)
+#define SNDCTL_DSP_CHANNELS _SIOWR('P', 6, int)
#define SOUND_PCM_WRITE_CHANNELS SNDCTL_DSP_CHANNELS
-#define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int)
-#define SNDCTL_DSP_POST _IO ('P', 8)
-#define SNDCTL_DSP_SUBDIVIDE _IOWR('P', 9, int)
-#define SNDCTL_DSP_SETFRAGMENT _IOWR('P',10, int)
+#define SOUND_PCM_WRITE_FILTER _SIOWR('P', 7, int)
+#define SNDCTL_DSP_POST _SIO ('P', 8)
+#define SNDCTL_DSP_SUBDIVIDE _SIOWR('P', 9, int)
+#define SNDCTL_DSP_SETFRAGMENT _SIOWR('P',10, int)
/* Audio data formats (Note! U8=8 and S16_LE=16 for compatibility) */
-#define SNDCTL_DSP_GETFMTS _IOR ('P',11, int) /* Returns a mask */
-#define SNDCTL_DSP_SETFMT _IOWR('P',5, int) /* Selects ONE fmt*/
+#define SNDCTL_DSP_GETFMTS _SIOR ('P',11, int) /* Returns a mask */
+#define SNDCTL_DSP_SETFMT _SIOWR('P',5, int) /* Selects ONE fmt*/
# define AFMT_QUERY 0x00000000 /* Return current fmt */
# define AFMT_MU_LAW 0x00000001
# define AFMT_A_LAW 0x00000002
/* Note! 'bytes' could be more than fragments*fragsize */
} audio_buf_info;
-#define SNDCTL_DSP_GETOSPACE _IOR ('P',12, audio_buf_info)
-#define SNDCTL_DSP_GETISPACE _IOR ('P',13, audio_buf_info)
-#define SNDCTL_DSP_NONBLOCK _IO ('P',14)
-#define SNDCTL_DSP_GETCAPS _IOR ('P',15, int)
+#define SNDCTL_DSP_GETOSPACE _SIOR ('P',12, audio_buf_info)
+#define SNDCTL_DSP_GETISPACE _SIOR ('P',13, audio_buf_info)
+#define SNDCTL_DSP_NONBLOCK _SIO ('P',14)
+#define SNDCTL_DSP_GETCAPS _SIOR ('P',15, int)
# define DSP_CAP_REVISION 0x000000ff /* Bits for revision level (0 to 255) */
# define DSP_CAP_DUPLEX 0x00000100 /* Full duplex record/playback */
# define DSP_CAP_REALTIME 0x00000200 /* Real time capability */
# define DSP_CAP_TRIGGER 0x00001000 /* Supports SETTRIGGER */
# define DSP_CAP_MMAP 0x00002000 /* Supports mmap() */
-#define SNDCTL_DSP_GETTRIGGER _IOR ('P',16, int)
-#define SNDCTL_DSP_SETTRIGGER _IOW ('P',16, int)
+#define SNDCTL_DSP_GETTRIGGER _SIOR ('P',16, int)
+#define SNDCTL_DSP_SETTRIGGER _SIOW ('P',16, int)
# define PCM_ENABLE_INPUT 0x00000001
# define PCM_ENABLE_OUTPUT 0x00000002
int ptr; /* Current DMA pointer value */
} count_info;
-#define SNDCTL_DSP_GETIPTR _IOR ('P',17, count_info)
-#define SNDCTL_DSP_GETOPTR _IOR ('P',18, count_info)
+#define SNDCTL_DSP_GETIPTR _SIOR ('P',17, count_info)
+#define SNDCTL_DSP_GETOPTR _SIOR ('P',18, count_info)
typedef struct buffmem_desc {
unsigned *buffer;
int size;
} buffmem_desc;
-#define SNDCTL_DSP_MAPINBUF _IOR ('P', 19, buffmem_desc)
-#define SNDCTL_DSP_MAPOUTBUF _IOR ('P', 20, buffmem_desc)
-#define SNDCTL_DSP_SETSYNCRO _IO ('P', 21)
-#define SNDCTL_DSP_SETDUPLEX _IO ('P', 22)
+#define SNDCTL_DSP_MAPINBUF _SIOR ('P', 19, buffmem_desc)
+#define SNDCTL_DSP_MAPOUTBUF _SIOR ('P', 20, buffmem_desc)
+#define SNDCTL_DSP_SETSYNCRO _SIO ('P', 21)
+#define SNDCTL_DSP_SETDUPLEX _SIO ('P', 22)
-#define SOUND_PCM_READ_RATE _IOR ('P', 2, int)
-#define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int)
-#define SOUND_PCM_READ_BITS _IOR ('P', 5, int)
-#define SOUND_PCM_READ_FILTER _IOR ('P', 7, int)
+#define SOUND_PCM_READ_RATE _SIOR ('P', 2, int)
+#define SOUND_PCM_READ_CHANNELS _SIOR ('P', 6, int)
+#define SOUND_PCM_READ_BITS _SIOR ('P', 5, int)
+#define SOUND_PCM_READ_FILTER _SIOR ('P', 7, int)
/* Some alias names */
#define SOUND_PCM_WRITE_BITS SNDCTL_DSP_SETFMT
unsigned char data[4000];
} copr_msg;
-#define SNDCTL_COPR_RESET _IO ('C', 0)
-#define SNDCTL_COPR_LOAD _IOWR('C', 1, copr_buffer)
-#define SNDCTL_COPR_RDATA _IOWR('C', 2, copr_debug_buf)
-#define SNDCTL_COPR_RCODE _IOWR('C', 3, copr_debug_buf)
-#define SNDCTL_COPR_WDATA _IOW ('C', 4, copr_debug_buf)
-#define SNDCTL_COPR_WCODE _IOW ('C', 5, copr_debug_buf)
-#define SNDCTL_COPR_RUN _IOWR('C', 6, copr_debug_buf)
-#define SNDCTL_COPR_HALT _IOWR('C', 7, copr_debug_buf)
-#define SNDCTL_COPR_SENDMSG _IOWR('C', 8, copr_msg)
-#define SNDCTL_COPR_RCVMSG _IOR ('C', 9, copr_msg)
+#define SNDCTL_COPR_RESET _SIO ('C', 0)
+#define SNDCTL_COPR_LOAD _SIOWR('C', 1, copr_buffer)
+#define SNDCTL_COPR_RDATA _SIOWR('C', 2, copr_debug_buf)
+#define SNDCTL_COPR_RCODE _SIOWR('C', 3, copr_debug_buf)
+#define SNDCTL_COPR_WDATA _SIOW ('C', 4, copr_debug_buf)
+#define SNDCTL_COPR_WCODE _SIOW ('C', 5, copr_debug_buf)
+#define SNDCTL_COPR_RUN _SIOWR('C', 6, copr_debug_buf)
+#define SNDCTL_COPR_HALT _SIOWR('C', 7, copr_debug_buf)
+#define SNDCTL_COPR_SENDMSG _SIOWR('C', 8, copr_msg)
+#define SNDCTL_COPR_RCVMSG _SIOR ('C', 9, copr_msg)
/*********************************************
* IOCTL commands for /dev/mixer
#define SOUND_ONOFF_MAX 30
/* Note! Number 31 cannot be used since the sign bit is reserved */
-
+#define SOUND_MIXER_NONE 31
/*
* The following unsupported macros are no longer functional.
* Use SOUND_MIXER_PRIVATE# macros in future.
*/
-#define SOUND_MIXER_ENHANCE 31
-#define SOUND_MIXER_MUTE 31
-#define SOUND_MIXER_LOUD 31
+#define SOUND_MIXER_ENHANCE SOUND_MIXER_NONE
+#define SOUND_MIXER_MUTE SOUND_MIXER_NONE
+#define SOUND_MIXER_LOUD SOUND_MIXER_NONE
#define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \
#define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE)
#define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD)
-#define MIXER_READ(dev) _IOR('M', dev, int)
+#define MIXER_READ(dev) _SIOR('M', dev, int)
#define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME)
#define SOUND_MIXER_READ_BASS MIXER_READ(SOUND_MIXER_BASS)
#define SOUND_MIXER_READ_TREBLE MIXER_READ(SOUND_MIXER_TREBLE)
#define SOUND_MIXER_READ_STEREODEVS MIXER_READ(SOUND_MIXER_STEREODEVS)
#define SOUND_MIXER_READ_CAPS MIXER_READ(SOUND_MIXER_CAPS)
-#define MIXER_WRITE(dev) _IOWR('M', dev, int)
+#define MIXER_WRITE(dev) _SIOWR('M', dev, int)
#define SOUND_MIXER_WRITE_VOLUME MIXER_WRITE(SOUND_MIXER_VOLUME)
#define SOUND_MIXER_WRITE_BASS MIXER_WRITE(SOUND_MIXER_BASS)
#define SOUND_MIXER_WRITE_TREBLE MIXER_WRITE(SOUND_MIXER_TREBLE)
{
char id[16];
char name[32];
+ int modify_counter;
+ int fillers[10];
} mixer_info;
-#define SOUND_MIXER_INFO _IOR ('M', 101, mixer_info)
+typedef struct _old_mixer_info /* Obsolete */
+{
+ char id[16];
+ char name[32];
+} _old_mixer_info;
+
+#define SOUND_MIXER_INFO _SIOR ('M', 101, mixer_info)
+#define SOUND_OLD_MIXER_INFO _SIOR ('M', 101, _old_mixer_info)
/*
* A mechanism for accessing "proprietary" mixer features. This method
*/
typedef unsigned char mixer_record[128];
-#define SOUND_MIXER_ACCESS _IOWR('M', 102, mixer_record)
+#define SOUND_MIXER_ACCESS _SIOWR('M', 102, mixer_record)
/*
* The SOUND_MIXER_PRIVATE# commands can be redefined by low level drivers.
* These features can be used when accessing device specific features.
*/
-#define SOUND_MIXER_PRIVATE1 _IOWR('M', 111, int)
-#define SOUND_MIXER_PRIVATE2 _IOWR('M', 112, int)
-#define SOUND_MIXER_PRIVATE3 _IOWR('M', 113, int)
-#define SOUND_MIXER_PRIVATE4 _IOWR('M', 114, int)
-#define SOUND_MIXER_PRIVATE5 _IOWR('M', 115, int)
+#define SOUND_MIXER_PRIVATE1 _SIOWR('M', 111, int)
+#define SOUND_MIXER_PRIVATE2 _SIOWR('M', 112, int)
+#define SOUND_MIXER_PRIVATE3 _SIOWR('M', 113, int)
+#define SOUND_MIXER_PRIVATE4 _SIOWR('M', 114, int)
+#define SOUND_MIXER_PRIVATE5 _SIOWR('M', 115, int)
+
+/*
+ * SOUND_MIXER_GETLEVELS and SOUND_MIXER_SETLEVELS calls can be used
+ * for querying current mixer settings from the driver and for loading
+ * default volume settings _prior_ activating the mixer (loading
+ * doesn't affect current state of the mixer hardware). These calls
+ * are for internal use only.
+ */
+
+typedef struct mixer_vol_table {
+ int num; /* Index to volume table */
+ char name[32];
+ int levels[32];
+} mixer_vol_table;
+
+#define SOUND_MIXER_GETLEVELS _SIOWR('M', 116, mixer_vol_table)
+#define SOUND_MIXER_SETLEVELS _SIOWR('M', 117, mixer_vol_table)
+
+/*
+ * An ioctl for identifying the driver version. It will return value
+ * of the SOUND_VERSION macro used when compiling the driver.
+ * This call was introduced in OSS version 3.6 and it will not work
+ * with earlier versions (returns EINVAL).
+ */
+#define OSS_GETVERSION _SIOR ('M', 118, int)
/*
* Level 2 event types for /dev/sequencer
/*
* Copyright (C) by Hannu Savolainen 1993-1996
*
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
+ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
#include <linux/kerneld.h>
#include <linux/interrupt.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
*/
#include <linux/errno.h>
-#include <asm/segment.h>
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/sem.h>
#include <linux/stat.h>
#include <linux/malloc.h>
+#include <asm/uaccess.h>
+
extern int ipcperms (struct ipc_perm *ipcp, short semflg);
static int newary (key_t, int, int);
static int findkey (key_t key);
#include <linux/malloc.h>
#include <linux/swap.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
extern int ipcperms (struct ipc_perm *ipcp, short shmflg);
#include <linux/config.h>
#include <linux/errno.h>
-#include <asm/segment.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/sem.h>
#include <linux/shm.h>
#include <linux/stat.h>
+#include <asm/uaccess.h>
+
#if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
extern void sem_init (void), msg_init (void), shm_init (void);
#include <linux/malloc.h>
#include <linux/interrupt.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
extern void sem_exit (void);
#include <linux/malloc.h>
#include <linux/smp.h>
-#include <asm/segment.h>
#include <asm/system.h>
#include <asm/pgtable.h>
+#include <asm/uaccess.h>
int nr_tasks=1;
int nr_running=1;
/* This implements the sysinfo() system call */
-#include <asm/segment.h>
-
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/unistd.h>
#include <linux/mm.h>
#include <linux/swap.h>
+#include <asm/uaccess.h>
+
asmlinkage int sys_sysinfo(struct sysinfo *info)
{
int error;
#include <linux/time.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
/*
* change timeval to jiffies, trying to avoid the
#include <linux/errno.h>
#include <linux/kernel.h>
-#include <asm/segment.h>
#include <linux/mm.h> /* defines GFP_KERNEL */
#include <linux/string.h>
#include <linux/module.h>
#include <linux/malloc.h>
#include <linux/vmalloc.h>
#include <linux/config.h>
+
+#include <asm/uaccess.h>
/*
* Originally by Anonymous (as far as I know...)
* Linux version by Bas Laarhoven <bas@vimec.nl>
}
/*
- * GCC 2.5.8 doesn't always optimize correctly; see include/asm/segment.h
+ * GCC 2.5.8 doesn't always optimize correctly; see include/asm/uaccess.h
*/
int bad_user_access_length(void)
#include <stdarg.h>
-#include <asm/segment.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
+#include <asm/uaccess.h>
+
#define LOG_BUF_LEN 8192
static char buf[1024];
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/mmu_context.h>
#include <linux/unistd.h>
#include <linux/mm.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#define _S(nr) (1<<((nr)-1))
#include <linux/apm_bios.h>
#endif
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
/*
asmlinkage int sys_uname(struct old_utsname * name)
{
int error = -EFAULT;;
- if (!name &&
- !copy_to_user(&name->sysname,&system_utsname.sysname,
- sizeof (system_utsname.sysname)) &&
- !copy_to_user(&name->nodename,&system_utsname.nodename,
- sizeof (system_utsname.nodename)) &&
- !copy_to_user(&name->release,&system_utsname.release,
- sizeof (system_utsname.release)) &&
- !copy_to_user(&name->version,&system_utsname.version,
- sizeof (system_utsname.version)) &&
- !copy_to_user(&name->machine,&system_utsname.machine,
- sizeof (system_utsname.machine))
- )
+ if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
error = 0;
return error;
}
#include <linux/malloc.h>
#include <linux/stat.h>
#include <linux/ctype.h>
-#include <asm/bitops.h>
-#include <asm/segment.h>
-
#include <linux/utsname.h>
#include <linux/swapctl.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
/* External variables not in a header file. */
extern int panic_timeout;
#include <linux/mm.h>
#include <linux/timex.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
/*
* The timezone where the local system is located. Used as a default by some
#include <linux/pagemap.h>
#include <linux/swap.h>
-#include <asm/segment.h>
#include <asm/system.h>
#include <asm/pgtable.h>
+#include <asm/uaccess.h>
/*
* Shared mappings implemented 30.11.1994. It's not fully working yet,
#include <linux/swap.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/string.h>
#include <linux/string.h>
#include <linux/malloc.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <linux/string.h>
#include <linux/malloc.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <linux/malloc.h>
#include <linux/swap.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/dma.h>
#include <asm/system.h> /* for cli()/sti() */
-#include <asm/segment.h> /* for copy_to/from_user */
+#include <asm/uaccess.h> /* for copy_to/from_user */
#include <asm/bitops.h>
#include <asm/pgtable.h>
#include <asm/dma.h>
#include <asm/system.h> /* for cli()/sti() */
-#include <asm/segment.h> /* for copy_to/from_user */
+#include <asm/uaccess.h> /* for copy_to/from_user */
#include <asm/bitops.h>
#include <asm/pgtable.h>
#include <asm/dma.h>
#include <asm/system.h> /* for cli()/sti() */
-#include <asm/segment.h> /* for copy_to/from_user */
+#include <asm/uaccess.h> /* for copy_to/from_user */
#include <asm/bitops.h>
#include <asm/pgtable.h>
#include <asm/dma.h>
#include <asm/system.h> /* for cli()/sti() */
-#include <asm/segment.h> /* for cop_to/from_user */
+#include <asm/uaccess.h> /* for cop_to/from_user */
#include <asm/bitops.h>
#include <asm/pgtable.h>
#include <asm/dma.h>
#include <asm/system.h> /* for cli()/sti() */
-#include <asm/segment.h> /* for copy_to/from_user */
+#include <asm/uaccess.h> /* for copy_to/from_user */
#include <asm/bitops.h>
#include <asm/pgtable.h>
#include <linux/malloc.h>
#include <linux/vmalloc.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
static struct vm_struct * vmlist = NULL;
#include <asm/dma.h>
#include <asm/system.h> /* for cli()/sti() */
-#include <asm/segment.h> /* for copy_to/from_user */
+#include <asm/uaccess.h> /* for copy_to/from_user */
#include <asm/bitops.h>
#include <asm/pgtable.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
* Inside Appletalk (2nd Ed).
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <linux/types.h>
#include <linux/config.h>
#include <linux/module.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <linux/types.h>
if(optval==NULL)
return(-EINVAL);
- err=verify_area(VERIFY_READ,optval,sizeof(int));
- if(err)
+ err = get_user(opt, (int *)optval);
+ if (err)
return err;
- opt=get_fs_long((unsigned long *)optval);
switch(level)
{
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <net/sock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/termios.h> /* For TIOCINQ/OUTQ */
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/ip.h> /* For ip_rcv */
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <net/sock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <net/br.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
*
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <linux/config.h>
extern int lance_init(void);
extern int ni65_init(void);
extern int pi_init(void);
+extern int scc_init(void);
extern void sdla_setup(void);
extern void dlci_setup(void);
#if defined(CONFIG_PI)
pi_init();
#endif
+#if defined(CONFIG_SCC)
+ scc_init();
+#endif
#if defined(CONFIG_PT)
pt_init();
#endif
* 2 of the License, or (at your option) any later version.
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/net.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
extern inline int min(int x, int y)
#include <net/udp.h>
#include <net/sock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
/*
#include <linux/mm.h>
#include <linux/interrupt.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/inet.h>
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/inet.h>
#endif
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <stdarg.h>
#include <linux/config.h> /* For CONFIG_IP_CLASSLESS */
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <net/checksum.h>
#define min(a,b) ((a)<(b)?(a):(b))
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
{
NETDEBUG(printk("Invalid fragment list: Fragment over size.\n"));
ip_free(qp);
- frag_kfree_skb(skb,FREE_WRITE);
+ kfree_skb(skb,FREE_WRITE);
ip_statistics.IpReasmFails++;
return NULL;
}
return NULL;
}
}
+
+ /*
+ * Attempt to construct an oversize packet.
+ */
+
+ if(ntohs(iph->tot_len)+(int)offset>65535)
+ {
+ skb->sk = NULL;
+ frag_kfree_skb(skb, FREE_READ);
+ ip_statistics.IpReasmFails++;
+ return NULL;
+ }
/*
* Determine the position of this fragment.
*/
#include <linux/config.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
static struct ip_fw **chains[] =
{&ip_fw_fwd_chain, &ip_fw_in_chain, &ip_fw_out_chain, &ip_acct_chain};
+#endif /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */
+#ifdef CONFIG_IP_FIREWALL
int ip_fw_fwd_policy=IP_FW_F_ACCEPT;
int ip_fw_in_policy=IP_FW_F_ACCEPT;
int ip_fw_out_policy=IP_FW_F_ACCEPT;
* 2 of the License, or (at your option) any later version.
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
* output firewall rules)
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mroute.h>
#include <net/route.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#ifdef CONFIG_IP_MULTICAST
#include <linux/config.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
/*
* We really ought to have a single public _inline_ min function!
* 2 of the License, or (at your option) any later version.
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/config.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <stdarg.h>
#include <linux/inet.h>
#include <linux/etherdevice.h>
#include <linux/config.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/errno.h>
*/
#include <linux/config.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <linux/types.h>
#include <net/icmp.h>
#include <net/tcp.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
unsigned long seq_offset;
struct tcp_mib tcp_statistics;
*/
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/fcntl.h>
* 2 of the License, or (at your option) any later version.
*/
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/inet.h>
#include <linux/route.h>
#include <net/sock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
static int
ipxitf_ioctl_real(unsigned int cmd, void *arg)
{
- int err;
switch(cmd)
{
- case SIOCSIFADDR:
- {
+ case SIOCSIFADDR: {
struct ifreq ifr;
struct sockaddr_ipx *sipx;
ipx_interface_definition f;
- err=verify_area(VERIFY_READ,arg,sizeof(ifr));
- if(err)
- return err;
- copy_from_user(&ifr,arg,sizeof(ifr));
+
+ if (copy_from_user(&ifr,arg,sizeof(ifr)))
+ return -EFAULT;
sipx=(struct sockaddr_ipx *)&ifr.ifr_addr;
if(sipx->sipx_family!=AF_IPX)
return -EINVAL;
else
return ipxitf_create(&f);
}
- case SIOCGIFADDR:
- {
+ case SIOCGIFADDR: {
struct ifreq ifr;
struct sockaddr_ipx *sipx;
ipx_interface *ipxif;
struct device *dev;
- err=verify_area(VERIFY_WRITE,arg,sizeof(ifr));
- if(err)
- return err;
- copy_from_user(&ifr,arg,sizeof(ifr));
+
+ if (copy_from_user(&ifr,arg,sizeof(ifr)))
+ return -EFAULT;
sipx=(struct sockaddr_ipx *)&ifr.ifr_addr;
dev=dev_get(ifr.ifr_name);
if(!dev)
sipx->sipx_family=AF_IPX;
sipx->sipx_network=ipxif->if_netnum;
memcpy(sipx->sipx_node, ipxif->if_node, sizeof(sipx->sipx_node));
- copy_to_user(arg,&ifr,sizeof(ifr));
+ if (copy_to_user(arg,&ifr,sizeof(ifr)))
+ return -EFAULT;
return 0;
}
- case SIOCAIPXITFCRT:
- err=verify_area(VERIFY_READ,arg,sizeof(char));
- if(err)
+ case SIOCAIPXITFCRT: {
+ int err, val;
+ err = get_user(val, (unsigned char *) arg);
+ if (err)
return err;
- return ipxcfg_set_auto_create(get_fs_byte(arg));
- case SIOCAIPXPRISLT:
- err=verify_area(VERIFY_READ,arg,sizeof(char));
- if(err)
+ return ipxcfg_set_auto_create(val);
+ }
+ case SIOCAIPXPRISLT: {
+ int err, val;
+ err = get_user(val, (unsigned char *) arg);
+ if (err)
return err;
- return ipxcfg_set_auto_select(get_fs_byte(arg));
+ return ipxcfg_set_auto_select(val);
+ }
default:
return -EINVAL;
}
sk=(ipx_socket *)sock->data;
- if(optval==NULL)
+ if (optval==NULL)
return(-EINVAL);
- err=verify_area(VERIFY_READ,optval,sizeof(int));
- if(err)
+ err = get_user(opt, (unsigned int *)optval);
+ if (err)
return err;
- opt=get_fs_long((unsigned long *)optval);
switch(level)
{
#include <net/netlink.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
static int (*netlink_handler[MAX_LINKS])(struct sk_buff *skb);
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <net/sock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/termios.h> /* For TIOCINQ/OUTQ */
#include <linux/if_ether.h> /* For the statistics structure. */
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/inet.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/ip.h> /* For ip_rcv */
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <net/sock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/termios.h> /* For TIOCINQ/OUTQ */
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <net/netlink.h>
#include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#if defined(CONFIG_MODULES) && defined(CONFIG_NET)
extern void export_net_symbols(void);
#include <linux/in.h>
#include <linux/fs.h>
#include <linux/malloc.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <net/sock.h>
#include <linux/in.h>
#include <linux/fs.h>
#include <linux/malloc.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <net/sock.h>
#
# Load config options from a file.
-# Converts all "# OPTION is not set" lines to "OPTION=" lines
+# Converts all "# OPTION is not set" lines to "OPTION=n" lines
#
function load_config_file () {
awk '
- /# .* is not set.*/ { printf("%s=\n", $2) }
+ /# .* is not set.*/ { printf("%s=n\n", $2) }
! /# .* is not set.*/ { print }
' $1 >.tmpconfig
Please enter a hexadecimal value. \
Use the <TAB> key to move from the input field to the buttons below it."
-backtitle="Linux Kernel Configuration"
-
DIALOG="./scripts/lxdialog/lxdialog"
kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}"
+backtitle="Linux Kernel v$kernel_version Configuration"
+
trap "cleanup ; rm -f .menuconfig ; exit 1" 1 2 15
echo "#"
echo "# Using defaults found in" $DEFAULTS
echo "#"
- . $DEFAULTS
+ load_config_file $DEFAULTS
else
echo "#"
echo "# No defaults found"