From 2e59abdfb0c73ae04a9af8498935e37d064ab534 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:17:33 -0500 Subject: [PATCH] Linux 2.1.132pre1 There's a new pre-patch out there. I'm back from Finland, and have caught up with just about half the email that I got during the stay. However, even the part I caught up with I may have partly missed something in, because (for obvious reasons) I didn't read them as carefully (*) as I usually do. This should fix at least part of the NFS problems people have reported: there was code to completely incorrectly invalidate quite valid write requests under some circumstances. The pre-patch also contains the first batch of patches merged in from Alan, and the "rmdir" problems should be fixed (mostly thanks to Al Viro). This pre-patch also gets rid of some imho completely unnecessary complexity in some of the VM memory freeing routines. There have been patches floating around that added more heuristics on when to do something, and this tries to get the same result by just removing old heuristics that didn't make much sense. Linus (*) Even my usual "careful" is not very careful by other peoples standards. So when _I_ say that I wasn't very careful, you should just assume that I was reading my email about as carefully as a hyper-active hedgehog on some serious uppers. Can you say "ignored email" three times quickly while chewing on an apple? --- Documentation/Changes | 260 +- Documentation/devices.txt | 12 +- Documentation/sound/AD1816 | 118 + .../sound}/ChangeLog.awe | 24 + Documentation/sound/ChangeLog.multisound | 13 + Documentation/sound/ESS1868 | 2 +- Documentation/sound/INSTALL.awe | 137 + Documentation/sound/Introduction | 253 ++ Documentation/sound/MultiSound | 128 +- Documentation/sound/README.awe | 219 ++ Documentation/video4linux/bttv/CARDS | 13 +- arch/i386/kernel/entry.S | 3 +- arch/i386/kernel/process.c | 18 +- arch/i386/kernel/sys_i386.c | 98 +- drivers/block/nbd.c | 14 +- drivers/char/Config.in | 13 +- drivers/char/Makefile | 8 + drivers/char/bttv.c | 57 +- drivers/char/busmouse.c | 4 + drivers/char/c-qcam.c | 202 +- drivers/char/c-qcam.h | 18 - drivers/char/isicom.c | 1951 +++++++++++++ drivers/char/joystick/Config.in | 6 +- drivers/char/macmouse.c | 312 -- drivers/char/mem.c | 1 + drivers/char/msbusmouse.c | 4 + drivers/char/pc_keyb.c | 2 +- drivers/fc4/fc.c | 2 +- drivers/fc4/fcp_scsi.h | 2 +- drivers/fc4/soc.c | 4 +- drivers/net/3c503.c | 1 - drivers/net/e2100.c | 1 - drivers/net/es3210.c | 1 - drivers/net/hp-plus.c | 1 - drivers/net/hp.c | 1 - drivers/net/lne390.c | 1 - drivers/net/ltpc.c | 18 +- drivers/net/ne.c | 841 +++--- drivers/net/ne2.c | 3 - drivers/net/ne3210.c | 1 - drivers/net/smc-mca.c | 1 - drivers/net/smc-ultra.c | 1 - drivers/net/smc-ultra32.c | 1 - drivers/net/z85230.c | 6 +- drivers/pci/pcisyms.c | 8 + drivers/pci/quirks.c | 28 +- drivers/scsi/hosts.c | 3 + drivers/scsi/hosts.h | 3 + drivers/scsi/imm.c | 4 +- drivers/scsi/ppa.c | 4 +- drivers/scsi/ppa.h | 6 +- drivers/scsi/scsi.c | 8 +- drivers/scsi/scsi_error.c | 1 - drivers/scsi/scsi_obsolete.c | 19 +- drivers/sound/Config.in | 26 +- drivers/sound/Makefile | 7 +- drivers/sound/ad1816.c | 1400 +++++++++ drivers/sound/ad1848.c | 19 +- drivers/sound/audio.c | 7 +- drivers/sound/cs4232.c | 42 +- drivers/sound/dev_table.h | 11 +- drivers/sound/dmabuf.c | 27 +- drivers/sound/es1370.c | 2 - drivers/sound/es1371.c | 22 +- drivers/sound/gus_wave.c | 1 - drivers/sound/legacy.h | 1 + drivers/sound/lowlevel/README.awe | 205 -- drivers/sound/lowlevel/awe_compat-fbsd.h | 173 ++ drivers/sound/lowlevel/awe_compat-linux.h | 248 ++ drivers/sound/lowlevel/awe_compat.h | 219 +- drivers/sound/lowlevel/awe_config.h | 115 +- drivers/sound/lowlevel/awe_hw.h | 21 +- drivers/sound/lowlevel/awe_version.h | 34 +- drivers/sound/lowlevel/awe_voice.h | 490 ---- drivers/sound/lowlevel/awe_wave.c | 2544 ++++++++++++++--- drivers/sound/midibuf.c | 14 +- drivers/sound/msnd.h | 4 +- drivers/sound/msnd_pinnacle.c | 214 +- drivers/sound/opl3sa2.c | 14 +- drivers/sound/pss.c | 4 +- drivers/sound/sb_audio.c | 19 +- drivers/sound/sb_common.c | 6 +- drivers/sound/sequencer.c | 2 +- drivers/sound/sound_calls.h | 32 +- drivers/sound/soundcard.c | 3 + drivers/sound/vidc.c | 72 +- drivers/sound/vidc.h | 20 +- drivers/sound/vidc_audio.c | 101 +- drivers/sound/vidc_fill.S | 79 +- drivers/sound/vidc_mixer.c | 6 +- drivers/sound/vidc_synth.c | 54 +- fs/ChangeLog | 64 + fs/affs/inode.c | 5 +- fs/affs/namei.c | 13 +- fs/ext2/namei.c | 14 - fs/hfs/dir.c | 3 - fs/minix/namei.c | 13 - fs/msdos/namei.c | 5 - fs/namei.c | 126 +- fs/nfs/dir.c | 3 + fs/nfs/inode.c | 57 +- fs/nfsd/vfs.c | 48 +- fs/qnx4/namei.c | 26 +- fs/smbfs/dir.c | 4 - fs/sysv/namei.c | 15 +- fs/ufs/namei.c | 32 +- fs/umsdos/namei.c | 8 - fs/vfat/namei.c | 6 - include/asm-alpha/dma.h | 8 + include/asm-alpha/termios.h | 2 + include/asm-arm/termios.h | 2 + include/asm-i386/dma.h | 8 + include/asm-i386/termios.h | 2 + include/asm-m68k/termios.h | 2 + include/asm-mips/termios.h | 2 + include/asm-ppc/termios.h | 2 + include/asm-sparc/termios.h | 2 + include/asm-sparc64/termios.h | 2 + include/linux/awe_voice.h | 42 +- include/linux/fs.h | 1 + include/linux/if_arp.h | 1 + include/linux/if_ether.h | 2 + include/linux/interrupt.h | 3 +- include/linux/isicom.h | 301 ++ include/linux/socket.h | 3 + include/linux/videodev.h | 6 +- kernel/ksyms.c | 1 + mm/filemap.c | 18 +- mm/vmscan.c | 32 +- net/802/tr.c | 2 + 130 files changed, 9010 insertions(+), 2994 deletions(-) create mode 100644 Documentation/sound/AD1816 rename {drivers/sound/lowlevel => Documentation/sound}/ChangeLog.awe (88%) create mode 100644 Documentation/sound/INSTALL.awe create mode 100644 Documentation/sound/Introduction create mode 100644 Documentation/sound/README.awe delete mode 100644 drivers/char/c-qcam.h create mode 100644 drivers/char/isicom.c delete mode 100644 drivers/char/macmouse.c create mode 100644 drivers/sound/ad1816.c delete mode 100644 drivers/sound/lowlevel/README.awe create mode 100644 drivers/sound/lowlevel/awe_compat-fbsd.h create mode 100644 drivers/sound/lowlevel/awe_compat-linux.h delete mode 100644 drivers/sound/lowlevel/awe_voice.h create mode 100644 include/linux/isicom.h diff --git a/Documentation/Changes b/Documentation/Changes index 32e528ea8fdf..2c6bff3bd8d7 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -33,7 +33,7 @@ http://cyberbuzz.gatech.edu/kaboom/linux/ as well. Also, don't forget http://www.linuxhq.com/ for all your Linux kernel needs. -Last updated: October 9, 1998 +Last updated: December 12, 1998 Current Author: Chris Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu). Current Minimal Requirements @@ -51,19 +51,18 @@ running, the suggested command should tell you. - Dynamic Linker (ld.so) 1.9.9 ; ldd --version or ldd -v - Linux C++ Library 2.7.2.8 ; ls -l /usr/lib/libg++.so.* - Procps 1.2.9 ; ps --version -- Procinfo 14 ; procinfo -v +- Procinfo 15 ; procinfo -v - Psmisc 17 ; pstree -V -- Mount 2.7l ; mount --version -- Net-tools 1.45 ; hostname -V +- Net-tools 1.49 ; hostname -V - Loadlin 1.6a - Sh-utils 1.16 ; basename --v -- Autofs 0.3.11 ; automount --version +- Autofs 3.1.1 ; automount --version - NFS 2.2beta37 ; showmount --version - Bash 1.14.7 ; bash -version - Ncpfs 2.2.0 ; ncpmount -v -- Pcmcia-cs 3.0.5 ; cardmgr -V +- Pcmcia-cs 3.0.6 ; cardmgr -V - PPP 2.3.5 ; pppd -v -- PCI Utilities 1.08 ; lspci --version +- Util-linux 2.9 ; chsh -v Upgrade notes ************* @@ -122,7 +121,7 @@ Libc (libc5) Linux-2.1.x is ELF-only. You can still compile a.out apps if you really want, but your kernel must be compiled ELF. If you can't currently compile ELF, consult the ELF howto at -http://sunsite.unc.edu/mdw/HOWTO/ELF-HOWTO.html and upgrade your system +http://metalab.unc.edu/mdw/HOWTO/ELF-HOWTO.html and upgrade your system accordingly. For modules to work, you need to be running libc-5.4.x or greater. @@ -143,8 +142,8 @@ unless you're running glibc2 / libc6. you're using NIS. If you upgrade to libc-5.4.46, please read and pay attention to its -accompanying release notes. The section about it breaking make is not -a joke. +accompanying release notes. The section about it breaking make is not a +joke. GNU libc (libc6) ================ @@ -225,9 +224,6 @@ presence. To turn on IP forwarding, issue the following command: echo 1 > /proc/sys/net/ipv4/ip_forward - To run bootpd, you'll need to issue the following command: echo 1 ->/proc/sys/net/ipv4/ip_boot_agent - Similar procedures are necessary to turn on other features. If something appears broken, check the /proc/sys/net/ipv4/ directory. "1" generally denotes enabled, while "0" generally denotes disabled. @@ -239,11 +235,11 @@ features like IPv6. As of 2.1.102, the IP firewalling code has been replaced; ipfwadm will no longer work. You need to obtain "ipchains," available from -http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html, and use -that instead of ipfwadm. +http://www.rustcorp.com/linux/ipchains/ , and use that instead of +ipfwadm. - To use port forwarding and auto forwarding you will need to obtain -"ipmasqadm," available from http://juanjox.home.ml.org/. + To use masq forwarding you will need to obtain "ipmasqadm," +available from http://juanjox.linuxhq.com/ Memory ====== @@ -252,16 +248,23 @@ Memory many memory utils, which have to be upgraded. Get the new procps-1.2 and you should be set. -Mount and network file systems -============================== +Network File System +=================== The NFS code in the kernel is currently being revised, resulting in -much-improved performance. As a result, you'll need to upgrade mount -to a recent 2.6 release. Also, amd is being phased out in favor of the -much better autofs. You'll also have to get the appropriate utils to -use autofs as well as the new NFS utils. In addition, you have the +much-improved performance. Also, amd is being phased out in favor of +the much better autofs. You'll also have to get the appropriate utils +to use autofs as well as the new NFS utils. In addition, you have the choice of user-land NFS or kernel-level NFS (knfs). +Util-linux (including mount) +============================ + + Among other changes in the 2.1.x development, the 128 meg limit on +IA32 swap partition sizes has been eliminated. To use larger swap +spaces, you need the new mkswap found in util-linux. You also need to +upgrade this to get the latest version of mount. + RPM === @@ -272,7 +275,7 @@ DOSEMU ====== A new "stable" version of DOSEMU is available for 2.1.x kernels. -Upgrade to 0.66.7 or later. +Upgrade to 0.98.4 or later. Loadlin ======= @@ -295,7 +298,9 @@ driver. Be aware that with Plug-and-Play support turned on, your parallel port may no longer be where you expect it; for example, LPT1 (under DOS) was sometimes /dev/lp1 in Linux, but will probably be /dev/lp0 with the new Plug-and-Play driver. If printing breaks with -the new driver, try checking your lpd configuration. +the new driver, try checking your lpd configuration. A good source of +more information is the Documentation/parport.txt file included with +the kernel. Setserial ========= @@ -331,6 +336,11 @@ SMBfs To mount SMB (Samba / Windows) shares, you'll need to use the smbmount utility included with recent Samba releases. Documentation/filesystems/smbfs.txt has more information about this. +Note that smbmount must have been built against 2.1.x headers to work +with 2.1.x; if all else fails, recompile it and hope it works ;-). In +addition, Mike Warfield has a script and some information at +http://www.wittsend.com/mhw/smbmount.html that you will probably find +useful. Pcmcia-cs ========= @@ -361,6 +371,52 @@ Psmisc fuser, which comes with psmisc, reads /proc/*/fd/* to do its job. Upgrade psmisc if 2.1 changes to /proc broke the version you're using. +Tunelp +====== + + A new version of tunelp is available which will allow you to enable +"trustirq" mode, improving printing while using IRQ-driven lp ports. + +PCI utils +========= + + Linux PCI utils are available; these include lspci, which displays +the detailed information about your system's PCI devices which used to +be in /proc/pci, and setpci, which allws you to read and write +configuration registers on your PCI devices. + +Xosview +======= + + /proc interface changes require a recent xosview. + +RealPlayer +========== + + Current releases of Real Player 5.0 depend on a bug in the sound +sub-system which is no longer there. Consequently, they don't work. +Real is aware of the problem and should have an updated version of the +software available shortly. In the mean time, you can always try +backing up your copy of rvplayer, and then editing it by: + + dd if=/dev/zero of=rvplayer bs=1 count=1 seek=657586 conv=notrunc dd +if=/dev/zero of=rvplayer bs=1 count=1 seek=665986 conv=notrunc + + If you're lucky, you'll then have sound.... + +Quotas +====== + + If you are using large quotas, you should upgrade your quota utils; +newer versions count file sizes in blocks instead of bytes, providing +an upper limit of terabytes instead of 4 GB. + +Ping +==== + + Most distributed ping clients are buggy. Get an updated one from the +iputils package. + Where to get the files ********************** @@ -369,21 +425,21 @@ Binutils The 2.8.1.0.23 release: ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.1.0.23.bin.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.8.1.0.23.bin.tar.gz +ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.8.1.0.23.bin.tar.gz Installation notes: ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.1.0.23 -ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.23 - -The 2.9.1.0.12 release: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.12-glibc.x86.tar.gz -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.12-libc5.x86.tar.gz -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.12.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.12-glibc.x86.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.12-libc5.x86.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.12.tar.gz +ftp://metalab.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.23 + +The 2.9.1.0.15 release: +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.15-glibc.x86.tar.gz +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.15-libc5.x86.tar.gz +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.15.tar.gz +ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.15-glibc.x86.tar.gz +ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.15-libc5.x86.tar.gz +ftp://metalab.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.15.tar.gz Installation notes: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.9.1.0.12 -ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.9.1.0.12 +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.9.1.0.15 +ftp://metalab.unc.edu/pub/Linux/GCC/release.binutils-2.9.1.0.15 Gnu C ===== @@ -391,25 +447,25 @@ Gnu C The egcs-1.0.3 release: ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.3-glibc.x86.tar.bz2 ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.3-libc5.x86.tar.bz2 -ftp://sunsite.unc.edu/pub/Linux/GCC/egcs-1.0.3-glibc.x86.tar.bz2 -ftp://sunsite.unc.edu/pub/Linux/GCC/egcs-1.0.3-libc5.x86.tar.bz2 +ftp://metalab.unc.edu/pub/Linux/GCC/egcs-1.0.3-glibc.x86.tar.bz2 +ftp://metalab.unc.edu/pub/Linux/GCC/egcs-1.0.3-libc5.x86.tar.bz2 Installation notes: ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.egcs-1.0.3 -ftp://sunsite.unc.edu/pub/Linux/GCC/release.egcs-1.0.3 +ftp://metalab.unc.edu/pub/Linux/GCC/release.egcs-1.0.3 Gnu C 2.7.2.3 source: ftp://prep.ai.mit.edu/pub/gnu/gcc-2.7.2.3.tar.gz -ftp://sunsite.unc.edu/pub/gnu/gcc-2.7.2.3.tar.gz +ftp://metalab.unc.edu/pub/gnu/gcc-2.7.2.3.tar.gz Linux C Library =============== The (libc5) 5.4.46 release: ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.46.bin.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.46.bin.tar.gz +ftp://metalab.unc.edu/pub/Linux/GCC/libc-5.4.46.bin.tar.gz Installation notes for 5.4.46: ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.46 -ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.46 +ftp://metalab.unc.edu/pub/Linux/GCC/release.libc-5.4.46 The (libc6) GNU libc 2.0.7pre6 release: ftp://ftp.kernel.org/pub/software/libs/glibc/glibc-2.0.7pre6.tar.gz @@ -420,17 +476,17 @@ Linux C++ Library The 2.7.2.8 release: ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libg++-2.7.2.8.bin.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.2.8.bin.tar.gz +ftp://metalab.unc.edu/pub/Linux/GCC/libg++-2.7.2.8.bin.tar.gz Installation notes: ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libg++-2.7.2.8 -ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.2.8 +ftp://metalab.unc.edu/pub/Linux/GCC/release.libg++-2.7.2.8 Dynamic Linker ============== The 1.9.9 release: ftp://tsx-11.mit.edu/pub/linux/packages/GCC/ld.so-1.9.9.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/ld.so-1.9.9.tar.gz +ftp://metalab.unc.edu/pub/Linux/GCC/ld.so-1.9.9.tar.gz Modules utilities ================= @@ -443,20 +499,20 @@ Procps utilities The 1.2 release: ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.9.tar.gz -ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.9.tgz +ftp://metalab.unc.edu/pub/Linux/system/status/ps/procps-1.2.9.tgz Procinfo utilities ================== -The 14 release: -ftp://ftp.cistron.nl/pub/people/svm/procinfo-14.tar.gz +The 15 release: +ftp://ftp.cistron.nl/pub/people/svm/procinfo-15.tar.gz Psmisc utilities ================ The 17 release: ftp://lrcftp.epfl.ch/pub/linux/local/psmisc/psmisc-17.tar.gz -ftp://sunsite.unc.edu/pub/Linux/system/status/ps/psmisc-17.tar.gz +ftp://metalab.unc.edu/pub/Linux/system/status/ps/psmisc-17.tar.gz RPM utilities ============= @@ -475,8 +531,8 @@ DOSEMU ====== The 0.98.1 release: -ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu-0.98.1.tgz -ftp://ftp.dosemu.org/dosemu/dosemu-0.98.1.tgz +ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu-0.98.4.tgz +ftp://ftp.dosemu.org/dosemu/dosemu-0.98.4.tgz Loadlin ======= @@ -489,14 +545,14 @@ Sh-utils ======== The 1.16 release: -ftp://sunsite.unc.edu/pub/gnu/sh-utils-1.16.tar.gz +ftp://metalab.unc.edu/pub/gnu/sh-utils-1.16.tar.gz ftp://prep.ai.mit.edu/pub/gnu/sh-utils-1.16.tar.gz -Mount -===== +Util-linux +========== -The 2.7l release: -ftp://ftp.win.tue.nl/pub/linux/util/mount/mount-2.7l.tar.gz +The 2.9 release: +ftp://ftp.win.tue.nl/pub/linux/util/util-linux-2.9.tar.gz Autofs ====== @@ -511,22 +567,22 @@ The user-land 2.2beta37 release: ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/nfs-server-2.2beta37.tar.gz ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/nfs-server-2.2beta37.tar.gz -The kernel-level 9/30/98 release: -ftp://ftp.yggdrasil.com/private/hjl/knfsd-980930.tar.gz -ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-980930.tar.gz +The kernel-level 12/04/98 release: +ftp://ftp.yggdrasil.com/private/hjl/knfsd-981204.tar.gz +ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-981204.tar.gz Net-tools ========= -The 1.45 release: -ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.45.tar.gz -http://www.tazenda.demon.co.uk/phil/net-tools/net-tools-1.45.tar.gz +The 1.49 release: +ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.49.tar.gz +http://www.tazenda.demon.co.uk/phil/net-tools/net-tools-1.49.tar.gz Ypbind ====== -The 3.2 release: -ftp://ftp.uni-paderborn.de/pub/linux/local/yp/ypbind-3.2.tar.gz +The 3.3 release: +ftp://ftp.uni-paderborn.de/pub/linux/local/yp/ypbind-3.3.tar.gz Bash ==== @@ -534,6 +590,9 @@ Bash The 1.14.7 release: ftp://prep.ai.mit.edu/pub/gnu/bash-1.14.7.tar.gz +The 2.02.1 release: +ftp://prep.ai.mit.edu/pub/gnu/bash-2.02.1.tar.gz + Ncpfs ===== @@ -544,20 +603,20 @@ SMBfs ===== The 1.9.18p10 release of Samba: -ftp://samba.anu.edu.au/pub/samba/samba-1.9.18p10.tar.gz +ftp://ftp.samba.org/pub/samba/samba-1.9.18p10.tar.gz Pcmcia-cs ========= -The 3.0.5 release: -ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.5.tar.gz +The 3.0.6 release: +ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.6.tar.gz Setserial ========= -The 2.14 release: -ftp://tsx-11.mit.edu/pub/linux/sources/sbin/setserial-2.14.tar.gz -ftp://sunsite.unc.edu/pub/Linux/system/serial/setserial-2.14.tar.gz +The 2.15 release: +ftp://tsx-11.mit.edu/pub/linux/sources/sbin/setserial-2.15.tar.gz +ftp://metalab.unc.edu/pub/Linux/system/serial/setserial-2.15.tar.gz PPP === @@ -568,21 +627,21 @@ ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.5.tar.gz IP Chains ========= -The 1.3.3 release: -http://www.adelaide.net.au/~rustcorp/ipfwchains/ipchains-source-1.3.3.tar.gz -http://www.adelaide.net.au/~rustcorp/ipfwchains/ipchains-source-1.3.3.tar.bz2 +The 1.3.8 release: +ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.8.tar.gz +ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.8.tar.bz2 IP Masq Adm =========== -The 0.4.1 release: -http://juanjox.home.ml.org/ipmasqadm-0.4.1.tar.gz +The 0.4.2 release: +http://juanjox.linuxhq.com/ipmasqadm-0.4.2.tar.gz iBCS ==== -The 8/30/98 release: -ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-2.1-980830-ALPHA.tar.gz +The 11/05/98 release: +ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-2.1-981105-ALPHA.tar.gz Asun netatalk ============= @@ -593,22 +652,47 @@ ftp://ftp.u.washington.edu/pub/user-supported/asun/netatalk-1.4b2+asun2.0a18.2.t Fbset ===== -The 7/13/98 release: -http://www.cs.kuleuven.ac.be/~geert/bin/fbset-2.0-pre-19980713.tar.gz +The 11/04/98 release: +http://www.cs.kuleuven.ac.be/~geert/bin/fbset-2.0-pre-19981104.tar.gz + +PCI utils +========= + +The 1.09 release: +ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-1.09.tar.gz +ftp://metalab.unc.edu/pub/Linux/hardware/pciutils-1.09.tar.gz + +Tunelp +====== + +The 0-2.1.131 release: +ftp://e-mind.com/pub/linux/tunelp/tunelp-0-2.1.131.tar.gz + +Xosview +======= + +The 1.6.1 release: +ftp://metalab.unc.edu/pub/Linux/system/status/xstatus/xosview-1.6.1.tar.gz + +Quota utils +=========== + +The 1.55 release: +ftp://ftp.uk.linux.org/pub/linux/sct/quota/quota-1.55-10.i386.rpm +ftp://ftp.uk.linux.org/pub/linux/sct/quota/quota-1.55-10.src.rpm -PCIutils +IP utils ======== -The 1.08 release: -ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-1.08.tar.gz -ftp://sunsite.unc.edu/pub/Linux/hardware/pciutils-1.08.tar.gz +The 11/01/98 release: +ftp://ftp.inr.ac.ru/pub/ip-routing/iputils-ss981101.tar.gz Other Info ========== Please remember that most of these utils are available on your favorite local linux mirror. If you can, please get them from a closer -site before checking sunsite. +site before checking metalab. You may also want to check for updated versions of this software in a package format for the distribution you use. @@ -616,9 +700,9 @@ package format for the distribution you use. For those of you running Red Hat (or RPM on a different distribution), most of these are available in RPM format. Check around your favorite Red Hat mirror site before installing the non-RPM -version. Remember, you might need to use the -force option to get the -upgrade to install. ftp://ftp.redhat.com/pub/contrib/ will have almost -everything you need, and Red Hat 5.1 ships with most necessary software. +version. Remember, you might need to use the --force option to get the +upgrade to install. ftp://contrib.redhat.com/ will have almost +everything you need, and Red Hat 5.2 ships with most necessary software. Those of you running Debian (or a different distribution that supports .deb packages) can look in the "unstable" and diff --git a/Documentation/devices.txt b/Documentation/devices.txt index d91a44323943..2d27f3644b95 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt @@ -98,10 +98,14 @@ Your cooperation is appreciated. demand. block Floppy disks - 0 = /dev/fd0 First floppy disk autodetect - 1 = /dev/fd1 Second floppy disk autodetect - 2 = /dev/fd2 Third floppy disk autodetect - 3 = /dev/fd3 Fourth floppy disk autodetect + 0 = /dev/fd0 Controller 1, drive 1 autodetect + 1 = /dev/fd1 Controller 1, drive 2 autodetect + 2 = /dev/fd2 Controller 1, drive 3 autodetect + 3 = /dev/fd3 Controller 1, drive 4 autodetect + 128 = /dev/fd4 Controller 2, drive 1 autodetect + 129 = /dev/fd5 Controller 2, drive 2 autodetect + 130 = /dev/fd6 Controller 2, drive 3 autodetect + 131 = /dev/fd7 Controller 2, drive 4 autodetect To specify format, add to the autodetect device number: 0 = /dev/fd? Autodetect format diff --git a/Documentation/sound/AD1816 b/Documentation/sound/AD1816 new file mode 100644 index 000000000000..aaadeaf46c6e --- /dev/null +++ b/Documentation/sound/AD1816 @@ -0,0 +1,118 @@ +Documentation for the AD1816(A) sound driver +============================================ + +NOTE: This driver is still EXPERIMENTAL, so don't use it on production +systems! + + +Installation: +------------- + +To get your AD1816(A) based sound card work, you'll have to enable +module support ("Enable loadable module support") and support for +experimental code ("Prompt for development and/or incomplete +code/drivers") during kernel configuration. Enable "Sound card +support", "OSS modules support" and "Support for AD1816(A) based cards +(EXPERIMENTAL)" in the sound configuration menu, too. Be sure, that +you build "Support for AD1816(A) based cards (EXPERIMENTAL)" as a MODULE, +otherwise you may run into problems later. +Now build, install and reboot the new kernel as usual. + +Since the AD1816(A) is a P'n'P sound chip you'll usually have to +configure it using the isapnptools. See isapnptools documentation for +details on configuring P'n'P cards. + +After you have successfully configured the card using isapnp, you may +load the AD1816 driver using modprobe. A typical modprobe call should +look like this: + + modprobe ad1816 io=0x530 irq=5 dma=1 dma2=3 ad1816_clockfreq=33000 + +if your isapnp.conf file looks like this (relevant lines only): + + (INT 0 (IRQ 5 (MODE +E))) + (DMA 0 (CHANNEL 1)) + (DMA 1 (CHANNEL 3)) + (IO 0 (BASE 0x0220)) + (IO 1 (BASE 0x0388)) + (IO 2 (BASE 0x0530)) + +NOTE: Be sure, that you use the address IO 2 (in our example 0x530) when +loading the module! + +If your setup was correct, you should see the following messages in +/var/log/messages (numbers may be different): + +Nov 6 17:07:26 tek01 kernel: ad1816_detect(530) +Nov 6 17:07:26 tek01 kernel: ad1816_detect() - Detected OK +Nov 6 17:07:26 tek01 kernel: AD1816 Version: 3 + + +Features: +--------- + +List of features supported by this driver: +- full-duplex support +- supported audio formats: unsigned 8bit, signed 16bit little endian, + signed 16bit big endian, ยต-law, A-law +- supported channels: mono and stereo +- supported recording sources: Master, CD, Line, Line1, Line2, Mic +- supports phat 3d stereo circuit (Line 3) + + +Supported cards: +---------------- + +The following cards are known to work with this driver: +- Terratec Base 1 +- Terratec Base 64 +- HP Kayak +- Acer FX-3D +- SY-1816 +- Highscreen Sound-Boostar 32 Wave 3D +- ... + + +Troubleshooting: +---------------- + +First of all you should check, if the driver has been loaded +properly. If you get the following message in your /var/log/messages: + +Nov 6 17:06:31 tek01 kernel: ad1816_detect(530) +Nov 6 17:06:31 tek01 kernel: Chip is not an AD1816 or chip is not active + +you either used the wrong address for loading the driver, your chip is +not an AD1816 or you forgot to initialize the card with isapnp. + +If loading of the driver succeeds, but playback/capture fails, check +if you used the correct values for irq, dma and dma2 when loading the module. +If one of them is wrong you usually get the following error message: + +Nov 6 17:06:13 tek01 kernel: Sound: DMA (output) timed out - IRQ/DRQ config error? + +If playback/capture is too fast or to slow, you should have a look at +the clock chip of your sound card. The AD1816 was designed for a 33MHz +oscillator, however most sound card manufacturer use slightly +different oscillators as they are cheaper than 33MHz oscillators. If +you have such a card you have to adjust the ad1816_clockfreq parameter +above. For example: For a card using a 32.875MHz oscillator use +ad1816_clockfreq=32875 instead of ad1816_clockfreq=33000. + + +Updates, bugfixes and bugreports: +-------------------------------- + +As the driver is still experimental and under development, you should +watch out for updates. Updates of the driver are available on the +internet from one of my home pages: + http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html +or: + http://www.tu-darmstadt.de/~tek01/projects/linux.html + +Bugreports, bugfixes and related questions should be sent via E-Mail to: + tek@rbg.informatik.tu-darmstadt.de + + +Thorsten Knabe + Last modified: 1998/11/06 diff --git a/drivers/sound/lowlevel/ChangeLog.awe b/Documentation/sound/ChangeLog.awe similarity index 88% rename from drivers/sound/lowlevel/ChangeLog.awe rename to Documentation/sound/ChangeLog.awe index 196da64d43d8..ad6fad06193e 100644 --- a/drivers/sound/lowlevel/ChangeLog.awe +++ b/Documentation/sound/ChangeLog.awe @@ -1,3 +1,27 @@ +ver.0.4.3p4 + - Bug fix for invalid memory detection when initialized twice + - Add sample sharing function - works together with awesfx-0.4.3p3 + - Add AWE_PROBE_DATA for probing sample id + +ver.0.4.3p3 + - Replace memset to MEMSET (for FreeBSD) + - Add PAN_EXCHANGE switch + +ver.0.4.3p2 + - MIDI emulation device is added + - Controls volume and filter targets + - Include chorus/reverb/equalizer values in MISC_MODE + +ver.0.4.3p1 + - Change the volume calculation method + - Support for Tom Lees' PnP driver (v0.3) + +ver.0.4.2d + - Support for OSS/Free 3.8 on 2.0 kernels. + - Support for Linux PnP driver + - Support for module (for recent 2.1 kernels and RH5.0) + - Support for FreeBSD-3.0 system + ver.0.4.2c - Add a mode to enable drum channel toggle via bank number change. diff --git a/Documentation/sound/ChangeLog.multisound b/Documentation/sound/ChangeLog.multisound index bd329565214e..a05a74365dd3 100644 --- a/Documentation/sound/ChangeLog.multisound +++ b/Documentation/sound/ChangeLog.multisound @@ -1,3 +1,16 @@ +1998-12-04 Andrew T. Veliath + + * Update version to 0.8.2.2 + + * Add msndreset program to shell archive. + +1998-11-11 Andrew T. Veliath + + * msnd_pinnacle.c (mixer_ioctl): Add a mixer ioctl for + SOUND_MIXER_PRIVATE1 which does a full reset on the card. + (mixer_set): Move line in recording source to input monitor, aux + input level added, some mixer fixes. + 1998-09-10 Andrew Veliath * Update version to 0.8.2 diff --git a/Documentation/sound/ESS1868 b/Documentation/sound/ESS1868 index d508349dcd10..8fb778925f95 100644 --- a/Documentation/sound/ESS1868 +++ b/Documentation/sound/ESS1868 @@ -40,7 +40,7 @@ the sound modules with the proper I/O information. Here is my setup: # ESS1868F AudioDrive initialization -/sbin/insmod sound +/sbin/modprobe sound /sbin/insmod uart401 /sbin/insmod sb io=0x220 irq=5 dma=1 dma16=-1 /sbin/insmod mpu401 io=0x330 diff --git a/Documentation/sound/INSTALL.awe b/Documentation/sound/INSTALL.awe new file mode 100644 index 000000000000..bffd115ddfa7 --- /dev/null +++ b/Documentation/sound/INSTALL.awe @@ -0,0 +1,137 @@ +================================================================ + INSTALLATION OF AWE32 SOUND DRIVER FOR LINUX + Takashi Iwai +================================================================ + +---------------------------------------------------------------- +* Attention to SB-PnP Card Users + +If you're using PnP cards, the initialization of PnP is required +before loading this driver. You have now three options: + 1. Use isapnptools. + 2. Install PnP kernel driver patch. + 3. Initialize PnP on DOS/Windows, then boot linux by loadlin. +In this document, only the case 1 case is treated. +For the case 2, please refer to the instruction in PnP driver project. +The home page of PnP driver project is the following URL: + http://www-jcr.lmh.ox.ac.uk/~pnp/ + +---------------------------------------------------------------- +* Installation on RedHat 5.0 Sound Driver + +Please use install-rh.sh under RedHat5.0 directory. +DO NOT USE install.sh below. +See INSTALL.RH for more details. + +---------------------------------------------------------------- +* Installation/Update by Shell Script + + 1. Become root + + % su + + 2. If you have never configured the kernel tree yet, run make config + once (to make depencies and symlinks). + + # cd /usr/src/linux + # make xconfig + + 3. Run install.sh script + + # sh ./install.sh + + 4. Configure your kenrel + + (for Linux 2.[01].x user) + # cd /usr/src/linux + # make xconfig (or make menuconfig) + + (for Linux 1.2.x user) + # cd /usr/src/linux + # make config + + Answer YES to both "lowlevel drivers" and "AWE32 wave synth" items + in Sound menu. ("lowlevel drivers" will appear only in 2.x + kernel.) + + 5. Make your kernel (and modules), and install them as usual. + + 5a. make kernel image + # make zImage + + 5b. make modules and install them + # make modules && make modules_install + + 5c. If you're using lilo, copy the kernel image and run lilo. + Otherwise, copy the kernel image to suitable directory or + media for your system. + + 6. Reboot the kernel if necessary. + - If you updated only the modules, you don't have to reboot + the system. Just remove the old sound modules here. + in + # rmmod sound.o (linux-2.0 or OSS/Free) + # rmmod awe_wave.o (linux-2.1) + + 7. If your AWE card is a PnP and not initialized yet, you'll have to + do it by isapnp tools. Otherwise, skip to 8. + + This section described only a brief explanation. For more + detaills, please see AWE64-Mini-HOWTO or isapnp tools FAQ. + + 7a. If you have no isapnp.conf file, generate it by pnpdump. + Otherwise, skip to 7d. + # pnpdump > /etc/isapnp.conf + + 7b. Edit isapnp.conf file. Comment out the appropriate + lines containing desirable I/O ports, DMA and IRQs. + Don't forget to enable (ACT Y) line. + + 7c. Add two i/o ports (0xA20 and 0xE20) in WaveTable part. + ex) + (CONFIGURE CTL0048/58128 (LD 2 + # ANSI string -->WaveTable<-- + (IO 0 (BASE 0x0620)) + (IO 1 (BASE 0x0A20)) + (IO 2 (BASE 0x0E20)) + (ACT Y) + )) + + 7d. Load the config file. + CAUTION: This will reset all PnP cards! + + # isapnp /etc/isapnp.conf + + 8. Load the sound module (if you configured it as a module): + + for 2.0 kernel or OSS/Free monolithic module: + + # modprobe sound.o + + for 2.1 kernel: + + # modprobe sound + # insmod uart401 + # insmod sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330 + (These values depend on your settings.) + # insmod awe_wave + (Be sure to load awe_wave after sb!) + + See /usr/src/linux/Documentation/sound/AWE32 for + more details. + + 9. (only for obsolete systems) If you don't have /dev/sequencer + device file, make it according to Readme.linux file on + /usr/src/linux/drivers/sound. (Run a shell script included in + that file). <-- This file no longer exists in the recent kernels! + + 10. OK, load your own soundfont file, and enjoy MIDI! + + % sfxload synthgm.sbk + % drvmidi foo.mid + + 11. For more advanced use (eg. dynamic loading, virtual bank and + etc.), please read the awedrv FAQ or the instructions in awesfx + and awemidi packages. + +Good luck! diff --git a/Documentation/sound/Introduction b/Documentation/sound/Introduction new file mode 100644 index 000000000000..362547df3f53 --- /dev/null +++ b/Documentation/sound/Introduction @@ -0,0 +1,253 @@ +Soundcore Notes on Modular Sound Drivers and Soundcore +Wade Hampton +11/20/1998 + +Purpose: +======== +This document provides some general notes on the modular +sound drivers and their configuration, along with the +support modules sound.o, soundlow.o and soundcore.o. + +Note, some of this probably should be added to the Sound-HOWTO! + +Copying: +======== +none + +History: +======== +0.1.0 11/20/1998 First version + + +Modular Sound Drivers: +====================== + +Thanks to the GREAT work by Alan Cox (alan@lxorguk.ukuu.org.uk), + +[And Oleg Drokin, Thomas Sailer, Andrew Veliath and more than a few + others - not to mention Hannu's original code being designed well + enough to cope with that kind of chopping up](Alan) + +the standard Linux kernels support a modular sound driver. From +Alan's comments in linux/drivers/sound/README.FIRST: + + The modular sound driver patches were funded by Red Hat Software + (www.redhat.com). The sound driver here is thus a modified version of + Hannu's code. Please bear that in mind when considering the appropriate + forums for bug reporting. + +The modular sound drivers may be loaded via insmod or modprobe. +To support all the various sound modules, there are three general +support modules that must be loaded first: + + soundcore.o: Top level handler for the sound system, provides + a set of functions for registration of devices + by type. + + soundlow.o: Low-level sound drivers which are not part of + OSS/Lite (Open Sound System), including SB32/AWE + synthesizer, etc. + + sound.o: Common sound functions required by all modules. + +For the specific sound modules (e.g., sb.o for the Soundblaster), +read the documentation on that module to determine what options +are available, for example IRQ, address, DMA. + +Warning, the options for different cards sometime use different names +for the same or a similar feature (dma1= versus dma16=). As a last +resort, inspect the code (search for MODULE_PARM). + + +INSMOD: +======= + +If loading via insmod, the common modules must be loaded in the +order below BEFORE loading the other sound modules. The card-specific +modules may then be loaded (most require parameters). For example, +I use the following via a shell script to load my SoundBlaster: + +SB_BASE=0x240 +SB_IRQ=9 +SB_DMA=3 +SB_DMA2=5 +SB_MPU=0x300 +# +echo Starting sound +/sbin/insmod soundcore +/sbin/insmod soundlow +/sbin/insmod sound +# +echo Starting sound blaster.... +/sbin/insmod uart401 +/sbin/insmod sb io=$SB_BASE irq=$SB_IRQ dma=$SB_DMA dma16=$SB_DMA2 mpu_io=$SB_MP + + +MODPROBE: +========= + +If loading via modprobe, these common files are automatically loaded +when requested by modprobe. For example, my /etc/conf.modules contains: + +alias sound sb +options sb io=0x240 irq=9 dma=3 dma16=5 mpu_io=0x300 + +All you need to do to load the module is: + + /sbin/modprobe sb + + +Sound Status: +============= + +The status of sound may be read/checked by: + cat /proc/sound + cat /dev/sndstat + cat (anyfile).au >/dev/audio + +The status of the modules and which modules depend on +which other modules may be checked by: + /sbin/lsmod + +/sbin/lsmod should show something like the following: + sb 26280 0 + uart401 5640 0 [sb] + sound 57112 0 [sb uart401] + soundlow 208 0 [sound] + soundcore 1968 8 [sb sound] + + +Removing Sound: +=============== + +Sound may be removed by using /sbin/rmmod in the reverse order +in which you load the modules. Note, if a program has a sound device +open (e.g., xmixer), that module (and the modules on which it +depends) may not be unloaded. + +For example, I use the following to remove my Soundblaster (rmmod +in the reverse order in which I loaded the modules): + +/sbin/rmmod sb +/sbin/rmmod uart401 +/sbin/rmmod sound +/sbin/rmmod soundlow +/sbin/rmmod soundcore + + +Multiple Sound Cards: +===================== + +The sound drivers will support multiple sound cards and there +are some great applications like multitrack that support them. +Typically, you need two sound cards of different types. Note, this +uses more precious interrupts and DMA channels and sometimes +can be a configuration nightmare. I have heard reports of 3-4 +sound cards (typically I only use 2). + +On my machine I have two sound cards (cs4232 and Soundblaster Vibra +16). By loading sound as modules, I can control which is the first +sound device (/dev/dsp, /dev/audio, /dev/mixer) and which is +the second. Normally, the cs4232 (Dell sound on the motherboard) +would be the first sound device, but I prefer the Soundblaster. +All you have to do is to load the one you want as /dev/dsp +first (in my case "sb") and then load the other one +(in my case "cs4232"). + +Warning: I have never been able to get two PnP sound cards of the +same type to load at the same time. I have tried this several times +with the Soundblaster Vibra 16 cards. OSS has indicated that this +is a PnP problem.... If anyone has any luck doing this, please +send me an E-MAIL. PCI sound cards should not have this problem. + + +Sound Problems: +=============== + +First RTFM (including the troubleshooting section +in the Sound-HOWTO). + +1) If you are having problems loading the modules (for + example, if you get device conflict errors) try the + following: + + A) If you have Win95 or NT on the same computer, + write down what addresses, IRQ, and DMA channels + those were using for the same hardware. You probably + can use these addresses, IRQs, and DMA channels. + + B) Check (cat) /proc/interrupts, /proc/ioports, + and /proc/dma. Are you trying to use an address, + IRQ or DMA port that another device is using? + + C) Check (cat) /proc/sys/pnp (if this exists, you + may need a kernel patch to get this device). + + D) Inspect your /var/log/messages file. Often that will + indicate what IRQ or IO port could not be obtained + + E) Try another port or IRQ. Note this may involve + using the PnP tools to move the sound card to + another location. + +2) If you get motorboating (the same sound or part of a + sound clip repeated), you probably have either an IRQ + or DMA conflict. Move the card to another address. This + has happened to me when playing long files when I had + an IRQ conflict. + +3) Ask for help on the sound list or send E-MAIL to the + sound driver author/maintainer. + +4) Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB). + + +Configuring Sound: +================== + +There are several ways of configuring your sound: + +1) Hardcoded in the kernel at compile time (not applicable when + using sound modules). This was the OLD way! + +2) On the command line when using insmod. + +3) In /etc/conf.modules when using modprobe. + +4) Via RedHat's /usr/sbin/sndconfig program (text based). + +5) Via the OSS soundconf program (with the commercial version + of the OSS driver. + +And I am sure, several other ways. + +Anyone want to write a linuxconf module for configuring sound? + + + +For More Information (RTFM): +============================ +1) Information on kernel modules: linux/Documentation/modules.txt + and manual pages for insmod and modprobe. + +2) Information on PnP, RTFM manual pages for isapnp. + +3) Sound-HOWTO and Sound-Playing-HOWTO. + +4) OSS's WWW site at http://www.opensound.com. + +5) All the files in linux/Documentation/sound. + +6) The comments and code in linux/drivers/sound. + +7) The sndconfig and rhsound documentation from RedHat. + +8) The Linux-sound mailing list: sound-list@redhat.com + + + +Contact Information: +==================== +Wade Hampton: (whampton@staffnet.com) + + diff --git a/Documentation/sound/MultiSound b/Documentation/sound/MultiSound index 20284de9fa51..e8ae21aaf724 100644 --- a/Documentation/sound/MultiSound +++ b/Documentation/sound/MultiSound @@ -157,13 +157,13 @@ # # * MultiSound Classic/Monterey/Tahiti: # -# insmod soundcore +# modprobe soundcore # insmod msnd # insmod msnd_classic io=0x290 irq=7 mem=0xd0000 # # * MultiSound Pinnacle in PnP mode: # -# insmod soundcore +# modprobe soundcore # insmod msnd # isapnp mypinnacle.conf # insmod msnd_pinnacle io=0x210 irq=5 mem=0xd8000 <-- match mypinnacle.conf values @@ -359,8 +359,8 @@ # attempting to record at a sampling rate other than the DAT rate may # be problematic (i.e. trying to record at 8000Hz when the DAT signal # is 44100Hz). If you have a problem with this, set the recording -# input to the line in if you need to record at a rate other than -# that of the DAT rate. +# input to analog if you need to record at a rate other than that of +# the DAT rate. # # # -- Shell archive attached below, just run `sh MultiSound' to extract. @@ -373,7 +373,7 @@ # To extract the files from this archive, save it to some FILE, remove # everything before the `!/bin/sh' line above, then type `sh FILE'. # -# Made on 1998-09-05 08:26 EDT by . +# Made on 1998-12-04 10:07 EST by . # Source directory was `/home/andrewtv/programming/pinnacle/pinnacle'. # # Existing files will *not* be overwritten unless `-c' is specified. @@ -381,10 +381,11 @@ # This shar contains: # length mode name # ------ ---------- ------------------------------------------ -# 2111 -rw-rw-r-- MultiSound.d/setdigital.c -# 10301 -rw-rw-r-- MultiSound.d/pinnaclecfg.c -# 96 -rw-rw-r-- MultiSound.d/Makefile +# 2046 -rw-rw-r-- MultiSound.d/setdigital.c +# 10235 -rw-rw-r-- MultiSound.d/pinnaclecfg.c +# 106 -rw-rw-r-- MultiSound.d/Makefile # 141 -rw-rw-r-- MultiSound.d/conv.l +# 1472 -rw-rw-r-- MultiSound.d/msndreset.c # save_IFS="${IFS}" IFS="${IFS}:" @@ -431,7 +432,7 @@ else fi rm -f 1231235999 $$.touch # -if mkdir _sh21233; then +if mkdir _sh01426; then $echo 'x -' 'creating lock directory' else $echo 'failed to create lock directory' @@ -467,8 +468,6 @@ X * You should have received a copy of the GNU General Public License X * along with this program; if not, write to the Free Software X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. X * -X * $Id: setdigital.c,v 1.1 1998/08/29 03:32:33 andrewtv Exp $ -X * X ********************************************************************/ X #include @@ -528,19 +527,19 @@ X X return 0; } SHAR_EOF - $shar_touch -am 0828233298 'MultiSound.d/setdigital.c' && + $shar_touch -am 1204092598 'MultiSound.d/setdigital.c' && chmod 0664 'MultiSound.d/setdigital.c' || $echo 'restore of' 'MultiSound.d/setdigital.c' 'failed' if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then md5sum -c << SHAR_EOF >/dev/null 2>&1 \ || $echo 'MultiSound.d/setdigital.c:' 'MD5 check failed' -47720746d4367bae9954787c311c56fd MultiSound.d/setdigital.c +e87217fc3e71288102ba41fd81f71ec4 MultiSound.d/setdigital.c SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/setdigital.c'`" - test 2111 -eq "$shar_count" || - $echo 'MultiSound.d/setdigital.c:' 'original size' '2111,' 'current size' "$shar_count!" + test 2046 -eq "$shar_count" || + $echo 'MultiSound.d/setdigital.c:' 'original size' '2046,' 'current size' "$shar_count!" fi fi # ============= MultiSound.d/pinnaclecfg.c ============== @@ -575,8 +574,6 @@ X * You should have received a copy of the GNU General Public License X * along with this program; if not, write to the Free Software X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. X * -X * $Id: pinnaclecfg.c,v 1.3 1998/08/29 03:32:32 andrewtv Exp $ -X * X ********************************************************************/ X #include @@ -984,19 +981,19 @@ X X return 0; } SHAR_EOF - $shar_touch -am 0905082598 'MultiSound.d/pinnaclecfg.c' && + $shar_touch -am 1204092598 'MultiSound.d/pinnaclecfg.c' && chmod 0664 'MultiSound.d/pinnaclecfg.c' || $echo 'restore of' 'MultiSound.d/pinnaclecfg.c' 'failed' if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then md5sum -c << SHAR_EOF >/dev/null 2>&1 \ || $echo 'MultiSound.d/pinnaclecfg.c:' 'MD5 check failed' -71f99b834a2845daae8ae034623e313e MultiSound.d/pinnaclecfg.c +366bdf27f0db767a3c7921d0a6db20fe MultiSound.d/pinnaclecfg.c SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/pinnaclecfg.c'`" - test 10301 -eq "$shar_count" || - $echo 'MultiSound.d/pinnaclecfg.c:' 'original size' '10301,' 'current size' "$shar_count!" + test 10235 -eq "$shar_count" || + $echo 'MultiSound.d/pinnaclecfg.c:' 'original size' '10235,' 'current size' "$shar_count!" fi fi # ============= MultiSound.d/Makefile ============== @@ -1007,26 +1004,26 @@ else sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/Makefile' && CC = gcc CFLAGS = -O -PROGS = setdigital pinnaclecfg conv +PROGS = setdigital msndreset pinnaclecfg conv X all: $(PROGS) X clean: X rm -f $(PROGS) SHAR_EOF - $shar_touch -am 0828231798 'MultiSound.d/Makefile' && + $shar_touch -am 1204092398 'MultiSound.d/Makefile' && chmod 0664 'MultiSound.d/Makefile' || $echo 'restore of' 'MultiSound.d/Makefile' 'failed' if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then md5sum -c << SHAR_EOF >/dev/null 2>&1 \ || $echo 'MultiSound.d/Makefile:' 'MD5 check failed' -ab95a049d10611a5e5d559a56965b33f MultiSound.d/Makefile +76ca8bb44e3882edcf79c97df6c81845 MultiSound.d/Makefile SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/Makefile'`" - test 96 -eq "$shar_count" || - $echo 'MultiSound.d/Makefile:' 'original size' '96,' 'current size' "$shar_count!" + test 106 -eq "$shar_count" || + $echo 'MultiSound.d/Makefile:' 'original size' '106,' 'current size' "$shar_count!" fi fi # ============= MultiSound.d/conv.l ============== @@ -1059,5 +1056,82 @@ SHAR_EOF $echo 'MultiSound.d/conv.l:' 'original size' '141,' 'current size' "$shar_count!" fi fi -rm -fr _sh21233 +# ============= MultiSound.d/msndreset.c ============== +if test -f 'MultiSound.d/msndreset.c' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'MultiSound.d/msndreset.c' '(file already exists)' +else + $echo 'x -' extracting 'MultiSound.d/msndreset.c' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/msndreset.c' && +/********************************************************************* +X * +X * msndreset.c - resets the MultiSound card +X * +X * Copyright (C) 1998 Andrew Veliath +X * +X * This program is free software; you can redistribute it and/or modify +X * it under the terms of the GNU General Public License as published by +X * the Free Software Foundation; either version 2 of the License, or +X * (at your option) any later version. +X * +X * This program is distributed in the hope that it will be useful, +X * but WITHOUT ANY WARRANTY; without even the implied warranty of +X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +X * GNU General Public License for more details. +X * +X * You should have received a copy of the GNU General Public License +X * along with this program; if not, write to the Free Software +X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +X * +X ********************************************************************/ +X +#include +#include +#include +#include +#include +#include +#include +X +int main(int argc, char *argv[]) +{ +X int fd; +X +X if (argc != 2) { +X fprintf(stderr, "usage: msndreset \n"); +X exit(1); +X } +X +X if ((fd = open(argv[1], O_RDWR)) < 0) { +X perror(argv[1]); +X exit(1); +X } +X +X if (ioctl(fd, SOUND_MIXER_PRIVATE1, 0) < 0) { +X fprintf(stderr, "error: msnd ioctl reset failed\n"); +X perror("ioctl"); +X close(fd); +X exit(1); +X } +X +X close(fd); +X +X return 0; +} +SHAR_EOF + $shar_touch -am 1204100698 'MultiSound.d/msndreset.c' && + chmod 0664 'MultiSound.d/msndreset.c' || + $echo 'restore of' 'MultiSound.d/msndreset.c' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'MultiSound.d/msndreset.c:' 'MD5 check failed' +c52f876521084e8eb25e12e01dcccb8a MultiSound.d/msndreset.c +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/msndreset.c'`" + test 1472 -eq "$shar_count" || + $echo 'MultiSound.d/msndreset.c:' 'original size' '1472,' 'current size' "$shar_count!" + fi +fi +rm -fr _sh01426 exit 0 diff --git a/Documentation/sound/README.awe b/Documentation/sound/README.awe new file mode 100644 index 000000000000..a9f86a670492 --- /dev/null +++ b/Documentation/sound/README.awe @@ -0,0 +1,219 @@ +================================================================ + AWE32 Sound Driver for Linux / FreeBSD + version 0.4.3; Nov. 1, 1998 + + Takashi Iwai +================================================================ + +* GENERAL NOTES + +This is a sound driver extension for SoundBlaster AWE32 and other +compatible cards (AWE32-PnP, SB32, SB32-PnP, AWE64 & etc) to enable +the wave synth operations. The driver is provided for both Linux +1.2.x and 2.[01].x kernels, and also FreeBSD, on Intel x86 and DEC +Alpha systems. + +This driver was written by Takashi Iwai , +and provided "as is". The original source (awedrv-0.4.3.tar.gz) and +binary packages are available on the following URL: + http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/ +Note that since the author is apart from this web site, the update is +not frequent now. + + +* NOTE TO LINUX USERS + +To enable this driver on linux-2.[01].x kernels, you need turn on both +"lowlevel drivers support" and "AWE32 synth support" options in sound +menu when configure your linux kernel and modules. The precise +installation procedure is described in the AWE64-Mini-HOWTO and +linux-kernel/Documetation/sound/AWE32. + +If you're using PnP cards, the card must be initialized before loading +the sound driver. There're several options to do this: + - Initialize the card via ISA PnP tools, and load the sound module. + - Initialize the card on DOS, and load linux by loadlin.exe + - Use PnP kernel driver (for Linux-2.x.x) +The detailed instruction for the solution using isapnp tools is found +in many documents like above. A brief instruction is also included in +the installation document of this package. +For PnP driver project, please refer to the following URL: + http://www-jcr.lmh.ox.ac.uk/~pnp/ + + +* USING THE DRIVER + +The awedrv has several different playing modes to realize easy channel +allocation for MIDI songs. To hear the exact sound quality, you need +to obtain the extended sequencer program, drvmidi or playmidi-2.5. + +For playing MIDI files, you *MUST* load the soundfont file on the +driver previously by sfxload utility. Otherwise you'll here no sounds +at all! All the utilities and driver source packages are found in the +above URL. The sfxload program is included in the package +awesfx-0.4.3.tgz. Binary packages are available there, too. See the +instruction in each package for installation. + +Loading a soundfont file is very simple. Just execute the command + + % sfxload synthgm.sbk + +Then, sfxload transfers the file "synthgm.sbk" to the driver. +Both SF1 and SF2 formats are accepted. + +Now you can hear midi musics by a midi player. + + % drvmidi foo.mid + +If you run MIDI player after MOD player, you need to load soundfont +files again, since MOD player programs clear the previous loaded +samples by their own data. + +If you have only 512kb on the sound card, I recommend to use dynamic +sample loading via -L option of drvmidi. 2MB GM/GS soundfont file is +available in most midi files. + + % sfxload synthgm + % drvmidi -L 2mbgmgs foo.mid + +This makes a big differece (believe me)! For more details, please +refer to the FAQ list which is available on the URL above. + +The current chorus, reverb and equalizer status can be changed by +aweset utility program (included in awesfx package). Note that +some awedrv-native programs (like drvmidi and xmp) will change the +current settings by themselves. The aweset program is effective +only for other programs like playmidi. + +Enjoy. + + +* COMPILE FLAGS + +Compile conditions are defined in awe_config.h. + +[Compatibility Conditions] +The following flags are defined automatically when using installation +shell script. + +- AWE_MODULE_SUPPORT + indicates your linux kernel supports module for each soundcard + (in recent 2.1 kernels and unofficial patched 2.0 kernels as + distributed in the RH5.0 package). + This flag is automatically set when you're using 2.1.x kernels. + You can pass the base address and memory size via the following + module options, + io = base I/O port address (eg. 0x620) + memsize = DRAM size in Kbyes (eg. 512) + As default, AWE driver probes these values automatically. + + +[Hardware Conditions] +You DON'T have to define the following two values. +Define them only when the driver couldn't detect the card properly. + +- AWE_DEFAULT_BASE_ADDR (default: not defined) + specifies the base port address of your AWE32 card. + 0 means to autodetect the address. + +- AWE_DEFAULT_MEM_SIZE (default: not defined) + specifies the memory size of your AWE32 card in kilo bytes. + -1 means to autodetect its size. + + +[Sample Table Size] +From ver.0.4.0, sample tables are allocated dynamically (except +Linux-1.2.x system), so you need NOT to touch these parameters. +Linux-1.2.x users may need to increase these values to apropriate size +if larger DRAM is equipped with the soundcard. + +- AWE_MAX_SF_LISTS, AWE_MAX_SAMPLES, AWE_MAX_INFOS + + +[Other Conditions] + +- AWE_ALWAYS_INIT_FM (default: not defined) + indicates the AWE driver always initialize FM passthrough even + without DRAM on board. Emu8000 chip has a restriction for playing + samples on DRAM that at least two channels must be occupied as + passthrough channels. + +- AWE_DEBUG_ON (default: defined) + turns on debuggin messages if defined. + +- AWE_HAS_GUS_COMPATIBILITY (default: defined) + Enables GUS compatibility mode if defined, reading GUS patches and + GUS control commands. Define this option to use GMOD or other + GUS module players. + +- CONFIG_AWE32_MIDIEMU (default: defined) + Adds a MIDI emulation device by Emu8000 wavetable. The emulation + device can be accessed as an external MIDI, and sends the MIDI + control codes directly. XG and GS sysex/NRPN are accepted. + No MIDI input is supported. + +- CONFIG_AWE32_MIXER (default: not defined) + Adds a mixer device for AWE32 bass/treble equalizer control. + You can access this device using /dev/mixer?? (usually mixer01). + +- AWE_USE_NEW_VOLUME_CALC (default: defined) + Use the new method to calculate the volume change as compatible + with DOS/Win drivers. This option can be toggled via aweset + program, or drvmidi player. + +- AWE_CHECK_VTARGET (default: defined) + Check the current volume target value when searching for an + empty channel to allocate a new voice. This is experimentally + implemented in this version. (probably, this option doesn't + affect the sound quality severely...) + +- AWE_ALLOW_SAMPLE_SHARING (default: defined) + Allow sample sharing for differently loaded patches. + This function is available only together with awesfx-0.4.3p3. + Note that this is still an experimantal option. + +- DEF_FM_CHORUS_DEPTH (default: 0x10) + The default strength to be sent to the chorus effect engine. + From 0 to 0xff. Larger numbers may often cause weird sounds. + +- DEF_FM_REVERB_DEPTH (default: 0x10) + The default strength to be sent to the reverb effect engine. + From 0 to 0xff. Larger numbers may often cause weird sounds. + + +* 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 awedrv to FreeBSD is done by Randall Hopper +(rhh@ct.picker.com). +The new volume calculation routine was derived from Mark Weaver's +ADIP compatible routines. +I also thank linux-awe-ml members for their efforts +to reboot their system many times :-) + + +* TODO'S + +- Complete DOS/Win compatibility +- DSP-like output + + +* COPYRIGHT + +Copyright (C) 1996-1998 Takashi Iwai + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. diff --git a/Documentation/video4linux/bttv/CARDS b/Documentation/video4linux/bttv/CARDS index 0cfd4d72e037..cd66ee3c5241 100644 --- a/Documentation/video4linux/bttv/CARDS +++ b/Documentation/video4linux/bttv/CARDS @@ -90,15 +90,14 @@ e.g.: AverMedia --------- - ... +ADS Channel Surfer +------------------ +... - - - - - - +Maxi TV Video PCI 2 card +------------------------ +... diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 390c10c1f74c..d977acbab50e 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -155,7 +155,7 @@ ENTRY(lcall7) ret_from_fork: GET_CURRENT(%ebx) #ifdef __SMP__ - btrl $0, SYMBOL_NAME(scheduler_lock) + lock ; btrl $0, SYMBOL_NAME(scheduler_lock) #endif /* __SMP__ */ jmp ret_from_sys_call @@ -193,6 +193,7 @@ restore_all: ALIGN signal_return: + sti # we can get here from an interrupt handler testl $(VM_MASK),EFLAGS(%esp) movl %esp,%eax jne v86_signal_return diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 00f39d4ed5ed..0841530cf5a2 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -105,19 +105,24 @@ static void hard_idle(void) */ static int cpu_idle(void *unused) { - unsigned long start_idle = jiffies; + int work = 1; + unsigned long start_idle = 0; /* endless idle loop with no priority at all */ + current->priority = 0; + current->counter = -100; for (;;) { + if (work) + start_idle = jiffies; + if (jiffies - start_idle > HARD_IDLE_TIMEOUT) hard_idle(); else { if (boot_cpu_data.hlt_works_ok && !hlt_counter && !current->need_resched) __asm__("hlt"); } - if (current->need_resched) - start_idle = jiffies; - current->policy = SCHED_YIELD; + + work = current->need_resched; schedule(); check_pgt_cache(); } @@ -131,12 +136,12 @@ static int cpu_idle(void *unused) int cpu_idle(void *unused) { - /* endless idle loop with no priority at all */ + current->priority = 0; + current->counter = -100; while(1) { if (current_cpu_data.hlt_works_ok && !hlt_counter && !current->need_resched) __asm__("hlt"); - current->policy = SCHED_YIELD; schedule(); check_pgt_cache(); } @@ -579,7 +584,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, *childregs = *regs; childregs->eax = 0; childregs->esp = esp; - childregs->eflags = regs->eflags & 0xffffcfff; /* iopl always 0 for a new process */ p->tss.esp = (unsigned long) childregs; p->tss.esp0 = (unsigned long) (childregs+1); diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c index d95d64069d0e..92bd3b293605 100644 --- a/arch/i386/kernel/sys_i386.c +++ b/arch/i386/kernel/sys_i386.c @@ -108,108 +108,94 @@ asmlinkage int old_select(struct sel_arg_struct *arg) * * This is really horribly ugly. */ -asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) +asmlinkage int sys_ipc (uint call, int first, int second, + int third, void *ptr, long fifth) { int version, ret; - lock_kernel(); - version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; if (call <= SEMCTL) switch (call) { case SEMOP: - ret = sys_semop (first, (struct sembuf *)ptr, second); - goto out; + return sys_semop (first, (struct sembuf *)ptr, second); case SEMGET: - ret = sys_semget (first, second, third); - goto out; + return sys_semget (first, second, third); case SEMCTL: { union semun fourth; - ret = -EINVAL; if (!ptr) - goto out; - ret = -EFAULT; + return -EINVAL; if (get_user(fourth.__pad, (void **) ptr)) - goto out; - ret = sys_semctl (first, second, third, fourth); - goto out; + return -EFAULT; + return sys_semctl (first, second, third, fourth); } default: - ret = -EINVAL; - goto out; + return -EINVAL; } + + version = call >> 16; /* hack for backward compatibility */ if (call <= MSGCTL) switch (call) { case MSGSND: - ret = sys_msgsnd (first, (struct msgbuf *) ptr, + return sys_msgsnd (first, (struct msgbuf *) ptr, second, third); - goto out; case MSGRCV: switch (version) { case 0: { struct ipc_kludge tmp; - ret = -EINVAL; if (!ptr) - goto out; - ret = -EFAULT; - if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, - sizeof (tmp))) - goto out; - ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); - goto out; + return -EINVAL; + + if (copy_from_user(&tmp, + (struct ipc_kludge *) ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); } - case 1: default: - ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); - goto out; + default: + return sys_msgrcv (first, + (struct msgbuf *) ptr, + second, fifth, third); } case MSGGET: - ret = sys_msgget ((key_t) first, second); - goto out; + return sys_msgget ((key_t) first, second); case MSGCTL: - ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); - goto out; + return sys_msgctl (first, second, + (struct msqid_ds *) ptr); default: - ret = -EINVAL; - goto out; + return -EINVAL; } if (call <= SHMCTL) switch (call) { case SHMAT: switch (version) { - case 0: default: { + default: { ulong raddr; - ret = sys_shmat (first, (char *) ptr, second, &raddr); + ret = sys_shmat (first, (char *) ptr, + second, &raddr); if (ret) - goto out; - ret = put_user (raddr, (ulong *) third); - goto out; + return ret; + return put_user (raddr, (ulong *) third); } case 1: /* iBCS2 emulator entry point */ - ret = -EINVAL; if (!segment_eq(get_fs(), get_ds())) - goto out; - ret = sys_shmat (first, (char *) ptr, second, (ulong *) third); - goto out; + return -EINVAL; + return sys_shmat (first, (char *) ptr, + second, (ulong *) third); } case SHMDT: - ret = sys_shmdt ((char *)ptr); - goto out; + return sys_shmdt ((char *)ptr); case SHMGET: - ret = sys_shmget (first, second, third); - goto out; + return sys_shmget (first, second, third); case SHMCTL: - ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); - goto out; + return sys_shmctl (first, second, + (struct shmid_ds *) ptr); default: - ret = -EINVAL; - goto out; + return -EINVAL; } - else - ret = -EINVAL; -out: - unlock_kernel(); - return ret; + + return -EINVAL; } /* diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 87a7d6495ceb..8b316d116c33 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -44,8 +44,9 @@ #define LO_MAGIC 0x68797548 -static int nbd_blksizes[MAX_NBD] = {1024, 1024,}; -static int nbd_sizes[MAX_NBD] = {0x7fffffff, 0x7fffffff,}; +static int nbd_blksizes[MAX_NBD]; +static int nbd_sizes[MAX_NBD]; +static int nbd_bytesizes[MAX_NBD]; static struct nbd_device nbd_dev[MAX_NBD]; @@ -382,9 +383,11 @@ static int nbd_ioctl(struct inode *inode, struct file *file, if ((arg & 511) || (arg > PAGE_SIZE)) return -EINVAL; nbd_blksizes[dev] = arg; + nbd_sizes[dev] = arg/nbd_blksizes[dev]; return 0; case NBD_SET_SIZE: - nbd_sizes[dev] = arg; + nbd_bytesizes[dev] = arg; + nbd_sizes[dev] = arg/nbd_blksizes[dev]; return 0; case NBD_DO_IT: if (!lo->file) @@ -400,6 +403,8 @@ static int nbd_ioctl(struct inode *inode, struct file *file, dev, (long) lo->head, (long) lo->tail, requests_in, requests_out); return 0; #endif + case BLKGETSIZE: + return put_user(nbd_bytesizes[dev]/512, (long *) arg); } return -EINVAL; } @@ -472,6 +477,9 @@ int nbd_init(void) nbd_dev[i].file = NULL; nbd_dev[i].magic = LO_MAGIC; nbd_dev[i].flags = 0; + nbd_blksizes[i] = 1024; + nbd_bytesizes[i] = 0x7fffffff; + nbd_sizes[i] = nbd_bytesizes[i]/nbd_blksizes[i]; } return 0; } diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 16a24938e4c6..6fb352f15564 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -35,10 +35,13 @@ if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then fi tristate 'SDL RISCom/8 card support' CONFIG_RISCOM8 tristate 'Specialix IO8+ card support' CONFIG_SPECIALIX - if [ "$CONFIG_SPECIALIX" = "y" -o "$CONFIG_SPECIALIX" = "m" ]; then + if [ "$CONFIG_SPECIALIX" != "n" ]; then bool 'Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS fi tristate 'Hayes ESP serial port support' CONFIG_ESPSERIAL + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate 'Multi-Tech multiport card support' CONFIG_ISI m + fi fi bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then @@ -107,10 +110,12 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350 fi dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV - dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV + if [ "$CONFIG_PCI" != "n" ]; then + dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV + fi if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV - dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV + dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT + dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT fi dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV dep_tristate 'SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 5f84aed5286a..ad7e1f9986e8 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -118,6 +118,14 @@ else endif endif +ifeq ($(CONFIG_ISI),y) +L_OBJS += isicom.o +else + ifeq ($(CONFIG_ISI),m) + M_OBJS += isicom.o + endif +endif + ifeq ($(CONFIG_ESPSERIAL),y) L_OBJS += esp.o else diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c index de2d25b0e24c..fec307af5634 100644 --- a/drivers/char/bttv.c +++ b/drivers/char/bttv.c @@ -31,7 +31,7 @@ * fix RAW Composite grabbing for NTSC * fix VBI reading double frames when grabbing is active * allow for different VDELAYs - * extra modules for tda9850, tda8425, any volunteers??? + * handle tda8425 properly */ #include @@ -98,7 +98,8 @@ static int bttv_num; /* number of Bt848s in use */ static struct bttv bttvs[BTTV_MAX]; #define I2C_TIMING (0x7<<4) -#define I2C_DELAY 10 +#define I2C_DELAY 50 /* Was 10 - some reports that more is needed + regardless of what the spec says */ #define I2C_SET(CTRL,DATA) \ { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); } #define I2C_GET() (btread(BT848_I2C)&1) @@ -1460,6 +1461,12 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) v.rangelow=0; v.rangehigh=0xFFFFFFFF; v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; + if (btv->audio_chip == TDA9850) { + unsigned char ALR1; + ALR1 = I2CRead(&(btv->i2c), I2C_TDA9850|1); + if (ALR1 & 32) + v.flags |= VIDEO_TUNER_STEREO_ON; + } v.mode = btv->win.norm; v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; if(copy_to_user(arg,&v,sizeof(v))) @@ -1687,8 +1694,17 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE); v.flags|=VIDEO_AUDIO_MUTABLE; strcpy(v.name,"TV"); - if (btv->have_msp3400) - { + if (btv->audio_chip == TDA9850) { + unsigned char ALR1; + v.flags|=VIDEO_AUDIO_VOLUME; + ALR1 = I2CRead(&(btv->i2c), I2C_TDA9850|1); + v.mode = VIDEO_SOUND_MONO; + v.mode |= (ALR1 & 32) ? VIDEO_SOUND_STEREO:0; + v.mode |= (ALR1 & 32) ? VIDEO_SOUND_LANG1:0; + v.volume = 32768; /* fixme */ + v.step = 4096; + } + else if (btv->have_msp3400) { v.flags|=VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE; @@ -1726,8 +1742,20 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) bt848_muxsel(btv,v.audio); if(!(v.flags&VIDEO_AUDIO_MUTE)) audio(btv, AUDIO_UNMUTE); - if (btv->have_msp3400) - { + if (btv->audio_chip == TDA9850) { + unsigned char con3 = 0; + if (v.mode & VIDEO_SOUND_LANG1) + con3 = 0x80; /* sap */ + if (v.mode & VIDEO_SOUND_STEREO) + con3 = 0x40; /* stereo */ + I2CWrite(&(btv->i2c), I2C_TDA9850, + TDA9850_CON3, con3, 1); + if (v.flags & VIDEO_AUDIO_VOLUME) + I2CWrite(&(btv->i2c), I2C_TDA9850, + TDA9850_CON4, + (v.volume>>12) & 15, 1); + } + else if (btv->have_msp3400) { i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400, MSP_SET_VOLUME,&(v.volume)); @@ -2389,7 +2417,11 @@ static void idcard(int i) if (I2CRead(&(btv->i2c), I2C_HAUPEE)>=0) { if(btv->id>849) + { btv->type=BTTV_HAUPPAUGE878; + btv->pll.pll_ifreq = 28636363; + btv->pll.pll_crystal = BT848_IFORM_XT0; + } else btv->type=BTTV_HAUPPAUGE; } @@ -2397,7 +2429,7 @@ static void idcard(int i) if (I2CRead(&(btv->i2c), I2C_STBEE)>=0) btv->type=BTTV_STB; - if (btv->type == BTTV_MIRO) { + if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) { /* auto detect tuner for MIRO cards */ btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7; } @@ -2582,10 +2614,13 @@ static int init_bt848(int i) btv->grabcount=0; btv->grab=0; btv->lastgrab=0; - btv->field=btv->last_field=0; - btv->video_dev.minor = -1; - btv->vbi_dev.minor = -1; - btv->radio_dev.minor = -1; + btv->field=btv->last_field=0; + /* cevans - prevents panic if initialization bails due to memory + * alloc failures! + */ + btv->video_dev.minor = -1; + btv->vbi_dev.minor = -1; + btv->radio_dev.minor = -1; /* i2c */ memcpy(&(btv->i2c),&bttv_i2c_bus_template,sizeof(struct i2c_bus)); diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c index 34651f9e9a00..d4fc2d7f9f45 100644 --- a/drivers/char/busmouse.c +++ b/drivers/char/busmouse.c @@ -56,6 +56,10 @@ static struct mouse_status mouse; static int mouse_irq = MOUSE_IRQ; +#ifdef MODULE +MODULE_PARM(mouse_irq, "i"); +#endif + __initfunc(void bmouse_setup(char *str, int *ints)) { if (ints[0] > 0) diff --git a/drivers/char/c-qcam.c b/drivers/char/c-qcam.c index 6ffb80a54a83..5f9341eaca55 100644 --- a/drivers/char/c-qcam.c +++ b/drivers/char/c-qcam.c @@ -1,13 +1,9 @@ /* - * Video4Linux: Colour QuickCam driver + * Video4Linux Colour QuickCam driver + * Copyright 1997-1998 Philip Blundell * - * Philip Blundell , December 30 1997 - * - * Largely untested (seems to work at 24bpp with a bidirectional port, - * though). */ - #include #include #include @@ -22,27 +18,47 @@ #include #include -#include "c-qcam.h" +struct qcam_device { + struct video_device vdev; + struct pardevice *pdev; + struct parport *pport; + int width, height; + int ccd_width, ccd_height; + int mode; + int contrast, brightness, whitebal; + int top, left; + unsigned int bidirectional; +}; + +/* The three possible QuickCam modes */ +#define QC_MILLIONS 0x18 +#define QC_BILLIONS 0x10 +#define QC_THOUSANDS 0x08 /* with VIDEC compression (not supported) */ + +/* The three possible decimations */ +#define QC_DECIMATION_1 0 +#define QC_DECIMATION_2 2 +#define QC_DECIMATION_4 4 -static __inline__ void qcam_set_ack(struct qcam_device *qcam, unsigned int i) +static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i) { /* note: the QC specs refer to the PCAck pin by voltage, not software level. PC ports have builtin inverters. */ parport_frob_control(qcam->pport, 8, i?8:0); } -static __inline__ unsigned int qcam_ready1(struct qcam_device *qcam) +static inline unsigned int qcam_ready1(struct qcam_device *qcam) { return (parport_read_status(qcam->pport) & 0x8)?1:0; - } -static __inline__ unsigned int qcam_ready2(struct qcam_device *qcam) +static inline unsigned int qcam_ready2(struct qcam_device *qcam) { return (parport_read_data(qcam->pport) & 0x1)?1:0; } -static inline unsigned int qcam_await_ready1(struct qcam_device *qcam, int value) +static unsigned int qcam_await_ready1(struct qcam_device *qcam, + int value) { unsigned long oldjiffies = jiffies; unsigned int i; @@ -68,7 +84,7 @@ static inline unsigned int qcam_await_ready1(struct qcam_device *qcam, int value return 1; } -static inline unsigned int qcam_await_ready2(struct qcam_device *qcam, int value) +static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value) { unsigned long oldjiffies = jiffies; unsigned int i; @@ -95,7 +111,7 @@ static inline unsigned int qcam_await_ready2(struct qcam_device *qcam, int value return 1; } -static inline int qcam_read_data(struct qcam_device *qcam) +static int qcam_read_data(struct qcam_device *qcam) { unsigned int idata; qcam_set_ack(qcam, 0); @@ -179,11 +195,10 @@ static void qc_setup(struct qcam_device *q) /* Set the brightness. */ qcam_set(q, 11, q->brightness); - /* Set the height. */ - qcam_set(q, 17, q->height); - - /* Set the width. */ - qcam_set(q, 19, q->width/2); + /* Set the height and width. These refer to the actual + CCD area *before* applying the selected decimation. */ + qcam_set(q, 17, q->ccd_height); + qcam_set(q, 19, q->ccd_width / 2); /* Set top and left. */ qcam_set(q, 0xd, q->top); @@ -236,53 +251,24 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, u if (qcam_await_ready1(q, 0)) return bytes; lo = (parport_read_status(q->pport) & 0xf0); qcam_set_ack(q, 0); - /* flip some bits; cqcam gets this wrong */ - buf[bytes++] = (hi | lo) ^ 0x88; + /* flip some bits */ + buf[bytes++] = (hi | (lo >> 4)) ^ 0x88; } } return bytes; } -/* Convert the data the camera gives us into the desired output format. - At the moment this is a no-op because read_bytes() does all the - required stuff, for 24bpp at least. */ -static size_t qcam_munge_buffer(struct qcam_device *q, char *inbuf, size_t inlen, char *outbuf, size_t outlen) -{ - size_t outptr = 0; - switch (q->bpp) - { - case 24: - while (inlen && (outptr <= (outlen-3))) - { - unsigned char r, g, b; - r = inbuf[0]; - g = inbuf[1]; - b = inbuf[2]; - put_user(r, outbuf+(outptr++)); - put_user(g, outbuf+(outptr++)); - put_user(b, outbuf+(outptr++)); - inlen -= 3; - inbuf += 3; - } - break; - default: - printk("c-qcam: can't convert this format (%d).\n", q->bpp); - return 0; - } - return outptr; -} +#define BUFSZ 150 static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) { - unsigned int tbpp = 0, tdecimation = 0, lines, pixelsperline, bitsperxfer; + unsigned lines, pixelsperline, bitsperxfer; unsigned int is_bi_dir = q->bidirectional; size_t wantlen, outptr = 0; - char *tmpbuf = kmalloc(768, GFP_KERNEL); - if (tmpbuf == NULL) - { - printk(KERN_ERR "cqcam: couldn't allocate a buffer.\n"); - return -ENOMEM; - } + char tmpbuf[BUFSZ]; + + if (verify_area(VERIFY_WRITE, buf, len)) + return -EFAULT; /* Wait for camera to become ready */ for (;;) @@ -290,33 +276,19 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) int i = qcam_get(q, 41); if (i == -1) { qc_setup(q); - kfree(tmpbuf); return -EIO; } - if (i & 0x80) - schedule(); - else + if ((i & 0x80) == 0) break; + else + schedule(); } - switch (q->bpp) - { - case 24: tbpp = QC_24BPP; break; - case 32: tbpp = QC_32BPP; break; - case 16: tbpp = QC_16BPP; break; - default: printk("qcam: Bad bpp.\n"); - } - switch (q->transfer_scale) { - case 1: tdecimation = QC_1_1; break; - case 2: tdecimation = QC_2_1; break; - case 4: tdecimation = QC_4_1; break; - default: printk("qcam: Bad decimation.\n"); - } + if (qcam_set(q, 7, (q->mode | (is_bi_dir?1:0)) + 1)) + return -EIO; - qcam_set(q, 7, (tbpp | tdecimation) + ((is_bi_dir)?1:0) + 1); - - lines = q->height / q->transfer_scale; - pixelsperline = q->width / q->transfer_scale; + lines = q->height; + pixelsperline = q->width; bitsperxfer = (is_bi_dir) ? 24 : 8; if (is_bi_dir) @@ -326,33 +298,33 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) mdelay(3); qcam_set_ack(q, 0); if (qcam_await_ready1(q, 1)) { - kfree(tmpbuf); qc_setup(q); return -EIO; } qcam_set_ack(q, 1); if (qcam_await_ready1(q, 0)) { - kfree(tmpbuf); qc_setup(q); return -EIO; } } - wantlen = lines * pixelsperline * q->bpp / 8; + wantlen = lines * pixelsperline * 24 / 8; while (wantlen) { - size_t t, s, o; - s = (wantlen > 768)?768:wantlen; + size_t t, s; + s = (wantlen > BUFSZ)?BUFSZ:wantlen; t = qcam_read_bytes(q, tmpbuf, s); if (outptr < len) { - o = qcam_munge_buffer(q, tmpbuf, t, buf + outptr, - len - outptr); - outptr += o; + size_t sz = len - outptr; + if (sz > t) sz = t; + if (__copy_to_user(buf+outptr, tmpbuf, sz)) + break; + outptr += sz; } wantlen -= t; - if (t < s) + if (t < s) break; if (current->need_resched) schedule(); @@ -366,7 +338,6 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) if (is_bi_dir) parport_frob_control(q->pport, 0x20, 0); qc_setup(q); - kfree(tmpbuf); return len; } @@ -386,7 +357,6 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) printk("qcam: no ack after EOF\n"); parport_frob_control(q->pport, 0x20, 0); qc_setup(q); - kfree(tmpbuf); return len; } parport_frob_control(q->pport, 0x20, 0); @@ -396,7 +366,6 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) { printk("qcam: no ack to port turnaround\n"); qc_setup(q); - kfree(tmpbuf); return len; } } @@ -413,10 +382,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) printk("qcam: bad EOF\n"); } - kfree(tmpbuf); - qcam_write_data(q, 0); - return len; } @@ -526,7 +492,7 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg) p.brightness=qcam->brightness<<8; p.contrast=qcam->contrast<<8; p.whiteness=qcam->whitebal<<8; - p.depth=qcam->bpp; + p.depth=24; p.palette=VIDEO_PALETTE_RGB24; if(copy_to_user(arg, &p, sizeof(p))) return -EFAULT; @@ -538,7 +504,10 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg) if(copy_from_user(&p, arg, sizeof(p))) return -EFAULT; - if (p.palette != VIDEO_PALETTE_RGB24) + /* + * Sanity check args + */ + if (p.depth != 24 || p.palette != VIDEO_PALETTE_RGB24) return -EINVAL; /* @@ -547,7 +516,6 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg) qcam->brightness = p.brightness>>8; qcam->contrast = p.contrast>>8; qcam->whitebal = p.whiteness>>8; - qcam->bpp = p.depth; parport_claim_or_block(qcam->pdev); qc_setup(qcam); @@ -557,6 +525,7 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg) case VIDIOCSWIN: { struct video_window vw; + if(copy_from_user(&vw, arg,sizeof(vw))) return -EFAULT; if(vw.flags) @@ -568,21 +537,33 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg) if(vw.width<80||vw.width>320) return -EINVAL; - qcam->width = 320; - qcam->height = 240; - qcam->transfer_scale = 4; + qcam->width = 80; + qcam->height = 60; + qcam->mode = QC_DECIMATION_4; if(vw.width>=160 && vw.height>=120) { - qcam->transfer_scale = 2; + qcam->width = 160; + qcam->height = 120; + qcam->mode = QC_DECIMATION_2; } if(vw.width>=320 && vw.height>=240) { qcam->width = 320; qcam->height = 240; - qcam->transfer_scale = 1; + qcam->mode = QC_DECIMATION_1; + } + qcam->mode |= QC_MILLIONS; +#if 0 + if(vw.width>=640 && vw.height>=480) + { + qcam->width = 640; + qcam->height = 480; + qcam->mode = QC_BILLIONS | QC_DECIMATION_1; } - /* Ok we figured out what to use from our wide choice */ +#endif + /* Ok we figured out what to use from our + wide choice */ parport_claim_or_block(qcam->pdev); qc_setup(qcam); parport_release(qcam->pdev); @@ -593,8 +574,8 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg) struct video_window vw; vw.x=0; vw.y=0; - vw.width=qcam->width/qcam->transfer_scale; - vw.height=qcam->height/qcam->transfer_scale; + vw.width=qcam->width; + vw.height=qcam->height; vw.chromakey=0; vw.flags=0; if(copy_to_user(arg, &vw, sizeof(vw))) @@ -677,10 +658,9 @@ static struct qcam_device *qcam_init(struct parport *port) memcpy(&q->vdev, &qcam_template, sizeof(qcam_template)); - q->width = 320; - q->height = 240; - q->bpp = 32; - q->transfer_scale = 1; + q->width = q->ccd_width = 320; + q->height = q->ccd_height = 240; + q->mode = QC_MILLIONS | QC_DECIMATION_1; q->contrast = 192; q->brightness = 240; q->whitebal = 128; @@ -723,7 +703,7 @@ int init_cqcam(struct parport *port) parport_release(qcam->pdev); - printk(KERN_INFO "Connectix Colour Quickcam on %s\n", + printk(KERN_INFO "Colour Quickcam found on %s\n", qcam->pport->name); if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1) @@ -745,11 +725,15 @@ void close_cqcam(struct qcam_device *qcam) kfree(qcam); } +#define BANNER "Connectix Colour Quickcam driver v0.02\n" + #ifdef MODULE int init_module(void) { struct parport *port; + printk(BANNER); + for (port = parport_enumerate(); port; port=port->next) init_cqcam(port); @@ -767,6 +751,8 @@ __initfunc(int init_colour_qcams(struct video_init *unused)) { struct parport *port; + printk(BANNER); + for (port = parport_enumerate(); port; port=port->next) init_cqcam(port); return 0; diff --git a/drivers/char/c-qcam.h b/drivers/char/c-qcam.h deleted file mode 100644 index b0dbe3015d36..000000000000 --- a/drivers/char/c-qcam.h +++ /dev/null @@ -1,18 +0,0 @@ -struct qcam_device { - struct video_device vdev; - struct pardevice *pdev; - struct parport *pport; - int width, height; - int bpp; - int contrast, brightness, whitebal; - int transfer_scale; - int top, left; - unsigned int bidirectional; -}; - -#define QC_1_1 0 -#define QC_2_1 2 -#define QC_4_1 4 -#define QC_16BPP 8 -#define QC_32BPP 16 -#define QC_24BPP 24 diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c new file mode 100644 index 000000000000..1ccf11bc5bbe --- /dev/null +++ b/drivers/char/isicom.c @@ -0,0 +1,1951 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Original driver code supplied by Multi-Tech + * + * Changes + * 1/9/98 alan@redhat.com Merge to 2.0.x kernel tree + * Obtain and use official major/minors + * Loader switched to a misc device + * (fixed range check bug as a side effect) + * Printk clean up + * 9/12/98 alan@redhat.com Rough port to 2.1.x + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +static int isicom_refcount = 0; +static int prev_card = 3; /* start servicing isi_card[0] */ +static struct isi_board * irq_to_board[16] = { NULL, }; +static struct tty_driver isicom_normal, isicom_callout; +static struct tty_struct * isicom_table[PORT_COUNT] = { NULL, }; +static struct termios * isicom_termios[PORT_COUNT] = { NULL, }; +static struct termios * isicom_termios_locked[PORT_COUNT] = { NULL, }; + +static struct isi_board isi_card[BOARD_COUNT]; +static struct isi_port isi_ports[PORT_COUNT]; + +DECLARE_TASK_QUEUE(tq_isicom); + +static struct timer_list tx; +static char re_schedule = 1; +#ifdef ISICOM_DEBUG +static unsigned long tx_count = 0; +#endif + +static int ISILoad_open(struct inode *inode, struct file *filp); +static int ISILoad_release(struct inode *inode, struct file *filp); +static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); + +static void isicom_tx(unsigned long _data); +static void isicom_start(struct tty_struct * tty); + +static unsigned char * tmp_buf = 0; +static struct semaphore tmp_buf_sem = MUTEX; + +/* baud index mappings from linux defns to isi */ + +static char linuxb_to_isib[] = { + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, + 18, 19 +}; + +/* + * Firmware loader driver specific routines + * + */ + +static struct file_operations ISILoad_fops = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + ISILoad_ioctl, + NULL, /* mmap */ + ISILoad_open, + NULL, /* flush */ + ISILoad_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ +}; + +struct miscdevice isiloader_device = { + ISILOAD_MISC_MINOR, "isictl", &ISILoad_fops +}; + + +extern inline int WaitTillCardIsFree(unsigned short base) +{ + unsigned long count=0; + while( (!(inw(base+0xe) & 0x1)) && (count++ < 6000000)); + if (inw(base+0xe)&0x1) + return 0; + else + return 1; +} + +static int ISILoad_open(struct inode *inode, struct file *filp) +{ +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISILoad:Firmware loader Opened!!!\n"); +#endif + return 0; +} + +static int ISILoad_release(struct inode *inode, struct file *filp) +{ +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISILoad:Firmware loader Close(Release)d\n",); +#endif + return 0; +} + +static int ISILoad_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + unsigned int card, i, j, signature, status; + unsigned short word_count, base; + bin_frame frame; + /* exec_record exec_rec; */ + + if(get_user(card, (int *)arg)) + return -EFAULT; + + if(card < 0 || card >= BOARD_COUNT) + return -ENXIO; + + base=isi_card[card].base; + + if(base==0) + return -ENXIO; /* disabled or not used */ + + switch(cmd) { + case MIOCTL_RESET_CARD: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + printk(KERN_DEBUG "ISILoad:Resetting Card%d at 0x%x ",card+1,base); + + inw(base+0x8); + + for(i=jiffies+HZ/100;i>jiffies;); + + outw(0,base+0x8); /* Reset */ + + for(j=1;j<=3;j++) { + for(i=jiffies+HZ;i>jiffies;); + printk("."); + } + signature=(inw(base+0x4)) & 0xff; + + if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) { +#ifdef ISICOM_DEBUG + printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe)); +#endif + printk("\nISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base); + return -EIO; + } + + switch(signature) { + case 0xa5: + case 0xbb: + case 0xdd: isi_card[card].port_count = 8; + isi_card[card].shift_count = 12; + break; + + case 0xcc: isi_card[card].port_count = 16; + isi_card[card].shift_count = 11; + break; + + default: printk("ISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base); +#ifdef ISICOM_DEBUG + printk("Sig=0x%x\n",signature); +#endif + return -EIO; + } + printk("-Done\n"); + return put_user(signature,(unsigned int*)arg); + + case MIOCTL_LOAD_FIRMWARE: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if(copy_from_user(&frame, (void *) arg, sizeof(bin_frame))) + return -EFAULT; + + if (WaitTillCardIsFree(base)) + return -EIO; + + outw(0xf0,base); /* start upload sequence */ + outw(0x00,base); + outw((frame.addr), base);/* lsb of adderess */ + + word_count=(frame.count >> 1) + frame.count % 2; + outw(word_count, base); + InterruptTheCard(base); + + for(i=0;i<=0x2f;i++); /* a wee bit of delay */ + + if (WaitTillCardIsFree(base)) + return -EIO; + + if ((status=inw(base+0x4))!=0) { + printk(KERN_WARNING "ISILoad:Card%d rejected load header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n", + card+1, frame.addr, frame.count, status); + return -EIO; + } + outsw(base, (void *) frame.bin_data, word_count); + + InterruptTheCard(base); + + for(i=0;i<=0x0f;i++); /* another wee bit of delay */ + + if (WaitTillCardIsFree(base)) + return -EIO; + + if ((status=inw(base+0x4))!=0) { + printk(KERN_ERR "ISILoad:Card%d got out of sync.Card Status:0x%x\n",card+1, status); + return -EIO; + } + return 0; + + case MIOCTL_READ_FIRMWARE: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if(copy_from_user(&frame, (void *) arg, sizeof(bin_header))) + return -EFAULT; + + if (WaitTillCardIsFree(base)) + return -EIO; + + outw(0xf1,base); /* start download sequence */ + outw(0x00,base); + outw((frame.addr), base);/* lsb of adderess */ + + word_count=(frame.count >> 1) + frame.count % 2; + outw(word_count+1, base); + InterruptTheCard(base); + + for(i=0;i<=0xf;i++); /* a wee bit of delay */ + + if (WaitTillCardIsFree(base)) + return -EIO; + + if ((status=inw(base+0x4))!=0) { + printk(KERN_WARNING "ISILoad:Card%d rejected verify header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n", + card+1, frame.addr, frame.count, status); + return -EIO; + } + + inw(base); + insw(base, frame.bin_data, word_count); + InterruptTheCard(base); + + for(i=0;i<=0x0f;i++); /* another wee bit of delay */ + + if (WaitTillCardIsFree(base)) + return -EIO; + + if ((status=inw(base+0x4))!=0) { + printk(KERN_ERR "ISILoad:Card%d verify got out of sync.Card Status:0x%x\n",card+1, status); + return -EIO; + } + + if(copy_to_user((void *) arg, &frame, sizeof(bin_frame))) + return -EFAULT; + return 0; + + case MIOCTL_XFER_CTRL: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (WaitTillCardIsFree(base)) + return -EIO; + + outw(0xf2, base); + outw(0x800, base); + outw(0x0, base); + outw(0x0, base); + InterruptTheCard(base); + + isi_card[card].status |= FIRMWARE_LOADED; + return 0; + + default: +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISILoad: Received Ioctl cmd 0x%x.\n", cmd); +#endif + return -ENOIOCTLCMD; + + } + +} + + +/* + * ISICOM Driver specific routines ... + * + */ + +static inline int isicom_paranoia_check(struct isi_port const * port, kdev_t dev, + const char * routine) +{ +#ifdef ISICOM_DEBUG + static const char * badmagic = + KERN_WARNING "ISICOM: Warning: bad isicom magic for dev %s in %s.\n"; + static const char * badport = + KERN_WARNING "ISICOM: Warning: NULL isicom port for dev %s in %s.\n"; + if (!port) { + printk(badport, kdevname(dev), routine); + return 1; + } + if (port->magic != ISICOM_MAGIC) { + printk(badmagic, kdevname(dev), routine); + return 1; + } +#endif + return 0; +} + +extern inline void schedule_bh(struct isi_port * port) +{ + queue_task(&port->bh_tqueue, &tq_isicom); + mark_bh(ISICOM_BH); +} + +/* Transmitter */ + +static void isicom_tx(unsigned long _data) +{ + short count = (BOARD_COUNT-1), card, base; + short txcount, wait, wrd, residue, word_count, cnt; + struct isi_port * port; + struct tty_struct * tty; + unsigned long flags; + +#ifdef ISICOM_DEBUG + ++tx_count; +#endif + + /* find next active board */ + card = (prev_card + 1) & 0x0003; + while(count-- > 0) { + if (isi_card[card].status & BOARD_ACTIVE) + break; + card = (card + 1) & 0x0003; + } + if (!(isi_card[card].status & BOARD_ACTIVE)) + goto sched_again; + + prev_card = card; + + count = isi_card[card].port_count; + port = isi_card[card].ports; + base = isi_card[card].base; + for (;count > 0;count--, port++) { + /* port not active or tx disabled to force flow control */ + if (!(port->status & ISI_TXOK)) + continue; + + tty = port->tty; + save_flags(flags); cli(); + txcount = MIN(TX_SIZE, port->xmit_cnt); + if ((txcount <= 0) || tty->stopped || tty->hw_stopped) { + restore_flags(flags); + continue; + } + wait = 200; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + restore_flags(flags); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: isicom_tx:Card(0x%x) found busy.\n", + card); +#endif + continue; + } + if (!(inw(base + 0x02) & (1 << port->channel))) { + restore_flags(flags); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: isicom_tx: cannot tx to 0x%x:%d.\n", + base, port->channel + 1); +#endif + continue; + } +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: txing %d bytes, port%d.\n", + txcount, port->channel+1); +#endif + outw((port->channel << isi_card[card].shift_count) | txcount + , base); + residue = NO; + wrd = 0; + while (1) { + cnt = MIN(txcount, (SERIAL_XMIT_SIZE - port->xmit_tail)); + if (residue == YES) { + residue = NO; + if (cnt > 0) { + wrd |= (port->xmit_buf[port->xmit_tail] << 8); + port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); + port->xmit_cnt--; + txcount--; + cnt--; + outw(wrd, base); + } + else { + outw(wrd, base); + break; + } + } + if (cnt <= 0) break; + word_count = cnt >> 1; + outsw(base, port->xmit_buf+port->xmit_tail, word_count); + port->xmit_tail = (port->xmit_tail + (word_count << 1)) & + (SERIAL_XMIT_SIZE - 1); + txcount -= (word_count << 1); + port->xmit_cnt -= (word_count << 1); + if (cnt & 0x0001) { + residue = YES; + wrd = port->xmit_buf[port->xmit_tail]; + port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); + port->xmit_cnt--; + txcount--; + } + } +/* + * Replaced the code below with hopefully a faster loop - sameer + */ + +/* + while (1) { + wrd = port->xmit_buf[port->xmit_tail++]; + port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1); + port->xmit_cnt--; + if (--txcount > 0) { + wrd |= (port->xmit_buf[port->xmit_tail++] << 8); + port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1); + port->xmit_cnt--; + outw(wrd, base); + if (--txcount <= 0) break; + } + else { + outw(wrd, base); + break; + } + } +*/ + InterruptTheCard(base); + if (port->xmit_cnt <= 0) + port->status &= ~ISI_TXOK; + if (port->xmit_cnt <= WAKEUP_CHARS) + schedule_bh(port); + restore_flags(flags); + } + + /* schedule another tx for hopefully in about 10ms */ +sched_again: + if (!re_schedule) + return; + init_timer(&tx); + tx.expires = jiffies + HZ/100; + tx.data = 0; + tx.function = isicom_tx; + add_timer(&tx); + + return; +} + +/* Interrupt handlers */ + +static void do_isicom_bh(void) +{ + run_task_queue(&tq_isicom); +} + + + +static void isicom_bottomhalf(void * data) +{ + struct isi_port * port = (struct isi_port *) data; + struct tty_struct * tty = port->tty; + + if (!tty) + return; + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); +} + +/* main interrupt handler routine */ +static void isicom_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + struct isi_board * card; + struct isi_port * port; + struct tty_struct * tty; + unsigned short base, header, word_count, count; + unsigned char channel; + short byte_count; + + card = irq_to_board[irq]; + if (!card || !(card->status & FIRMWARE_LOADED)) { + printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq); + return; + } + base = card->base; + + inw(base); /* get the dummy word out */ + header = inw(base); + channel = (header & 0x7800) >> card->shift_count; + byte_count = header & 0xff; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM:Intr:(0x%x:%d).\n", base, channel+1); +#endif + if ((channel+1) > card->port_count) { + printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%x): %d(channel) > port_count.\n", + base, channel+1); + ClearInterrupt(base); + return; + } + port = card->ports + channel; + if (!(port->flags & ASYNC_INITIALIZED)) { + ClearInterrupt(base); + return; + } + + tty = port->tty; + + if (header & 0x8000) { /* Status Packet */ + header = inw(base); + switch(header & 0xff) { + case 0: /* Change in EIA signals */ + + if (port->flags & ASYNC_CHECK_CD) { + if (port->status & ISI_DCD) { + if (!(header & ISI_DCD)) { + /* Carrier has been lost */ +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: interrupt: DCD->low.\n"); +#endif + port->status &= ~ISI_DCD; + if (!((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_CALLOUT_NOHUP))) + queue_task(&port->hangup_tq, + &tq_scheduler); + } + } + else { + if (header & ISI_DCD) { + /* Carrier has been detected */ +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: interrupt: DCD->high.\n"); +#endif + port->status |= ISI_DCD; + wake_up_interruptible(&port->open_wait); + } + } + } + else { + if (header & ISI_DCD) + port->status |= ISI_DCD; + else + port->status &= ~ISI_DCD; + } + + if (port->flags & ASYNC_CTS_FLOW) { + if (port->tty->hw_stopped) { + if (header & ISI_CTS) { + port->tty->hw_stopped = 0; + /* start tx ing */ + port->status |= (ISI_TXOK | ISI_CTS); + schedule_bh(port); + } + } + else { + if (!(header & ISI_CTS)) { + port->tty->hw_stopped = 1; + /* stop tx ing */ + port->status &= ~(ISI_TXOK | ISI_CTS); + } + } + } + else { + if (header & ISI_CTS) + port->status |= ISI_CTS; + else + port->status &= ~ISI_CTS; + } + + if (header & ISI_DSR) + port->status |= ISI_DSR; + else + port->status &= ~ISI_DSR; + + if (header & ISI_RI) + port->status |= ISI_RI; + else + port->status &= ~ISI_RI; + + break; + + case 1: /* Received Break !!! */ + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; + *tty->flip.flag_buf_ptr++ = TTY_BREAK; + /* dunno if this is right */ + *tty->flip.char_buf_ptr++ = 0; + tty->flip.count++; + if (port->flags & ASYNC_SAK) + do_SAK(tty); + queue_task(&tty->flip.tqueue, &tq_timer); + break; + + case 2: /* Statistics */ + printk(KERN_DEBUG "ISICOM: isicom_interrupt: stats!!!.\n"); + break; + + default: + printk(KERN_WARNING "ISICOM: Intr: Unknown code in status packet.\n"); + break; + } + } + else { /* Data Packet */ + count = MIN(byte_count, (TTY_FLIPBUF_SIZE - tty->flip.count)); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: Intr: Can rx %d of %d bytes.\n", + count, byte_count); +#endif + word_count = count >> 1; + insw(base, tty->flip.char_buf_ptr, word_count); + tty->flip.char_buf_ptr += (word_count << 1); + byte_count -= (word_count << 1); + if (count & 0x0001) { + *tty->flip.char_buf_ptr++ = (char)(inw(base) & 0xff); + byte_count -= 2; + } + memset(tty->flip.flag_buf_ptr, 0, count); + tty->flip.flag_buf_ptr += count; + tty->flip.count += count; + + if (byte_count > 0) { + printk(KERN_DEBUG "ISICOM: Intr(0x%x:%d): Flip buffer overflow! dropping bytes...\n", + base, channel+1); + while(byte_count > 0) { /* drain out unread xtra data */ + inw(base); + byte_count -= 2; + } + } + queue_task(&tty->flip.tqueue, &tq_timer); + } + ClearInterrupt(base); + return; +} + + /* called with interrupts disabled */ +static void isicom_config_port(struct isi_port * port) +{ + struct isi_board * card = port->card; + struct tty_struct * tty; + unsigned long baud; + unsigned short channel_setup, wait, base = card->base; + unsigned short channel = port->channel, shift_count = card->shift_count; + unsigned char flow_ctrl; + + if (!(tty = port->tty) || !tty->termios) + return; + baud = C_BAUD(tty); + if (baud & CBAUDEX) { + baud &= ~CBAUDEX; + + /* if CBAUDEX bit is on and the baud is set to either 50 or 75 + * then the card is programmed for 57.6Kbps or 115Kbps + * respectively. + */ + + if (baud < 1 || baud > 2) + port->tty->termios->c_cflag &= ~CBAUDEX; + else + baud += 15; + } + if (baud == 15) { + + /* the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set + * by the set_serial_info ioctl ... this is done by + * the 'setserial' utility. + */ + + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + baud++; /* 57.6 Kbps */ + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + baud +=2; /* 115 Kbps */ + } + if (linuxb_to_isib[baud] == -1) { + /* hang up */ + drop_dtr(port); + return; + } + else + raise_dtr(port); + + wait = 100; + while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); + if (!wait) { + printk(KERN_WARNING "ISICOM: Card found busy in isicom_config_port at channel setup.\n"); + return; + } + outw(0x8000 | (channel << shift_count) |0x03, base); + outw(linuxb_to_isib[baud] << 8 | 0x03, base); + channel_setup = 0; + switch(C_CSIZE(tty)) { + case CS5: + channel_setup |= ISICOM_CS5; + break; + case CS6: + channel_setup |= ISICOM_CS6; + break; + case CS7: + channel_setup |= ISICOM_CS7; + break; + case CS8: + channel_setup |= ISICOM_CS8; + break; + } + + if (C_CSTOPB(tty)) + channel_setup |= ISICOM_2SB; + + if (C_PARENB(tty)) + channel_setup |= ISICOM_EVPAR; + if (C_PARODD(tty)) + channel_setup |= ISICOM_ODPAR; + outw(channel_setup, base); + InterruptTheCard(base); + + if (C_CLOCAL(tty)) + port->flags &= ~ASYNC_CHECK_CD; + else + port->flags |= ASYNC_CHECK_CD; + + /* flow control settings ...*/ + flow_ctrl = 0; + port->flags &= ~ASYNC_CTS_FLOW; + if (C_CRTSCTS(tty)) { + port->flags |= ASYNC_CTS_FLOW; + flow_ctrl |= ISICOM_CTSRTS; + } + if (I_IXON(tty)) + flow_ctrl |= ISICOM_RESPOND_XONXOFF; + if (I_IXOFF(tty)) + flow_ctrl |= ISICOM_INITIATE_XONXOFF; + + wait = 100; + while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); + if (!wait) { + printk(KERN_WARNING "ISICOM: Card found busy in isicom_config_port at flow setup.\n"); + return; + } + outw(0x8000 | (channel << shift_count) |0x04, base); + outw(flow_ctrl << 8 | 0x05, base); + outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base); + InterruptTheCard(base); + + /* rx enabled -> enable port for rx on the card */ + if (C_CREAD(tty)) { + card->port_status |= (1 << channel); + outw(card->port_status, base + 0x02); + } + +} + +/* open et all */ + +extern inline void isicom_setup_board(struct isi_board * bp) +{ + int channel; + struct isi_port * port; + unsigned long flags; + + if (bp->status & BOARD_ACTIVE) + return; + port = bp->ports; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: setup_board: drop_dtr_rts start, port_count %d...\n", bp->port_count); +#endif + for(channel = 0; channel < bp->port_count; channel++, port++) { + save_flags(flags); cli(); + drop_dtr_rts(port); + restore_flags(flags); + } +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: setup_board: drop_dtr_rts stop...\n"); +#endif + + bp->status |= BOARD_ACTIVE; + MOD_INC_USE_COUNT; + return; +} + +static int isicom_setup_port(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned long flags; + + if (port->flags & ASYNC_INITIALIZED) + return 0; + if (!port->xmit_buf) { + unsigned long page; + + if (!(page = get_free_page(GFP_KERNEL))) + return -ENOMEM; + + if (port->xmit_buf) { + free_page(page); + return -ERESTARTSYS; + } + port->xmit_buf = (unsigned char *) page; + } + save_flags(flags); cli(); + if (port->tty) + clear_bit(TTY_IO_ERROR, &port->tty->flags); + if (port->count == 1) + card->count++; + + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + + /* discard any residual data */ + kill_queue(port, ISICOM_KILLTX | ISICOM_KILLRX); + + isicom_config_port(port); + port->flags |= ASYNC_INITIALIZED; + + restore_flags(flags); + + return 0; +} + +static int block_til_ready(struct tty_struct * tty, struct file * filp, struct isi_port * port) +{ + int do_clocal = 0, retval; + struct wait_queue wait = { current, NULL }; + + /* block if port is in the process of being closed */ + + if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: block_til_ready: close in progress.\n"); +#endif + interruptible_sleep_on(&port->close_wait); + if (port->flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; + } + + /* trying to open a callout device... check for constraints */ + + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: bl_ti_rdy: callout open.\n"); +#endif + if (port->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_SESSION_LOCKOUT) && + (port->session != current->session)) + return -EBUSY; + + if ((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_PGRP_LOCKOUT) && + (port->pgrp != current->pgrp)) + return -EBUSY; + port->flags |= ASYNC_CALLOUT_ACTIVE; + cli(); + raise_dtr_rts(port); + sti(); + return 0; + } + + /* if non-blocking mode is set ... */ + + if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: block_til_ready: non-block mode.\n"); +#endif + if (port->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + port->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (port->flags & ASYNC_CALLOUT_ACTIVE) { + if (port->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (C_CLOCAL(tty)) + do_clocal = 1; + } +#ifdef ISICOM_DEBUG + if (do_clocal) + printk(KERN_DEBUG "ISICOM: block_til_ready: CLOCAL set.\n"); +#endif + + /* block waiting for DCD to be asserted, and while + callout dev is busy */ + retval = 0; + add_wait_queue(&port->open_wait, &wait); + cli(); + if (!tty_hung_up_p(filp)) + port->count--; + sti(); + port->blocked_open++; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: block_til_ready: waiting for DCD...\n"); +#endif + while (1) { + cli(); + if (!(port->flags & ASYNC_CALLOUT_ACTIVE)) + raise_dtr_rts(port); + + sti(); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { + if (port->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: block_til_ready: tty_hung_up_p || not init.\n"); +#endif + break; + } + if (!(port->flags & ASYNC_CALLOUT_ACTIVE) && + !(port->flags & ASYNC_CLOSING) && + (do_clocal || (port->status & ISI_DCD))) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: block_til_ready: do_clocal || DCD.\n"); +#endif + break; + } + if (signal_pending(current)) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: block_til_ready: sig blocked.\n"); +#endif + retval = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&port->open_wait, &wait); + if (!tty_hung_up_p(filp)) + port->count++; + port->blocked_open--; + if (retval) + return retval; + port->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static int isicom_open(struct tty_struct * tty, struct file * filp) +{ + struct isi_port * port; + struct isi_board * card; + unsigned int line, board; + unsigned long flags; + int error; + +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: open start!!!.\n"); +#endif + line = MINOR(tty->device) - tty->driver.minor_start; + +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "line = %d.\n", line); +#endif + + if ((line < 0) || (line > (PORT_COUNT-1))) + return -ENODEV; + board = BOARD(line); + +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "board = %d.\n", board); +#endif + + card = &isi_card[board]; + if (!(card->status & FIRMWARE_LOADED)) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG"ISICOM: Firmware not loaded to card%d.\n", board); +#endif + return -ENODEV; + } + + /* open on higher 8 dev files on a 8 port card !!! */ + if (card->port_count == 8) + if (line > ((board * 16)+7)) { + printk(KERN_ERR "ISICOM: Opened >8 on a 8 port card.\n"); + return -ENODEV; + } + port = &isi_ports[line]; + if (isicom_paranoia_check(port, tty->device, "isicom_open")) + return -ENODEV; + +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: isicom_setup_board ...\n"); +#endif + isicom_setup_board(card); + + port->count++; + tty->driver_data = port; + port->tty = tty; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: isicom_setup_port ...\n"); +#endif + if ((error = isicom_setup_port(port))!=0) + return error; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: block_til_ready ...\n"); +#endif + if ((error = block_til_ready(tty, filp, port))!=0) + return error; + + if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = port->normal_termios; + else + *tty->termios = port->callout_termios; + save_flags(flags); cli(); + isicom_config_port(port); + restore_flags(flags); + } + + port->session = current->session; + port->pgrp = current->pgrp; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: open end!!!.\n"); +#endif + return 0; +} + +/* close et all */ + +extern inline void isicom_shutdown_board(struct isi_board * bp) +{ + int channel; + struct isi_port * port; + + if (!(bp->status & BOARD_ACTIVE)) + return; + bp->status &= ~BOARD_ACTIVE; + port = bp->ports; + for(channel = 0; channel < bp->port_count; channel++, port++) { + drop_dtr_rts(port); + } + MOD_DEC_USE_COUNT; +} + +static void isicom_shutdown_port(struct isi_port * port) +{ + struct isi_board * card = port->card; + struct tty_struct * tty; + + if (!(port->flags & ASYNC_INITIALIZED)) + return; + if (port->xmit_buf) { + free_page((unsigned long) port->xmit_buf); + port->xmit_buf = NULL; + } + if (!(tty = port->tty) || C_HUPCL(tty)) + /* drop dtr on this port */ + drop_dtr(port); + + /* any other port uninits */ + + if (tty) + set_bit(TTY_IO_ERROR, &tty->flags); + port->flags &= ~ASYNC_INITIALIZED; + + if (--card->count < 0) { + printk(KERN_DEBUG "ISICOM: isicom_shutdown_port: bad board(0x%x) count %d.\n", + card->base, card->count); + card->count = 0; + } + + /* last port was closed , shutdown that boad too */ + if (!card->count) + isicom_shutdown_board(card); +} + +static void isicom_close(struct tty_struct * tty, struct file * filp) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + struct isi_board * card = port->card; + unsigned long flags; + + if (!port) + return; + if (isicom_paranoia_check(port, tty->device, "isicom_close")) + return; + +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: Close start!!!.\n"); +#endif + + save_flags(flags); cli(); + if (tty_hung_up_p(filp)) { + restore_flags(flags); + return; + } + + if ((tty->count == 1) && (port->count != 1)) { + printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count" + "tty->count = 1 port count = %d.\n", + card->base, port->count); + port->count = 1; + } + if (--port->count < 0) { + printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count for" + "channel%d = %d", card->base, port->channel, + port->count); + port->count = 0; + } + + if (port->count) { + restore_flags(flags); + return; + } + port->flags |= ASYNC_CLOSING; + /* + * save termios struct since callout and dialin termios may be + * different. + */ + if (port->flags & ASYNC_NORMAL_ACTIVE) + port->normal_termios = *tty->termios; + if (port->flags & ASYNC_CALLOUT_ACTIVE) + port->callout_termios = *tty->termios; + + tty->closing = 1; + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->closing_wait); + /* indicate to the card that no more data can be received + on this port */ + if (port->flags & ASYNC_INITIALIZED) { + card->port_status &= ~(1 << port->channel); + outw(card->port_status, card->base + 0x02); + } + isicom_shutdown_port(port); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + port->tty = 0; + if (port->blocked_open) { + if (port->close_delay) { + current->state = TASK_INTERRUPTIBLE; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: scheduling until time out.\n"); +#endif + schedule_timeout(port->close_delay); + } + wake_up_interruptible(&port->open_wait); + } + port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | + ASYNC_CLOSING); + wake_up_interruptible(&port->close_wait); + restore_flags(flags); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: Close end!!!.\n"); +#endif +} + +/* write et all */ +static int isicom_write(struct tty_struct * tty, int from_user, + const unsigned char * buf, int count) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + unsigned long flags; + int cnt, total = 0; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: isicom_write for port%d: %d bytes.\n", + port->channel+1, count); +#endif + if (isicom_paranoia_check(port, tty->device, "isicom_write")) + return 0; + + if (!tty || !port->xmit_buf || !tmp_buf) + return 0; + if (from_user) + down(&tmp_buf_sem); /* acquire xclusive access to tmp_buf */ + + save_flags(flags); + while(1) { + cli(); + cnt = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + if (cnt <= 0) + break; + + if (from_user) { + /* the following may block for paging... hence + enabling interrupts but tx routine may have + created more space in xmit_buf when the ctrl + gets back here */ + sti(); + copy_from_user(tmp_buf, buf, cnt); + cli(); + cnt = MIN(cnt, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + memcpy(port->xmit_buf + port->xmit_head, tmp_buf, cnt); + } + else + memcpy(port->xmit_buf + port->xmit_head, buf, cnt); + port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - 1); + port->xmit_cnt += cnt; + restore_flags(flags); + buf += cnt; + count -= cnt; + total += cnt; + } + if (from_user) + up(&tmp_buf_sem); + if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped) + port->status |= ISI_TXOK; + restore_flags(flags); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: isicom_write %d bytes written.\n", total); +#endif + return total; +} + +/* put_char et all */ +static void isicom_put_char(struct tty_struct * tty, unsigned char ch) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + unsigned long flags; + + if (isicom_paranoia_check(port, tty->device, "isicom_put_char")) + return; + + if (!tty || !port->xmit_buf) + return; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: put_char, port %d, char %c.\n", port->channel+1, ch); +#endif + + save_flags(flags); cli(); + + if (port->xmit_cnt >= (SERIAL_XMIT_SIZE - 1)) { + restore_flags(flags); + return; + } + + port->xmit_buf[port->xmit_head++] = ch; + port->xmit_head &= (SERIAL_XMIT_SIZE - 1); + port->xmit_cnt++; + restore_flags(flags); +} + +/* flush_chars et all */ +static void isicom_flush_chars(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + + if (isicom_paranoia_check(port, tty->device, "isicom_flush_chars")) + return; + + if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !port->xmit_buf) + return; + + /* this tells the transmitter to consider this port for + data output to the card ... that's the best we can do. */ + port->status |= ISI_TXOK; +} + +/* write_room et all */ +static int isicom_write_room(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + int free; + if (isicom_paranoia_check(port, tty->device, "isicom_write_room")) + return 0; + + free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; + if (free < 0) + free = 0; + return free; +} + +/* chars_in_buffer et all */ +static int isicom_chars_in_buffer(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + if (isicom_paranoia_check(port, tty->device, "isicom_chars_in_buffer")) + return 0; + return port->xmit_cnt; +} + +/* ioctl et all */ +extern inline void isicom_send_break(struct isi_port * port, unsigned long length) +{ + struct isi_board * card = port->card; + short wait = 10; + unsigned short base = card->base; + unsigned long flags; + + save_flags(flags); cli(); + while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); + if (!wait) { + printk(KERN_DEBUG "ISICOM: Card found busy in isicom_send_break.\n"); + return; + } + outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base); + outw((length & 0xff) << 8 | 0x00, base); + outw((length & 0xff00), base); + InterruptTheCard(base); + restore_flags(flags); +} + +static int isicom_get_modem_info(struct isi_port * port, unsigned int * value) +{ + /* just send the port status */ + unsigned int info; + unsigned short status = port->status; + + info = ((status & ISI_RTS) ? TIOCM_RTS : 0) | + ((status & ISI_DTR) ? TIOCM_DTR : 0) | + ((status & ISI_DCD) ? TIOCM_CAR : 0) | + ((status & ISI_DSR) ? TIOCM_DSR : 0) | + ((status & ISI_CTS) ? TIOCM_CTS : 0) | + ((status & ISI_RI ) ? TIOCM_RI : 0); + put_user(info, (unsigned long *) value); + return 0; +} + +static int isicom_set_modem_info(struct isi_port * port, unsigned int cmd, + unsigned int * value) +{ + unsigned int arg; + unsigned long flags; + + if(get_user(arg, value)) + return -EFAULT; + + save_flags(flags); cli(); + + switch(cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + raise_rts(port); + if (arg & TIOCM_DTR) + raise_dtr(port); + break; + + case TIOCMBIC: + if (arg & TIOCM_RTS) + drop_rts(port); + if (arg & TIOCM_DTR) + drop_dtr(port); + break; + + case TIOCMSET: + if (arg & TIOCM_RTS) + raise_rts(port); + else + drop_rts(port); + + if (arg & TIOCM_DTR) + raise_dtr(port); + else + drop_dtr(port); + break; + + default: + restore_flags(flags); + return -EINVAL; + } + restore_flags(flags); + return 0; +} + +static int isicom_set_serial_info(struct isi_port * port, + struct serial_struct * info) +{ + struct serial_struct newinfo; + unsigned long flags; + int reconfig_port; + + if(copy_from_user(&newinfo, info, sizeof(newinfo))) + return -EFAULT; + + reconfig_port = ((port->flags & ASYNC_SPD_MASK) != + (newinfo.flags & ASYNC_SPD_MASK)); + + if (!suser()) { + if ((newinfo.close_delay != port->close_delay) || + (newinfo.closing_wait != port->closing_wait) || + ((newinfo.flags & ~ASYNC_USR_MASK) != + (port->flags & ~ASYNC_USR_MASK))) + return -EPERM; + port->flags = ((port->flags & ~ ASYNC_USR_MASK) | + (newinfo.flags & ASYNC_USR_MASK)); + } + else { + port->close_delay = newinfo.close_delay; + port->closing_wait = newinfo.closing_wait; + port->flags = ((port->flags & ~ASYNC_FLAGS) | + (newinfo.flags & ASYNC_FLAGS)); + } + if (reconfig_port) { + save_flags(flags); cli(); + isicom_config_port(port); + restore_flags(flags); + } + return 0; +} + +static int isicom_get_serial_info(struct isi_port * port, + struct serial_struct * info) +{ + struct serial_struct out_info; + + memset(&out_info, 0, sizeof(out_info)); +/* out_info.type = ? */ + out_info.line = port - isi_ports; + out_info.port = port->card->base; + out_info.irq = port->card->irq; + out_info.flags = port->flags; +/* out_info.baud_base = ? */ + out_info.close_delay = port->close_delay; + out_info.closing_wait = port->closing_wait; + if(copy_to_user(info, &out_info, sizeof(out_info))) + return -EFAULT; + return 0; +} + +static int isicom_ioctl(struct tty_struct * tty, struct file * filp, + unsigned int cmd, unsigned long arg) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + int retval; + + if (isicom_paranoia_check(port, tty->device, "isicom_ioctl")) + return -ENODEV; + + switch(cmd) { + case TCSBRK: + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (!arg) + isicom_send_break(port, HZ/4); + return 0; + + case TCSBRKP: + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + isicom_send_break(port, arg ? arg * (HZ/10) : HZ/4); + return 0; + + case TIOCGSOFTCAR: + return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); + + case TIOCSSOFTCAR: + if(get_user(arg, (unsigned long *) arg)) + return -EFAULT; + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return 0; + + case TIOCMGET: + return isicom_get_modem_info(port, (unsigned int*) arg); + + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return isicom_set_modem_info(port, cmd, + (unsigned int *) arg); + + case TIOCGSERIAL: + return isicom_get_serial_info(port, + (struct serial_struct *) arg); + + case TIOCSSERIAL: + return isicom_set_serial_info(port, + (struct serial_struct *) arg); + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +/* set_termios et all */ +static void isicom_set_termios(struct tty_struct * tty, struct termios * old_termios) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + unsigned long flags; + + if (isicom_paranoia_check(port, tty->device, "isicom_set_termios")) + return; + + if (tty->termios->c_cflag == old_termios->c_cflag && + tty->termios->c_iflag == old_termios->c_iflag) + return; + + save_flags(flags); cli(); + isicom_config_port(port); + restore_flags(flags); + + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + isicom_start(tty); + } +} + +/* throttle et all */ +static void isicom_throttle(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + struct isi_board * card = port->card; + unsigned long flags; + + if (isicom_paranoia_check(port, tty->device, "isicom_throttle")) + return; + + /* tell the card that this port cannot handle any more data for now */ + save_flags(flags); cli(); + card->port_status &= ~(1 << port->channel); + outw(card->port_status, card->base + 0x02); + restore_flags(flags); +} + +/* unthrottle et all */ +static void isicom_unthrottle(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + struct isi_board * card = port->card; + unsigned long flags; + + if (isicom_paranoia_check(port, tty->device, "isicom_unthrottle")) + return; + + /* tell the card that this port is ready to accept more data */ + save_flags(flags); cli(); + card->port_status |= (1 << port->channel); + outw(card->port_status, card->base + 0x02); + restore_flags(flags); +} + +/* stop et all */ +static void isicom_stop(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + + if (isicom_paranoia_check(port, tty->device, "isicom_stop")) + return; + + /* this tells the transmitter not to consider this port for + data output to the card. */ + port->status &= ~ISI_TXOK; +} + +/* start et all */ +static void isicom_start(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + + if (isicom_paranoia_check(port, tty->device, "isicom_start")) + return; + + /* this tells the transmitter to consider this port for + data output to the card. */ + port->status |= ISI_TXOK; +} + +/* hangup et all */ +static void do_isicom_hangup(void * data) +{ + struct isi_port * port = (struct isi_port *) data; + struct tty_struct * tty; + + tty = port->tty; + if (!tty) + return; + + tty_hangup(tty); +} + +static void isicom_hangup(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + + if (isicom_paranoia_check(port, tty->device, "isicom_hangup")) + return; + + isicom_shutdown_port(port); + port->count = 0; + port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + port->tty = 0; + wake_up_interruptible(&port->open_wait); +} + +/* flush_buffer et all */ +static void isicom_flush_buffer(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + unsigned long flags; + + if (isicom_paranoia_check(port, tty->device, "isicom_flush_buffer")) + return; + + save_flags(flags); cli(); + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + + +static int register_ioregion(void) +{ + int count, done=0; + for (count=0; count < BOARD_COUNT; count++ ) { + if (isi_card[count].base) { + if (check_region(isi_card[count].base,16)) { + printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x is busy. Card%d will be disabled.\n", + isi_card[count].base,isi_card[count].base+15,count+1); + isi_card[count].base=0; + } + else { + request_region(isi_card[count].base,16,ISICOM_NAME); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x requested for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1); +#endif + done++; + } + } + } + return done; +} + +static void unregister_ioregion(void) +{ + int count; + for (count=0; count < BOARD_COUNT; count++ ) + if (isi_card[count].base) { + release_region(isi_card[count].base,16); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x released for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1); +#endif + } +} + +static int register_drivers(void) +{ + int error; + + /* tty driver structure initialization */ + memset(&isicom_normal, 0, sizeof(struct tty_driver)); + isicom_normal.magic = TTY_DRIVER_MAGIC; + isicom_normal.name = "ttyM"; + isicom_normal.major = ISICOM_NMAJOR; + isicom_normal.minor_start = 0; + isicom_normal.num = PORT_COUNT; + isicom_normal.type = TTY_DRIVER_TYPE_SERIAL; + isicom_normal.subtype = SERIAL_TYPE_NORMAL; + isicom_normal.init_termios = tty_std_termios; + isicom_normal.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL |CLOCAL; + isicom_normal.flags = TTY_DRIVER_REAL_RAW; + isicom_normal.refcount = &isicom_refcount; + + isicom_normal.table = isicom_table; + isicom_normal.termios = isicom_termios; + isicom_normal.termios_locked = isicom_termios_locked; + + isicom_normal.open = isicom_open; + isicom_normal.close = isicom_close; + isicom_normal.write = isicom_write; + isicom_normal.put_char = isicom_put_char; + isicom_normal.flush_chars = isicom_flush_chars; + isicom_normal.write_room = isicom_write_room; + isicom_normal.chars_in_buffer = isicom_chars_in_buffer; + isicom_normal.ioctl = isicom_ioctl; + isicom_normal.set_termios = isicom_set_termios; + isicom_normal.throttle = isicom_throttle; + isicom_normal.unthrottle = isicom_unthrottle; + isicom_normal.stop = isicom_stop; + isicom_normal.start = isicom_start; + isicom_normal.hangup = isicom_hangup; + isicom_normal.flush_buffer = isicom_flush_buffer; + + /* callout device */ + + isicom_callout = isicom_normal; + isicom_callout.name = "cum"; + isicom_callout.major = ISICOM_CMAJOR; + isicom_callout.subtype = SERIAL_TYPE_CALLOUT; + + if ((error=tty_register_driver(&isicom_normal))!=0) { + printk(KERN_DEBUG "ISICOM: Couldn't register the dialin driver, error=%d\n", + error); + return error; + } + if ((error=tty_register_driver(&isicom_callout))!=0) { + tty_unregister_driver(&isicom_normal); + printk(KERN_DEBUG "ISICOM: Couldn't register the callout driver, error=%d\n", + error); + return error; + } + return 0; +} + +static void unregister_drivers(void) +{ + int error; + if ((error=tty_unregister_driver(&isicom_callout))!=0) + printk(KERN_DEBUG "ISICOM: couldn't unregister callout driver error=%d.\n",error); + if (tty_unregister_driver(&isicom_normal)) + printk(KERN_DEBUG "ISICOM: couldn't unregister normal driver error=%d.\n",error); +} + +static int register_isr(void) +{ + int count, done=0; + for (count=0; count < BOARD_COUNT; count++ ) { + if (isi_card[count].base) { + if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT, ISICOM_NAME, NULL)) { + printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n", + isi_card[count].irq, count+1); + release_region(isi_card[count].base,16); + isi_card[count].base=0; + } + else { + printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n", + count+1, isi_card[count].base, isi_card[count].irq); + + irq_to_board[isi_card[count].irq]=&isi_card[count]; + done++; + } + } + } + return done; +} + +static void unregister_isr(void) +{ + int count; + for (count=0; count < BOARD_COUNT; count++ ) + if (isi_card[count].base) { + free_irq(isi_card[count].irq, NULL); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1); +#endif + } +} + +static int isicom_init(void) +{ + int card, channel, base; + struct isi_port * port; + unsigned long page; + + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + if (!page) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: Couldn't allocate page for tmp_buf.\n"); +#else + printk(KERN_ERR "ISICOM: Not enough memory...\n"); +#endif + return 0; + } + tmp_buf = (unsigned char *) page; + } + + if (!register_ioregion()) + { + printk(KERN_ERR "ISICOM: All required I/O space found busy.\n"); + free_page((unsigned long)tmp_buf); + return 0; + } + if (register_drivers()) + { + unregister_ioregion(); + free_page((unsigned long)tmp_buf); + return 0; + } + if (!register_isr()) + { + unregister_drivers(); + /* ioports already uregistered in register_isr */ + free_page((unsigned long)tmp_buf); + return 0; + } + + /* initialize bottom half */ + init_bh(ISICOM_BH, do_isicom_bh); + + + memset(isi_ports, 0, sizeof(isi_ports)); + for (card = 0; card < BOARD_COUNT; card++) { + port = &isi_ports[card * 16]; + isi_card[card].ports = port; + base = isi_card[card].base; + for (channel = 0; channel < 16; channel++, port++) { + port->magic = ISICOM_MAGIC; + port->card = &isi_card[card]; + port->channel = channel; + port->normal_termios = isicom_normal.init_termios; + port->callout_termios = isicom_callout.init_termios; + port->close_delay = 50 * HZ/100; + port->closing_wait = 3000 * HZ/100; + port->hangup_tq.routine = do_isicom_hangup; + port->hangup_tq.data = port; + port->bh_tqueue.routine = isicom_bottomhalf; + port->bh_tqueue.data = port; + port->status = 0; + + /* . . . */ + } + } + + return 1; +} + +/* + * Insmod can set static symbols so keep these static + */ + +static int io[4]; +static int irq[4]; + +MODULE_AUTHOR("MultiTech"); +MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech"); +MODULE_PARM(io, "1-4i"); +MODULE_PARM_DESC(io, "I/O ports for the cards"); +MODULE_PARM(irq, "1-4i"); +MODULE_PARM_DESC(irq, "Interrupts for the cards"); + +int init_module(void) +{ + int retval, card; + + for(card=0; card < BOARD_COUNT; card++) + { + isi_card[card].base=io[card]; + isi_card[card].irq=irq[card]; + } + + for (card=0 ;card < BOARD_COUNT; card++) { + if (!((isi_card[card].irq==2)||(isi_card[card].irq==3)|| + (isi_card[card].irq==4)||(isi_card[card].irq==5)|| + (isi_card[card].irq==7)||(isi_card[card].irq==10)|| + (isi_card[card].irq==11)||(isi_card[card].irq==12)|| + (isi_card[card].irq==15))) { + + if (isi_card[card].base) { + printk(KERN_ERR "ISICOM: Irq %d unsupported. Disabling Card%d...\n", + isi_card[card].irq, card+1); + isi_card[card].base=0; + } + } + } + + if (!(isi_card[0].base || isi_card[1].base || isi_card[2].base || isi_card[3].base)) { + printk(KERN_ERR "ISICOM: No valid card configuration. Driver cannot be initialized...\n"); + return -EIO; + } + retval=misc_register(&isiloader_device); + if (retval<0) { + printk(KERN_ERR "ISICOM: Unable to register firmware loader driver.\n"); + return -EIO; + } + + if (!isicom_init()) { + if (misc_deregister(&isiloader_device)) + printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n"); + return -EIO; + } + + init_timer(&tx); + tx.expires = jiffies + 1; + tx.data = 0; + tx.function = isicom_tx; + re_schedule = 1; + add_timer(&tx); + + return 0; +} + +void cleanup_module(void) +{ + re_schedule = 0; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ); + disable_bh(ISICOM_BH); + +#ifdef ISICOM_DEBUG + printk("ISICOM: isicom_tx tx_count = %ld.\n", tx_count); +#endif + +#ifdef ISICOM_DEBUG + printk("ISICOM: uregistering isr ...\n"); +#endif + unregister_isr(); + +#ifdef ISICOM_DEBUG + printk("ISICOM: unregistering drivers ...\n"); +#endif + unregister_drivers(); + +#ifdef ISICOM_DEBUG + printk("ISICOM: unregistering ioregion ...\n"); +#endif + unregister_ioregion(); + +#ifdef ISICOM_DEBUG + printk("ISICOM: freeing tmp_buf ...\n"); +#endif + free_page((unsigned long)tmp_buf); + +#ifdef ISICOM_DEBUG + printk("ISICOM: unregistering firmware loader ...\n"); +#endif + if (misc_deregister(&isiloader_device)) + printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n"); +} diff --git a/drivers/char/joystick/Config.in b/drivers/char/joystick/Config.in index db5585cd1692..a41eaac33d98 100644 --- a/drivers/char/joystick/Config.in +++ b/drivers/char/joystick/Config.in @@ -10,9 +10,9 @@ dep_tristate ' Microsoft SideWinder, Genius Digital joysticks and gamepads' CO dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK dep_tristate ' PDPI Lightning 4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK - dep_tristate ' Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK - dep_tristate ' TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK + dep_tristate ' NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT + dep_tristate ' Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT + dep_tristate ' TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT fi if [ "$CONFIG_AMIGA" = "y" ]; then dep_tristate ' Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK diff --git a/drivers/char/macmouse.c b/drivers/char/macmouse.c deleted file mode 100644 index b9236bb9375e..000000000000 --- a/drivers/char/macmouse.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Macintosh ADB Mouse driver for Linux - * - * 27 Oct 1997 Michael Schmitz - * - * Apple mouse protocol according to: - * - * Device code shamelessly stolen from: - */ -/* - * Atari Mouse Driver for Linux - * by Robert de Vries (robert@and.nl) 19Jul93 - * - * 16 Nov 1994 Andreas Schwab - * Compatibility with busmouse - * Support for three button mouse (shamelessly stolen from MiNT) - * third button wired to one of the joystick directions on joystick 1 - * - * 1996/02/11 Andreas Schwab - * Module support - * Allow multiple open's - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -static struct mouse_status mouse; -static int mac_mouse_x_threshold = 2, mac_mouse_y_threshold = 2; -static int mac_mouse_buttons = 0; - -extern void (*mac_mouse_interrupt_hook) (char *, int); -extern int mac_emulate_button2; -extern int mac_emulate_button3; - -extern int console_loglevel; - -/* - * XXX: need to figure out what ADB mouse packets mean ... - * This is the stuff stolen from the Atari driver ... - */ -static void mac_mouse_interrupt(char *buf, int nb) -{ - static int buttons = 7; /* all mouse buttons _up_ !! */ - - /* - Handler 1 -- 100cpi original Apple mouse protocol. - Handler 2 -- 200cpi original Apple mouse protocol. - - For Apple's standard one-button mouse protocol the data array will - contain the following values: - - BITS COMMENTS - data[0] = 0000 0000 ADB packet identifer. - data[1] = ???? ???? (?) - data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device. - data[3] = bxxx xxxx First button and x-axis motion. - data[4] = byyy yyyy Second button and y-axis motion. - - NOTE: data[0] is confirmed by the parent function and need not be - checked here. - */ - - /* - Handler 4 -- Apple Extended mouse protocol. - - For Apple's 3-button mouse protocol the data array will contain the - following values: - - BITS COMMENTS - data[0] = 0000 0000 ADB packet identifer. - data[1] = 0100 0000 Extended protocol register. - Bits 6-7 are the device id, which should be 1. - Bits 4-5 are resolution which is in "units/inch". - The Logitech MouseMan returns these bits clear but it has - 200/300cpi resolution. - Bits 0-3 are unique vendor id. - data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device. - Bits 2-3 should be 8 + 4. - Bits 4-7 should be 3 for a mouse device. - data[3] = bxxx xxxx Left button and x-axis motion. - data[4] = byyy yyyy Second button and y-axis motion. - data[5] = byyy bxxx Third button and fourth button. - Y is additiona. high bits of y-axis motion. - X is additional high bits of x-axis motion. - - NOTE: data[0] and data[2] are confirmed by the parent function and - need not be checked here. - */ - - /* - * 'buttons' here means 'button down' states! - * Button 1 (left) : bit 2, busmouse button 3 - * Button 2 (right) : bit 0, busmouse button 1 - * Button 3 (middle): bit 1, busmouse button 2 - */ - - /* x/y and buttons swapped */ - - if (buf[0] == 0) { /* real packet : use buttons? */ -#ifdef DEBUG_ADBMOUSE - if (console_loglevel >= 8) - printk("mac_mouse: real data; "); -#endif - /* button 1 (left, bit 2) : always significant ! */ - buttons = (buttons&3) | (buf[3] & 0x80 ? 4 : 0); /* 1+2 unchanged */ - /* button 2 (right, bit 0) present ? */ - if ( !mac_emulate_button2 ) - buttons = (buttons&6) | (buf[4] & 0x80 ? 1 : 0); /* 2+3 unchanged */ - /* button 2 (middle) present? */ - /* data valid only if extended mouse format ! (buf[3] = 0 else)*/ - if ( !mac_emulate_button3 && buf[1]&0x40 ) - buttons = (buttons&5) | (buf[5] & 0x80 ? 2 : 0); /* 1+3 unchanged */ - } else { /* fake packet : use 2+3 */ -#ifdef DEBUG_ADBMOUSE - if (console_loglevel >= 8) - printk("mac_mouse: fake data; "); -#endif - /* we only see state changes here, but the fake driver takes care - * to preserve state... button 1 state must stay unchanged! */ - buttons = (buttons&4) | ((buf[4] & 0x80 ? 1 : 0) | (buf[5] & 0x80 ? 2 : 0)); - } - - add_mouse_randomness(((~buttons & 7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f)); - mouse.buttons = buttons & 7; - mouse.dx += ((buf[4]&0x7f) < 64 ? (buf[4]&0x7f) : (buf[4]&0x7f)-128 ); - mouse.dy -= ((buf[3]&0x7f) < 64 ? (buf[3]&0x7f) : (buf[3]&0x7f)-128 ); - -#ifdef DEBUG_ADBMOUSE - if (console_loglevel >= 8) - printk(" %X %X %X buttons %x dx %d dy %d \n", - buf[3], buf[4], buf[5], mouse.buttons, mouse.dx, mouse.dy); -#endif - - mouse.ready = 1; - wake_up_interruptible(&mouse.wait); - if (mouse.fasyncptr) - kill_fasync(mouse.fasyncptr, SIGIO); - -} - -static int fasync_mouse(int fd, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(fd, filp, on, &mouse.fasyncptr); - if (retval < 0) - return retval; - return 0; -} - -static int release_mouse(struct inode *inode, struct file *file) -{ - fasync_mouse(-1, file, 0); - if (--mouse.active) - return 0; - - mac_mouse_interrupt_hook = NULL; - MOD_DEC_USE_COUNT; - return 0; -} - -static int open_mouse(struct inode *inode, struct file *file) -{ - if (mouse.active++) - return 0; - - mouse.ready = 0; - - mouse.dx = mouse.dy = 0; - mac_mouse_buttons = 0; - MOD_INC_USE_COUNT; - mac_mouse_interrupt_hook = mac_mouse_interrupt; - return 0; -} - -static ssize_t write_mouse(struct file *file, const char *buffer, - size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -static ssize_t read_mouse(struct file *file, char *buffer, size_t count, - loff_t *ppos) -{ - int dx, dy, buttons; - - if (count < 3) - return -EINVAL; - if (!mouse.ready) - return -EAGAIN; - dx = mouse.dx; - dy = mouse.dy; - buttons = mouse.buttons; - if (dx > 127) - dx = 127; - else if (dx < -128) - dx = -128; - if (dy > 127) - dy = 127; - else if (dy < -128) - dy = -128; - mouse.dx -= dx; - mouse.dy -= dy; - if (mouse.dx == 0 && mouse.dy == 0) - mouse.ready = 0; - if (put_user(buttons | 0x80, buffer++) || - put_user((char) dx, buffer++) || - put_user((char) dy, buffer++)) - return -EFAULT; - if (count > 3) - if (clear_user(buffer, count - 3)) - return -EFAULT; - return count; -} - -static unsigned int mouse_poll(struct file *file, poll_table *wait) -{ - poll_wait(file, &mouse.wait, wait); - if (mouse.ready) - return POLLIN | POLLRDNORM; - return 0; -} - -struct file_operations mac_mouse_fops = { - NULL, /* mouse_seek */ - read_mouse, - write_mouse, - NULL, /* mouse_readdir */ - mouse_poll, - NULL, /* mouse_ioctl */ - NULL, /* mouse_mmap */ - open_mouse, - NULL, /* flush */ - release_mouse, - NULL, - fasync_mouse, -}; - -#define ADB_MOUSE_MINOR 10 - -static struct miscdevice mac_mouse = { - ADB_MOUSE_MINOR, "adbmouse", &mac_mouse_fops -}; - -__initfunc(int mac_mouse_init(void)) -{ - mouse.active = 0; - mouse.ready = 0; - mouse.wait = NULL; - - if (!MACH_IS_MAC) - return -ENODEV; - - printk(KERN_INFO "Macintosh ADB mouse installed.\n"); - misc_register(&mac_mouse); - return 0; -} - - -#define MIN_THRESHOLD 1 -#define MAX_THRESHOLD 20 /* more seems not reasonable... */ - -__initfunc(void mac_mouse_setup(char *str, int *ints)) -{ - if (ints[0] < 1) { - printk( "mac_mouse_setup: no arguments!\n" ); - return; - } - else if (ints[0] > 2) { - printk( "mac_mouse_setup: too many arguments\n" ); - } - - if (ints[1] < MIN_THRESHOLD || ints[1] > MAX_THRESHOLD) - printk( "mac_mouse_setup: bad threshold value (ignored)\n" ); - else { - mac_mouse_x_threshold = ints[1]; - mac_mouse_y_threshold = ints[1]; - if (ints[0] > 1) { - if (ints[2] < MIN_THRESHOLD || ints[2] > MAX_THRESHOLD) - printk("mac_mouse_setup: bad threshold value (ignored)\n" ); - else - mac_mouse_y_threshold = ints[2]; - } - } - -} - -#ifdef MODULE -#include - -int init_module(void) -{ - return mac_mouse_init(); -} - -void cleanup_module(void) -{ - misc_deregister(&mac_mouse); -} -#endif diff --git a/drivers/char/mem.c b/drivers/char/mem.c index f4cd55fdd870..227eff3e3385 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include diff --git a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c index b49bfe9a6208..07c733b5b448 100644 --- a/drivers/char/msbusmouse.c +++ b/drivers/char/msbusmouse.c @@ -51,6 +51,10 @@ static struct mouse_status mouse; static int mouse_irq = MOUSE_IRQ; +#ifdef MODULE +MODULE_PARM(mouse_irq, "i"); +#endif + __initfunc(void msmouse_setup(char *str, int *ints)) { if (ints[0] > 0) diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c index c5a5f15c9128..2b0d8f3a7737 100644 --- a/drivers/char/pc_keyb.c +++ b/drivers/char/pc_keyb.c @@ -64,7 +64,7 @@ static volatile unsigned char acknowledge = 0; static volatile unsigned char resend = 0; -#if defined CONFIG_PSMOUSE +#if defined(CONFIG_PSMOUSE) /* * PS/2 Auxiliary Device */ diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c index 720453a87c0b..8984a0fad20e 100644 --- a/drivers/fc4/fc.c +++ b/drivers/fc4/fc.c @@ -1,7 +1,7 @@ /* fc.c: Generic Fibre Channel and FC4 SCSI driver. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 1997,1998 Jiri Hanika (geo@ff.cuni.cz) + * Copyright (C) 1997,1998 Jirka Hanika (geo@ff.cuni.cz) * * Sources: * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994 diff --git a/drivers/fc4/fcp_scsi.h b/drivers/fc4/fcp_scsi.h index 3717740c7cf0..1e194cdf66c9 100644 --- a/drivers/fc4/fcp_scsi.h +++ b/drivers/fc4/fcp_scsi.h @@ -1,7 +1,7 @@ /* fcp_scsi.h: Generic SCSI on top of FC4 - interface defines. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 1998 Jiri Hanika (geo@ff.cuni.cz) + * Copyright (C) 1998 Jirka Hanika (geo@ff.cuni.cz) */ #ifndef _FCP_SCSI_H diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c index 3d23f6b1954b..2f9bfbc89665 100644 --- a/drivers/fc4/soc.c +++ b/drivers/fc4/soc.c @@ -1,7 +1,7 @@ /* soc.c: Sparc SUNW,soc (Serial Optical Channel) Fibre Channel Sbus adapter support. * * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 1997,1998 Jiri Hanika (geo@ff.cuni.cz) + * Copyright (C) 1997,1998 Jirka Hanika (geo@ff.cuni.cz) * * Sources: * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994 @@ -20,7 +20,7 @@ */ static char *version = - "soc.c:v1.2 27/Feb/98 Jakub Jelinek (jj@sunsite.mff.cuni.cz), Jiri Hanika (geo@ff.cuni.cz)\n"; + "soc.c:v1.2 27/Feb/98 Jakub Jelinek (jj@sunsite.mff.cuni.cz), Jirka Hanika (geo@ff.cuni.cz)\n"; #include #include diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 75a2e37ad82d..9f922c43e9d0 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -684,7 +684,6 @@ cleanup_module(void) void *priv = dev->priv; /* NB: el2_close() handles free_irq */ release_region(dev->base_addr, EL2_IO_EXTENT); - dev->priv = NULL; unregister_netdev(dev); kfree(priv); } diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c index d95d34a4a808..529158e81649 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -449,7 +449,6 @@ cleanup_module(void) void *priv = dev->priv; /* NB: e21_close() handles free_irq */ release_region(dev->base_addr, E21_IO_EXTENT); - dev->priv = NULL; unregister_netdev(dev); kfree(priv); } diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index 6aeb146db242..f57e76cda918 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -439,7 +439,6 @@ cleanup_module(void) void *priv = dev->priv; free_irq(dev->irq, dev); release_region(dev->base_addr, ES_IO_EXTENT); - dev->priv = NULL; unregister_netdev(dev); kfree(priv); } diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index 55506e0ef3c3..bcb76242a9d6 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -474,7 +474,6 @@ cleanup_module(void) void *priv = dev->priv; /* NB: hpp_close() handles free_irq */ release_region(ioaddr, HP_IO_EXTENT); - dev->priv = NULL; unregister_netdev(dev); kfree(priv); } diff --git a/drivers/net/hp.c b/drivers/net/hp.c index a7dcba56b10c..8963b5562651 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -445,7 +445,6 @@ cleanup_module(void) void *priv = dev->priv; free_irq(dev->irq, dev); release_region(ioaddr, HP_IO_EXTENT); - dev->priv = NULL; unregister_netdev(dev); kfree(priv); } diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 1d3b02a86e39..1fa60e04d518 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -430,7 +430,6 @@ void cleanup_module(void) release_region(dev->base_addr, LNE390_IO_EXTENT); if (ei_status.reg0) iounmap((void *)dev->mem_start); - dev->priv = NULL; unregister_netdev(dev); kfree(priv); } diff --git a/drivers/net/ltpc.c b/drivers/net/ltpc.c index c90f059451af..e2b37a3b4e71 100644 --- a/drivers/net/ltpc.c +++ b/drivers/net/ltpc.c @@ -1059,14 +1059,14 @@ __initfunc(int ltpc_probe_dma(int base)) inb_p(io+1); inb_p(io+0); - timeout = jiffies+100; - while(timeout>jiffies) { + timeout = jiffies+100*HZ/100; + while(time_before(jiffies, timeout)) { if ( 0xfa == inb_p(io+6) ) break; } inb_p(io+3); inb_p(io+2); - while(timeout>jiffies) { + while(time_before(jiffies, timeout)) { if ( 0xfb == inb_p(io+6) ) break; } @@ -1161,8 +1161,8 @@ __initfunc(int ltpc_probe(struct device *dev)) inb_p(io+1); inb_p(io+3); - timeout = jiffies+2; - while(timeout>jiffies) ; /* hold it in reset for a coupla jiffies */ + timeout = jiffies+2*HZ/100; + while(time_before(jiffies, timeout)) ; /* hold it in reset for a coupla jiffies */ inb_p(io+0); inb_p(io+2); inb_p(io+7); /* clear reset */ @@ -1171,9 +1171,9 @@ __initfunc(int ltpc_probe(struct device *dev)) inb_p(io+5); /* enable dma */ inb_p(io+6); /* tri-state interrupt line */ - timeout = jiffies+100; + timeout = jiffies+100*HZ/100; - while(timeout>jiffies) { + while(time_before(jiffies, timeout)) { /* wait for the card to complete initialization */ } @@ -1220,8 +1220,8 @@ __initfunc(int ltpc_probe(struct device *dev)) (void) inb_p(io+3); (void) inb_p(io+2); - timeout = jiffies+100; - while(timeout>jiffies) { + timeout = jiffies+100*HZ/100; + while(time_before(jiffies, timeout)) { if( 0xf9 == inb_p(io+6)) break; } diff --git a/drivers/net/ne.c b/drivers/net/ne.c index ab284bf09f26..36b9123e8aa2 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -68,8 +68,9 @@ static const char *version = /* A zero-terminated list of I/O addresses to be probed at boot. */ #ifndef MODULE -static unsigned int netcard_portlist[] __initdata = -{ 0x300, 0x280, 0x320, 0x340, 0x360, 0x380, 0}; +static unsigned int netcard_portlist[] __initdata = { + 0x300, 0x280, 0x320, 0x340, 0x360, 0x380, 0 +}; #endif #ifdef CONFIG_PCI @@ -85,6 +86,8 @@ pci_clone_list[] __initdata = { {PCI_VENDOR_ID_SURECOM, PCI_DEVICE_ID_SURECOM_NE34, "SureCom NE34"}, {0,} }; + +static int probe_pci = 1; #endif #ifdef SUPPORT_NE_BAD_CLONES @@ -175,32 +178,32 @@ struct netdev_entry netcard_drv = __initfunc(int ne_probe(struct device *dev)) { - int base_addr = dev ? dev->base_addr : 0; + int base_addr = dev ? dev->base_addr : 0; - /* First check any supplied i/o locations. User knows best. */ - if (base_addr > 0x1ff) /* Check a single specified location. */ - return ne_probe1(dev, base_addr); - else if (base_addr != 0) /* Don't probe at all. */ - return ENXIO; + /* First check any supplied i/o locations. User knows best. */ + if (base_addr > 0x1ff) /* Check a single specified location. */ + return ne_probe1(dev, base_addr); + else if (base_addr != 0) /* Don't probe at all. */ + return ENXIO; #ifdef CONFIG_PCI - /* Then look for any installed PCI clones */ - if (pci_present() && (ne_probe_pci(dev) == 0)) - return 0; + /* Then look for any installed PCI clones */ + if (probe_pci && pci_present() && (ne_probe_pci(dev) == 0)) + return 0; #endif #ifndef MODULE - /* Last resort. The semi-risky ISA auto-probe. */ - for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) { - int ioaddr = netcard_portlist[base_addr]; - if (check_region(ioaddr, NE_IO_EXTENT)) - continue; - if (ne_probe1(dev, ioaddr) == 0) - return 0; - } + /* Last resort. The semi-risky ISA auto-probe. */ + for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) { + int ioaddr = netcard_portlist[base_addr]; + if (check_region(ioaddr, NE_IO_EXTENT)) + continue; + if (ne_probe1(dev, ioaddr) == 0) + return 0; + } #endif - return ENODEV; + return ENODEV; } #endif @@ -223,7 +226,7 @@ __initfunc(static int ne_probe_pci(struct device *dev)) } if (!pdev) continue; - printk("ne.c: PCI BIOS reports %s at i/o %#x, irq %d.\n", + printk(KERN_INFO "ne.c: PCI BIOS reports %s at i/o %#x, irq %d.\n", pci_clone_list[i].name, pci_ioaddr, pci_irq_line); printk("*\n* Use of the PCI-NE2000 driver with this card is recommended!\n*\n"); @@ -241,61 +244,65 @@ __initfunc(static int ne_probe_pci(struct device *dev)) __initfunc(static int ne_probe1(struct device *dev, int ioaddr)) { - int i; - unsigned char SA_prom[32]; - int wordlength = 2; - const char *name = NULL; - int start_page, stop_page; - int neX000, ctron, bad_card; - int reg0 = inb_p(ioaddr); - static unsigned version_printed = 0; - - if (reg0 == 0xFF) - return ENODEV; - - /* Do a preliminary verification that we have a 8390. */ - { int regd; - outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD); - regd = inb_p(ioaddr + 0x0d); - outb_p(0xff, ioaddr + 0x0d); - outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD); - inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */ - if (inb_p(ioaddr + EN0_COUNTER0) != 0) { - outb_p(reg0, ioaddr); - outb_p(regd, ioaddr + 0x0d); /* Restore the old values. */ - return ENODEV; + int i; + unsigned char SA_prom[32]; + int wordlength = 2; + const char *name = NULL; + int start_page, stop_page; + int neX000, ctron, copam, bad_card; + int reg0 = inb_p(ioaddr); + static unsigned version_printed = 0; + + if (reg0 == 0xFF) + return ENODEV; + + /* Do a preliminary verification that we have a 8390. */ + { + int regd; + outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD); + regd = inb_p(ioaddr + 0x0d); + outb_p(0xff, ioaddr + 0x0d); + outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD); + inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */ + if (inb_p(ioaddr + EN0_COUNTER0) != 0) { + outb_p(reg0, ioaddr); + outb_p(regd, ioaddr + 0x0d); /* Restore the old values. */ + return ENODEV; + } } - } - if (load_8390_module("ne.c")) - return -ENOSYS; + if (load_8390_module("ne.c")) + return -ENOSYS; + + /* We should have a "dev" from Space.c or the static module table. */ + if (dev == NULL) + { + printk(KERN_ERR "ne.c: Passed a NULL device.\n"); + dev = init_etherdev(0, 0); + } - /* We should have a "dev" from Space.c or the static module table. */ - if (dev == NULL) { - printk(KERN_ERR "ne.c: Passed a NULL device.\n"); - dev = init_etherdev(0, 0); - } + if (ei_debug && version_printed++ == 0) + printk(version); - if (ei_debug && version_printed++ == 0) - printk(version); + printk(KERN_INFO "NE*000 ethercard probe at %#3x:", ioaddr); - printk("NE*000 ethercard probe at %#3x:", ioaddr); + /* A user with a poor card that fails to ack the reset, or that + does not have a valid 0x57,0x57 signature can still use this + without having to recompile. Specifying an i/o address along + with an otherwise unused dev->mem_end value of "0xBAD" will + cause the driver to skip these parts of the probe. */ - /* A user with a poor card that fails to ack the reset, or that - does not have a valid 0x57,0x57 signature can still use this - without having to recompile. Specifying an i/o address along - with an otherwise unused dev->mem_end value of "0xBAD" will - cause the driver to skip these parts of the probe. */ + bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad)); - bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad)); + /* Reset card. Who knows what dain-bramaged state it was left in. */ - /* Reset card. Who knows what dain-bramaged state it was left in. */ - { unsigned long reset_start_time = jiffies; + { + unsigned long reset_start_time = jiffies; - /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ - outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET); + /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ + outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET); - while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0) + while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0) if (jiffies - reset_start_time > 2*HZ/100) { if (bad_card) { printk(" (warning: no reset ack)"); @@ -305,252 +312,265 @@ __initfunc(static int ne_probe1(struct device *dev, int ioaddr)) return ENODEV; } } + + outb_p(0xff, ioaddr + EN0_ISR); /* Ack all intr. */ + } + + /* Read the 16 bytes of station address PROM. + We must first initialize registers, similar to NS8390_init(eifdev, 0). + We can't reliably read the SAPROM address without this. + (I learned the hard way!). */ + { + struct {unsigned char value, offset; } program_seq[] = + { + {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ + {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ + {0x00, EN0_RCNTLO}, /* Clear the count regs. */ + {0x00, EN0_RCNTHI}, + {0x00, EN0_IMR}, /* Mask completion irq. */ + {0xFF, EN0_ISR}, + {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ + {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ + {32, EN0_RCNTLO}, + {0x00, EN0_RCNTHI}, + {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ + {0x00, EN0_RSARHI}, + {E8390_RREAD+E8390_START, E8390_CMD}, + }; + + for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); - outb_p(0xff, ioaddr + EN0_ISR); /* Ack all intr. */ - } - - /* Read the 16 bytes of station address PROM. - We must first initialize registers, similar to NS8390_init(eifdev, 0). - We can't reliably read the SAPROM address without this. - (I learned the hard way!). */ - { - struct {unsigned char value, offset; } program_seq[] = { - {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ - {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ - {0x00, EN0_RCNTLO}, /* Clear the count regs. */ - {0x00, EN0_RCNTHI}, - {0x00, EN0_IMR}, /* Mask completion irq. */ - {0xFF, EN0_ISR}, - {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ - {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ - {32, EN0_RCNTLO}, - {0x00, EN0_RCNTHI}, - {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ - {0x00, EN0_RSARHI}, - {E8390_RREAD+E8390_START, E8390_CMD}, - }; - for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) - outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); - - } - for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) { - SA_prom[i] = inb(ioaddr + NE_DATAPORT); - SA_prom[i+1] = inb(ioaddr + NE_DATAPORT); - if (SA_prom[i] != SA_prom[i+1]) - wordlength = 1; - } - - /* At this point, wordlength *only* tells us if the SA_prom is doubled - up or not because some broken PCI cards don't respect the byte-wide - request in program_seq above, and hence don't have doubled up values. - These broken cards would otherwise be detected as an ne1000. */ - - if (wordlength == 2) - for (i = 0; i < 16; i++) - SA_prom[i] = SA_prom[i+i]; - - if (pci_irq_line || ioaddr >= 0x400) - wordlength = 2; /* Catch broken PCI cards mentioned above. */ - - if (wordlength == 2) { - /* We must set the 8390 for word mode. */ - outb_p(0x49, ioaddr + EN0_DCFG); - start_page = NESM_START_PG; - stop_page = NESM_STOP_PG; - } else { - start_page = NE1SM_START_PG; - stop_page = NE1SM_STOP_PG; - } - - neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57); - ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d); - - /* Set up the rest of the parameters. */ - if (neX000 || bad_card) { - name = (wordlength == 2) ? "NE2000" : "NE1000"; - } else if (ctron) { - name = (wordlength == 2) ? "Ctron-8" : "Ctron-16"; - start_page = 0x01; - stop_page = (wordlength == 2) ? 0x40 : 0x20; - } else { -#ifdef SUPPORT_NE_BAD_CLONES - /* Ack! Well, there might be a *bad* NE*000 clone there. - Check for total bogus addresses. */ - for (i = 0; bad_clone_list[i].name8; i++) { - if (SA_prom[0] == bad_clone_list[i].SAprefix[0] && - SA_prom[1] == bad_clone_list[i].SAprefix[1] && - SA_prom[2] == bad_clone_list[i].SAprefix[2]) { - if (wordlength == 2) { - name = bad_clone_list[i].name16; - } else { - name = bad_clone_list[i].name8; - } - break; - } } - if (bad_clone_list[i].name8 == NULL) { - printk(" not found (invalid signature %2.2x %2.2x).\n", - SA_prom[14], SA_prom[15]); - return ENXIO; + for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) { + SA_prom[i] = inb(ioaddr + NE_DATAPORT); + SA_prom[i+1] = inb(ioaddr + NE_DATAPORT); + if (SA_prom[i] != SA_prom[i+1]) + wordlength = 1; } + + /* At this point, wordlength *only* tells us if the SA_prom is doubled + up or not because some broken PCI cards don't respect the byte-wide + request in program_seq above, and hence don't have doubled up values. + These broken cards would otherwise be detected as an ne1000. */ + + if (wordlength == 2) + for (i = 0; i < 16; i++) + SA_prom[i] = SA_prom[i+i]; + + if (pci_irq_line || ioaddr >= 0x400) + wordlength = 2; /* Catch broken PCI cards mentioned above. */ + + if (wordlength == 2) + { + /* We must set the 8390 for word mode. */ + outb_p(0x49, ioaddr + EN0_DCFG); + start_page = NESM_START_PG; + stop_page = NESM_STOP_PG; + } else { + start_page = NE1SM_START_PG; + stop_page = NE1SM_STOP_PG; + } + + neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57); + ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d); + copam = (SA_prom[14] == 0x49 && SA_prom[15] == 0x00); + + + /* Set up the rest of the parameters. */ + if (neX000 || bad_card || copam) { + name = (wordlength == 2) ? "NE2000" : "NE1000"; + } + else if (ctron) + { + name = (wordlength == 2) ? "Ctron-8" : "Ctron-16"; + start_page = 0x01; + stop_page = (wordlength == 2) ? 0x40 : 0x20; + } + else + { +#ifdef SUPPORT_NE_BAD_CLONES + /* Ack! Well, there might be a *bad* NE*000 clone there. + Check for total bogus addresses. */ + for (i = 0; bad_clone_list[i].name8; i++) + { + if (SA_prom[0] == bad_clone_list[i].SAprefix[0] && + SA_prom[1] == bad_clone_list[i].SAprefix[1] && + SA_prom[2] == bad_clone_list[i].SAprefix[2]) + { + if (wordlength == 2) + { + name = bad_clone_list[i].name16; + } else { + name = bad_clone_list[i].name8; + } + break; + } + } + if (bad_clone_list[i].name8 == NULL) + { + printk(" not found (invalid signature %2.2x %2.2x).\n", + SA_prom[14], SA_prom[15]); + return ENXIO; + } #else - printk(" not found.\n"); - return ENXIO; + printk(" not found.\n"); + return ENXIO; #endif + } - } - - if (pci_irq_line) - dev->irq = pci_irq_line; - - if (dev->irq < 2) { - autoirq_setup(0); - outb_p(0x50, ioaddr + EN0_IMR); /* Enable one interrupt. */ - outb_p(0x00, ioaddr + EN0_RCNTLO); - outb_p(0x00, ioaddr + EN0_RCNTHI); - outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */ - mdelay(10); /* wait 10ms for interrupt to propagate */ - outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */ - dev->irq = autoirq_report(0); - if (ei_debug > 2) - printk(" autoirq is %d\n", dev->irq); - } else if (dev->irq == 2) - /* Fixup for users that don't know that IRQ 2 is really IRQ 9, - or don't know which one to set. */ - dev->irq = 9; - - if (! dev->irq) { - printk(" failed to detect IRQ line.\n"); - return EAGAIN; - } - - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) { - printk (" unable to get memory for dev->priv.\n"); - return -ENOMEM; - } + if (pci_irq_line) + dev->irq = pci_irq_line; + + if (dev->irq < 2) + { + autoirq_setup(0); + outb_p(0x50, ioaddr + EN0_IMR); /* Enable one interrupt. */ + outb_p(0x00, ioaddr + EN0_RCNTLO); + outb_p(0x00, ioaddr + EN0_RCNTHI); + outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */ + mdelay(10); /* wait 10ms for interrupt to propagate */ + outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */ + dev->irq = autoirq_report(0); + if (ei_debug > 2) + printk(" autoirq is %d\n", dev->irq); + } else if (dev->irq == 2) + /* Fixup for users that don't know that IRQ 2 is really IRQ 9, + or don't know which one to set. */ + dev->irq = 9; + + if (! dev->irq) { + printk(" failed to detect IRQ line.\n"); + return EAGAIN; + } + + /* Allocate dev->priv and fill in 8390 specific dev fields. */ + if (ethdev_init(dev)) + { + printk (" unable to get memory for dev->priv.\n"); + return -ENOMEM; + } - /* Snarf the interrupt now. There's no point in waiting since we cannot - share and the board will usually be enabled. */ - { - int irqval = request_irq(dev->irq, ei_interrupt, - pci_irq_line ? SA_SHIRQ : 0, name, dev); - if (irqval) { - printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval); + /* Snarf the interrupt now. There's no point in waiting since we cannot + share and the board will usually be enabled. */ - kfree(dev->priv); - dev->priv = NULL; - return EAGAIN; + { + int irqval = request_irq(dev->irq, ei_interrupt, + pci_irq_line ? SA_SHIRQ : 0, name, dev); + if (irqval) { + printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval); + kfree(dev->priv); + dev->priv = NULL; + return EAGAIN; + } } - } - dev->base_addr = ioaddr; - request_region(ioaddr, NE_IO_EXTENT, name); + dev->base_addr = ioaddr; + request_region(ioaddr, NE_IO_EXTENT, name); - for(i = 0; i < ETHER_ADDR_LEN; i++) { - printk(" %2.2x", SA_prom[i]); - dev->dev_addr[i] = SA_prom[i]; - } + for(i = 0; i < ETHER_ADDR_LEN; i++) { + printk(" %2.2x", SA_prom[i]); + dev->dev_addr[i] = SA_prom[i]; + } - printk("\n%s: %s found at %#x, using IRQ %d.\n", - dev->name, name, ioaddr, dev->irq); + printk("\n%s: %s found at %#x, using IRQ %d.\n", + dev->name, name, ioaddr, dev->irq); - ei_status.name = name; - ei_status.tx_start_page = start_page; - ei_status.stop_page = stop_page; - ei_status.word16 = (wordlength == 2); + ei_status.name = name; + ei_status.tx_start_page = start_page; + ei_status.stop_page = stop_page; + ei_status.word16 = (wordlength == 2); - ei_status.rx_start_page = start_page + TX_PAGES; + ei_status.rx_start_page = start_page + TX_PAGES; #ifdef PACKETBUF_MEMSIZE - /* Allow the packet buffer size to be overridden by know-it-alls. */ - ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE; + /* Allow the packet buffer size to be overridden by know-it-alls. */ + ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE; #endif - ei_status.reset_8390 = &ne_reset_8390; - ei_status.block_input = &ne_block_input; - ei_status.block_output = &ne_block_output; - ei_status.get_8390_hdr = &ne_get_8390_hdr; - dev->open = &ne_open; - dev->stop = &ne_close; - NS8390_init(dev, 0); - return 0; + ei_status.reset_8390 = &ne_reset_8390; + ei_status.block_input = &ne_block_input; + ei_status.block_output = &ne_block_output; + ei_status.get_8390_hdr = &ne_get_8390_hdr; + dev->open = &ne_open; + dev->stop = &ne_close; + NS8390_init(dev, 0); + return 0; } -static int -ne_open(struct device *dev) +static int ne_open(struct device *dev) { - ei_open(dev); - MOD_INC_USE_COUNT; - return 0; + ei_open(dev); + MOD_INC_USE_COUNT; + return 0; } -static int -ne_close(struct device *dev) +static int ne_close(struct device *dev) { - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); - ei_close(dev); - MOD_DEC_USE_COUNT; - return 0; + if (ei_debug > 1) + printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name); + ei_close(dev); + MOD_DEC_USE_COUNT; + return 0; } /* Hard reset the card. This used to pause for the same period that a 8390 reset command required, but that shouldn't be necessary. */ -static void -ne_reset_8390(struct device *dev) + +static void ne_reset_8390(struct device *dev) { - unsigned long reset_start_time = jiffies; + unsigned long reset_start_time = jiffies; - if (ei_debug > 1) printk("resetting the 8390 t=%ld...", jiffies); + if (ei_debug > 1) + printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies); - /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ - outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); + /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ + outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); - ei_status.txing = 0; - ei_status.dmaing = 0; + ei_status.txing = 0; + ei_status.dmaing = 0; - /* This check _should_not_ be necessary, omit eventually. */ - while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2*HZ/100) { - printk("%s: ne_reset_8390() did not complete.\n", dev->name); - break; - } - outb_p(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */ + /* This check _should_not_ be necessary, omit eventually. */ + while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) + if (jiffies - reset_start_time > 2*HZ/100) { + printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name); + break; + } + outb_p(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */ } /* Grab the 8390 specific header. Similar to the block_input routine, but we don't need to be concerned with ring wrap as the header will be at the start of a page, so we optimize accordingly. */ -static void -ne_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) +static void ne_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) { + int nic_base = dev->base_addr; - int nic_base = dev->base_addr; + /* This *shouldn't* happen. If it does, it's the last thing you'll see */ - /* This *shouldn't* happen. If it does, it's the last thing you'll see */ - if (ei_status.dmaing) { - printk("%s: DMAing conflict in ne_get_8390_hdr " - "[DMAstat:%d][irqlock:%d][intr:%ld].\n", - dev->name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); - return; - } - - ei_status.dmaing |= 0x01; - outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); - outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO); - outb_p(0, nic_base + EN0_RCNTHI); - outb_p(0, nic_base + EN0_RSARLO); /* On page boundary */ - outb_p(ring_page, nic_base + EN0_RSARHI); - outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); - - if (ei_status.word16) - insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1); - else - insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)); - - outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ - ei_status.dmaing &= ~0x01; + if (ei_status.dmaing) + { + printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr " + "[DMAstat:%d][irqlock:%d][intr:%ld].\n", + dev->name, ei_status.dmaing, ei_status.irqlock, + dev->interrupt); + return; + } + + ei_status.dmaing |= 0x01; + outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); + outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO); + outb_p(0, nic_base + EN0_RCNTHI); + outb_p(0, nic_base + EN0_RSARLO); /* On page boundary */ + outb_p(ring_page, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); + + if (ei_status.word16) + insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1); + else + insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)); + + outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x01; } /* Block input and output, similar to the Crynwr packet driver. If you @@ -558,164 +578,176 @@ ne_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) The NEx000 doesn't share the on-board packet memory -- you have to put the packet out through the "remote DMA" dataport using outb. */ -static void -ne_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset) +static void ne_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset) { #ifdef NE_SANITY_CHECK - int xfer_count = count; + int xfer_count = count; #endif - int nic_base = dev->base_addr; - char *buf = skb->data; - - /* This *shouldn't* happen. If it does, it's the last thing you'll see */ - if (ei_status.dmaing) { - printk("%s: DMAing conflict in ne_block_input " - "[DMAstat:%d][irqlock:%d][intr:%ld].\n", - dev->name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); - return; - } - ei_status.dmaing |= 0x01; - outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); - outb_p(count & 0xff, nic_base + EN0_RCNTLO); - outb_p(count >> 8, nic_base + EN0_RCNTHI); - outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); - outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); - outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); - if (ei_status.word16) { - insw(NE_BASE + NE_DATAPORT,buf,count>>1); - if (count & 0x01) { - buf[count-1] = inb(NE_BASE + NE_DATAPORT); + int nic_base = dev->base_addr; + char *buf = skb->data; + + /* This *shouldn't* happen. If it does, it's the last thing you'll see */ + if (ei_status.dmaing) + { + printk(KERN_EMERG "%s: DMAing conflict in ne_block_input " + "[DMAstat:%d][irqlock:%d][intr:%ld].\n", + dev->name, ei_status.dmaing, ei_status.irqlock, + dev->interrupt); + return; + } + ei_status.dmaing |= 0x01; + outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); + outb_p(count & 0xff, nic_base + EN0_RCNTLO); + outb_p(count >> 8, nic_base + EN0_RCNTHI); + outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); + outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); + if (ei_status.word16) + { + insw(NE_BASE + NE_DATAPORT,buf,count>>1); + if (count & 0x01) + { + buf[count-1] = inb(NE_BASE + NE_DATAPORT); #ifdef NE_SANITY_CHECK - xfer_count++; + xfer_count++; #endif - } - } else { - insb(NE_BASE + NE_DATAPORT, buf, count); - } + } + } else { + insb(NE_BASE + NE_DATAPORT, buf, count); + } #ifdef NE_SANITY_CHECK - /* This was for the ALPHA version only, but enough people have - been encountering problems so it is still here. If you see - this message you either 1) have a slightly incompatible clone - or 2) have noise/speed problems with your bus. */ - if (ei_debug > 1) { /* DMA termination address check... */ - int addr, tries = 20; - do { - /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here - -- it's broken for Rx on some cards! */ - int high = inb_p(nic_base + EN0_RSARHI); - int low = inb_p(nic_base + EN0_RSARLO); - addr = (high << 8) + low; - if (((ring_offset + xfer_count) & 0xff) == low) - break; - } while (--tries > 0); - if (tries <= 0) - printk("%s: RX transfer address mismatch," - "%#4.4x (expected) vs. %#4.4x (actual).\n", - dev->name, ring_offset + xfer_count, addr); - } + /* This was for the ALPHA version only, but enough people have + been encountering problems so it is still here. If you see + this message you either 1) have a slightly incompatible clone + or 2) have noise/speed problems with your bus. */ + + if (ei_debug > 1) + { + /* DMA termination address check... */ + int addr, tries = 20; + do { + /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here + -- it's broken for Rx on some cards! */ + int high = inb_p(nic_base + EN0_RSARHI); + int low = inb_p(nic_base + EN0_RSARLO); + addr = (high << 8) + low; + if (((ring_offset + xfer_count) & 0xff) == low) + break; + } while (--tries > 0); + if (tries <= 0) + printk(KERN_WARNING "%s: RX transfer address mismatch," + "%#4.4x (expected) vs. %#4.4x (actual).\n", + dev->name, ring_offset + xfer_count, addr); + } #endif - outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ - ei_status.dmaing &= ~0x01; + outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x01; } -static void -ne_block_output(struct device *dev, int count, +static void ne_block_output(struct device *dev, int count, const unsigned char *buf, const int start_page) { - int nic_base = NE_BASE; - unsigned long dma_start; + int nic_base = NE_BASE; + unsigned long dma_start; #ifdef NE_SANITY_CHECK - int retries = 0; + int retries = 0; #endif - /* Round the count up for word writes. Do we need to do this? - What effect will an odd byte count have on the 8390? - I should check someday. */ - if (ei_status.word16 && (count & 0x01)) - count++; - - /* This *shouldn't* happen. If it does, it's the last thing you'll see */ - if (ei_status.dmaing) { - printk("%s: DMAing conflict in ne_block_output." - "[DMAstat:%d][irqlock:%d][intr:%ld]\n", - dev->name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); - return; - } - ei_status.dmaing |= 0x01; - /* We should already be in page 0, but to be safe... */ - outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); + /* Round the count up for word writes. Do we need to do this? + What effect will an odd byte count have on the 8390? + I should check someday. */ + + if (ei_status.word16 && (count & 0x01)) + count++; + + /* This *shouldn't* happen. If it does, it's the last thing you'll see */ + if (ei_status.dmaing) + { + printk(KERN_EMERG "%s: DMAing conflict in ne_block_output." + "[DMAstat:%d][irqlock:%d][intr:%ld]\n", + dev->name, ei_status.dmaing, ei_status.irqlock, + dev->interrupt); + return; + } + ei_status.dmaing |= 0x01; + /* We should already be in page 0, but to be safe... */ + outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); #ifdef NE_SANITY_CHECK - retry: +retry: #endif #ifdef NE8390_RW_BUGFIX - /* Handle the read-before-write bug the same way as the - Crynwr packet driver -- the NatSemi method doesn't work. - Actually this doesn't always work either, but if you have - problems with your NEx000 this is better than nothing! */ - outb_p(0x42, nic_base + EN0_RCNTLO); - outb_p(0x00, nic_base + EN0_RCNTHI); - outb_p(0x42, nic_base + EN0_RSARLO); - outb_p(0x00, nic_base + EN0_RSARHI); - outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); - /* Make certain that the dummy read has occurred. */ - udelay(6); + /* Handle the read-before-write bug the same way as the + Crynwr packet driver -- the NatSemi method doesn't work. + Actually this doesn't always work either, but if you have + problems with your NEx000 this is better than nothing! */ + + outb_p(0x42, nic_base + EN0_RCNTLO); + outb_p(0x00, nic_base + EN0_RCNTHI); + outb_p(0x42, nic_base + EN0_RSARLO); + outb_p(0x00, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); + /* Make certain that the dummy read has occurred. */ + udelay(6); #endif - outb_p(ENISR_RDC, nic_base + EN0_ISR); + outb_p(ENISR_RDC, nic_base + EN0_ISR); - /* Now the normal output. */ - outb_p(count & 0xff, nic_base + EN0_RCNTLO); - outb_p(count >> 8, nic_base + EN0_RCNTHI); - outb_p(0x00, nic_base + EN0_RSARLO); - outb_p(start_page, nic_base + EN0_RSARHI); + /* Now the normal output. */ + outb_p(count & 0xff, nic_base + EN0_RCNTLO); + outb_p(count >> 8, nic_base + EN0_RCNTHI); + outb_p(0x00, nic_base + EN0_RSARLO); + outb_p(start_page, nic_base + EN0_RSARHI); - outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD); - if (ei_status.word16) { - outsw(NE_BASE + NE_DATAPORT, buf, count>>1); - } else { - outsb(NE_BASE + NE_DATAPORT, buf, count); - } + outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD); + if (ei_status.word16) { + outsw(NE_BASE + NE_DATAPORT, buf, count>>1); + } else { + outsb(NE_BASE + NE_DATAPORT, buf, count); + } - dma_start = jiffies; + dma_start = jiffies; #ifdef NE_SANITY_CHECK - /* This was for the ALPHA version only, but enough people have - been encountering problems so it is still here. */ - if (ei_debug > 1) { /* DMA termination address check... */ - int addr, tries = 20; - do { - int high = inb_p(nic_base + EN0_RSARHI); - int low = inb_p(nic_base + EN0_RSARLO); - addr = (high << 8) + low; - if ((start_page << 8) + count == addr) - break; - } while (--tries > 0); - if (tries <= 0) { - printk("%s: Tx packet transfer address mismatch," - "%#4.4x (expected) vs. %#4.4x (actual).\n", - dev->name, (start_page << 8) + count, addr); - if (retries++ == 0) - goto retry; + /* This was for the ALPHA version only, but enough people have + been encountering problems so it is still here. */ + + if (ei_debug > 1) + { + /* DMA termination address check... */ + int addr, tries = 20; + do { + int high = inb_p(nic_base + EN0_RSARHI); + int low = inb_p(nic_base + EN0_RSARLO); + addr = (high << 8) + low; + if ((start_page << 8) + count == addr) + break; + } while (--tries > 0); + + if (tries <= 0) + { + printk(KERN_WARNING "%s: Tx packet transfer address mismatch," + "%#4.4x (expected) vs. %#4.4x (actual).\n", + dev->name, (start_page << 8) + count, addr); + if (retries++ == 0) + goto retry; + } } - } #endif - while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0) - if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ - printk("%s: timeout waiting for Tx RDC.\n", dev->name); - ne_reset_8390(dev); - NS8390_init(dev,1); - break; - } + while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0) + if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ + printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name); + ne_reset_8390(dev); + NS8390_init(dev,1); + break; + } - outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ - ei_status.dmaing &= ~0x01; - return; + outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x01; + return; } @@ -740,13 +772,16 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); +#ifdef CONFIG_PCI +MODULE_PARM(probe_pci, "i"); +#endif + /* This is set up so that no ISA autoprobe takes place. We can't guarantee that the ne2k probe is the last 8390 based probe to take place (as it is at boot) and so the probe will get confused by any other 8390 cards. ISA device autoprobes on a running machine are not recommended anyway. */ -int -init_module(void) +int init_module(void) { int this_dev, found = 0; @@ -775,8 +810,7 @@ init_module(void) return 0; } -void -cleanup_module(void) +void cleanup_module(void) { int this_dev; @@ -786,7 +820,6 @@ cleanup_module(void) void *priv = dev->priv; free_irq(dev->irq, dev); release_region(dev->base_addr, NE_IO_EXTENT); - dev->priv = NULL; unregister_netdev(dev); kfree(priv); } diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index 429699c34610..1bcaac3b44d3 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -677,10 +677,7 @@ void cleanup_module(void) mca_mark_as_unused(ei_status.priv); mca_set_adapter_procfn( ei_status.priv, NULL, NULL); kfree(dev->priv); - dev->priv = NULL; free_irq(dev->irq, dev); - /* removed (temporary) fot */ - /* irq2dev_map[dev->irq] = NULL; */ release_region(dev->base_addr, NE_IO_EXTENT); unregister_netdev(dev); } diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index d5764928a267..eb3098095223 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -421,7 +421,6 @@ void cleanup_module(void) release_region(dev->base_addr, NE3210_IO_EXTENT); if (ei_status.reg0) iounmap((void *)dev->mem_start); - dev->priv = NULL; unregister_netdev(dev); kfree(priv); } diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index cd10798a2bde..a588a1b9a4fb 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -375,7 +375,6 @@ void cleanup_module(void) /* NB: ultra_close_card() does free_irq */ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; release_region(ioaddr, ULTRA_IO_EXTENT); - dev->priv = NULL; unregister_netdev(dev); kfree(priv); } diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index f51ced5ad040..dbb30af09f3d 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -483,7 +483,6 @@ cleanup_module(void) void *priv = dev->priv; /* NB: ultra_close_card() does free_irq */ release_region(ioaddr, ULTRA_IO_EXTENT); - dev->priv = NULL; unregister_netdev(dev); kfree(priv); } diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c index 64772c48c723..f78f02a6e03c 100644 --- a/drivers/net/smc-ultra32.c +++ b/drivers/net/smc-ultra32.c @@ -413,7 +413,6 @@ void cleanup_module(void) void *priv = dev->priv; /* NB: ultra32_close_card() does free_irq */ release_region(ioaddr, ULTRA32_IO_EXTENT); - dev->priv = NULL; unregister_netdev(dev); kfree(priv); } diff --git a/drivers/net/z85230.c b/drivers/net/z85230.c index 26cf57793a6a..9fd3dd20ad1e 100644 --- a/drivers/net/z85230.c +++ b/drivers/net/z85230.c @@ -605,7 +605,7 @@ static char reg_init[16]= int z8530_sync_open(struct device *dev, struct z8530_channel *c) { c->sync = 1; - c->mtu = dev->mtu; + c->mtu = dev->mtu+64; c->count = 0; c->skb = NULL; c->skb2 = NULL; @@ -641,7 +641,7 @@ int z8530_sync_dma_open(struct device *dev, struct z8530_channel *c) unsigned long flags; c->sync = 1; - c->mtu = dev->mtu; + c->mtu = dev->mtu+64; c->count = 0; c->skb = NULL; c->skb2 = NULL; @@ -822,7 +822,7 @@ int z8530_sync_txdma_open(struct device *dev, struct z8530_channel *c) { printk("Opening sync interface for TX-DMA\n"); c->sync = 1; - c->mtu = dev->mtu; + c->mtu = dev->mtu+64; c->count = 0; c->skb = NULL; c->skb2 = NULL; diff --git a/drivers/pci/pcisyms.c b/drivers/pci/pcisyms.c index f7399c9fb6ce..f26adfc7c949 100644 --- a/drivers/pci/pcisyms.c +++ b/drivers/pci/pcisyms.c @@ -9,6 +9,7 @@ #include #include #include +#include /* isa_dma_bridge_buggy */ EXPORT_SYMBOL(pcibios_present); EXPORT_SYMBOL(pcibios_read_config_byte); @@ -38,3 +39,10 @@ EXPORT_SYMBOL(pci_proc_detach_device); EXPORT_SYMBOL(pcibios_find_class); EXPORT_SYMBOL(pcibios_find_device); + +/* Quirk info */ + +#ifdef CONFIG_PCI_QUIRKS +EXPORT_SYMBOL(isa_dma_bridge_buggy); +#endif + diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 77ef16f917a2..18e27f46a705 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -125,6 +125,25 @@ __initfunc(static void quirk_passive_release(struct pci_dev *dev, int arg)) } } +/* The VIA VP2/VP3/MVP3 seem to have some 'features'. There may be a workaround + but VIA don't answer queries. If you happen to have good contacts at VIA + ask them for me please -- Alan + + This appears to be BIOS not version dependant. So presumably there is a + chipset level fix */ + + +int isa_dma_bridge_buggy = 0; /* Exported */ + +__initfunc(static void quirk_isa_dma_hangs(struct pci_dev *dev, int arg)) +{ + if(!isa_dma_bridge_buggy) + { + isa_dma_bridge_buggy=1; + printk(KERN_INFO "Activating ISA DMA hang workarounds.\n"); + } +} + typedef void (*quirk_handler)(struct pci_dev *, int); @@ -141,7 +160,8 @@ static struct quirk_name quirk_names[] __initdata = { #ifdef CONFIG_PCI_OPTIMIZE { quirk_bridge, "Bridge optimization" }, #endif - { quirk_passive_release, "Passive release enable" }, + { quirk_passive_release,"Passive release enable" }, + { quirk_isa_dma_hangs, "Work around ISA DMA hangs" }, }; @@ -176,6 +196,12 @@ static struct quirk_info quirk_list[] __initdata = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82430, quirk_bridge, 0x00 }, #endif { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release, 0x00 }, + /* + * Its not totally clear which chipsets are the problematic ones + * This is the 82C586 variants. At the moment the 596 is an unknown + * quantity + */ + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs, 0x00 }, }; __initfunc(void pci_quirks_init(void)) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 2088c0ede5d7..2a32b19e65d5 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -7,6 +7,8 @@ * Subsequent revisions: Eric Youngdale * * + * + * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli */ @@ -581,6 +583,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){ next_scsi_host++; retval->host_queue = NULL; retval->host_wait = NULL; + retval->resetting = 0; retval->last_reset = 0; retval->irq = 0; retval->dma_channel = 0xff; diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h index 1ed41771b9f1..b70cac30f5cd 100644 --- a/drivers/scsi/hosts.h +++ b/drivers/scsi/hosts.h @@ -14,6 +14,8 @@ * * Further modified by Eric Youngdale to support multiple host adapters * of the same type. + * + * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli */ #ifndef _HOSTS_H @@ -320,6 +322,7 @@ struct Scsi_Host /* public: */ unsigned short extra_bytes; unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ + int resetting; /* if set, it means that last_reset is a valid value */ unsigned long last_reset; diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 7bb8f961a201..689ddb0743c5 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -186,7 +186,7 @@ int imm_detect(Scsi_Host_Template * host) while (imm_hosts[i].p_busy) { schedule(); /* We are safe to schedule here */ - if (jiffies > now + 3*HZ) + if (time_after(jiffies,now + 3*HZ)) { printk(KERN_ERR "imm%d: failed to claim parport because a " "pardevice is owning the port for too longtime!\n", @@ -831,7 +831,7 @@ static int imm_completion(Scsi_Cmnd * cmd) * If we have been running for more than a full timer tick * then take a rest. */ - if (jiffies > start_jiffies + 1) + if (time_after(jiffies,start_jiffies + 1)) return 0; /* diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index 75ab70e594fa..a3e37481513d 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -147,7 +147,7 @@ int ppa_detect(Scsi_Host_Template * host) while (ppa_hosts[i].p_busy) { schedule(); /* We are safe to schedule here */ - if (jiffies > now + 3*HZ) + if (time_after(jiffies,now + 3*HZ)) { printk(KERN_ERR "ppa%d: failed to claim parport because a " "pardevice is owning the port for too longtime!\n", @@ -867,7 +867,7 @@ static int ppa_completion(Scsi_Cmnd * cmd) * If we have been running for more than a full timer tick * then take a rest. */ - if (jiffies > start_jiffies + 1) + if (time_after(jiffies,start_jiffies + 1)) return 0; if (((r & 0xc0) != 0xc0) || (cmd->SCp.this_residual <= 0)) { diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h index c58dd39b2abd..91e26cd1d4be 100644 --- a/drivers/scsi/ppa.h +++ b/drivers/scsi/ppa.h @@ -159,10 +159,8 @@ int ppa_biosparam(Disk *, kdev_t, int *); release: ppa_release, \ command: ppa_command, \ queuecommand: ppa_queuecommand, \ - eh_abort_handler: ppa_abort, \ - eh_device_reset_handler: NULL, \ - eh_bus_reset_handler: ppa_reset, \ - eh_host_reset_handler: ppa_reset, \ + abort: ppa_abort, \ + reset: ppa_reset, \ bios_param: ppa_biosparam, \ this_id: -1, \ sg_tablesize: SG_ALL, \ diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 1aa855f5138b..f56fdda55cee 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -30,6 +30,8 @@ * Leonard N. Zubkoff * * Converted cli() code to spinlocks, Ingo Molnar + * + * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli */ #include @@ -1297,7 +1299,7 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt) */ timeout = host->last_reset + MIN_RESET_DELAY; - if (jiffies < timeout) { + if (host->resetting && time_before(jiffies, timeout)) { int ticks_remaining = timeout - jiffies; /* * NOTE: This may be executed from within an interrupt @@ -1310,7 +1312,7 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt) */ spin_unlock_irq(&io_request_lock); while (--ticks_remaining >= 0) mdelay(1+999/HZ); - host->last_reset = jiffies - MIN_RESET_DELAY; + host->resetting = 0; spin_lock_irq(&io_request_lock); } @@ -1367,7 +1369,7 @@ inline int internal_cmnd (Scsi_Cmnd * SCpnt) #ifdef DEBUG_DELAY clock = jiffies + 4 * HZ; spin_unlock_irq(&io_request_lock); - while (jiffies < clock) barrier(); + while (time_before(jiffies, clock)) barrier(); spin_lock_irq(&io_request_lock); printk("done(host = %d, result = %04x) : routine at %p\n", host->host_no, temp, host->hostt->command); diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 057963ca6fe6..fd6374cc9696 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -142,7 +142,6 @@ scsi_delete_timer(Scsi_Cmnd * SCset) SCSI_LOG_ERROR_RECOVERY(5,printk("Clearing timer for command %p\n", SCset)); SCset->eh_timeout.data = (unsigned long) NULL; - SCset->eh_timeout.expires = 0; SCset->eh_timeout.function = NULL; return rtn; diff --git a/drivers/scsi/scsi_obsolete.c b/drivers/scsi/scsi_obsolete.c index 064785074f51..2af06f835f46 100644 --- a/drivers/scsi/scsi_obsolete.c +++ b/drivers/scsi/scsi_obsolete.c @@ -607,9 +607,7 @@ void scsi_old_done (Scsi_Cmnd * SCpnt) if ((++SCpnt->retries) < SCpnt->allowed) { if ((SCpnt->retries >= (SCpnt->allowed >> 1)) - /* FIXME: last_reset == 0 is allowed */ - && time_after(jiffies, SCpnt->host->last_reset - + MIN_RESET_PERIOD) + && !(SCpnt->host->resetting && time_before(jiffies, SCpnt->host->last_reset + MIN_RESET_PERIOD)) && !(SCpnt->flags & WAS_RESET)) { printk("scsi%d channel %d : resetting for second half of retries.\n", @@ -617,7 +615,6 @@ void scsi_old_done (Scsi_Cmnd * SCpnt) scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS); break; } - } else { @@ -935,6 +932,12 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) } host->last_reset = jiffies; + host->resetting = 1; + /* + * I suppose that the host reset callback will not play + * with the resetting field. We have just set the resetting + * flag here. -arca + */ temp = host->hostt->reset(SCpnt, reset_flags); /* This test allows the driver to introduce an additional bus @@ -953,7 +956,13 @@ static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) { if (!host->block) host->host_busy++; host->last_reset = jiffies; - SCpnt->flags |= (WAS_RESET | IS_RESETTING); + host->resetting = 1; + SCpnt->flags |= (WAS_RESET | IS_RESETTING); + /* + * I suppose that the host reset callback will not play + * with the resetting field. We have just set the resetting + * flag here. -arca + */ temp = host->hostt->reset(SCpnt, reset_flags); if (time_before(host->last_reset, jiffies) || (time_after(host->last_reset, jiffies + 20 * HZ))) diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index b13122e4e5d6..a49b16805c40 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -15,6 +15,12 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'Joystick support at boot time' CONFIG_SOUND_ES1370_JOYPORT_BOOT fi dep_tristate 'Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND + if [ "$CONFIG_SOUND_ES1371" = "y" ]; then + bool 'Joystick support at boot time' CONFIG_SOUND_ES1371_JOYPORT_BOOT + if [ "$CONFIG_SOUND_ES1371_JOYPORT_BOOT" = "y" ]; then + hex 'Gameport I/O 200,208,210,218' CONFIG_SOUND_ES1371_GAMEPORT 200 + fi + fi dep_tristate 'S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND fi @@ -224,6 +230,17 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then int 'SGALAXY second (duplex) DMA 0, 1 or 3' CONFIG_SGALAXY_DMA2 3 hex 'SGALAXY SB I/O base 220 or 240' CONFIG_SGALAXY_SGBASE 220 fi + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate 'Support for AD1816(A) based cards (EXPERIMENTAL)' CONFIG_SOUND_AD1816 $CONFIG_SOUND + if [ "$CONFIG_SOUND_AD1816" = "y" ]; then + hex 'AD1816 audio I/O base 530, 604, E80 or F40' CONFIG_AD1816_BASE 530 + int 'AD1816 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_AD1816_IRQ 7 + int 'AD1816 audio DMA 0, 1 or 3' CONFIG_AD1816_DMA 0 + int 'AD1816 second (duplex) DMA 0, 1 or 3' CONFIG_AD1816_DMA2 3 + int 'AD1816 clock chip frequency' CONFIG_AD1816_CLOCK 33000 + fi + fi dep_tristate 'Yamaha OPL3-SA1 audio controller' CONFIG_SOUND_OPL3SA1 $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_OPL3SA1" = "y" ]; then @@ -252,7 +269,14 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then fi if [ "$CONFIG_ARM" = "y" ]; then - bool 'VIDC 16-bit sound' CONFIG_VIDC_SOUND + dep_tristate 'VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS + dep_tristate 'Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS + if [ "$CONFIG_SOUND_WAVEARTIST" != "n" ]; then + hex ' WaveArtist I/O base' CONFIG_WAVEARTIST_BASE 250 + int ' WaveArtist IRQ' CONFIG_WAVEARTIST_IRQ 28 + int ' WaveArtist DMA' CONFIG_WAVEARTIST_DMA 3 + int ' WaveArtist second DMA' CONFIG_WAVEARTIST_DMA2 7 + fi fi diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index c4fb47dcef5f..38e4b8a42a56 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -25,7 +25,7 @@ endif export-objs := ad1848.o audio_syms.o midi_syms.o mpu401.o \ msnd.o opl3.o sb_card.o sequencer_syms.o \ sound_core.o sound_firmware.o sound_syms.o \ - uart401.o + uart401.o ad1816.o @@ -66,13 +66,16 @@ obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_SB) += sb.o uart401.o obj-$(CONFIG_SOUND_SOFTOSS) += softoss2.o obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o +obj-$(CONFIG_SOUND_AD1816) += ad1816.o obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb.o uart401.o obj-$(CONFIG_SOUND_UART6850) += uart6850.o obj-$(CONFIG_SOUND_VMIDI) += v_midi.o obj-$(CONFIG_SOUND_YM3812) += adlib_card.o opl3.o -obj-$(CONFIG_VIDC_SOUND) += vidc_mod.o +obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o +obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o + #jnx obj-$(CONFIG_SOUND_ES1370) += es1370.o obj-$(CONFIG_SOUND_ES1371) += es1371.o diff --git a/drivers/sound/ad1816.c b/drivers/sound/ad1816.c new file mode 100644 index 000000000000..70af92ce7ec6 --- /dev/null +++ b/drivers/sound/ad1816.c @@ -0,0 +1,1400 @@ +/* + +AD1816 lowlevel sound driver for Linux 2.1.128 (and above) + +Copyright (C) 1998 by Thorsten Knabe +Based on the CS4232/AD1848 driver Copyright (C) by Hannu Savolainen 1993-1996 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +------------------------------------------------------------------------------- +NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! + +This software is still under development. New versions of the driver +are available from: + http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html +or + http://www.tu-darmstadt.de/~tek01/projects/linux.html + +Please report any bugs to: tek@rbg.informatik.tu-darmstadt.de + +------------------------------------------------------------------------------- + +version: 1.1 +cvs: $Header: /home/tek/tmp/CVSROOT/sound21/ad1816.c,v 1.24.2.8 1998/12/04 16:39:46 tek Exp $ +status: experimental +date: 1998/12/04 + +Changes: + Oleg Drokin: Some cleanup of load/unload functions. 1998/11/24 + + Thorsten Knabe: attach and unload rewritten, + some argument checks added 1998/11/30 +*/ + +#include +#include +#include +#include "soundmodule.h" +#include "sound_config.h" + +#ifdef CONFIG_AD1816 + +#define DEBUGNOISE(x) +#define DEBUGINFO(x) +#define DEBUGLOG(x) x +#define DEBUGWARN(x) x + +#define CHECK_FOR_POWER { int timeout=100; \ + while (timeout > 0 && (inb(devc->base)&0x80)!= 0x80) {\ + timeout--; \ + } \ + if (timeout==0) {\ + printk("ad1816: Check for power failed in %s line: %d\n",__FILE__,__LINE__); \ + } \ +} + +/* structure to hold device specific information */ +typedef struct +{ + int base; /* set in attach */ + int irq; + int dma_playback; + int dma_capture; + + int speed; /* open */ + int channels; + int audio_format; + unsigned char format_bits; + int audio_mode; + int opened; + + int recmask; /* setup */ + int supported_devices; + int supported_rec_devices; + unsigned short levels[SOUND_MIXER_NRDEVICES]; + int dev_no; /* this is the # in audio_devs and NOT + in ad1816_info */ + int irq_ok; + int *osp; + +} + +ad1816_info; + +static int nr_ad1816_devs = 0; + +static int ad1816_clockfreq=33000; + +/* for backward mapping of irq to sound device */ + +static volatile char irq2dev[17] = {-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1}; + + +/* supported audio formats */ +static int ad_format_mask = +AFMT_U8 | AFMT_S16_LE | AFMT_S16_BE | AFMT_MU_LAW | AFMT_A_LAW; + +/* array of device info structures */ +static ad1816_info dev_info[MAX_AUDIO_DEV]; + + +/* ------------------------------------------------------------------- */ + +/* functions for easier access to inderect registers */ + +static int ad_read (ad1816_info * devc, int reg) +{ + unsigned long flags; + int result; + + CHECK_FOR_POWER; + + save_flags (flags); /* make register access atomic */ + cli (); + outb ((unsigned char) (reg & 0x3f), devc->base+0); + result = inb(devc->base+2); + result+= inb(devc->base+3)<<8; + restore_flags (flags); + + return (result); +} + + +static void ad_write (ad1816_info * devc, int reg, int data) +{ + unsigned long flags; + + CHECK_FOR_POWER; + + save_flags (flags); /* make register access atomic */ + cli (); + outb ((unsigned char) (reg & 0xff), devc->base+0); + outb ((unsigned char) (data & 0xff),devc->base+2); + outb ((unsigned char) ((data>>8)&0xff),devc->base+3); + restore_flags (flags); + +} + +/* ------------------------------------------------------------------- */ + +/* function interface required by struct audio_driver */ + +static void ad1816_halt_input (int dev) +{ + unsigned long flags; + ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc; + unsigned char buffer; + + DEBUGINFO (printk("ad1816: halt_input called\n")); + + save_flags (flags); + cli (); + + disable_dma(audio_devs[dev]->dmap_in->dma); + + buffer=inb(devc->base+9); + if (buffer & 0x01) { + /* disable capture */ + outb(buffer & ~0x01,devc->base+9); + } + + enable_dma(audio_devs[dev]->dmap_in->dma); + + /* Clear interrupt status */ + outb (~0x40, devc->base+1); + + devc->audio_mode &= ~PCM_ENABLE_INPUT; + restore_flags (flags); +} + +static void ad1816_halt_output (int dev) +{ + unsigned long flags; + ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc; + + unsigned char buffer; + + DEBUGINFO (printk("ad1816: halt_output called!\n")); + + save_flags (flags); + cli (); + /* Mute pcm output */ + ad_write(devc, 4, ad_read(devc,4)|0x8080); + + disable_dma(audio_devs[dev]->dmap_out->dma); + + buffer=inb(devc->base+8); + if (buffer & 0x01) { + /* disable capture */ + outb(buffer & ~0x01,devc->base+8); + } + enable_dma(audio_devs[dev]->dmap_out->dma); + + /* Clear interrupt status */ + outb ((unsigned char)~0x80, devc->base+1); + + devc->audio_mode &= ~PCM_ENABLE_OUTPUT; + restore_flags (flags); +} + +static void ad1816_output_block (int dev, unsigned long buf, + int count, int intrflag) +{ + unsigned long flags; + unsigned long cnt; + ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc; + + DEBUGINFO(printk("ad1816: output_block called buf=%ld count=%d flags=%d\n",buf,count,intrflag)); + + cnt = count/4 - 1; + + save_flags (flags); + cli (); + + /* set transfer count */ + ad_write (devc, 8, cnt & 0xffff); + + devc->audio_mode |= PCM_ENABLE_OUTPUT; + restore_flags (flags); +} + + +static void ad1816_start_input (int dev, unsigned long buf, int count, + int intrflag) +{ + unsigned long flags; + unsigned long cnt; + ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc; + + DEBUGINFO(printk("ad1816: start_input called buf=%ld count=%d flags=%d\n",buf,count,intrflag)); + + cnt = count/4 - 1; + + save_flags (flags); /* make register access atomic */ + cli (); + + /* set transfer count */ + ad_write (devc, 10, cnt & 0xffff); + + devc->audio_mode |= PCM_ENABLE_INPUT; + restore_flags (flags); +} + + +static int ad1816_ioctl (int dev, unsigned int cmd, caddr_t arg) +{ + return -(EINVAL); +} + + +static int ad1816_prepare_for_input (int dev, int bsize, int bcount) +{ + unsigned long flags; + unsigned int freq; + ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc; + unsigned char fmt_bits; + + DEBUGINFO (printk ("ad1816: prepare_for_input called: bsize=%d bcount=%d\n",bsize,bcount)); + + save_flags (flags); + cli (); + + fmt_bits= (devc->format_bits&0x7)<<3; + + /* set mono/stereo mode */ + if (devc->channels > 1) { + fmt_bits |=0x4; + } + + /* set Mono/Stereo in playback/capture register */ + outb( (inb(devc->base+8) & ~0x3C)|fmt_bits, devc->base+8); + outb( (inb(devc->base+9) & ~0x3C)|fmt_bits, devc->base+9); + + /* If compiled into kernel, AD1816_CLOCK is defined, so use it */ +#ifdef AD1816_CLOCK + ad1816_clockfreq=AD1816_CLOCK; +#endif + + /* capture/playback frequency correction for soundcards + with clock chips != 33MHz (allowed range 5 - 100 kHz) */ + + if (ad1816_clockfreq<5000 || ad1816_clockfreq>100000) { + ad1816_clockfreq=33000; + } + + freq=((unsigned int)devc->speed*33000)/ad1816_clockfreq; + + /* write playback/capture speeds */ + ad_write (devc, 2, freq & 0xffff); + ad_write (devc, 3, freq & 0xffff); + + restore_flags (flags); + + ad1816_halt_input(dev); + return 0; +} + +static int ad1816_prepare_for_output (int dev, int bsize, int bcount) +{ + unsigned long flags; + unsigned int freq; + ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc; + unsigned char fmt_bits; + + DEBUGINFO (printk ("ad1816: prepare_for_output called: bsize=%d bcount=%d\n",bsize,bcount)); + + save_flags (flags); /* make register access atomic */ + cli (); + + fmt_bits= (devc->format_bits&0x7)<<3; + /* set mono/stereo mode */ + if (devc->channels > 1) { + fmt_bits |=0x4; + } + + /* write format bits to playback/capture registers */ + outb( (inb(devc->base+8) & ~0x3C)|fmt_bits, devc->base+8); + outb( (inb(devc->base+9) & ~0x3C)|fmt_bits, devc->base+9); + +#ifdef AD1816_CLOCK + ad1816_clockfreq=AD1816_CLOCK; +#endif + + /* capture/playback frequency correction for soundcards + with clock chips != 33MHz (allowed range 5 - 100 kHz)*/ + + if (ad1816_clockfreq<5000 || ad1816_clockfreq>100000) { + ad1816_clockfreq=33000; + } + + freq=((unsigned int)devc->speed*33000)/ad1816_clockfreq; + + /* write playback/capture speeds */ + ad_write (devc, 2, freq & 0xffff); + ad_write (devc, 3, freq & 0xffff); + + restore_flags (flags); + + ad1816_halt_output(dev); + return 0; + +} + +static void ad1816_trigger (int dev, int state) +{ + unsigned long flags; + ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc; + + DEBUGINFO (printk("ad1816: trigger called! (devc=%d,devc->base=%d\n",devc,devc->base)); + + /* mode may have changed */ + + save_flags (flags); /* make register access atomic */ + cli (); + + /* mask out modes not specified on open call */ + state &= devc->audio_mode; + + /* setup soundchip to new io-mode */ + if (state & PCM_ENABLE_INPUT) { + /* enable capture */ + outb(inb(devc->base+9)|0x01, devc->base+9); + } else { + /* disable capture */ + outb(inb(devc->base+9)&~0x01, devc->base+9); + } + + if (state & PCM_ENABLE_OUTPUT) { + /* enable playback */ + outb(inb(devc->base+8)|0x01, devc->base+8); + /* unmute pcm output */ + ad_write(devc, 4, ad_read(devc,4)&~0x8080); + } else { + /* mute pcm output */ + ad_write(devc, 4, ad_read(devc,4)|0x8080); + /* disable capture */ + outb(inb(devc->base+8)&~0x01, devc->base+8); + } + restore_flags (flags); +} + + +/* halt input & output */ +static void ad1816_halt (int dev) +{ + ad1816_halt_input(dev); + ad1816_halt_output(dev); +} + +static void ad1816_reset (int dev) +{ + ad1816_halt (dev); +} + +/* set playback speed */ +static int ad1816_set_speed (int dev, int arg) +{ + ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc; + + if (arg == 0) { + return devc->speed; + } + /* range checking */ + if (arg < 4000) { + arg = 4000; + } + if (arg > 55000) { + arg = 55000; + } + + devc->speed = arg; + return devc->speed; + +} + +static unsigned int ad1816_set_bits (int dev, unsigned int arg) +{ + ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc; + + static struct format_tbl + { + int format; + unsigned char bits; + } + format2bits[] = + { + { + 0, 0 + } + , + { + AFMT_MU_LAW, 1 + } + , + { + AFMT_A_LAW, 3 + } + , + { + AFMT_IMA_ADPCM, 0 + } + , + { + AFMT_U8, 0 + } + , + { + AFMT_S16_LE, 2 + } + , + { + AFMT_S16_BE, 6 + } + , + { + AFMT_S8, 0 + } + , + { + AFMT_U16_LE, 0 + } + , + { + AFMT_U16_BE, 0 + } + }; + int i, n = sizeof (format2bits) / sizeof (struct format_tbl); + + /* return current format */ + if (arg == 0) { + return devc->audio_format; + } + + devc->audio_format = arg; + + /* search matching format bits */ + for (i = 0; i < n; i++) { + if (format2bits[i].format == arg) { + devc->format_bits = format2bits[i].bits; + devc->audio_format = arg; + return arg; + } + } + /* Still hanging here. Something must be terribly wrong */ + devc->format_bits = 0; + return devc->audio_format = AFMT_U8; +} + +static short ad1816_set_channels (int dev, short arg) +{ + ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc; + + if (arg != 1 && arg != 2) { + return devc->channels; + } + + devc->channels = arg; + return arg; +} + +/* open device */ +static int ad1816_open (int dev, int mode) +{ + ad1816_info *devc = NULL; + unsigned long flags; + + /* is device number valid ? */ + if (dev < 0 || dev >= num_audiodevs) { + return -(ENXIO); + } + + /* get device info of this dev */ + devc = (ad1816_info *) audio_devs[dev]->devc; + + /* make check if device already open atomic */ + save_flags (flags); + cli (); + + if (devc->opened) { + restore_flags (flags); + return -(EBUSY); + } + + /* mark device as open */ + devc->opened = 1; + + devc->audio_mode = 0; + devc->speed = 8000; + devc->audio_format=AFMT_U8; + devc->channels=1; + + ad1816_reset(devc->dev_no); /* halt all pending output */ + restore_flags (flags); + return 0; +} + +static void ad1816_close (int dev) /* close device */ +{ + unsigned long flags; + ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc; + + save_flags (flags); + cli (); + + /* halt all pending output */ + ad1816_reset(devc->dev_no); + + devc->opened = 0; + devc->audio_mode = 0; + devc->speed = 8000; + devc->audio_format=AFMT_U8; + devc->format_bits = 0; + + + restore_flags (flags); +} + + +/* ------------------------------------------------------------------- */ + +/* Audio driver structure */ + +static struct audio_driver ad1816_audio_driver = +{ + ad1816_open, + ad1816_close, + ad1816_output_block, + ad1816_start_input, + ad1816_ioctl, + ad1816_prepare_for_input, + ad1816_prepare_for_output, + ad1816_halt, + NULL, + NULL, + ad1816_halt_input, + ad1816_halt_output, + ad1816_trigger, + ad1816_set_speed, + ad1816_set_bits, + ad1816_set_channels, + NULL, + NULL +}; + + +/* ------------------------------------------------------------------- */ + +/* Interrupt handler */ + +void ad1816_interrupt (int irq, void *dev_id, struct pt_regs *dummy) +{ + unsigned char status; + ad1816_info *devc; + int dev; + unsigned long flags; + + + if (irq < 0 || irq > 15) { + printk ("ad1816: Got bogus interrupt %d\n", irq); + return; + } + + dev = irq2dev[irq]; + + if (dev < 0 || dev >= num_audiodevs) { + printk ("ad1816: IRQ2AD1816-mapping failed for irq %d device %d\n", irq,dev); + return; + } + + devc = (ad1816_info *) audio_devs[dev]->devc; + + save_flags(flags); + cli(); + + /* read interrupt register */ + status = inb (devc->base+1); + /* Clear all interrupt */ + outb (~status, devc->base+1); + + DEBUGNOISE (printk("ad1816: Got interrupt subclass %d\n",status)); + + devc->irq_ok=1; + + if (status == 0) { + DEBUGWARN(printk ("ad1816: interrupt: Got interrupt, but no reason?\n")); + } + if (devc->opened && (devc->audio_mode & PCM_ENABLE_INPUT) + && (status&64)){ + DMAbuf_inputintr (dev); + } + + if (devc->opened && (devc->audio_mode & PCM_ENABLE_OUTPUT) && + (status & 128)) { + DMAbuf_outputintr (dev, 1); + } + restore_flags(flags); +} + +/* ------------------------------------------------------------------- */ + +/* Mixer stuff */ + +struct mixer_def { + unsigned int regno: 7; + unsigned int polarity:1; /* 0=normal, 1=reversed */ + unsigned int bitpos:4; + unsigned int nbits:4; +}; + +static char mix_cvt[101] = { + 0, 0,3,7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42, + 43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65, + 65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79, + 80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90, + 91,91,92,92,93,93,94,94,95,95,96,96,96,97,97,98,98,98,99,99, + 100 +}; + +typedef struct mixer_def mixer_ent; + +/* + * Most of the mixer entries work in backwards. Setting the polarity field + * makes them to work correctly. + * + * The channel numbering used by individual soundcards is not fixed. Some + * cards have assigned different meanings for the AUX1, AUX2 and LINE inputs. + * The current version doesn't try to compensate this. + */ + +#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[SOUND_MIXER_NRDEVICES][2] = { +MIX_ENT(SOUND_MIXER_VOLUME, 14, 1, 8, 5, 14, 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, 5, 1, 8, 6, 5, 1, 0, 6), +MIX_ENT(SOUND_MIXER_PCM, 4, 1, 8, 6, 4, 1, 0, 6), +MIX_ENT(SOUND_MIXER_SPEAKER, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_LINE, 18, 1, 8, 5, 18, 1, 0, 5), +MIX_ENT(SOUND_MIXER_MIC, 19, 1, 8, 5, 19, 1, 0, 5), +MIX_ENT(SOUND_MIXER_CD, 15, 1, 8, 5, 15, 1, 0, 5), +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, 20, 0, 8, 4, 20, 0, 0, 4), +MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_LINE1, 17, 1, 8, 5, 17, 1, 0, 5), +MIX_ENT(SOUND_MIXER_LINE2, 16, 1, 8, 5, 16, 1, 0, 5), +MIX_ENT(SOUND_MIXER_LINE3, 39, 0, 9, 4, 39, 1, 0, 5) +}; + + +static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] = +{ + 0x6464, /* Master Volume */ + 0x3232, /* Bass */ + 0x3232, /* Treble */ + 0x0000, /* FM */ + 0x6464, /* PCM */ + 0x0000, /* PC Speaker */ + 0x0000, /* Ext Line */ + 0x0000, /* Mic */ + 0x0000, /* CD */ + 0x0000, /* Recording monitor */ + 0x0000, /* SB PCM */ + 0x0000, /* Recording level */ + 0x0000, /* Input gain */ + 0x0000, /* Output gain */ + 0x0000, /* Line1 */ + 0x0000, /* Line2 */ + 0x0000 /* Line3 (usually line in)*/ +}; + +#define LEFT_CHN 0 +#define RIGHT_CHN 1 + + + +static int +ad1816_set_recmask (ad1816_info * devc, int mask) +{ + unsigned char recdev; + int i, n; + + mask &= devc->supported_rec_devices; + + n = 0; + /* Count selected device bits */ + for (i = 0; i < 32; i++) { + if (mask & (1 << i)) { + n++; + } + } + + if (n == 0) { + mask = SOUND_MASK_MIC; + } else if (n != 1) { /* Too many devices selected */ + /* Filter out active settings */ + mask &= ~devc->recmask; + + n = 0; + /* Count selected device bits */ + for (i = 0; i < 32; i++) { + if (mask & (1 << i)) { + n++; + } + } + + if (n != 1) { + mask = SOUND_MASK_MIC; + } + } + + switch (mask) { + case SOUND_MASK_MIC: + recdev = 5; + break; + + case SOUND_MASK_LINE: + recdev = 0; + break; + + case SOUND_MASK_CD: + recdev = 2; + break; + + case SOUND_MASK_LINE1: + recdev = 4; + break; + + case SOUND_MASK_LINE2: + recdev = 3; + break; + + case SOUND_MASK_VOLUME: + recdev = 1; + break; + + default: + mask = SOUND_MASK_MIC; + recdev = 5; + } + + recdev <<= 4; + ad_write (devc, 20, + (ad_read (devc, 20) & 0x8f8f) | recdev | (recdev<<8)); + + devc->recmask = mask; + return mask; +} + +static void +change_bits (int *regval, int dev, int chn, int newval) +{ + unsigned char mask; + int shift; + + /* Reverse polarity*/ + + if (mix_devices[dev][chn].polarity == 1) { + newval = 100 - newval; + } + + mask = (1 << mix_devices[dev][chn].nbits) - 1; + shift = mix_devices[dev][chn].bitpos; + /* Scale it */ + newval = (int) ((newval * mask) + 50) / 100; + /* Clear bits */ + *regval &= ~(mask << shift); + /* Set new value */ + *regval |= (newval & mask) << shift; +} + +static int +ad1816_mixer_get (ad1816_info * devc, int dev) +{ + DEBUGINFO(printk("ad1816: mixer_get called!\n")); + + /* range check + supported mixer check */ + if (dev < 0 || dev >= SOUND_MIXER_NRDEVICES ) { + return (-(EINVAL)); + } + if (!((1 << dev) & devc->supported_devices)) { + return -(EINVAL); + } + + return devc->levels[dev]; +} + +static int +ad1816_mixer_set (ad1816_info * devc, int dev, int value) +{ + int left = value & 0x000000ff; + int right = (value & 0x0000ff00) >> 8; + int retvol; + + int regoffs; + int val; + int valmute; + + DEBUGINFO(printk("ad1816: mixer_set called!\n")); + + if (dev < 0 || dev >= SOUND_MIXER_NRDEVICES ) { + return -(EINVAL); + } + + if (left > 100) { + left = 100; + } + if (left < 0) { + left = 0; + } + if (right > 100) { + right = 100; + } + if (right < 0) { + right = 0; + } + + /* Mono control */ + if (mix_devices[dev][RIGHT_CHN].nbits == 0) { + right = left; + } + retvol = left | (right << 8); + + /* Scale it */ + + left = mix_cvt[left]; + right = mix_cvt[right]; + + /* reject all mixers that are not supported */ + if (!(devc->supported_devices & (1 << dev))) { + return -(EINVAL); + } + + /* sanity check */ + if (mix_devices[dev][LEFT_CHN].nbits == 0) { + return -(EINVAL); + } + + /* keep precise volume internal */ + devc->levels[dev] = retvol; + + /* Set the left channel */ + regoffs = mix_devices[dev][LEFT_CHN].regno; + val = ad_read (devc, regoffs); + change_bits (&val, dev, LEFT_CHN, left); + + valmute=val; + + /* Mute bit masking on some registers */ + if ( regoffs==5 || regoffs==14 || regoffs==15 || + regoffs==16 || regoffs==17 || regoffs==18 || + regoffs==19 || regoffs==39) { + if (left==0) { + valmute |= 0x8000; + } else { + valmute &= ~0x8000; + } + } + ad_write (devc, regoffs, valmute); /* mute */ + + /* + * Set the right channel + */ + + /* Was just a mono channel */ + if (mix_devices[dev][RIGHT_CHN].nbits == 0) { + return retvol; + } + regoffs = mix_devices[dev][RIGHT_CHN].regno; + val = ad_read (devc, regoffs); + change_bits (&val, dev, RIGHT_CHN, right); + + valmute=val; + if ( regoffs==5 || regoffs==14 || regoffs==15 || + regoffs==16 || regoffs==17 || regoffs==18 || + regoffs==19 || regoffs==39) { + if (right==0) { + valmute |= 0x80; + } else { + valmute &= ~0x80; + } + } + ad_write (devc, regoffs, valmute); /* mute */ + + return retvol; +} + +#define MIXER_DEVICES ( SOUND_MASK_VOLUME | \ + SOUND_MASK_SYNTH | \ + SOUND_MASK_PCM | \ + SOUND_MASK_LINE | \ + SOUND_MASK_LINE1 | \ + SOUND_MASK_LINE2 | \ + SOUND_MASK_LINE3 | \ + SOUND_MASK_MIC | \ + SOUND_MASK_CD | \ + SOUND_MASK_RECLEV \ + ) +#define REC_DEVICES ( SOUND_MASK_LINE2 |\ + SOUND_MASK_LINE |\ + SOUND_MASK_LINE1 |\ + SOUND_MASK_MIC |\ + SOUND_MASK_CD |\ + SOUND_MASK_VOLUME \ + ) + +static void +ad1816_mixer_reset (ad1816_info * devc) +{ + int i; + + devc->supported_devices = MIXER_DEVICES; + + devc->supported_rec_devices = REC_DEVICES; + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (devc->supported_devices & (1 << i)) { + ad1816_mixer_set (devc, i, default_mixer_levels[i]); + } + } + ad1816_set_recmask (devc, SOUND_MASK_MIC); +} + +static int +ad1816_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +{ + ad1816_info *devc = mixer_devs[dev]->devc; + int val; + + DEBUGINFO(printk("ad1816: mixer_ioctl called!\n")); + + /* Mixer ioctl */ + if (((cmd >> 8) & 0xff) == 'M') { + + /* set ioctl */ + if (_IOC_DIR (cmd) & _IOC_WRITE) { + switch (cmd & 0xff){ + case SOUND_MIXER_RECSRC: + + if (get_user(val, (int *)arg)) { + return -EFAULT; + } + val=ad1816_set_recmask (devc, val); + return put_user(val, (int *)arg); + break; + + default: + if (get_user(val, (int *)arg)){ + return -EFAULT; + } + if ((val=ad1816_mixer_set (devc, cmd & 0xff, val))<0) { + return val; + } else { + return put_user(val, (int *)arg); + } + } + } else { + /* read ioctl */ + switch (cmd & 0xff) { + + case SOUND_MIXER_RECSRC: + val=devc->recmask; + return put_user(val, (int *)arg); + break; + + case SOUND_MIXER_DEVMASK: + val=devc->supported_devices; + return put_user(val, (int *)arg); + break; + + case SOUND_MIXER_STEREODEVS: + val=devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); + return put_user(val, (int *)arg); + break; + + case SOUND_MIXER_RECMASK: + val=devc->supported_rec_devices; + return put_user(val, (int *)arg); + break; + + case SOUND_MIXER_CAPS: + val=SOUND_CAP_EXCL_INPUT; + return put_user(val, (int *)arg); + break; + + default: + if ((val=ad1816_mixer_get (devc, cmd & 0xff))<0) { + return val; + } else { + return put_user(val, (int *)arg); + } + } + } + } else { + /* not for mixer */ + return -(EINVAL); + } +} + +/* ------------------------------------------------------------------- */ + +/* Mixer structure */ + +static struct mixer_operations ad1816_mixer_operations = +{ + "AD1816", + "AD1816 Mixer", + ad1816_mixer_ioctl +}; + + +/* ------------------------------------------------------------------- */ + +/* stuff for card recognition, init and unloading */ + + +/* replace with probe routine */ +int probe_ad1816 ( struct address_info *hw_config ) +{ + ad1816_info *devc = &dev_info[nr_ad1816_devs]; + int io_base=hw_config->io_base; + int *osp=hw_config->osp; + int tmp; + + printk("ad1816: AD1816 sounddriver Copyright (C) 1998 by Thorsten Knabe\n"); + printk("ad1816: $Header: /home/tek/tmp/CVSROOT/sound21/ad1816.c,v 1.24.2.8 1998/12/04 16:39:46 tek Exp $\n"); + + if (check_region (io_base, 16)) { + printk ("ad1816: I/O port 0x%03x not free\n", io_base); + return 0; + } + + DEBUGLOG(printk ("ad1816: detect(%x)\n", io_base)); + + if (nr_ad1816_devs >= MAX_AUDIO_DEV) { + printk ("ad1816: detect error - step 0\n"); + return 0; + } + + devc->base = io_base; + devc->irq_ok = 0; + devc->irq = 0; + devc->opened = 0; + devc->osp = osp; + + /* base+0: bit 1 must be set but not 255 */ + tmp=inb(devc->base); + if ( (tmp&0x80)==0 || tmp==255 ) { + DEBUGLOG (printk ("ad1816: Chip is not an AD1816 or chip is not active (Test 0)\n")); + return(0); + } + + + /* writes to ireg 8 are copied to ireg 9 */ + ad_write(devc,8,12345); + if (ad_read(devc,9)!=12345) { + DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 1)\n")); + return(0); + } + + /* writes to ireg 8 are copied to ireg 9 */ + ad_write(devc,8,54321); + if (ad_read(devc,9)!=54321) { + DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 2)\n")); + return(0); + } + + /* writes to ireg 10 are copied to ireg 11 */ + ad_write(devc,10,54321); + if (ad_read(devc,11)!=54321) { + DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 3)\n")); + return(0); + } + + /* writes to ireg 10 are copied to ireg 11 */ + ad_write(devc,10,12345); + if (ad_read(devc,11)!=12345) { + DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 4)\n")); + return(0); + } + + /* bit in base +1 cannot be set to 1 */ + tmp=inb(devc->base+1); + outb(0xff,devc->base+1); + if (inb(devc->base+1)!=tmp) { + DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 5)\n")); + return(0); + } + + + DEBUGLOG (printk ("ad1816: detect() - Detected OK\n")); + DEBUGLOG (printk ("ad1816: AD1816 Version: %d\n",ad_read(devc,45))); + + /* detection was successful */ + return 1; +} + + +/* allocate resources from the kernel. If any allocation fails, free + all allocated resources and exit attach. + + */ + +void attach_ad1816 (struct address_info *hw_config) +{ + int my_dev; + char dev_name[100]; + ad1816_info *devc = &dev_info[nr_ad1816_devs]; + + + /* allocate i/o ports */ + request_region (hw_config->io_base, 16, "AD1816 Sound"); + devc->base = hw_config->io_base; + + /* disable all interrupts */ + ad_write(devc,1,0); + + /* Clear pending interrupts */ + outb (0, devc->base+1); + + /* allocate irq */ + if (hw_config->irq < 0 || hw_config->irq > 15) { + release_region(hw_config->io_base, 16); + return; + } + if (request_irq(hw_config->irq, ad1816_interrupt,0, + "SoundPort", + hw_config->osp) < 0) { + printk ("ad1816: IRQ in use\n"); + release_region(hw_config->io_base, 16); + return; + } + devc->irq=hw_config->irq; + + /* DMA stuff */ + if (sound_alloc_dma (hw_config->dma, "Sound System")) { + printk ("ad1816: Can't allocate DMA%d\n", hw_config->dma); + free_irq(hw_config->irq,hw_config->osp); + release_region(hw_config->io_base, 16); + return; + } + devc->dma_playback=hw_config->dma; + + if ( hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) { + if (sound_alloc_dma (hw_config->dma2, "Sound System (capture)")) { + printk ("ad1816: Can't allocate DMA%d\n", hw_config->dma2); + sound_free_dma(hw_config->dma); + free_irq(hw_config->irq,hw_config->osp); + release_region(hw_config->io_base, 16); + return; + } + devc->dma_capture=hw_config->dma2; + devc->audio_mode=DMA_AUTOMODE|DMA_DUPLEX; + } else { + devc->dma_capture=-1; + devc->audio_mode=DMA_AUTOMODE; + } + + sprintf (dev_name,"AD1816 audio driver"); + + conf_printf2 (dev_name, + devc->base, devc->irq, hw_config->dma, hw_config->dma2); + + /* register device */ + if ((my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION, + dev_name, + &ad1816_audio_driver, + sizeof (struct audio_driver), + devc->audio_mode, + ad_format_mask, + devc, + hw_config->dma, + hw_config->dma2)) < 0) { + printk ("ad1816: Can't install sound driver\n"); + if (devc->dma_capture>=0) { + sound_free_dma(hw_config->dma2); + } + sound_free_dma(hw_config->dma); + free_irq(hw_config->irq,hw_config->osp); + release_region(hw_config->io_base, 16); + return; + + } + + /* fill rest of structure with reasonable default values */ + irq2dev[hw_config->irq] = devc->dev_no = my_dev; + devc->opened = 0; + devc->irq_ok = 0; + devc->osp = hw_config->osp; + nr_ad1816_devs++; + + ad_write(devc,32,0x80f0); /* sound system mode */ + ad_write(devc,33,0x03f8); /* enable all audiosources for dsp */ + ad_write(devc,4,0x8080); /* default values for volumes (muted)*/ + ad_write(devc,5,0x8080); + ad_write(devc,6,0x8080); + ad_write(devc,7,0x8080); + ad_write(devc,15,0x8888); + ad_write(devc,16,0x8888); + ad_write(devc,17,0x8888); + ad_write(devc,18,0x8888); + ad_write(devc,19,0xc888); /* +20db mic active */ + ad_write(devc,14,0x0000); /* Master volume unmuted full power */ + ad_write(devc,39,0x009f); /* 3D effect on 0% phone out muted */ + ad_write(devc,44,0x0080); /* everything on power, 3d enabled for d/a */ + outb(0x10,devc->base+8); /* set dma mode */ + outb(0x10,devc->base+9); + + /* enable capture + playback interrupt */ + ad_write(devc,1,0xc000); + + /* set mixer defaults */ + ad1816_mixer_reset (devc); + + /* register mixer */ + if ((audio_devs[my_dev]->mixer_dev=sound_install_mixer( + MIXER_DRIVER_VERSION, + dev_name, + &ad1816_mixer_operations, + sizeof (struct mixer_operations), + devc)) >= 0) { + audio_devs[my_dev]->min_fragment = 0; + } +} + +void unload_card(ad1816_info *devc) +{ + int mixer, dev = 0; + + if (devc != NULL) { + DEBUGLOG (printk("ad1816: Unloading card at base=%x\n",devc->base)); + + dev = devc->dev_no; + mixer = audio_devs[dev]->mixer_dev; + + /* unreg mixer*/ + if(mixer>=0) { + sound_unload_mixerdev(mixer); + } + sound_unload_audiodev(dev); + + /* free dma channels */ + if (devc->dma_capture>=0) { + sound_free_dma(devc->dma_capture); + } + + /* card wont get added if resources could not be allocated + thus we need not ckeck if allocation was successful */ + sound_free_dma (devc->dma_playback); + free_irq(devc->irq, devc->osp); + release_region (devc->base, 16); + + DEBUGLOG (printk("ad1816: Unloading card at base=%x was successful\n",devc->base)); + + } else { + printk ("ad1816: no device/card specified\n"); + } +} + +void unload_ad1816 (struct address_info *hw_config) +{ + int i; + ad1816_info *devc = NULL; + + /* remove any soundcard */ + if (hw_config==NULL) { + for (i = 0; i < nr_ad1816_devs; i++) { + devc = &dev_info[i]; + unload_card(devc); + } + nr_ad1816_devs=0; + } else { + /* remove specified soundcard */ + for (i = 0; i < nr_ad1816_devs; i++) { + int j; + + if (dev_info[i].base == hw_config->io_base) { + devc = &dev_info[i]; + unload_card(devc); + nr_ad1816_devs--; + for ( j=i; j < nr_ad1816_devs ; j++) { + dev_info[j] = dev_info[j+1]; + } + i--; + } + } + } +} + + +/* ----------------------------- 2.1.xxx module stuff ----------------- */ + +EXPORT_SYMBOL(ad1816_interrupt); +EXPORT_SYMBOL(probe_ad1816); +EXPORT_SYMBOL(attach_ad1816); +EXPORT_SYMBOL(unload_ad1816); + + +#ifdef MODULE + +int io = -1; +int irq = -1; +int dma = -1; +int dma2 = -1; + +MODULE_PARM(io,"i"); +MODULE_PARM(irq,"i"); +MODULE_PARM(dma,"i"); +MODULE_PARM(dma2,"i"); +MODULE_PARM(ad1816_clockfreq,"i"); + +struct address_info cfg; + + +int init_module(void) +{ + if (io == -1 || irq == -1 || dma == -1 || dma2 == -1) { + printk("ad1816: dma, dma2, irq and io must be set.\n"); + return -EINVAL; + } + cfg.io_base = io; + cfg.irq = irq; + cfg.dma = dma; + cfg.dma2 = dma2; + + if (probe_ad1816(&cfg) == 0) { + return -ENODEV; + } + attach_ad1816(&cfg); + SOUND_LOCK; + return 0; +} + + +void cleanup_module(void) +{ + unload_ad1816(NULL); + SOUND_LOCK_END; +} + +#endif /* MODULE */ + +#endif /* CONFIG_AD1816 */ diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c index d3a74355088d..af172bac2137 100644 --- a/drivers/sound/ad1848.c +++ b/drivers/sound/ad1848.c @@ -442,10 +442,6 @@ static int ad1848_mixer_set(ad1848_info * devc, int dev, int value) left = mix_cvt[left]; right = mix_cvt[right]; - /* Scale it again */ - left = mix_cvt[left]; - right = mix_cvt[right]; - if (devc->mix_devices[dev][LEFT_CHN].nbits == 0) return -EINVAL; @@ -1205,15 +1201,17 @@ static void ad1848_halt_input(int dev) { int tmout; - - disable_dma(audio_devs[dev]->dmap_in->dma); + + if(!isa_dma_bridge_buggy) + disable_dma(audio_devs[dev]->dmap_in->dma); 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]->dmap_in->dma); + if(!isa_dma_bridge_buggy) + enable_dma(audio_devs[dev]->dmap_in->dma); devc->audio_mode &= ~PCM_ENABLE_INPUT; } @@ -1240,14 +1238,17 @@ static void ad1848_halt_output(int dev) { int tmout; - disable_dma(audio_devs[dev]->dmap_out->dma); + if(!isa_dma_bridge_buggy) + disable_dma(audio_devs[dev]->dmap_out->dma); 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]->dmap_out->dma); + if(!isa_dma_bridge_buggy) + enable_dma(audio_devs[dev]->dmap_out->dma); + devc->audio_mode &= ~PCM_ENABLE_OUTPUT; } diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c index 286eca0116b6..605a03ba5088 100644 --- a/drivers/sound/audio.c +++ b/drivers/sound/audio.c @@ -199,6 +199,9 @@ int audio_write(int dev, struct file *file, const char *buf, int count) p = 0; c = count; + + if(count < 0) + return -EINVAL; if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) return -EPERM; @@ -810,8 +813,10 @@ int dma_ioctl(int dev, unsigned int cmd, caddr_t arg) { reorganize_buffers(dev, dmap_in, 1); if ((err = audio_devs[dev]->d->prepare_for_input(dev, - dmap_in->fragment_size, dmap_in->nbufs)) < 0) + dmap_in->fragment_size, dmap_in->nbufs)) < 0) { + restore_flags(flags); return -err; + } dmap_in->dma_mode = DMODE_INPUT; audio_devs[dev]->enable_bits = bits; DMAbuf_activate_recording(dev, dmap_in); diff --git a/drivers/sound/cs4232.c b/drivers/sound/cs4232.c index 122b0198fb41..4d529bcaf5e1 100644 --- a/drivers/sound/cs4232.c +++ b/drivers/sound/cs4232.c @@ -63,9 +63,7 @@ static void CS_OUT(unsigned char a) #define CS_OUT3(a, b, c) {CS_OUT(a);CS_OUT(b);CS_OUT(c);} static int mpu_base = 0, mpu_irq = 0; -#ifdef CONFIG_SOUND_WAVEFRONT_MODULE static int synth_base = 0, synth_irq = 0; -#endif CONFIG_SOUND_WAVEFRONT_MODULE static int mpu_detected = 0; int probe_cs4232_mpu(struct address_info *hw_config) @@ -188,7 +186,7 @@ int probe_cs4232(struct address_info *hw_config) } #endif -#if defined(CONFIG_SOUND_WAVEFRONT) || defined(CONFIG_SOUND_WAVEFRONT_MODULE) + if(synth_base != 0) { CS_OUT2 (0x15, 0x04); /* logical device 4 (WaveFront) */ CS_OUT3 (0x47, (synth_base >> 8) & 0xff, @@ -196,7 +194,7 @@ int probe_cs4232(struct address_info *hw_config) CS_OUT2 (0x22, synth_irq); /* IRQ */ CS_OUT2 (0x33, 0x01); /* Activate logical dev 4 */ } -#endif + /* * Finally activate the chip */ @@ -331,12 +329,10 @@ MODULE_PARM(dma2,"i"); MODULE_PARM(mpuio,"i"); MODULE_PARM(mpuirq,"i"); -#ifdef CONFIG_SOUND_WAVEFRONT_MODULE int synthio = -1; int synthirq = -1; MODULE_PARM(synthio,"i"); MODULE_PARM(synthirq,"i"); -#endif CONFIG_SOUND_WAVEFRONT_MODULE EXPORT_NO_SYMBOLS; @@ -350,35 +346,29 @@ struct address_info mpu_cfg; int init_module(void) { - -#ifndef CONFIG_SOUND_WAVEFRONT_MODULE - if (io == -1 || irq == -1 || dma == -1 || dma2 == -1) { printk(KERN_ERR "cs4232: dma, dma2, irq and io must be set.\n"); return -EINVAL; } -#else - if (synthio == -1 || synthirq == -1 || - io == -1 || irq == -1 || dma == -1 || dma2 == -1) +#ifdef CONFIG_SOUND_WAVEFRONT_MODULE + if(synthio == -1) + printk(KERN_WARNING "cs4232: set synthio and synthirq to use the wavefront facilities.\n"); + else { - printk(KERN_ERR "cs4232: synthio, synthirq, dma, dma2, " - "irq and io must be set.\n"); - return -EINVAL; + synth_base = synthio; + synth_irq = synthirq; } - -#endif CONFIG_SOUND_WAVEFRONT_MODULE +#else + if(synthio != -1) + printk(KERN_WARNING "cs4232: wavefront support not enabled in this driver.\n"); +#endif cfg.io_base = io; cfg.irq = irq; cfg.dma = dma; cfg.dma2 = dma2; -#ifdef CONFIG_SOUND_WAVEFRONT_MODULE - synth_base = synthio; - synth_irq = synthirq; -#endif CONFIG_SOUND_WAVEFRONT_MODULE - if (probe_cs4232(&cfg) == 0) return -ENODEV; @@ -386,15 +376,15 @@ int init_module(void) mpu_cfg.irq = -1; if (mpuio != -1 && mpuirq != -1) { - mpu_cfg.io_base = mpuio; - mpu_cfg.irq = mpuirq; - probe_cs4232_mpu(&mpu_cfg); /* Bug always returns 0 not OK -- AC */ + mpu_cfg.io_base = mpuio; + mpu_cfg.irq = mpuirq; + probe_cs4232_mpu(&mpu_cfg); /* Bug always returns 0 not OK -- AC */ } attach_cs4232(&cfg); if (mpuio != -1 && mpuirq != -1) { - attach_cs4232_mpu(&mpu_cfg); + attach_cs4232_mpu(&mpu_cfg); } SOUND_LOCK; diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h index b440f3c095d3..eff3d1300fcc 100644 --- a/drivers/sound/dev_table.h +++ b/drivers/sound/dev_table.h @@ -33,6 +33,7 @@ #define SNDCARD_WAVEFRONT 41 #define SNDCARD_OPL3SA2 42 #define SNDCARD_OPL3SA2_MPU 43 +#define SNDCARD_AD1816 88 void attach_opl3sa_wss (struct address_info *hw_config); int probe_opl3sa_wss (struct address_info *hw_config); @@ -202,6 +203,7 @@ struct audio_driver short (*set_channels)(int dev, short channels); void (*postprocess_write)(int dev); /* Device spesific postprocessing for written data */ void (*preprocess_read)(int dev); /* Device spesific preprocessing for read data */ + void (*mmap)(int dev); }; struct audio_operations @@ -427,6 +429,11 @@ struct driver_info sound_drivers[] = {"SGALAXY", 0, SNDCARD_SGALAXY, "Sound Galaxy WSS", attach_sgalaxy, probe_sgalaxy, unload_sgalaxy}, #endif +#ifdef CONFIG_SOUND_AD1816 + {"AD1816", 0, SNDCARD_AD1816, "AD1816", attach_ad1816, +probe_ad1816, unload_ad1816}, +#endif + #ifdef CONFIG_SOUND_YM3812 {"OPL3", 0, SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib, unload_adlib}, #endif @@ -493,7 +500,7 @@ struct driver_info sound_drivers[] = #if defined(CONFIG_SOUND_VMIDI) && defined(CONFIG_MIDI) {"VMIDI", 0, SNDCARD_VMIDI,"Loopback MIDI Device", attach_v_midi, probe_v_midi, unload_v_midi}, #endif -#ifdef CONFIG_VIDC_SOUND +#ifdef CONFIG_SOUND_VIDC {"VIDC", 0, SNDCARD_VIDC, "ARM VIDC 16-bit D/A", attach_vidc, probe_vidc, unload_vidc }, #endif {NULL, 0, 0, "*?*", NULL, NULL, NULL} @@ -668,7 +675,7 @@ struct card_info snd_installed_cards[] = {SNDCARD_VMIDI, {0, 0, 0, -1}, SND_DEFAULT_ENABLE}, #endif -#ifdef CONFIG_VIDC_SOUND +#ifdef CONFIG_SOUND_VIDC { SNDCARD_VIDC, {0, 0, 0, 0}, SND_DEFAULT_ENABLE }, #endif {0, {0}, 0} diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index 014d6a73cc44..ccde8519ae0d 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -474,7 +474,7 @@ int DMAbuf_release(int dev, int mode) adev->dmap_in->closing = 1; if (adev->open_mode & OPEN_WRITE) - if (!(adev->dmap_in->mapping_flags & DMA_MAP_MAPPED)) + if (!(adev->dmap_out->mapping_flags & DMA_MAP_MAPPED)) if (!signal_pending(current) && (adev->dmap_out->dma_mode == DMODE_OUTPUT)) DMAbuf_sync(dev); if (adev->dmap_out->dma_mode == DMODE_OUTPUT) @@ -630,7 +630,10 @@ int DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction f=claim_dma_lock(); clear_dma_ff(chan); - disable_dma(dmap->dma); + + if(!isa_dma_bridge_buggy) + disable_dma(dmap->dma); + pos = get_dma_residue(chan); pos = dmap->bytes_in_use - pos; @@ -650,7 +653,10 @@ int DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction pos = 0; if (pos >= dmap->bytes_in_use) pos = 0; - enable_dma(dmap->dma); + + if(!isa_dma_bridge_buggy) + enable_dma(dmap->dma); + release_dma_lock(f); } restore_flags(flags); @@ -727,7 +733,7 @@ static int output_sleep(int dev, int dontblock) struct audio_operations *adev = audio_devs[dev]; int err = 0; struct dma_buffparms *dmap = adev->dmap_out; - int timeout; + long timeout; long timeout_value; if (dontblock) @@ -1016,10 +1022,13 @@ void DMAbuf_outputintr(int dev, int notify_only) unsigned long f; f=claim_dma_lock(); - disable_dma(dmap->dma); + + if(!isa_dma_bridge_buggy) + disable_dma(dmap->dma); clear_dma_ff(chan); pos = dmap->bytes_in_use - get_dma_residue(chan); - enable_dma(dmap->dma); + if(!isa_dma_bridge_buggy) + enable_dma(dmap->dma); release_dma_lock(f); pos = pos / dmap->fragment_size; /* Actual qhead */ @@ -1111,10 +1120,12 @@ void DMAbuf_inputintr(int dev) unsigned long f; f=claim_dma_lock(); - disable_dma(dmap->dma); + if(!isa_dma_bridge_buggy) + disable_dma(dmap->dma); clear_dma_ff(chan); pos = dmap->bytes_in_use - get_dma_residue(chan); - enable_dma(dmap->dma); + if(!isa_dma_bridge_buggy) + enable_dma(dmap->dma); release_dma_lock(f); pos = pos / dmap->fragment_size; /* Actual qhead */ diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index f7dd0c8a399c..d644e8bc1ddd 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -2401,8 +2401,6 @@ void cleanup_module(void) synchronize_irq(); free_irq(s->irq, s); release_region(s->io, ES1370_EXTENT); - if (s->ctrl & CTRL_JYSTK_EN) - release_region(0x200, JOY_EXTENT); unregister_sound_dsp(s->dev_audio); unregister_sound_mixer(s->dev_mixer); unregister_sound_dsp(s->dev_dac); diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index 754aa443b3c9..a6e8a9d92f6c 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -23,12 +23,10 @@ * * * Module command line parameters: - * joystick if 1 enables the joystick interface on the card; but it still - * needs a separate joystick driver (presumably PC standard, although - * the chip doc doesn't say anything and it looks slightly fishy from - * the PCI standpoint...) - * - * + * joystick must be set to the base I/O-Port to be used for + * the gameport. Legal values are 0x200, 0x208, 0x210 and 0x218. + * The gameport is mirrored eight times. + * * Supported devices: * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible @@ -49,11 +47,14 @@ * Now mixer behaviour can basically be selected between * "OSS documented" and "OSS actual" behaviour * 31.08.98 0.4 Fix realplayer problems - dac.count issues + * 27.10.98 0.5 Fix joystick support + * -- Oliver Neukum (c188@org.chemie.uni-muenchen.de) * */ /*****************************************************************************/ +#include #include #include #include @@ -2672,7 +2673,13 @@ static /*const*/ struct file_operations es1371_midi_fops = { /* maximum number of devices */ #define NR_DEVICE 5 +#if CONFIG_SOUND_ES1371_JOYPORT_BOOT +static int joystick[NR_DEVICE] = { +CONFIG_SOUND_ES1371_GAMEPORT +, 0, }; +#else static int joystick[NR_DEVICE] = { 0, }; +#endif /* --------------------------------------------------------------------- */ @@ -2758,7 +2765,6 @@ __initfunc(int init_es1371(void)) printk(KERN_ERR "es1371: joystick address 0x%x already in use\n", joystick[index]); else { s->ctrl |= CTRL_JYSTK_EN | (((joystick[index] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT); - request_region(joystick[index], JOY_EXTENT, "es1371"); } } s->sctrl = 0; @@ -2880,8 +2886,6 @@ void cleanup_module(void) synchronize_irq(); free_irq(s->irq, s); release_region(s->io, ES1371_EXTENT); - if (s->ctrl & CTRL_JYSTK_EN) - release_region(((((s->ctrl >> CTRL_JOY_SHIFT) & CTRL_JOY_MASK) << 3) | 0x200), JOY_EXTENT); unregister_sound_dsp(s->dev_audio); unregister_sound_mixer(s->dev_mixer); unregister_sound_dsp(s->dev_dac); diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c index 4bf4cd38dd08..6d6fee19fbda 100644 --- a/drivers/sound/gus_wave.c +++ b/drivers/sound/gus_wave.c @@ -1173,7 +1173,6 @@ static int guswave_kill_note(int dev, int voice, int note, int velocity) gus_voice_fade(voice); } - restore_flags(flags); return 0; } diff --git a/drivers/sound/legacy.h b/drivers/sound/legacy.h index cde5bc2fc48c..6c3b87ce6d32 100644 --- a/drivers/sound/legacy.h +++ b/drivers/sound/legacy.h @@ -33,6 +33,7 @@ #define CONFIG_SB #define CONFIG_SOFTOSS #define CONFIG_SSCAPE +#define CONFIG_AD1816 #define CONFIG_TRIX #define CONFIG_VMIDI #define CONFIG_YM3812 diff --git a/drivers/sound/lowlevel/README.awe b/drivers/sound/lowlevel/README.awe deleted file mode 100644 index 1765d4b15a6a..000000000000 --- a/drivers/sound/lowlevel/README.awe +++ /dev/null @@ -1,205 +0,0 @@ -================================================================ - AWE32 Sound Driver for Linux and FreeBSD - version 0.4.2c; Oct. 7, 1997 -================================================================ - -* GENERAL NOTES - -This is a sound driver extension for the Sound Blaster AWE32 and other -compatible cards (AWE32-PnP, SB32, SB32-PnP, AWE64, etc.) to enable -the wave synth operations. The driver is provided for both Linux -1.2.x and 2.[01].x kernels, and also FreeBSD on Intel x86 and DEC -Alpha systems. See INSTALL.awe (or INSTALL.fbsd) document for -installation of the driver package. - -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 Iwai (_NOT_ to Linus Torvalds or Hannu -Savolainen). - - -* NOTE TO LINUX USERS - -To enable this driver on linux-2.[01].x kernels, you need turn on both -"lowlevel drivers support" and "AWE32 synth support" options in sound -menu when configure your linux kernel and modules. For more details, -see the installation document in the original driver package -(awedrv-0.4.2.tar.gz) available at the web page: - http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/ - -If you're using PnP cards, the card must be initialized before loading -the sound driver. There're several options to do this: - - Initialize the card via ISA PnP tools, and load the sound module. - - Initialize the card on DOS, and load linux by loadlin.exe - - Use PnP driver (for Linux-2.x.x) -See the FAQ list on the URL above. - - -* USING THE DRIVER - -The GM and GS sounds include multiple instrument layers. -The current version supports this type of sounds with a special -extension, but it uses a non-standard way of sequencer calls. Then, -so far, only drvmidi and playmidi can play the multiple instruments -and stereo sounds properly as MIDI sequencers. - -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/ - -The sfxload is included in the package awesfx-0.4.2.tgz. Binary -packages are available there, too. See the instruction in each -package for installation. - -Sfxload reads a SoundFont file and transfers it to the sound driver. -Note that new sfxload no longer requires -i option. - - % sfxload synthgm.sbk - -You can tune up the sound via some new options, -A, -a and -d. - - % sfxload -A2 synthgm.sbk - -See the manual of sfxload for more details. - -Now you can hear midi musics by supported midi players (drvmidi or -playmidi-2.5). - - % drvmidi foo.mid - -If you have only 512kb on the sound card, I recommend to use dynamic -sample loading via -L option of drvmidi. 2MB GM/GS soundfont file is -available in most midi files. - - % sfxload synthgm - % drvmidi -L 2mbgmgs foo.mid - -Enjoy. - - -* COMPILE FLAGS - -Compile conditions are defined in awe_config.h. - -[Compatibility Conditions] -The following flags are defined automatically when using installation -shell script. - -- AWE_OBSOLETE_VOXWARE (default: not defined) - indicates the system is VoxWare-3.0.x (with linux 1.2.x or - FreeBSD) if defined. - -- AWE_NEW_KERNEL_INTERFACE (default: not defined) - indicates the system is OSSLite on Linux 2.1.6 or later if - defined. - -- HAS_LOWLEVEL_H (default: not defined) - indicates the system has "lowlevel.h" in the sound/lowlevel - directory. OSS driver has this file. - -- AWE_NO_PATCHMGR (default: not defined) - indicates the sound driver has no patch manager function (for - OSS-3.707 (in Linux-2.1.13) or newer). - -- AWE_OSS38 (default: not defined) - indicates the sound driver has an additional parameter in - operation table (for OSS-3.8b5 in Linux-2.1.25 or newer). - - -[Hardware Conditions] -You don't have to define the following two values. -Define them only when the driver couldn't detect the card properly. - -- AWE_DEFAULT_BASE_ADDR (default: not defined) - specifies the base port address of your AWE32 card. - -- AWE_DEFAULT_MEM_SIZE (default: not defined) - specifies the memory size of your AWE32 card in kilo bytes. - - -[Sample Table Size] -From ver.0.4.0, sample tables are allocated dynamically (except -Linux-1.2.x system), so you need NOT to touch these parameters. -Linux-1.2.x users may need to increase these values for sound -cards equipped with more DRAM. - -- AWE_MAX_SF_LISTS, AWE_MAX_SAMPLES, AWE_MAX_INFOS - - -[Other Conditions] - -- AWE_ALWAYS_INIT_FM (default: not defined) - indicates the AWE driver always initialize FM passthrough even - without DRAM on board. Emu8000 chip has a restriction for playing - samples on DRAM that at least two channels must be occupied as - passthrough channels. - -- AWE_DEBUG_ON (default: defined) - turns on debugging messages if defined. - -- AWE_HAS_GUS_COMPATIBILITY (default: defined) - Enables GUS compatibility mode if defined, reading GUS patches and - GUS control commands. Define this option to use GMOD or other - GUS module players. - -- AWE_ACCEPT_ALL_SOUNDS_CONTROL (default: defined) - Enables MIDI control #120 and #123 as "all notes off" and "all - sounds off" events, respectively. - -- CONFIG_AWE32_MIXER (default: defined) - Adds a mixer device for AWE32 bass/treble equalizer control. - You can access this device using /dev/mixer?? (usually mixer01). - -- AWE_LOOKUP_MIDI_PRIORIITY (default: defined) - Allocates voices according to MIDI channel priority. - Drum channels have the highest priorit, followed by #1, #2, and - so on. - -- DEF_FM_CHORUS_DEPTH (default: 0x10) - The default strength to be sent to the chorus effect engine. - From 0 to 0xff. Larger numbers may often cause weird sounds. - -- DEF_FM_REVERB_DEPTH (default: 0x10) - The default strength to be sent to the reverb effect engine. - From 0 to 0xff. Larger numbers may often cause weird sounds. - - -* ACKNOWLEDGMENTS - -Thanks to Witold Jachimczyk (witek@xfactor.wpi.edu) for much advice -on programming of AWE32. Much code is brought from his AWE32-native -MOD player, ALMP. -The port of awedrv to FreeBSD was done by Randall Hopper -(rhh@ct.picker.com). -I also thank linux-awe-ml members for their efforts -to reboot their systems many times. :-) - - -* BUGS & TODO'S - -- can't detect DRAM size on some cards -- smarter patch management -- smarter DRAM memory control -- etc., etc., etc. - - -* COPYRIGHT - -Copyright (C) 1996, 1997 Takashi Iwai - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - -Takashi Iwai diff --git a/drivers/sound/lowlevel/awe_compat-fbsd.h b/drivers/sound/lowlevel/awe_compat-fbsd.h new file mode 100644 index 000000000000..cbb01dc5c56c --- /dev/null +++ b/drivers/sound/lowlevel/awe_compat-fbsd.h @@ -0,0 +1,173 @@ +/* + * sound/awe_compat.h + * + * Compat defines for the AWE32/SB32/AWE64 wave table synth driver. + * version 0.4.3; Nov. 1, 1998 + * + * Copyright (C) 1996-1998 Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef AWE_COMPAT_H_DEF +#define AWE_COMPAT_H_DEF + +/*================================================================ + * version check + *================================================================*/ + +/* FreeBSD version check */ +#include + +#define AWE_OBSOLETE_VOXWARE +#if __FreeBSD__ >= 2 +# include +# if __FreeBSD_version >= 300000 +# undef AWE_OBSOLETE_VOXWARE +# endif +#endif +#ifdef __linux__ +# include +#endif + + +/*================================================================ + * INCLUDE OTHER HEADER FILES + *================================================================*/ + +/* reading configuration of sound driver */ + +#ifdef AWE_OBSOLETE_VOXWARE + +#include +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AWE32) +#define CONFIG_AWE32_SYNTH +#endif + +#else /* AWE_OBSOLETE_VOXWARE */ + +#ifdef HAS_LOWLEVEL_H +#include "lowlevel.h" +#endif + +#include +#if defined(CONFIGURE_SOUNDCARD) && defined(CONFIG_AWE32) +# define CONFIG_AWE32_SYNTH +#endif + +#endif /* AWE_OBSOLETE_VOXWARE */ + + +/*================================================================ + * include AWE header files + *================================================================*/ + +#if defined(CONFIG_AWE32_SYNTH) || defined(CONFIG_AWE32_SYNTH_MODULE) + +#include +#include +#include + +#ifdef AWE_HAS_GUS_COMPATIBILITY +/* include finetune table */ +#ifdef AWE_OBSOLETE_VOXWARE +# define SEQUENCER_C +#endif +#include +#include +#endif /* AWE_HAS_GUS_COMPATIBILITY */ + + +/*---------------------------------------------------------------- + * compatibility macros for AWE32 driver + *----------------------------------------------------------------*/ + +/* redefine following macros */ +#undef IOCTL_IN +#undef IOCTL_OUT +#undef OUTW +#undef COPY_FROM_USER +#undef COPY_TO_USER +#undef GET_BYTE_FROM_USER +#undef GET_SHORT_FROM_USER +#undef IOCTL_TO_USER + +/* inline is not checked yet.. maybe it'll work */ +#define INLINE /*inline*/ + +#define KERN_WARNING /**/ + +/*---------------------------------------------------------------- + * memory management for freebsd + *----------------------------------------------------------------*/ + +/* i/o requests; nothing */ +#define awe_check_port() 0 /* always false */ +#define awe_request_region() /* nothing */ +#define awe_release_region() /* nothing */ + +#define AWE_DYNAMIC_BUFFER + +#define my_malloc_init(ptr) /* nothing */ +#define my_malloc_memptr() 0 +#define my_malloc(size) malloc(size, M_TEMP, M_WAITOK) +#define my_free(ptr) if (ptr) {free(ptr, M_TEMP);} + +#define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;} + +/*---------------------------------------------------------------- + * i/o interfaces for freebsd + *----------------------------------------------------------------*/ + +/* according to linux rule; the arguments are swapped */ +#define OUTW(data,addr) outw(addr, data) + +#define COPY_FROM_USER(target,source,offs,count) \ + uiomove(((caddr_t)(target)),(count),((struct uio *)(source))) +#define COPY_TO_USER(target,source,offs,count) \ + uiomove(((caddr_t)(source)),(count),((struct uio *)(target))) +#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 IO_WRITE_CHECK(cmd) (cmd & IOC_IN) +#define IOCTL_IN(arg) (*(int*)(arg)) +#define IOCTL_OUT(arg,val) (*(int*)(arg) = (val)) +#define BZERO(target,len) bzero((caddr_t)target, len) +#define MEMCPY(dst,src,len) bcopy((caddr_t)src, (caddr_t)dst, len) + +#ifndef AWE_OBSOLETE_VOXWARE +# define printk printf +# define RET_ERROR(err) -err +#endif + + +/* old style device tables (not modulized) */ +#define sound_alloc_synthdev() \ + (num_synths >= MAX_SYNTH_DEV ? -1 : num_synths++) +#define sound_alloc_mixerdev() \ + (num_mixers >= MAX_MIXER_DEV ? -1 : num_mixers++) +#define sound_alloc_mididev() \ + (num_midis >= MAX_MIXER_DEV ? -1 : num_midis++) +#define sound_unload_synthdev(dev) /**/ +#define sound_unload_mixerdev(dev) /**/ +#define sound_unload_mididev(dev) /**/ + + +#endif /* CONFIG_AWE32_SYNTH */ + +#endif /* AWE_COMPAT_H_DEF */ diff --git a/drivers/sound/lowlevel/awe_compat-linux.h b/drivers/sound/lowlevel/awe_compat-linux.h new file mode 100644 index 000000000000..6ab482ac48b3 --- /dev/null +++ b/drivers/sound/lowlevel/awe_compat-linux.h @@ -0,0 +1,248 @@ +/* + * sound/awe_compat.h + * + * Compat defines for the AWE32/SB32/AWE64 wave table synth driver. + * version 0.4.3; Oct. 1, 1998 + * + * Copyright (C) 1996-1998 Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef AWE_COMPAT_H_DEF +#define AWE_COMPAT_H_DEF + +/*================================================================ + * version check + *================================================================*/ + +#include "awe_config.h" + +#define ASC_LINUX_VERSION(V,P,S) (((V) * 65536) + ((P) * 256) + (S)) + +#ifndef LINUX_VERSION_CODE +#include +#endif + +/* linux version check */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) +#define AWE_OBSOLETE_VOXWARE +#endif + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0) +#define AWE_NEW_KERNEL_INTERFACE +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,80) +#define AWE_MODULE_SUPPORT +#endif +#endif + +#ifdef AWE_OBSOLETE_VOXWARE +#include "soundvers.h" +#else +#include "../soundvers.h" +#endif + +#if defined(SOUND_INTERNAL_VERSION) && SOUND_INTERNAL_VERSION >= 0x30803 +/* OSS/Free-3.8 */ +#define AWE_NO_PATCHMGR +#define AWE_OSS38 +#define HAS_LOWLEVEL_H +#endif + +/*================================================================ + * INCLUDE OTHER HEADER FILES + *================================================================*/ + +/* set up module */ + +#if defined(AWE_MODULE_SUPPORT) && defined(MODULE) +#include +#include +#include +#include "../soundmodule.h" +#endif + + +/* reading configuration of sound driver */ + +#ifdef AWE_OBSOLETE_VOXWARE + +#include "sound_config.h" +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AWE32) +#define CONFIG_AWE32_SYNTH +#endif + +#else /* AWE_OBSOLETE_VOXWARE */ + +#ifdef HAS_LOWLEVEL_H +#include "lowlevel.h" +#endif + +#include "../sound_config.h" + +#endif /* AWE_OBSOLETE_VOXWARE */ + + +/*================================================================ + * include AWE header files + *================================================================*/ + +#if defined(CONFIG_AWE32_SYNTH) || defined(CONFIG_AWE32_SYNTH_MODULE) + +#include "awe_hw.h" +#include "awe_version.h" +#include + +#ifdef AWE_HAS_GUS_COMPATIBILITY +/* include finetune table */ +#ifdef AWE_OBSOLETE_VOXWARE +# include "tuning.h" +#else +# include "../tuning.h" +#endif +#include +#endif /* AWE_HAS_GUS_COMPATIBILITY */ + + +/*---------------------------------------------------------------- + * compatibility macros for AWE32 driver + *----------------------------------------------------------------*/ + +/* redefine following macros */ +#undef IOCTL_IN +#undef IOCTL_OUT +#undef OUTW +#undef COPY_FROM_USER +#undef COPY_TO_USER +#undef GET_BYTE_FROM_USER +#undef GET_SHORT_FROM_USER +#undef IOCTL_TO_USER + +/* use inline prefix */ +#define INLINE inline + +/*---------------------------------------------------------------- + * memory management for linux + *----------------------------------------------------------------*/ + +#ifdef AWE_OBSOLETE_VOXWARE +/* old type linux system */ + +/* i/o requests; nothing */ +#define awe_check_port() 0 /* always false */ +#define awe_request_region() /* nothing */ +#define awe_release_region() /* nothing */ + +static int _mem_start; /* memory pointer for permanent buffers */ + +#define my_malloc_init(memptr) _mem_start = (memptr) +#define my_malloc_memptr() _mem_start +#define my_free(ptr) /* do nothing */ + +/* allocate buffer only once */ +#define INIT_TABLE(buffer,index,nums,type) {\ +PERMANENT_MALLOC(buffer, char*, size, _mem_start); index = (nums);\ +} + +#else + +#define AWE_DYNAMIC_BUFFER + +#define my_malloc_init(ptr) /* nothing */ +#define my_malloc_memptr() 0 +#define my_malloc(size) vmalloc(size) +#define my_free(ptr) if (ptr) {vfree(ptr);} + +/* do not allocate buffer at beginning */ +#define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;} + +/* old type macro */ +#define RET_ERROR(err) -err + +#endif + +/*---------------------------------------------------------------- + * i/o interfaces for linux + *----------------------------------------------------------------*/ + +#define OUTW(data,addr) outw(data, addr) + +#ifdef AWE_NEW_KERNEL_INTERFACE +#define COPY_FROM_USER(target,source,offs,count) \ + copy_from_user(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])) +#ifdef AWE_OSS38 +#define IOCTL_TO_USER(target,offs,source,count) \ + memcpy(target, (source)+(offs), count) +#define IO_WRITE_CHECK(cmd) (_SIOC_DIR(cmd) & _IOC_WRITE) +#else +#define IOCTL_TO_USER(target,offs,source,count) \ + copy_to_user(target, (source)+(offs), count) +#define IO_WRITE_CHECK(cmd) (_IOC_DIR(cmd) & _IOC_WRITE) +#endif /* AWE_OSS38 */ +#define COPY_TO_USER IOCTL_TO_USER +#define IOCTL_IN(arg) (*(int*)(arg)) +#define IOCTL_OUT(arg,val) (*(int*)(arg) = (val)) + +#else /* old type i/o */ +#define COPY_FROM_USER(target,source,offs,count) \ + memcpy_fromfs(target, (source)+(offs), (count)) +#define GET_BYTE_FROM_USER(target,addr,offs) \ + *((char *)&(target)) = get_fs_byte((addr)+(offs)) +#define GET_SHORT_FROM_USER(target,addr,offs) \ + *((short *)&(target)) = get_fs_word((addr)+(offs)) +#ifdef AWE_OSS38 +#define IOCTL_TO_USER(target,offs,source,count) \ + memcpy(target, (source)+(offs), count) +#define COPY_TO_USER(target,offs,source,count) \ + memcpy_tofs(target, (source)+(offs), (count)) +#define IOCTL_IN(arg) (*(int*)(arg)) +#define IOCTL_OUT(arg,val) (*(int*)(arg) = (val)) +#define IO_WRITE_CHECK(cmd) (_SIOC_DIR(cmd) & _IOC_WRITE) +#else /* AWE_OSS38 */ +#define IOCTL_TO_USER(target,offs,source,count) \ + memcpy_tofs(target, (source)+(offs), (count)) +#define COPY_TO_USER IOCTL_TO_USER +#define IOCTL_IN(arg) get_fs_long((long *)(arg)) +#define IOCTL_OUT(arg,ret) snd_ioctl_return((int *)arg, ret) +#define IO_WRITE_CHECK(cmd) (cmd & IOC_IN) +#endif /* AWE_OSS38 */ + +#endif /* AWE_NEW_KERNEL_INTERFACE */ + +#define BZERO(target,len) memset(target, 0, len) +#define MEMCPY(dst,src,len) memcpy(dst, src, len) + +/* old style device tables (not modulized) */ +#ifndef AWE_MODULE_SUPPORT + +#define sound_alloc_synthdev() \ + (num_synths >= MAX_SYNTH_DEV ? -1 : num_synths++) +#define sound_alloc_mixerdev() \ + (num_mixers >= MAX_MIXER_DEV ? -1 : num_mixers++) +#define sound_alloc_mididev() \ + (num_midis >= MAX_MIXER_DEV ? -1 : num_midis++) +#define sound_unload_synthdev(dev) /**/ +#define sound_unload_mixerdev(dev) /**/ +#define sound_unload_mididev(dev) /**/ + +#endif /* AWE_MODULE_SUPPORT */ + +#endif /* CONFIG_AWE32_SYNTH */ + +#endif /* AWE_COMPAT_H_DEF */ diff --git a/drivers/sound/lowlevel/awe_compat.h b/drivers/sound/lowlevel/awe_compat.h index 0107bd2c1e5b..b496edd5654d 100644 --- a/drivers/sound/lowlevel/awe_compat.h +++ b/drivers/sound/lowlevel/awe_compat.h @@ -1,3 +1,121 @@ +/* + * sound/awe_compat.h + * + * Compat defines for the AWE32/SB32/AWE64 wave table synth driver. + * version 0.4.3; Oct. 1, 1998 + * + * Copyright (C) 1996-1998 Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef AWE_COMPAT_H_DEF +#define AWE_COMPAT_H_DEF + +/*================================================================ + * version check + *================================================================*/ + +#include "awe_config.h" + +#define ASC_LINUX_VERSION(V,P,S) (((V) * 65536) + ((P) * 256) + (S)) + +#ifndef LINUX_VERSION_CODE +#include +#endif + +/* linux version check */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) +#define AWE_OBSOLETE_VOXWARE +#endif + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0) +#define AWE_NEW_KERNEL_INTERFACE +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,80) +#define AWE_MODULE_SUPPORT +#endif +#endif + +#ifdef AWE_OBSOLETE_VOXWARE +#include "soundvers.h" +#else +#include "../soundvers.h" +#endif + +#if SOUND_INTERNAL_VERSION >= 0x30803 +/* OSS/Free-3.8 */ +#define AWE_NO_PATCHMGR +#define AWE_OSS38 +#define HAS_LOWLEVEL_H +#endif + +/*================================================================ + * INCLUDE OTHER HEADER FILES + *================================================================*/ + +/* set up module */ + +#if defined(AWE_MODULE_SUPPORT) && defined(MODULE) +#include +#include +#include +#include "../soundmodule.h" +#endif + + +/* reading configuration of sound driver */ + +#ifdef AWE_OBSOLETE_VOXWARE + +#include "sound_config.h" +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AWE32) +#define CONFIG_AWE32_SYNTH +#endif + +#else /* AWE_OBSOLETE_VOXWARE */ + +#ifdef HAS_LOWLEVEL_H +#include "lowlevel.h" +#endif + +#include "../sound_config.h" + +#endif /* AWE_OBSOLETE_VOXWARE */ + + +/*================================================================ + * include AWE header files + *================================================================*/ + +#if defined(CONFIG_AWE32_SYNTH) || defined(CONFIG_AWE32_SYNTH_MODULE) + +#include "awe_hw.h" +#include "awe_version.h" +#include + +#ifdef AWE_HAS_GUS_COMPATIBILITY +/* include finetune table */ +#ifdef AWE_OBSOLETE_VOXWARE +# include "tuning.h" +#else +# include "../tuning.h" +#endif +#include +#endif /* AWE_HAS_GUS_COMPATIBILITY */ + + /*---------------------------------------------------------------- * compatibility macros for AWE32 driver *----------------------------------------------------------------*/ @@ -12,14 +130,8 @@ #undef GET_SHORT_FROM_USER #undef IOCTL_TO_USER -#ifdef linux - -/*================================================================ - * Linux macros - *================================================================*/ - /* use inline prefix */ -#define INLINE inline +#define INLINE /*inline*/ /*---------------------------------------------------------------- * memory management for linux @@ -46,6 +158,8 @@ static void *my_malloc(int size) PERMANENT_MALLOC(ptr, char*, size, _mem_start); return (void*)ptr; } +#define my_kmalloc(size) my_malloc(size) +#define kfree(ptr) /* do nothing */ /* allocate buffer only once */ #define INIT_TABLE(buffer,index,nums,type) {\ @@ -60,6 +174,8 @@ buffer = my_malloc(sizeof(type) * (nums)); index = (nums);\ #define my_malloc_memptr() 0 #define my_malloc(size) vmalloc(size) #define my_free(ptr) if (ptr) {vfree(ptr);} +#define my_kmalloc(size) kmalloc(size,GFP_KERNEL) +#define my_kfree(ptr) kfree(ptr) static void *my_realloc(void *buf, int oldsize, int size) { @@ -92,7 +208,7 @@ static void *my_realloc(void *buf, int oldsize, int size) get_user(target, (unsigned char*)&((addr)[offs])) #define GET_SHORT_FROM_USER(target,addr,offs) \ get_user(target, (unsigned short*)&((addr)[offs])) -#ifdef AWE_OSS38_AND_IM_A_BANANA +#ifdef AWE_OSS38 #define IOCTL_TO_USER(target,offs,source,count) \ memcpy(target, (source)+(offs), count) #define IO_WRITE_CHECK(cmd) (_SIOC_DIR(cmd) & _IOC_WRITE) @@ -112,79 +228,44 @@ static void *my_realloc(void *buf, int oldsize, int size) *((char *)&(target)) = get_fs_byte((addr)+(offs)) #define GET_SHORT_FROM_USER(target,addr,offs) \ *((short *)&(target)) = get_fs_word((addr)+(offs)) +#ifdef AWE_OSS38 +#define IOCTL_TO_USER(target,offs,source,count) \ + memcpy(target, (source)+(offs), count) +#define COPY_TO_USER(target,offs,source,count) \ + memcpy_tofs(target, (source)+(offs), (count)) +#define IOCTL_IN(arg) (*(int*)(arg)) +#define IOCTL_OUT(arg,val) (*(int*)(arg) = (val)) +#define IO_WRITE_CHECK(cmd) (_SIOC_DIR(cmd) & _IOC_WRITE) +#else /* AWE_OSS38 */ #define IOCTL_TO_USER(target,offs,source,count) \ memcpy_tofs(target, (source)+(offs), (count)) #define COPY_TO_USER IOCTL_TO_USER -#define IO_WRITE_CHECK(cmd) (cmd & IOC_IN) #define IOCTL_IN(arg) get_fs_long((long *)(arg)) #define IOCTL_OUT(arg,ret) snd_ioctl_return((int *)arg, ret) +#define IO_WRITE_CHECK(cmd) (cmd & IOC_IN) +#endif /* AWE_OSS38 */ #endif /* AWE_NEW_KERNEL_INTERFACE */ #define BZERO(target,len) memset(target, 0, len) #define MEMCPY(dst,src,len) memcpy(dst, src, len) +#define MEMCMP(p1,p2,len) memcmp(p1, p2, len) +/* old style device tables (not modulized) */ +#ifndef AWE_MODULE_SUPPORT -#elif defined(__FreeBSD__) +#define sound_alloc_synthdev() \ + (num_synths >= MAX_SYNTH_DEV ? -1 : num_synths++) +#define sound_alloc_mixerdev() \ + (num_mixers >= MAX_MIXER_DEV ? -1 : num_mixers++) +#define sound_alloc_mididev() \ + (num_midis >= MAX_MIXER_DEV ? -1 : num_midis++) +#define sound_unload_synthdev(dev) /**/ +#define sound_unload_mixerdev(dev) /**/ +#define sound_unload_mididev(dev) /**/ -/*================================================================ - * FreeBSD macros - *================================================================*/ - -/* inline is not checked yet.. maybe it'll work */ -#define INLINE /*inline*/ - -/*---------------------------------------------------------------- - * memory management for freebsd - *----------------------------------------------------------------*/ - -/* i/o requests; nothing */ -#define awe_check_port() 0 /* always false */ -#define awe_request_region() /* nothing */ -#define awe_release_region() /* nothing */ - -#define AWE_DYNAMIC_BUFFER +#endif /* AWE_MODULE_SUPPORT */ -#define my_malloc_init(ptr) /* nothing */ -#define my_malloc_memptr() 0 -#define my_malloc(size) malloc(size, M_TEMP, M_WAITOK) -#define my_free(ptr) if (ptr) {free(ptr, M_TEMP);} - -#define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;} - -/* it should be realloc? */ -static void *my_realloc(void *buf, int oldsize, int size) -{ - void *ptr; - if ((ptr = my_malloc(size)) == NULL) - return NULL; - memcpy(ptr, buf, ((oldsize < size) ? oldsize : size) ); - my_free(buf); - return ptr; -} - -/*---------------------------------------------------------------- - * i/o interfaces for freebsd - *----------------------------------------------------------------*/ - -/* according to linux rule; the arguments are swapped */ -#define OUTW(data,addr) outw(addr, data) - -#define COPY_FROM_USER(target,source,offs,count) \ - uiomove(((caddr_t)(target)),(count),((struct uio *)(source))) -#define COPY_TO_USER(target,source,offs,count) \ - uiomove(((caddr_t)(source)),(count),((struct uio *)(target))) -#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 IO_WRITE_CHECK(cmd) (cmd & IOC_IN) -#define IOCTL_IN(arg) (*(int*)(arg)) -#define IOCTL_OUT(arg,val) (*(int*)(arg) = (val)) -#define BZERO(target,len) bzero((caddr_t)target, len) -#define MEMCPY(dst,src,len) bcopy((caddr_t)src, (caddr_t)dst, len) - -#endif +#endif /* CONFIG_AWE32_SYNTH */ +#endif /* AWE_COMPAT_H_DEF */ diff --git a/drivers/sound/lowlevel/awe_config.h b/drivers/sound/lowlevel/awe_config.h index c6b0dae6de6e..ffb958d497d5 100644 --- a/drivers/sound/lowlevel/awe_config.h +++ b/drivers/sound/lowlevel/awe_config.h @@ -1,10 +1,10 @@ /* * sound/awe_config.h * - * Configuration of AWE32 sound driver - * version 0.4.2; Sep. 15, 1997 + * Configuration of AWE32/SB32/AWE64 wave table synth driver. + * version 0.4.3; Mar. 1, 1998 * - * Copyright (C) 1996 Takashi Iwai + * Copyright (C) 1996-1998 Takashi Iwai * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,60 +28,12 @@ * system configuration *----------------------------------------------------------------*/ -/* if you're using obsolete VoxWare 3.0.x on Linux 1.2.x (or FreeBSD), - * define the following line. +/* if your kernel support module for each soundcard, define this. + * NOTE: it will be automatically set on linux-2.1.x kernels. + * only define here if you have moduler sound system on + * 2.0.x kernel (like RedHat). */ -#undef AWE_OBSOLETE_VOXWARE - -#ifdef __FreeBSD__ -# define AWE_OBSOLETE_VOXWARE -#endif - -/* if you're using OSS-Lite on Linux 2.1.6 or later, define the - * following line. - */ -#define AWE_NEW_KERNEL_INTERFACE - -/* if you have lowlevel.h in the lowlevel directory (OSS-Lite), define - * the following line. - */ -#define HAS_LOWLEVEL_H - -/* if your system doesn't support patch manager (OSS 3.7 or newer), - * define the following line. - */ -#define AWE_NO_PATCHMGR - -/* if your system has an additional parameter (OSS 3.8b5 or newer), - * define this. - */ -#define AWE_OSS38 - -/*---------------------------------------------------------------- - * AWE32 card configuration: - * uncomment the following lines only when auto detection doesn't - * work properly on your machine. - *----------------------------------------------------------------*/ - -/*#define AWE_DEFAULT_BASE_ADDR 0x620*/ /* base port address */ -/*#define AWE_DEFAULT_MEM_SIZE 512*/ /* kbytes */ - - -/*---------------------------------------------------------------- - * maximum size of soundfont list table: - * you usually don't need to touch this value. - *----------------------------------------------------------------*/ - -#define AWE_MAX_SF_LISTS 16 - - -/*---------------------------------------------------------------- - * chunk size of sample and voice tables: - * you usually don't need to touch these values. - *----------------------------------------------------------------*/ - -#define AWE_MAX_SAMPLES 400 -#define AWE_MAX_INFOS 800 +#undef AWE_MODULE_SUPPORT /*---------------------------------------------------------------- @@ -106,40 +58,45 @@ /* GUS compatible mode */ #define AWE_HAS_GUS_COMPATIBILITY -/* accept all notes/sounds off controls */ -#define AWE_ACCEPT_ALL_SOUNDS_CONTROL +/* add MIDI emulation by wavetable */ +#define CONFIG_AWE32_MIDIEMU /* add mixer control of emu8000 equalizer */ -#define CONFIG_AWE32_MIXER - -/* look up voices according to MIDI channel priority */ -#define AWE_LOOKUP_MIDI_PRIORITY +#undef CONFIG_AWE32_MIXER -/*----------------------------------------------------------------*/ +/* use new volume calculation method as default */ +#define AWE_USE_NEW_VOLUME_CALC -/* reading configuration of sound driver */ +/* check current volume target for searching empty voices */ +#define AWE_CHECK_VTARGET -#ifdef AWE_OBSOLETE_VOXWARE +/* allow sample sharing */ +#define AWE_ALLOW_SAMPLE_SHARING -#ifdef __FreeBSD__ -# include -#else -# include "sound_config.h" -#endif +/*================================================================ + * Usually, you don't have to touch the following options. + *================================================================*/ -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AWE32) -#define CONFIG_AWE32_SYNTH -#endif +/*---------------------------------------------------------------- + * AWE32 card configuration: + * uncomment the following lines *ONLY* when auto detection doesn't + * work properly on your machine. + *----------------------------------------------------------------*/ -#else /* AWE_OBSOLETE_VOXWARE */ +/*#define AWE_DEFAULT_BASE_ADDR 0x620*/ /* base port address */ +/*#define AWE_DEFAULT_MEM_SIZE 512*/ /* kbytes */ -#ifdef HAS_LOWLEVEL_H -#include "lowlevel.h" -#endif +/*---------------------------------------------------------------- + * maximum size of soundfont list table + *----------------------------------------------------------------*/ -#include "../sound_config.h" +#define AWE_MAX_SF_LISTS 16 -#endif /* AWE_OBSOLETE_VOXWARE */ +/*---------------------------------------------------------------- + * chunk size of sample and voice tables + *----------------------------------------------------------------*/ +#define AWE_MAX_SAMPLES 400 +#define AWE_MAX_INFOS 800 #endif /* AWE_CONFIG_H_DEF */ diff --git a/drivers/sound/lowlevel/awe_hw.h b/drivers/sound/lowlevel/awe_hw.h index 7d0d88e77d5c..c7dde26799f6 100644 --- a/drivers/sound/lowlevel/awe_hw.h +++ b/drivers/sound/lowlevel/awe_hw.h @@ -2,10 +2,10 @@ * sound/awe_hw.h * * Access routines and definitions for the low level driver for the - * AWE32/Sound Blaster 32 wave table synth. - * version 0.4.2; Sep. 15, 1997 + * Creative AWE32/SB32/AWE64 wave table synth. + * version 0.4.3; Mar. 1, 1998 * - * Copyright (C) 1996,1997 Takashi Iwai + * Copyright (C) 1996-1998 Takashi Iwai * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,16 +32,18 @@ #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 Data0 0 /* 0x620: doubleword r/w */ +#define Data1 1 /* 0xA20: doubleword r/w */ +#define Data2 2 /* 0xA22: word r/w */ +#define Data3 3 /* 0xE20: word r/w */ +#define Pointer 4 /* 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_0080(ch) awe_cmd_idx(4,ch), Data0 /* DW: ?? */ +#define AWE_00A0(ch) awe_cmd_idx(5,ch), Data0 /* DW: ?? */ #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 */ @@ -94,7 +96,4 @@ #define AWE_DRAM_OFFSET 0x200000 #define AWE_MAX_DRAM_SIZE (28 * 1024) /* 28 MB is max onboard memory */ -#define AWE_DEFAULT_ATTENUATION 32 /* 12dB below */ -#define AWE_DEFAULT_MOD_SENSE 18 - #endif diff --git a/drivers/sound/lowlevel/awe_version.h b/drivers/sound/lowlevel/awe_version.h index c1de31715806..a012d734a9fb 100644 --- a/drivers/sound/lowlevel/awe_version.h +++ b/drivers/sound/lowlevel/awe_version.h @@ -1,13 +1,35 @@ +/* + * sound/awe_version.h + * + * Version defines for the AWE32/SB32/AWE64 wave table synth driver. + * version 0.4.3; Mar. 1, 1998 + * + * Copyright (C) 1996-1998 Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + /* AWE32 driver version number */ #ifndef AWE_VERSION_H_DEF #define AWE_VERSION_H_DEF -#define AWE_VERSION_NUMBER 0x00040203 -#define AWEDRV_VERSION "0.4.2c" -#define AWE_MAJOR_VERSION(id) (((id) >> 16) & 0xff) -#define AWE_MINOR_VERSION(id) (((id) >> 8) & 0xff) -#define AWE_TINY_VERSION(id) ((id) & 0xff) +#define AWE_MAJOR_VERSION 0 +#define AWE_MINOR_VERSION 4 +#define AWE_TINY_VERSION 3 +#define AWE_VERSION_NUMBER ((AWE_MAJOR_VERSION<<16)|(AWE_MINOR_VERSION<<8)|AWE_TINY_VERSION) +#define AWEDRV_VERSION "0.4.3" #endif - diff --git a/drivers/sound/lowlevel/awe_voice.h b/drivers/sound/lowlevel/awe_voice.h deleted file mode 100644 index aa131313141b..000000000000 --- a/drivers/sound/lowlevel/awe_voice.h +++ /dev/null @@ -1,490 +0,0 @@ -/* - * sound/awe_voice.h - * - * Voice information definitions for the low level driver for the - * AWE32/Sound Blaster 32 wave table synth. - * version 0.4.2c; Oct. 7, 1997 - * - * Copyright (C) 1996,1997 Takashi Iwai - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef AWE_VOICE_H -#define AWE_VOICE_H - -#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 optarg; /* optional argument */ - int len; /* data length (without this header) */ - - short type; /* patch operation type */ -#define AWE_LOAD_INFO 0 /* awe_voice_rec */ -#define AWE_LOAD_DATA 1 /* awe_sample_info */ -#define AWE_OPEN_PATCH 2 /* awe_open_parm */ -#define AWE_CLOSE_PATCH 3 /* none */ -#define AWE_UNLOAD_PATCH 4 /* none */ -#define AWE_REPLACE_DATA 5 /* awe_sample_info (optarg=#channels)*/ -#define AWE_MAP_PRESET 6 /* awe_voice_map */ -#define AWE_LOAD_CHORUS_FX 0x10 /* awe_chorus_fx_rec (optarg=mode) */ -#define AWE_LOAD_REVERB_FX 0x11 /* awe_reverb_fx_rec (optarg=mode) */ - - short reserved; /* word alignment data */ - - /* the actual patch data begins after this */ -#if defined(AWE_COMPAT_030) && AWE_COMPAT_030 - char data[0]; -#endif -} awe_patch_info; - -/*#define AWE_PATCH_INFO_SIZE 16*/ -#define AWE_PATCH_INFO_SIZE sizeof(awe_patch_info) - - -/*---------------------------------------------------------------- - * open patch - *----------------------------------------------------------------*/ - -#define AWE_PATCH_NAME_LEN 32 - -typedef struct _awe_open_parm { - unsigned short type; /* sample type */ -#define AWE_PAT_TYPE_MISC 0 -#define AWE_PAT_TYPE_GM 1 -#define AWE_PAT_TYPE_GS 2 -#define AWE_PAT_TYPE_MT32 3 -#define AWE_PAT_TYPE_XG 4 -#define AWE_PAT_TYPE_SFX 5 -#define AWE_PAT_TYPE_GUS 6 -#define AWE_PAT_TYPE_MAP 7 - -#define AWE_PAT_LOCKED 0x100 /* lock the samples */ - - short reserved; - char name[AWE_PATCH_NAME_LEN]; -} awe_open_parm; - -/*#define AWE_OPEN_PARM_SIZE 28*/ -#define AWE_OPEN_PARM_SIZE sizeof(awe_open_parm) - - -/*---------------------------------------------------------------- - * 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; - -#define AWE_VOICE_PARM_SIZE 48 - - -/* wave table parameters: 92 bytes */ -typedef struct _awe_voice_info { - unsigned short sf_id; /* file id (should be zero) */ - unsigned short sample; /* sample id */ - int start, end; /* sample offset correction */ - int 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; - -/*#define AWE_VOICE_INFO_SIZE 92*/ -#define AWE_VOICE_INFO_SIZE sizeof(awe_voice_info) - -/*----------------------------------------------------------------*/ - -/* The info entry of awe_voice_rec is changed from 0 to 1 - * for some compilers refusing zero size array. - * Due to this change, sizeof(awe_voice_rec) becomes different - * from older versions. - * Use AWE_VOICE_REC_SIZE instead. - */ - -/* instrument info header: 4 bytes */ -typedef struct _awe_voice_rec_hdr { - unsigned char bank; /* midi bank number */ - unsigned char instr; /* midi preset number */ - char nvoices; /* number of voices */ - char write_mode; /* write mode; normally 0 */ -#define AWE_WR_APPEND 0 /* append anyway */ -#define AWE_WR_EXCLUSIVE 1 /* skip if already exists */ -#define AWE_WR_REPLACE 2 /* replace if already exists */ -} awe_voice_rec_hdr; - -/*#define AWE_VOICE_REC_SIZE 4*/ -#define AWE_VOICE_REC_SIZE sizeof(awe_voice_rec_hdr) - -/* the standard patch structure for one sample */ -typedef struct _awe_voice_rec_patch { - awe_patch_info patch; - awe_voice_rec_hdr hdr; - awe_voice_info info; -} awe_voice_rec_patch; - - -/* obsolete data type */ -#if defined(AWE_COMPAT_030) && AWE_COMPAT_030 -#define AWE_INFOARRAY_SIZE 0 -#else -#define AWE_INFOARRAY_SIZE 1 -#endif - -typedef struct _awe_voice_rec { - unsigned char bank; /* midi bank number */ - unsigned char instr; /* midi preset number */ - short nvoices; /* number of voices */ - /* voice information follows here */ - awe_voice_info info[AWE_INFOARRAY_SIZE]; -} 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 */ - int start, end; /* start & end offset */ - int loopstart, loopend; /* loop start & end offset */ - int 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 */ -#define AWE_SAMPLE_REVERSE_LOOP 128 /* reverse looping */ - unsigned int checksum; /* check sum */ -#if defined(AWE_COMPAT_030) && AWE_COMPAT_030 - unsigned short data[0]; /* sample data follows here */ -#endif -} awe_sample_info; - -/*#define AWE_SAMPLE_INFO_SIZE 32*/ -#define AWE_SAMPLE_INFO_SIZE sizeof(awe_sample_info) - - -/*---------------------------------------------------------------- - * voice preset mapping - *----------------------------------------------------------------*/ - -typedef struct awe_voice_map { - int map_bank, map_instr, map_key; /* key = -1 means all keys */ - int src_bank, src_instr, src_key; -} awe_voice_map; - -#define AWE_VOICE_MAP_SIZE sizeof(awe_voice_map) - - -/*---------------------------------------------------------------- - * 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_INITIAL_ATTEN _AWE_INITIAL_VOLUME -#define _AWE_RESET_CHANNEL 0x09 -#define _AWE_CHANNEL_MODE 0x0a -#define _AWE_DRUM_CHANNELS 0x0b -#define _AWE_MISC_MODE 0x0c -#define _AWE_RELEASE_ALL 0x0d -#define _AWE_NOTEOFF_ALL 0x0e -#define _AWE_CHN_PRESSURE 0x0f -/*#define _AWE_GET_CURRENT_MODE 0x10*/ -#define _AWE_EQUALIZER 0x11 -/*#define _AWE_GET_MISC_MODE 0x12*/ -/*#define _AWE_GET_FONTINFO 0x13*/ - -#define _AWE_MODE_FLAG 0x80 -#define _AWE_COOKED_FLAG 0x40 /* not supported */ -#define _AWE_MODE_VALUE_MASK 0x3F - -/*----------------------------------------------------------------*/ - -#define _AWE_SET_CMD(p,dev,voice,cmd,p1,p2) \ -{((char*)(p))[0] = SEQ_PRIVATE;\ - ((char*)(p))[1] = dev;\ - ((char*)(p))[2] = _AWE_MODE_FLAG|(cmd);\ - ((char*)(p))[3] = voice;\ - ((unsigned short*)(p))[2] = p1;\ - ((unsigned short*)(p))[3] = p2;} - -/* buffered access */ -#define _AWE_CMD(dev, voice, cmd, p1, p2) \ -{_SEQ_NEEDBUF(8);\ - _AWE_SET_CMD(_seqbuf + _seqbufptr, dev, voice, cmd, p1, p2);\ - _SEQ_ADVBUF(8);} - -/* direct access */ -#define _AWE_CMD_NOW(seqfd,dev,voice,cmd,p1,p2) \ -{struct seq_event_rec tmp;\ - _AWE_SET_CMD(&tmp, dev, voice, cmd, p1, p2);\ - ioctl(seqfd, SNDCTL_SEQ_OUTOFBAND, &tmp);} - -/*----------------------------------------------------------------*/ - -/* set debugging mode */ -#define AWE_DEBUG_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_DEBUG_MODE, p1, 0) -/* set reverb mode; from 0 to 7 */ -#define AWE_REVERB_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_REVERB_MODE, p1, 0) -/* set chorus mode; from 0 to 7 */ -#define AWE_CHORUS_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_CHORUS_MODE, p1, 0) - -/* reset channel */ -#define AWE_RESET_CHANNEL(dev,ch) _AWE_CMD(dev, ch, _AWE_RESET_CHANNEL, 0, 0) -#define AWE_RESET_CONTROL(dev,ch) _AWE_CMD(dev, ch, _AWE_RESET_CHANNEL, 1, 0) - -/* send an effect to all layers */ -#define AWE_SEND_EFFECT(dev,voice,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,type,value) -#define AWE_ADD_EFFECT(dev,voice,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((type)|0x80),value) -#define AWE_UNSET_EFFECT(dev,voice,type) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((type)|0x40),0) -/* send an effect to a layer */ -#define AWE_SEND_LAYER_EFFECT(dev,voice,layer,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)),value) -#define AWE_ADD_LAYER_EFFECT(dev,voice,layer,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)|0x80),value) -#define AWE_UNSET_LAYER_EFFECT(dev,voice,layer,type) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)|0x40),0) - -/* terminate sound on the channel/voice */ -#define AWE_TERMINATE_CHANNEL(dev,voice) _AWE_CMD(dev,voice,_AWE_TERMINATE_CHANNEL,0,0) -/* terminate all sounds */ -#define AWE_TERMINATE_ALL(dev) _AWE_CMD(dev, 0, _AWE_TERMINATE_ALL, 0, 0) -/* release all sounds (w/o sustain effect) */ -#define AWE_RELEASE_ALL(dev) _AWE_CMD(dev, 0, _AWE_RELEASE_ALL, 0, 0) -/* note off all sounds (w sustain effect) */ -#define AWE_NOTEOFF_ALL(dev) _AWE_CMD(dev, 0, _AWE_NOTEOFF_ALL, 0, 0) - -/* set initial attenuation */ -#define AWE_INITIAL_VOLUME(dev,atten) _AWE_CMD(dev, 0, _AWE_INITIAL_VOLUME, atten, 0) -#define AWE_INITIAL_ATTEN AWE_INITIAL_VOLUME -/* relative attenuation */ -#define AWE_SET_ATTEN(dev,atten) _AWE_CMD(dev, 0, _AWE_INITIAL_VOLUME, atten, 1) - -/* set channel playing mode; mode=0/1/2 */ -#define AWE_SET_CHANNEL_MODE(dev,mode) _AWE_CMD(dev, 0, _AWE_CHANNEL_MODE, mode, 0) -#define AWE_PLAY_INDIRECT 0 /* indirect voice mode (default) */ -#define AWE_PLAY_MULTI 1 /* multi note voice mode */ -#define AWE_PLAY_DIRECT 2 /* direct single voice mode */ -#define AWE_PLAY_MULTI2 3 /* sequencer2 mode; used internally */ - -/* set drum channel mask; channels is 32bit long value */ -#define AWE_DRUM_CHANNELS(dev,channels) _AWE_CMD(dev, 0, _AWE_DRUM_CHANNELS, ((channels) & 0xffff), ((channels) >> 16)) - -/* set bass and treble control; values are from 0 to 11 */ -#define AWE_EQUALIZER(dev,bass,treble) _AWE_CMD(dev, 0, _AWE_EQUALIZER, bass, treble) - -/* remove last loaded samples */ -#define AWE_REMOVE_LAST_SAMPLES(seqfd,dev) _AWE_CMD_NOW(seqfd, dev, 0, _AWE_REMOVE_LAST_SAMPLES, 0, 0) -/* initialize emu8000 chip */ -#define AWE_INITIALIZE_CHIP(seqfd,dev) _AWE_CMD_NOW(seqfd, dev, 0, _AWE_INITIALIZE_CHIP, 0, 0) - -/* set miscellaneous modes; meta command */ -#define AWE_MISC_MODE(dev,mode,value) _AWE_CMD(dev, 0, _AWE_MISC_MODE, mode, value) -/* exclusive sound off; 1=off */ -#define AWE_EXCLUSIVE_SOUND(dev,mode) AWE_MISC_MODE(dev,AWE_MD_EXCLUSIVE_SOUND,mode) -/* default GUS bank number */ -#define AWE_SET_GUS_BANK(dev,bank) AWE_MISC_MODE(dev,AWE_MD_GUS_BANK,bank) -/* change panning position in realtime; 0=don't 1=do */ -#define AWE_REALTIME_PAN(dev,mode) AWE_MISC_MODE(dev,AWE_MD_REALTIME_PAN,mode) - -/* extended pressure controls; not portable with other sound drivers */ -#define AWE_KEY_PRESSURE(dev,ch,note,vel) SEQ_START_NOTE(dev,ch,(note)+128,vel) -#define AWE_CHN_PRESSURE(dev,ch,vel) _AWE_CMD(dev,ch,_AWE_CHN_PRESSURE,vel,0) - -/*----------------------------------------------------------------*/ - -/* reverb mode parameters */ -#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 -#define AWE_REVERB_PREDEFINED 8 -/* user can define reverb modes up to 32 */ -#define AWE_REVERB_NUMBERS 32 - -typedef struct awe_reverb_fx_rec { - unsigned short parms[28]; -} awe_reverb_fx_rec; - -/*----------------------------------------------------------------*/ - -/* chorus mode parameters */ -#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 -#define AWE_CHORUS_PREDEFINED 8 -/* user can define chorus modes up to 32 */ -#define AWE_CHORUS_NUMBERS 32 - -typedef struct awe_chorus_fx_rec { - unsigned short feedback; /* feedback level (0xE600-0xE6FF) */ - unsigned short delay_offset; /* delay (0-0x0DA3) [1/44100 sec] */ - unsigned short lfo_depth; /* LFO depth (0xBC00-0xBCFF) */ - unsigned int delay; /* right delay (0-0xFFFFFFFF) [1/256/44100 sec] */ - unsigned int lfo_freq; /* LFO freq LFO freq (0-0xFFFFFFFF) */ -} awe_chorus_fx_rec; - -/*----------------------------------------------------------------*/ - -/* misc mode types */ -enum { -/* 0*/ AWE_MD_EXCLUSIVE_OFF, /* obsolete */ -/* 1*/ AWE_MD_EXCLUSIVE_ON, /* obsolete */ -/* 2*/ AWE_MD_VERSION, /* read only */ -/* 3*/ AWE_MD_EXCLUSIVE_SOUND, /* ignored */ -/* 4*/ AWE_MD_REALTIME_PAN, /* 0/1: do realtime pan change (default=1) */ -/* 5*/ AWE_MD_GUS_BANK, /* bank number for GUS patches (default=0) */ -/* 6*/ AWE_MD_KEEP_EFFECT, /* 0/1: keep effect values, (default=0) */ -/* 7*/ AWE_MD_ZERO_ATTEN, /* attenuation of max volume (default=32) */ -/* 8*/ AWE_MD_CHN_PRIOR, /* 0/1: set MIDI channel priority mode (default=1) */ -/* 9*/ AWE_MD_MOD_SENSE, /* integer: modwheel sensitivity (def=18) */ -/*10*/ AWE_MD_DEF_PRESET, /* integer: default preset number (def=0) */ -/*11*/ AWE_MD_DEF_BANK, /* integer: default bank number (def=0) */ -/*12*/ AWE_MD_DEF_DRUM, /* integer: default drumset number (def=0) */ -/*13*/ AWE_MD_TOGGLE_DRUM_BANK, /* 0/1: toggle drum flag with bank# (def=0) */ - AWE_MD_END, -}; - -/*----------------------------------------------------------------*/ - -/* effect parameters */ -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 */ -/*33*/ AWE_FX_ATTEN, /* BYTE: lo IFATN */ - - AWE_FX_END, -}; - -#endif /* AWE_VOICE_H */ diff --git a/drivers/sound/lowlevel/awe_wave.c b/drivers/sound/lowlevel/awe_wave.c index 111b0c5bec20..1c2472049b90 100644 --- a/drivers/sound/lowlevel/awe_wave.c +++ b/drivers/sound/lowlevel/awe_wave.c @@ -1,10 +1,10 @@ /* * sound/awe_wave.c * - * The low level driver for the AWE32/Sound Blaster 32 wave table synth. - * version 0.4.2c; Oct. 7, 1997 + * The low level driver for the AWE32/SB32/AWE64 wave table synth. + * version 0.4.3; Nov. 1, 1998 * - * Copyright (C) 1996,1997 Takashi Iwai + * Copyright (C) 1996-1998 Takashi Iwai * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,62 +21,27 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* include initial header files and compatibility macros */ #ifdef __FreeBSD__ -# include +# include #else -#ifdef MODULE -#include -#include -#include -# include "../soundmodule.h" -#endif -# include "awe_config.h" +# include "awe_compat.h" +#endif /* FreeBSD */ +#ifdef __linux__ +# include #endif /*----------------------------------------------------------------*/ #if defined(CONFIG_AWE32_SYNTH) || defined(CONFIG_AWE32_SYNTH_MODULE) -#ifdef __FreeBSD__ -# include -# include -# include -#else -# include "awe_hw.h" -# include "awe_version.h" -# include -#endif - -#ifdef AWE_HAS_GUS_COMPATIBILITY -/* include fine tuning table */ -#ifdef AWE_OBSOLETE_VOXWARE -# ifdef __FreeBSD__ -# define SEQUENCER_C -# include -# else -# include "tuning.h" -# endif -#else -# include "../tuning.h" -#endif - -#ifdef linux -# include -#elif defined(__FreeBSD__) -# include -#endif - -#endif /* AWE_HAS_GUS_COMPATIBILITY */ - - /*---------------------------------------------------------------- * debug message *----------------------------------------------------------------*/ -static int debug_mode = 0; #ifdef AWE_DEBUG_ON -#define DEBUG(LVL,XXX) {if (debug_mode > LVL) { XXX; }} -#define ERRMSG(XXX) {if (debug_mode) { XXX; }} +#define DEBUG(LVL,XXX) {if (ctrls[AWE_MD_DEBUG_MODE] > LVL) { XXX; }} +#define ERRMSG(XXX) {if (ctrls[AWE_MD_DEBUG_MODE]) { XXX; }} #define FATALERR(XXX) XXX #else #define DEBUG(LVL,XXX) /**/ @@ -97,7 +62,10 @@ typedef struct _sf_list { int mem_ptr; /* current word byte pointer */ int infos; int samples; - /*char name[AWE_PATCH_NAME_LEN];*/ +#ifdef AWE_ALLOW_SAMPLE_SHARING + int shared; /* shared index */ + unsigned char name[AWE_PATCH_NAME_LEN]; +#endif } sf_list; /* bank record */ @@ -203,10 +171,12 @@ typedef struct _voice_info { int apitch; /* pitch parameter */ int avol; /* volume parameter */ int apan; /* panning parameter */ + int acutoff; /* cutoff parameter */ + short aaux; /* aux word */ } voice_info; /* voice information */ -static voice_info *voices; +static voice_info voices[AWE_MAX_VOICES]; #define IS_NO_SOUND(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_RELEASED|AWE_ST_STANDBY|AWE_ST_SUSTAINED)) #define IS_NO_EFFECT(v) (voices[v].state != AWE_ST_ON) @@ -215,7 +185,7 @@ static voice_info *voices; /* MIDI channel effects information (for hw control) */ -static awe_chan_info *channels; +static awe_chan_info channels[AWE_MAX_CHANNELS]; /*---------------------------------------------------------------- @@ -227,13 +197,23 @@ static awe_chan_info *channels; #endif #ifndef AWE_DEFAULT_MEM_SIZE -#define AWE_DEFAULT_MEM_SIZE 0 /* autodetect */ +#define AWE_DEFAULT_MEM_SIZE -1 /* autodetect */ #endif +/* set variables */ +#if defined(AWE_MODULE_SUPPORT) && defined(MODULE) +/* replace awe_port variable with exported variable */ +#define awe_port io +#define BASEVAR_DECL /**/ +#else +#define BASEVAR_DECL static +#endif /* module */ + /* awe32 base address (overwritten at initialization) */ -static int awe_base = AWE_DEFAULT_BASE_ADDR; +BASEVAR_DECL int awe_port = AWE_DEFAULT_BASE_ADDR; /* memory byte size */ -static int awe_mem_size = AWE_DEFAULT_MEM_SIZE; +BASEVAR_DECL int memsize = AWE_DEFAULT_MEM_SIZE; /* for module option */ +static int awe_mem_size = -1; /* DRAM start offset */ static int awe_mem_start = AWE_DRAM_OFFSET; @@ -242,15 +222,13 @@ static int awe_max_voices = AWE_MAX_VOICES; static int patch_opened = 0; /* sample already loaded? */ -static int reverb_mode = 4; /* reverb mode */ -static int chorus_mode = 2; /* chorus mode */ -static short init_atten = AWE_DEFAULT_ATTENUATION; /* 12dB below */ +static char atten_relative = FALSE; +static short atten_offset = 0; static int awe_present = FALSE; /* awe device present? */ static int awe_busy = FALSE; /* awe device opened? */ static int my_dev = -1; -static int my_mixerdev = -1 ; #define DEFAULT_DRUM_FLAGS ((1 << 9) | (1 << 25)) #define IS_DRUM_CHANNEL(c) (drum_flags & (1 << (c))) @@ -264,31 +242,6 @@ static int playing_mode = AWE_PLAY_INDIRECT; static int current_alloc_time = 0; /* voice allocation index for channel mode */ -static struct MiscModeDef { - int value; - int init_each_time; -} misc_modes_default[AWE_MD_END] = { - {0,0}, {0,0}, /* <-- not used */ - {AWE_VERSION_NUMBER, FALSE}, - {TRUE, TRUE}, /* exclusive */ - {TRUE, TRUE}, /* realpan */ - {AWE_DEFAULT_BANK, TRUE}, /* gusbank */ - {FALSE, TRUE}, /* keep effect */ - {AWE_DEFAULT_ATTENUATION, FALSE}, /* zero_atten */ - {FALSE, TRUE}, /* chn_prior */ - {AWE_DEFAULT_MOD_SENSE, TRUE}, /* modwheel sense */ - {AWE_DEFAULT_PRESET, TRUE}, /* def_preset */ - {AWE_DEFAULT_BANK, TRUE}, /* def_bank */ - {AWE_DEFAULT_DRUM, TRUE}, /* def_drum */ - {FALSE, TRUE}, /* toggle_drum_bank */ -}; - -static int misc_modes[AWE_MD_END]; - -static int awe_bass_level = 5; -static int awe_treble_level = 9; - - static struct synth_info awe_info = { "AWE32 Synth", /* name */ 0, /* device */ @@ -308,14 +261,15 @@ static struct voice_alloc_info *voice_alloc; /* set at initialization */ * function prototypes *----------------------------------------------------------------*/ -#ifndef AWE_OBSOLETE_VOXWARE +#if defined(linux) && !defined(AWE_OBSOLETE_VOXWARE) static int awe_check_port(void); static void awe_request_region(void); static void awe_release_region(void); -#endif +#endif /* linux & obsolete */ static void awe_reset_samples(void); /* emu8000 chip i/o access */ +static void setup_ports(int p1, int p2, int p3); 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 int data); static unsigned short awe_peek(unsigned short cmd, unsigned short port); @@ -323,10 +277,12 @@ static unsigned int awe_peek_dw(unsigned short cmd, unsigned short port); static void awe_wait(unsigned short delay); /* initialize emu8000 chip */ +static int _attach_awe(void); +static void _unload_awe(void); static void awe_initialize(void); /* set voice parameters */ -static void awe_init_misc_modes(int init_all); +static void awe_init_ctrl_parms(int init_all); static void awe_init_voice_info(awe_voice_info *vp); static void awe_init_voice_parm(awe_voice_parm *pp); #ifdef AWE_HAS_GUS_COMPATIBILITY @@ -337,7 +293,7 @@ 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); -#endif +#endif /* gus compat */ /* turn on/off note */ static void awe_note_on(int voice); @@ -362,9 +318,13 @@ static void awe_calc_pitch(int voice); static void awe_calc_pitch_from_freq(int voice, int freq); #endif static void awe_calc_volume(int voice); +static void awe_update_volume(void); +static void awe_change_master_volume(short val); static void awe_voice_init(int voice, int init_all); static void awe_channel_init(int ch, int init_all); static void awe_fx_init(int ch); +static void awe_send_effect(int voice, int layer, int type, int val); +static void awe_modwheel_change(int voice, int value); /* sequencer interface */ static int awe_open(int dev, int mode); @@ -389,6 +349,8 @@ 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); +#define awe_key_pressure(dev,voice,key,press) awe_start_note(dev,voice,(key)+128,press) + /* hardware controls */ #ifdef AWE_HAS_GUS_COMPATIBILITY static void awe_hw_gus_control(int dev, int cmd, unsigned char *event); @@ -417,6 +379,8 @@ static int awe_load_map(awe_patch_info *patch, const char *addr, int count); #ifdef AWE_HAS_GUS_COMPATIBILITY static int awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag); #endif +/*static int awe_probe_info(awe_patch_info *patch, const char *addr, int count);*/ +static int awe_probe_data(awe_patch_info *patch, const char *addr, int count); static int check_patch_opened(int type, char *name); static int awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int channels); static void add_sf_info(int rec); @@ -426,6 +390,14 @@ static void add_info_list(int rec); static void awe_remove_samples(int sf_id); static void rebuild_preset_list(void); static short awe_set_sample(awe_voice_info *vp); +static int search_sample_index(int sf, int sample, int level); + +#ifdef AWE_ALLOW_SAMPLE_SHARING +static int is_identical_id(int id1, int id2); +static int is_identical_name(unsigned char *name, int id); +static int is_shared_sf(unsigned char *name); +static int info_duplicated(awe_voice_list *rec); +#endif /* allow sharing */ /* lowlevel functions */ static void awe_init_audio(void); @@ -441,23 +413,82 @@ static void awe_close_dram(void); static void awe_write_dram(unsigned short c); static int awe_detect_base(int addr); static int awe_detect(void); -static int awe_check_dram(void); +static void awe_check_dram(void); static int awe_load_chorus_fx(awe_patch_info *patch, const char *addr, int count); static void awe_set_chorus_mode(int mode); +static void awe_update_chorus_mode(void); static int awe_load_reverb_fx(awe_patch_info *patch, const char *addr, int count); static void awe_set_reverb_mode(int mode); +static void awe_update_reverb_mode(void); static void awe_equalizer(int bass, int treble); +static void awe_update_equalizer(void); + #ifdef CONFIG_AWE32_MIXER -static int awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg); +static void attach_mixer(void); +static void unload_mixer(void); +#endif + +#ifdef CONFIG_AWE32_MIDIEMU +static void attach_midiemu(void); +static void unload_midiemu(void); #endif -/* define macros for compatibility */ +#define limitvalue(x, a, b) if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b) + #ifdef __FreeBSD__ -# include -#else -# include "awe_compat.h" +/* FIXME */ +#define MALLOC_LOOP_DATA +#define WAIT_BY_LOOP #endif +/*---------------------------------------------------------------- + * control parameters + *----------------------------------------------------------------*/ + + +#ifdef AWE_USE_NEW_VOLUME_CALC +#define DEF_VOLUME_CALC TRUE +#else +#define DEF_VOLUME_CALC FALSE +#endif /* new volume */ + +#define DEF_ZERO_ATTEN 32 /* 12dB below */ +#define DEF_MOD_SENSE 18 +#define DEF_CHORUS_MODE 2 +#define DEF_REVERB_MODE 4 +#define DEF_BASS_LEVEL 5 +#define DEF_TREBLE_LEVEL 9 + +static struct CtrlParmsDef { + int value; + int init_each_time; + void (*update)(void); +} ctrl_parms[AWE_MD_END] = { + {0,0, NULL}, {0,0, NULL}, /* <-- not used */ + {AWE_VERSION_NUMBER, FALSE, NULL}, + {TRUE, FALSE, NULL}, /* exclusive */ + {TRUE, FALSE, NULL}, /* realpan */ + {AWE_DEFAULT_BANK, FALSE, NULL}, /* gusbank */ + {FALSE, TRUE, NULL}, /* keep effect */ + {DEF_ZERO_ATTEN, FALSE, awe_update_volume}, /* zero_atten */ + {FALSE, FALSE, NULL}, /* chn_prior */ + {DEF_MOD_SENSE, FALSE, NULL}, /* modwheel sense */ + {AWE_DEFAULT_PRESET, FALSE, NULL}, /* def_preset */ + {AWE_DEFAULT_BANK, FALSE, NULL}, /* def_bank */ + {AWE_DEFAULT_DRUM, FALSE, NULL}, /* def_drum */ + {FALSE, FALSE, NULL}, /* toggle_drum_bank */ + {DEF_VOLUME_CALC, FALSE, awe_update_volume}, /* new_volume_calc */ + {DEF_CHORUS_MODE, FALSE, awe_update_chorus_mode}, /* chorus mode */ + {DEF_REVERB_MODE, FALSE, awe_update_reverb_mode}, /* reverb mode */ + {DEF_BASS_LEVEL, FALSE, awe_update_equalizer}, /* bass level */ + {DEF_TREBLE_LEVEL, FALSE, awe_update_equalizer}, /* treble level */ + {0, FALSE, NULL}, /* debug mode */ + {FALSE, FALSE, NULL}, /* pan exchange */ +}; + +static int ctrls[AWE_MD_END]; + + /*---------------------------------------------------------------- * synth operation table *----------------------------------------------------------------*/ @@ -492,60 +523,34 @@ static struct synth_operations awe_operations = awe_setup_voice }; -#ifdef CONFIG_AWE32_MIXER -static struct mixer_operations awe_mixer_operations = { -#ifndef __FreeBSD__ - "AWE32", -#endif - "AWE32 Equalizer", - awe_mixer_ioctl, -}; -#endif - /*================================================================ - * attach / unload interface + * General attach / unload interface *================================================================*/ -#ifdef AWE_OBSOLETE_VOXWARE -#define ATTACH_DECL static -#else -#define ATTACH_DECL /**/ -#endif - -ATTACH_DECL -int attach_awe(void) +static int _attach_awe(void) { + if (awe_present) return 0; /* for OSS38.. called twice? */ + /* check presence of AWE32 card */ if (! awe_detect()) { - printk("AWE32: not detected\n"); + printk(KERN_WARNING "AWE32: not detected\n"); return 0; } /* check AWE32 ports are available */ +#if defined(linux) && !defined(AWE_OBSOLETE_VOXWARE) if (awe_check_port()) { - printk("AWE32: I/O area already used.\n"); + printk(KERN_WARNING "AWE32: I/O area already used.\n"); return 0; } +#endif /* set buffers to NULL */ - voices = NULL; - channels = NULL; sflists = NULL; samples = NULL; infos = NULL; - /* voice & channel info */ - voices = (voice_info*)my_malloc(AWE_MAX_VOICES * sizeof(voice_info)); - channels = (awe_chan_info*)my_malloc(AWE_MAX_CHANNELS * sizeof(awe_chan_info)); - - if (voices == NULL || channels == NULL) { - my_free(voices); - my_free(channels); - printk("AWE32: can't allocate sample tables\n"); - return 0; - } - /* allocate sample tables */ INIT_TABLE(sflists, max_sfs, AWE_MAX_SF_LISTS, sf_list); INIT_TABLE(samples, max_samples, AWE_MAX_SAMPLES, awe_sample_list); @@ -553,8 +558,6 @@ int attach_awe(void) my_dev = sound_alloc_synthdev(); if (my_dev == -1) { - my_free(voices); - my_free(channels); printk(KERN_WARNING "AWE32 Error: too many synthesizers\n"); return 0; } @@ -564,13 +567,16 @@ int attach_awe(void) synth_devs[my_dev] = &awe_operations; #ifdef CONFIG_AWE32_MIXER - if ((my_mixerdev=sound_alloc_mixerdev())!=-1) { - mixer_devs[my_mixerdev] = &awe_mixer_operations; - } + attach_mixer(); +#endif +#ifdef CONFIG_AWE32_MIDIEMU + attach_midiemu(); #endif +#if defined(linux) && !defined(AWE_OBSOLETE_VOXWARE) /* reserve I/O ports for awedrv */ awe_request_region(); +#endif /* clear all samples */ awe_reset_samples(); @@ -580,21 +586,14 @@ int attach_awe(void) sprintf(awe_info.name, "AWE32-%s (RAM%dk)", AWEDRV_VERSION, awe_mem_size/1024); -#ifdef __FreeBSD__ - printk("awe0: ", awe_mem_size/1024); -#elif defined(AWE_DEBUG_ON) - printk("%s\n", awe_info.name); -#endif - - /* set default values */ - awe_init_misc_modes(TRUE); - - /* set reverb & chorus modes */ - awe_set_reverb_mode(reverb_mode); - awe_set_chorus_mode(chorus_mode); + printk("\n", awe_mem_size/1024); awe_present = TRUE; +#if defined(AWE_MODULE_SUPPORT) && defined(MODULE) + SOUND_LOCK; +#endif + return 1; } @@ -602,48 +601,168 @@ int attach_awe(void) #ifdef AWE_DYNAMIC_BUFFER static void free_tables(void) { - my_free(sflists); + if (sflists) + my_free(sflists); sflists = NULL; max_sfs = 0; - my_free(samples); + if (samples) + my_free(samples); samples = NULL; max_samples = 0; - my_free(infos); + if (infos) + my_free(infos); infos = NULL; max_infos = 0; } -#else + +static void *realloc_block(void *buf, int oldsize, int size) +{ + void *ptr; + if (oldsize == size) + return buf; + if ((ptr = my_malloc(size)) == NULL) + return NULL; + if (oldsize && size) + MEMCPY(ptr, buf, ((oldsize < size) ? oldsize : size) ); + if (buf) + my_free(buf); + return ptr; +} + + +#else /* dynamic buffer */ + #define free_buffers() /**/ -#endif +#endif /* dynamic_buffer */ -ATTACH_DECL -void unload_awe(void) + +static void _unload_awe(void) { if (awe_present) { awe_reset_samples(); awe_release_region(); - my_free(voices); - my_free(channels); free_tables(); - sound_unload_mixerdev(my_mixerdev); +#ifdef CONFIG_AWE32_MIXER + unload_mixer(); +#endif +#ifdef CONFIG_AWE32_MIDIEMU + unload_midiemu(); +#endif sound_unload_synthdev(my_dev); awe_present = FALSE; +#if defined(AWE_MODULE_SUPPORT) && defined(MODULE) + SOUND_LOCK_END; +#endif } } +/*================================================================ + * Linux interface + *================================================================*/ + +#ifdef linux + /*---------------------------------------------------------------- - * old type interface + * Linux PnP driver support *----------------------------------------------------------------*/ -#ifdef AWE_OBSOLETE_VOXWARE +#ifdef CONFIG_PNP_DRV -#ifdef __FreeBSD__ -long attach_awe_obsolete(long mem_start, struct address_info *hw_config) -#else +#include + +BASEVAR_DECL int pnp = 1; /* use PnP as default */ + +#define AWE_NUM_CHIPS 3 +static unsigned int pnp_ids[AWE_NUM_CHIPS] = { + PNP_EISAID('C','T','L',0x0021), + PNP_EISAID('C','T','L',0x0022), + PNP_EISAID('C','T','L',0x0023), +}; +static struct pnp_driver pnp_awe[AWE_NUM_CHIPS]; +static int awe_pnp_ok = 0; + +static void awe_pnp_config(struct pnp_device *d) +{ + struct pnp_resource *r; + int port[3]; + int nio = 0; + + port[0] = port[1] = port[2] = 0; + for (r = d->res; r != NULL; r = r->next) { + if (r->type == PNP_RES_IO) { + if (nio >= 0 && nio < 3) + port[nio] = r->start; + nio++; + } + } + setup_ports(port[0], port[1], port[2]); + DEBUG(0,printk("AWE32: PnP setup ports: %x:%x:%x\n", port[0], port[1], port[2])); +} + +static int awe_pnp_event (struct pnp_device *d, struct pnp_drv_event *e) +{ + struct pnp_driver *drv = d->l.k.driver; + + switch (e->type) { + case PNP_DRV_ALLOC: + drv->flags |= PNP_DRV_INUSE; + awe_pnp_ok = 1; + awe_pnp_config(d); + _attach_awe(); + break; + + case PNP_DRV_DISABLE: + case PNP_DRV_EMERGSTOP: + drv->flags &= ~PNP_DRV_INUSE; + awe_pnp_ok = 0; + _unload_awe(); + break; + + case PNP_DRV_CONFIG: + if (awe_busy) return 1; /* used now */ + awe_release_region(); + awe_pnp_config(d); + awe_request_region(); + break; + + case PNP_DRV_RECONFIG: + break; + } + return 0; +} + +static int awe_initpnp (void) +{ + int i; + for (i = 0; i < AWE_NUM_CHIPS; i++) { + pnp_awe[i].id.type = PNP_HDL_ISA; + pnp_awe[i].id.t.isa.id = pnp_ids[i]; + pnp_awe[i].id.next = NULL; + pnp_awe[i].name = "Soundblaster AWE32/AWE64 PnP"; + pnp_awe[i].event = awe_pnp_event; + pnp_register_driver(&pnp_awe[i], 1); + } + return 0; +} + +static void awe_unload_pnp (void) +{ + int i; + for (i = 0; i < AWE_NUM_CHIPS; i++) + pnp_unregister_driver(&pnp_awe[i]); +} +#endif /* PnP support */ + +/*---------------------------------------------------------------- + * device / lowlevel (module) interface + *----------------------------------------------------------------*/ + +#ifdef AWE_OBSOLETEL_VOXWARE + +/* old type interface */ int attach_awe_obsolete(int mem_start, struct address_info *hw_config) -#endif { my_malloc_init(mem_start); - if (! attach_awe()) + if (! _attach_awe()) return 0; return my_malloc_memptr(); } @@ -654,8 +773,92 @@ int probe_awe_obsolete(struct address_info *hw_config) /*return awe_detect();*/ } +#else /* !obsolete */ + +/* new type interface */ +int attach_awe(void) +{ +#ifdef CONFIG_PNP_DRV + if (pnp) { + awe_initpnp(); + if (awe_pnp_ok) + return 0; + } +#endif /* pnp */ + _attach_awe(); + return 0; +} + +void unload_awe(void) +{ +#ifdef CONFIG_PNP_DRV + if (pnp) + awe_unload_pnp(); +#endif /* pnp */ + _unload_awe(); +} + +/* module interface */ + +#if defined(AWE_MODULE_SUPPORT) && defined(MODULE) +int init_module(void) +{ + return attach_awe(); +} + +void cleanup_module(void) +{ + unload_awe(); +} + +#ifdef MODULE_PARM +MODULE_AUTHOR("Takashi Iwai "); +MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver"); +MODULE_SUPPORTED_DEVICE("sound"); #endif +#endif /* module */ + +#endif /* AWE_OBSOLETE_VOXWARE */ + +#endif /* linux */ + + +/*================================================================ + * FreeBSD interface + *================================================================*/ + +#ifdef __FreeBSD__ + +#ifdef AWE_OBSOLETE_VOXWARE +long attach_awe_obsolete(long mem_start, struct address_info *hw_config) +{ + _attach_awe(); + return 0; +} + +int probe_awe_obsolete(struct address_info *hw_config) +{ + return 1; +} + +#else /* !obsolete */ + +/* new type interface */ +void attach_awe(struct address_info *hw_config) +{ + _attach_awe(); +} + +int probe_awe(struct address_info *hw_config) +{ + return 1; +} + +#endif /* obsolete */ + +#endif /* FreeBSD */ + /*================================================================ * clear sample tables @@ -683,26 +886,44 @@ awe_reset_samples(void) *================================================================*/ /* select a given AWE32 pointer */ +static int awe_ports[5]; +static int port_setuped = FALSE; static int awe_cur_cmd = -1; #define awe_set_cmd(cmd) \ -if (awe_cur_cmd != cmd) { OUTW(cmd, awe_base + 0x802); awe_cur_cmd = cmd; } -#define awe_port(port) (awe_base - 0x620 + port) +if (awe_cur_cmd != cmd) { OUTW(cmd, awe_ports[Pointer]); awe_cur_cmd = cmd; } + +/* store values to i/o port array */ +static void setup_ports(int port1, int port2, int port3) +{ + awe_ports[0] = port1; + if (port2 == 0) + port2 = port1 + 0x400; + awe_ports[1] = port2; + awe_ports[2] = port2 + 2; + if (port3 == 0) + port3 = port1 + 0x800; + awe_ports[3] = port3; + awe_ports[4] = port3 + 2; + + port_setuped = TRUE; +} /* write 16bit data */ INLINE static void awe_poke(unsigned short cmd, unsigned short port, unsigned short data) { awe_set_cmd(cmd); - OUTW(data, awe_port(port)); + OUTW(data, awe_ports[port]); } /* write 32bit data */ INLINE static void awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data) { + unsigned short addr = awe_ports[port]; awe_set_cmd(cmd); - OUTW(data, awe_port(port)); /* write lower 16 bits */ - OUTW(data >> 16, awe_port(port)+2); /* write higher 16 bits */ + OUTW(data, addr); /* write lower 16 bits */ + OUTW(data >> 16, addr + 2); /* write higher 16 bits */ } /* read 16bit data */ @@ -711,7 +932,7 @@ awe_peek(unsigned short cmd, unsigned short port) { unsigned short k; awe_set_cmd(cmd); - k = inw(awe_port(port)); + k = inw(awe_ports[port]); return k; } @@ -720,19 +941,21 @@ INLINE static unsigned int awe_peek_dw(unsigned short cmd, unsigned short port) { unsigned int k1, k2; + unsigned short addr = awe_ports[port]; awe_set_cmd(cmd); - k1 = inw(awe_port(port)); - k2 = inw(awe_port(port)+2); + k1 = inw(addr); + k2 = inw(addr + 2); k1 |= k2 << 16; return k1; } /* wait delay number of AWE32 44100Hz clocks */ +#ifdef WAIT_BY_LOOP /* wait by loop -- that's not good.. */ static void awe_wait(unsigned short delay) { unsigned short clock, target; - unsigned short port = awe_port(AWE_WC_Port); + unsigned short port = awe_ports[AWE_WC_Port]; int counter; /* sample counter */ @@ -749,6 +972,28 @@ awe_wait(unsigned short delay) if (counter > 65536) break; } +#else + +static struct wait_queue *awe_sleeper = NULL; +static void awe_wakeup(unsigned long dummy) +{ + wake_up(&awe_sleeper); +} + +static struct timer_list awe_timer = +{NULL, NULL, 0, 0, awe_wakeup}; + +static void awe_wait(unsigned short delay) +{ + unsigned long flags; + awe_timer.expires = jiffies + (HZ * (unsigned long)delay + 44099) / 44100; + add_timer(&awe_timer); + save_flags (flags); + cli(); + sleep_on(&awe_sleeper); + restore_flags(flags); +} +#endif /* wait by loop */ /* write a word data */ INLINE static void @@ -758,38 +1003,41 @@ awe_write_dram(unsigned short c) } -#ifndef AWE_OBSOLETE_VOXWARE +#if defined(linux) && !defined(AWE_OBSOLETE_VOXWARE) /*================================================================ * port check / request - * 0x620-622, 0xA20-A22, 0xE20-E22 + * 0x620-623, 0xA20-A23, 0xE20-E23 *================================================================*/ static int awe_check_port(void) { - return (check_region(awe_port(Data0), 4) || - check_region(awe_port(Data1), 4) || - check_region(awe_port(Data3), 4)); + if (! port_setuped) return 0; + return (check_region(awe_ports[0], 4) || + check_region(awe_ports[1], 4) || + check_region(awe_ports[3], 4)); } static void awe_request_region(void) { - request_region(awe_port(Data0), 4, "sound driver (AWE32)"); - request_region(awe_port(Data1), 4, "sound driver (AWE32)"); - request_region(awe_port(Data3), 4, "sound driver (AWE32)"); + if (! port_setuped) return; + request_region(awe_ports[0], 4, "sound driver (AWE32)"); + request_region(awe_ports[1], 4, "sound driver (AWE32)"); + request_region(awe_ports[3], 4, "sound driver (AWE32)"); } static void awe_release_region(void) { - release_region(awe_port(Data0), 4); - release_region(awe_port(Data1), 4); - release_region(awe_port(Data3), 4); + if (! port_setuped) return; + release_region(awe_ports[0], 4); + release_region(awe_ports[1], 4); + release_region(awe_ports[3], 4); } -#endif /* !AWE_OBSOLETE_VOXWARE */ +#endif /* linux && !AWE_OBSOLETE_VOXWARE */ /*================================================================ @@ -817,7 +1065,7 @@ awe_initialize(void) awe_init_array(); /* check DRAM memory size */ - awe_mem_size = awe_check_dram(); + awe_check_dram(); /* initialize the FM section of the AWE32 */ awe_init_fm(); @@ -828,8 +1076,15 @@ awe_initialize(void) /* enable audio */ awe_poke(AWE_HWCF3, 0x0004); + /* set default values */ + awe_init_ctrl_parms(TRUE); + /* set equalizer */ - awe_equalizer(5, 9); + awe_update_equalizer(); + + /* set reverb & chorus modes */ + awe_update_reverb_mode(); + awe_update_chorus_mode(); } @@ -1004,34 +1259,28 @@ calc_rate_offset(int Hz) /* attack & decay/release time table (msec) */ static short attack_time_tbl[128] = { -32767, 11878, 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, 0, +32767, 32767, 5989, 4235, 2994, 2518, 2117, 1780, 1497, 1373, 1259, 1154, 1058, 970, 890, 816, +707, 691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, +361, 345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, +180, 172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, +90, 86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, +45, 43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, +22, 21, 20, 19, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12, +11, 11, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 0, }; static short decay_time_tbl[128] = { -32767, 32766, 4589, 4400, 4219, 4045, 3879, 3719, 3566, 3419, 3279, 3144, 3014, 2890, 2771, 2657, - 2548, 2443, 2343, 2246, 2154, 2065, 1980, 1899, 1820, 1746, 1674, 1605, 1539, 1475, 1415, 1356, - 1301, 1247, 1196, 1146, 1099, 1054, 1011, 969, 929, 891, 854, 819, 785, 753, 722, 692, - 664, 636, 610, 585, 561, 538, 516, 494, 474, 455, 436, 418, 401, 384, 368, 353, - 339, 325, 311, 298, 286, 274, 263, 252, 242, 232, 222, 213, 204, 196, 188, 180, - 173, 166, 159, 152, 146, 140, 134, 129, 123, 118, 113, 109, 104, 100, 96, 92, - 88, 84, 81, 77, 74, 71, 68, 65, 63, 60, 58, 55, 53, 51, 49, 47, - 45, 43, 41, 39, 38, 36, 35, 33, 32, 30, 29, 28, 27, 26, 25, 24, +32767, 32767, 22614, 15990, 11307, 9508, 7995, 6723, 5653, 5184, 4754, 4359, 3997, 3665, 3361, 3082, +2828, 2765, 2648, 2535, 2428, 2325, 2226, 2132, 2042, 1955, 1872, 1793, 1717, 1644, 1574, 1507, +1443, 1382, 1324, 1267, 1214, 1162, 1113, 1066, 978, 936, 897, 859, 822, 787, 754, 722, +691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, 361, +345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, 180, +172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, 90, +86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, 45, +43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, 22, }; -/* -static int -calc_parm_delay(int msec) -{ - return (0x8000 - msec * 1000 / 725); -} -*/ +#define calc_parm_delay(msec) (0x8000 - (msec) * 1000 / 725); /* delay time = 0x8000 - msec/92 */ static int @@ -1095,6 +1344,7 @@ calc_parm_search(int msec, short *table) #define PARM_BYTE 0 #define PARM_WORD 1 +#define PARM_SIGN 2 static struct PARM_DEFS { int type; /* byte or word */ @@ -1119,13 +1369,13 @@ static struct PARM_DEFS { {PARM_WORD, 0, 0x8000, NULL}, /* lfo1 delay */ {PARM_BYTE, 0, 0xff, awe_fx_tremfrq}, /* lfo1 freq */ - {PARM_BYTE, 0, 0x7f, awe_fx_tremfrq}, /* lfo1 volume (positive only)*/ - {PARM_BYTE, 0, 0x7f, awe_fx_fmmod}, /* lfo1 pitch (positive only)*/ - {PARM_BYTE, 0, 0xff, awe_fx_fmmod}, /* lfo1 cutoff (positive only)*/ + {PARM_SIGN, -128, 127, awe_fx_tremfrq}, /* lfo1 volume */ + {PARM_SIGN, -128, 127, awe_fx_fmmod}, /* lfo1 pitch */ + {PARM_BYTE, 0, 0xff, awe_fx_fmmod}, /* lfo1 cutoff */ {PARM_WORD, 0, 0x8000, NULL}, /* lfo2 delay */ {PARM_BYTE, 0, 0xff, awe_fx_fm2frq2}, /* lfo2 freq */ - {PARM_BYTE, 0, 0x7f, awe_fx_fm2frq2}, /* lfo2 pitch (positive only)*/ + {PARM_SIGN, -128, 127, awe_fx_fm2frq2}, /* lfo2 pitch */ {PARM_WORD, 0, 0xffff, awe_set_voice_pitch}, /* initial pitch */ {PARM_BYTE, 0, 0xff, NULL}, /* chorus */ @@ -1152,8 +1402,16 @@ FX_BYTE(FX_Rec *rec, FX_Rec *lay, int type, unsigned char value) effect = lay->val[type]; if (!on && (on = FX_ON(rec, type)) != 0) effect = rec->val[type]; - if (on == FX_FLAG_ADD) - effect += (int)value; + if (on == FX_FLAG_ADD) { + if (parm_defs[type].type == PARM_SIGN) { + if (value > 0x7f) + effect += (int)value - 0x100; + else + effect += (int)value; + } else { + effect += (int)value; + } + } if (on) { if (effect < parm_defs[type].low) effect = parm_defs[type].low; @@ -1221,12 +1479,20 @@ FX_OFFSET(FX_Rec *rec, FX_Rec *lay, int lo, int hi, int mode) * turn on/off sample *================================================================*/ +/* table for volume target calculation */ +static unsigned short voltarget[16] = { + 0xEAC0, 0XE0C8, 0XD740, 0XCE20, 0XC560, 0XBD08, 0XB500, 0XAD58, + 0XA5F8, 0X9EF0, 0X9830, 0X91C0, 0X8B90, 0X85A8, 0X8000, 0X7A90 +}; + static void awe_note_on(int voice) { unsigned int temp; int addr; + int vtarget, ftarget, ptarget, pitch; awe_voice_info *vp; + awe_voice_parm_block *parm; FX_Rec *fx = &voices[voice].cinfo->fx; FX_Rec *fx_lay = NULL; if (voices[voice].layer < MAX_LAYERS) @@ -1236,32 +1502,73 @@ awe_note_on(int voice) if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; + parm = (awe_voice_parm_block*)&vp->parm; + /* 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_VTFT(voice), 0x0000FFFF); + awe_poke(AWE_CVCF(voice), 0x0000FFFF); awe_poke(AWE_PTRX(voice), 0); awe_poke(AWE_CPF(voice), 0); + /* set pitch offset */ + awe_set_pitch(voice, TRUE); + /* modulation & volume envelope */ - awe_poke(AWE_ENVVAL(voice), - FX_WORD(fx, fx_lay, AWE_FX_ENV1_DELAY, vp->parm.moddelay)); - awe_poke(AWE_ATKHLD(voice), - FX_COMB(fx, fx_lay, AWE_FX_ENV1_HOLD, AWE_FX_ENV1_ATTACK, - vp->parm.modatkhld)); + if (parm->modatk >= 0x80 && parm->moddelay >= 0x8000) { + awe_poke(AWE_ENVVAL(voice), 0xBFFF); + pitch = (parm->env1pit<<4) + voices[voice].apitch; + if (pitch > 0xffff) pitch = 0xffff; + /* calculate filter target */ + ftarget = parm->cutoff + parm->env1fc; + limitvalue(ftarget, 0, 255); + ftarget <<= 8; + } else { + awe_poke(AWE_ENVVAL(voice), + FX_WORD(fx, fx_lay, AWE_FX_ENV1_DELAY, parm->moddelay)); + ftarget = parm->cutoff; + ftarget <<= 8; + pitch = voices[voice].apitch; + } + + /* calcualte pitch target */ + if (pitch != 0xffff) { + ptarget = 1 << (pitch >> 12); + if (pitch & 0x800) ptarget += (ptarget*0x102e)/0x2710; + if (pitch & 0x400) ptarget += (ptarget*0x764)/0x2710; + if (pitch & 0x200) ptarget += (ptarget*0x389)/0x2710; + ptarget += (ptarget>>1); + if (ptarget > 0xffff) ptarget = 0xffff; + + } else ptarget = 0xffff; + if (parm->modatk >= 0x80) + awe_poke(AWE_ATKHLD(voice), + FX_BYTE(fx, fx_lay, AWE_FX_ENV1_HOLD, parm->modhld) << 8 | 0x7f); + else + awe_poke(AWE_ATKHLD(voice), + FX_COMB(fx, fx_lay, AWE_FX_ENV1_HOLD, AWE_FX_ENV1_ATTACK, + vp->parm.modatkhld)); awe_poke(AWE_DCYSUS(voice), FX_COMB(fx, fx_lay, AWE_FX_ENV1_SUSTAIN, AWE_FX_ENV1_DECAY, vp->parm.moddcysus)); - awe_poke(AWE_ENVVOL(voice), - FX_WORD(fx, fx_lay, AWE_FX_ENV2_DELAY, vp->parm.voldelay)); - awe_poke(AWE_ATKHLDV(voice), - FX_COMB(fx, fx_lay, AWE_FX_ENV2_HOLD, AWE_FX_ENV2_ATTACK, + + if (parm->volatk >= 0x80 && parm->voldelay >= 0x8000) { + awe_poke(AWE_ENVVAL(voice), 0xBFFF); + vtarget = voltarget[voices[voice].avol%0x10]>>(voices[voice].avol>>4); + } else { + awe_poke(AWE_ENVVOL(voice), + FX_WORD(fx, fx_lay, AWE_FX_ENV2_DELAY, vp->parm.voldelay)); + vtarget = 0; + } + if (parm->volatk >= 0x80) + awe_poke(AWE_ATKHLDV(voice), + FX_BYTE(fx, fx_lay, AWE_FX_ENV2_HOLD, parm->volhld) << 8 | 0x7f); + else + awe_poke(AWE_ATKHLDV(voice), + FX_COMB(fx, fx_lay, AWE_FX_ENV2_HOLD, AWE_FX_ENV2_ATTACK, vp->parm.volatkhld)); /* decay/sustain parameter for volume envelope must be set at last */ - /* pitch offset */ - awe_set_pitch(voice, TRUE); - /* cutoff and volume */ awe_set_volume(voice, TRUE); @@ -1303,9 +1610,13 @@ awe_note_on(int voice) awe_poke_dw(AWE_CCCA(voice), temp); DEBUG(4,printk("AWE32: [-- startaddr=%x/%x]\n", vp->start, addr)); + /* clear unknown registers */ + awe_poke_dw(AWE_00A0(voice), 0); + awe_poke_dw(AWE_0080(voice), 0); + /* reset volume */ - awe_poke_dw(AWE_VTFT(voice), 0x0000FFFF); - awe_poke_dw(AWE_CVCF(voice), 0x0000FFFF); + awe_poke_dw(AWE_VTFT(voice), (vtarget<<16)|ftarget); + awe_poke_dw(AWE_CVCF(voice), (vtarget<<16)|ftarget); /* turn on envelope */ awe_poke(AWE_DCYSUSV(voice), @@ -1313,9 +1624,9 @@ awe_note_on(int voice) vp->parm.voldcysus)); /* set reverb */ temp = FX_BYTE(fx, fx_lay, AWE_FX_REVERB, vp->parm.reverb); - temp = (awe_peek_dw(AWE_PTRX(voice)) & 0xffff0000) | (temp<<8); + temp = (temp << 8) | (ptarget << 16) | voices[voice].aaux; awe_poke_dw(AWE_PTRX(voice), temp); - awe_poke_dw(AWE_CPF(voice), 0x40000000); + awe_poke_dw(AWE_CPF(voice), ptarget << 16); voices[voice].state = AWE_ST_ON; @@ -1421,7 +1732,8 @@ awe_set_volume(int voice, int forced) if ((vp = voices[voice].sample) == NULL || vp->index < 0) return; - tmp2 = FX_BYTE(fx, fx_lay, AWE_FX_CUTOFF, vp->parm.cutoff); + tmp2 = FX_BYTE(fx, fx_lay, AWE_FX_CUTOFF, + (unsigned char)voices[voice].acutoff); tmp2 = (tmp2 << 8); tmp2 |= FX_BYTE(fx, fx_lay, AWE_FX_ATTEN, (unsigned char)voices[voice].avol); @@ -1463,22 +1775,22 @@ awe_set_pan(int voice, int forced) if (vp->pan >= 0) /* 0-127 */ pos = (int)vp->pan * 2 - 128; pos += voices[voice].cinfo->panning; /* -128 - 127 */ - pos = 127 - pos; - if (pos < 0) - temp = 0; - else if (pos > 255) - temp = 255; - else - temp = pos; + temp = 127 - pos; + } + limitvalue(temp, 0, 255); + if (ctrls[AWE_MD_PAN_EXCHANGE]) { + temp = 255 - temp; } if (forced || temp != voices[voice].apan) { + voices[voice].apan = temp; addr = vp->loopstart - 1; addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_START, AWE_FX_COARSE_LOOP_START, vp->mode); temp = (temp<<24) | (unsigned int)addr; awe_poke_dw(AWE_PSST(voice), temp); - voices[voice].apan = temp; DEBUG(4,printk("AWE32: [-- loopstart=%x/%x]\n", vp->loopstart, addr)); + if (temp == 0) voices[voice].aaux = 0xff; + else voices[voice].aaux = (-temp)&0xff; } } @@ -1674,6 +1986,55 @@ static int vol_table[128] = { 2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0, }; +/* tables for volume->attenuation calculation */ +static unsigned char voltab1[128] = { + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x2b, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, + 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, + 0x19, 0x19, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, + 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10, + 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d, + 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static unsigned char voltab2[128] = { + 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x2a, + 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x24, 0x23, 0x22, 0x21, + 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a, + 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15, + 0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x10, + 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, + 0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, + 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static unsigned char expressiontab[128] = { + 0x7f, 0x6c, 0x62, 0x5a, 0x54, 0x50, 0x4b, 0x48, 0x45, 0x42, + 0x40, 0x3d, 0x3b, 0x39, 0x38, 0x36, 0x34, 0x33, 0x31, 0x30, + 0x2f, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25, + 0x24, 0x24, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1f, 0x1e, 0x1e, + 0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18, + 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x15, 0x14, 0x14, 0x13, + 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10, 0x10, 0x0f, 0x0f, + 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, + 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, + 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, + 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, + 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + static void awe_calc_volume(int voice) { @@ -1693,22 +2054,69 @@ awe_calc_volume(int voice) return; } - /* 0 - 127 */ - vol = (vp->velocity * cp->main_vol * cp->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; + if (ctrls[AWE_MD_NEW_VOLUME_CALC]) { + int main_vol = cp->main_vol * ap->amplitude / 127; + limitvalue(vp->velocity, 0, 127); + limitvalue(main_vol, 0, 127); + limitvalue(cp->expression_vol, 0, 127); + + vol = voltab1[main_vol] + voltab2[vp->velocity]; + vol = (vol * 8) / 3; + vol += ap->attenuation; + if (cp->expression_vol < 127) + vol += ((0x100 - vol) * expressiontab[cp->expression_vol])/128; + vol += atten_offset; + if (atten_relative) + vol += ctrls[AWE_MD_ZERO_ATTEN]; + limitvalue(vol, 0, 255); + vp->avol = vol; + + } else { + /* 0 - 127 */ + vol = (vp->velocity * cp->main_vol * cp->expression_vol) / (127*127); + vol = vol * ap->amplitude / 127; + + if (vol < 0) vol = 0; + if (vol > 127) vol = 127; - vp->avol = vol; + /* calc to attenuation */ + vol = vol_table[vol]; + vol += (int)ap->attenuation; + vol += atten_offset; + if (atten_relative) + vol += ctrls[AWE_MD_ZERO_ATTEN]; + if (vol > 255) vol = 255; + + vp->avol = vol; + } + if (cp->bank != AWE_DRUM_BANK && ((awe_voice_parm_block*)(&ap->parm))->volatk < 0x7d) { + int atten; + if (vp->velocity < 70) atten = 70; + else atten = vp->velocity; + vp->acutoff = (atten * ap->parm.cutoff + 0xa0) >> 7; + } else { + vp->acutoff = ap->parm.cutoff; + } DEBUG(3,printk("AWE32: [-- voice(%d) vol=%x]\n", voice, vol)); } +/* change master volume */ +static void +awe_change_master_volume(short val) +{ + limitvalue(val, 0, 127); + atten_offset = vol_table[val]; + atten_relative = TRUE; + awe_update_volume(); +} + +/* update volumes of all available channels */ +static void awe_update_volume(void) +{ + int i; + for (i = 0; i < awe_max_voices; i++) + awe_set_voice_vol(i, TRUE); +} /* set sostenuto on */ static void awe_sostenuto_on(int voice, int forced) @@ -1785,7 +2193,7 @@ awe_voice_init(int voice, int init_all) /* clear effects */ static void awe_fx_init(int ch) { - if (SINGLE_LAYER_MODE() && !misc_modes[AWE_MD_KEEP_EFFECT]) { + if (SINGLE_LAYER_MODE() && !ctrls[AWE_MD_KEEP_EFFECT]) { BZERO(&channels[ch].fx, sizeof(channels[ch].fx)); BZERO(&channels[ch].fx_layer, sizeof(&channels[ch].fx_layer)); } @@ -1801,11 +2209,11 @@ static void awe_channel_init(int ch, int init_all) cp->bender_range = 200; /* sense * 100 */ cp->main_vol = 127; if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch)) { - cp->instr = misc_modes[AWE_MD_DEF_DRUM]; + cp->instr = ctrls[AWE_MD_DEF_DRUM]; cp->bank = AWE_DRUM_BANK; } else { - cp->instr = misc_modes[AWE_MD_DEF_PRESET]; - cp->bank = misc_modes[AWE_MD_DEF_BANK]; + cp->instr = ctrls[AWE_MD_DEF_PRESET]; + cp->bank = ctrls[AWE_MD_DEF_BANK]; } cp->vrec = -1; cp->def_vrec = -1; @@ -1816,7 +2224,7 @@ static void awe_channel_init(int ch, int init_all) cp->chan_press = 0; cp->sustained = 0; - if (! misc_modes[AWE_MD_KEEP_EFFECT]) { + if (! ctrls[AWE_MD_KEEP_EFFECT]) { BZERO(&cp->fx, sizeof(cp->fx)); BZERO(&cp->fx_layer, sizeof(cp->fx_layer)); } @@ -1861,8 +2269,9 @@ awe_open(int dev, int mode) awe_busy = TRUE; /* set default mode */ - awe_init_misc_modes(FALSE); - init_atten = misc_modes[AWE_MD_ZERO_ATTEN]; + awe_init_ctrl_parms(FALSE); + atten_relative = TRUE; + atten_offset = 0; drum_flags = DEFAULT_DRUM_FLAGS; playing_mode = AWE_PLAY_INDIRECT; @@ -1889,12 +2298,12 @@ awe_close(int dev) /* set miscellaneous mode parameters */ static void -awe_init_misc_modes(int init_all) +awe_init_ctrl_parms(int init_all) { int i; for (i = 0; i < AWE_MD_END; i++) { - if (init_all || misc_modes_default[i].init_each_time) - misc_modes[i] = misc_modes_default[i].value; + if (init_all || ctrl_parms[i].init_each_time) + ctrls[i] = ctrl_parms[i].value; } } @@ -2078,14 +2487,16 @@ awe_start_note(int dev, int voice, int note, int velocity) } /* if the same note still playing, stop it */ - for (i = 0; i < awe_max_voices; i++) - if (voices[i].key == key) { - if (voices[i].state == AWE_ST_ON) { - awe_note_off(i); - awe_voice_init(i, FALSE); - } else if (voices[i].state == AWE_ST_STANDBY) - awe_voice_init(i, TRUE); - } + if (playing_mode != AWE_PLAY_DIRECT || ctrls[AWE_MD_EXCLUSIVE_SOUND]) { + for (i = 0; i < awe_max_voices; i++) + if (voices[i].key == key) { + if (voices[i].state == AWE_ST_ON) { + awe_note_off(i); + awe_voice_init(i, FALSE); + } else if (voices[i].state == AWE_ST_STANDBY) + awe_voice_init(i, TRUE); + } + } /* allocate voices */ if (playing_mode == AWE_PLAY_DIRECT) @@ -2114,6 +2525,7 @@ awe_search_instr(int bank, int preset) { int i; + limitvalue(preset, 0, AWE_MAX_PRESETS-1); for (i = preset_table[preset]; i >= 0; i = infos[i].next_bank) { if (infos[i].bank == bank) return i; @@ -2158,15 +2570,16 @@ awe_set_instr(int dev, int voice, int instr_no) cinfo->def_vrec = -1; cinfo->vrec = awe_search_instr(def_bank, instr_no); if (def_bank == AWE_DRUM_BANK) /* search default drumset */ - cinfo->def_vrec = awe_search_instr(def_bank, misc_modes[AWE_MD_DEF_DRUM]); + cinfo->def_vrec = awe_search_instr(def_bank, ctrls[AWE_MD_DEF_DRUM]); else /* search default preset */ - cinfo->def_vrec = awe_search_instr(misc_modes[AWE_MD_DEF_BANK], instr_no); + cinfo->def_vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr_no); if (cinfo->vrec < 0 && cinfo->def_vrec < 0) { DEBUG(1,printk("AWE32 Warning: can't find instrument %d\n", instr_no)); } cinfo->instr = instr_no; + DEBUG(2,printk("AWE32: [program(%d) %d/%d]\n", voice, instr_no, def_bank)); return 0; } @@ -2296,7 +2709,7 @@ awe_hw_gus_control(int dev, int cmd, unsigned char *event) } } -#endif +#endif /* gus_compat */ /* AWE32 specific controls */ @@ -2306,8 +2719,6 @@ awe_hw_awe_control(int dev, int cmd, unsigned char *event) int voice; unsigned short p1; short p2; - awe_chan_info *cinfo; - FX_Rec *fx; int i; voice = event[3]; @@ -2322,19 +2733,20 @@ awe_hw_awe_control(int dev, int cmd, unsigned char *event) p1 = *(unsigned short *) &event[4]; p2 = *(short *) &event[6]; - cinfo = &channels[voice]; switch (cmd) { case _AWE_DEBUG_MODE: - debug_mode = p1; - printk("AWE32: debug mode = %d\n", debug_mode); + ctrls[AWE_MD_DEBUG_MODE] = p1; + printk("AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]); break; case _AWE_REVERB_MODE: - awe_set_reverb_mode(p1); + ctrls[AWE_MD_REVERB_MODE] = p1; + awe_update_reverb_mode(); break; case _AWE_CHORUS_MODE: - awe_set_chorus_mode(p1); + ctrls[AWE_MD_CHORUS_MODE] = p1; + awe_update_chorus_mode(); break; case _AWE_REMOVE_LAST_SAMPLES: @@ -2348,30 +2760,13 @@ awe_hw_awe_control(int dev, int cmd, unsigned char *event) break; case _AWE_SEND_EFFECT: - fx = &cinfo->fx; - i = FX_FLAG_SET; + i = -1; if (p1 >= 0x100) { - int layer = (p1 >> 8); - if (layer >= 0 && layer < MAX_LAYERS) - fx = &cinfo->fx_layer[layer]; - p1 &= 0xff; - } - if (p1 & 0x40) i = FX_FLAG_OFF; - if (p1 & 0x80) i = FX_FLAG_ADD; - p1 &= 0x3f; - if (p1 < AWE_FX_END) { - DEBUG(0,printk("AWE32: effects (%d) %d %d\n", voice, p1, p2)); - if (i == FX_FLAG_SET) - FX_SET(fx, p1, p2); - else if (i == FX_FLAG_ADD) - FX_ADD(fx, p1, p2); - else - FX_UNSET(fx, p1); - if (i != FX_FLAG_OFF && parm_defs[p1].realtime) { - DEBUG(0,printk("AWE32: fx_realtime (%d)\n", voice)); - awe_voice_change(voice, parm_defs[p1].realtime); - } + i = (p1 >> 8); + if (i < 0 || i >= MAX_LAYERS) + break; } + awe_send_effect(voice, i, p1, p2); break; case _AWE_RESET_CHANNEL: @@ -2395,22 +2790,14 @@ awe_hw_awe_control(int dev, int cmd, unsigned char *event) case _AWE_INITIAL_VOLUME: DEBUG(0,printk("AWE32: init attenuation %d\n", p1)); - if (p2 == 0) /* absolute value */ - init_atten = (short)p1; - else /* relative value */ - init_atten = misc_modes[AWE_MD_ZERO_ATTEN] + (short)p1; - if (init_atten < 0) init_atten = 0; - for (i = 0; i < awe_max_voices; i++) - awe_set_voice_vol(i, TRUE); + atten_relative = (char)p2; + atten_offset = (short)p1; + awe_update_volume(); break; case _AWE_CHN_PRESSURE: - cinfo->chan_press = p1; - p1 = p1 * misc_modes[AWE_MD_MOD_SENSE] / 1200; - FX_ADD(&cinfo->fx, AWE_FX_LFO1_PITCH, p1); - awe_voice_change(voice, awe_fx_fmmod); - FX_ADD(&cinfo->fx, AWE_FX_LFO2_PITCH, p1); - awe_voice_change(voice, awe_fx_fm2frq2); + channels[voice].chan_press = p1; + awe_modwheel_change(voice, p1); break; case _AWE_CHANNEL_MODE: @@ -2425,13 +2812,18 @@ awe_hw_awe_control(int dev, int cmd, unsigned char *event) break; case _AWE_MISC_MODE: - DEBUG(0,printk("AWE32: misc mode = %d %d\n", p1, p2)); - if (p1 > AWE_MD_VERSION && p1 < AWE_MD_END) - misc_modes[p1] = p2; + DEBUG(0,printk("AWE32: ctrl parms = %d %d\n", p1, p2)); + if (p1 > AWE_MD_VERSION && p1 < AWE_MD_END) { + ctrls[p1] = p2; + if (ctrl_parms[p1].update) + ctrl_parms[p1].update(); + } break; case _AWE_EQUALIZER: - awe_equalizer((int)p1, (int)p2); + ctrls[AWE_MD_BASS_LEVEL] = p1; + ctrls[AWE_MD_TREBLE_LEVEL] = p2; + awe_update_equalizer(); break; default: @@ -2441,6 +2833,60 @@ awe_hw_awe_control(int dev, int cmd, unsigned char *event) } +/* change effects */ +static void +awe_send_effect(int voice, int layer, int type, int val) +{ + awe_chan_info *cinfo; + FX_Rec *fx; + int mode; + + cinfo = &channels[voice]; + if (layer >= 0 && layer < MAX_LAYERS) + fx = &cinfo->fx_layer[layer]; + else + fx = &cinfo->fx; + + if (type & 0x40) + mode = FX_FLAG_OFF; + else if (type & 0x80) + mode = FX_FLAG_ADD; + else + mode = FX_FLAG_SET; + type &= 0x3f; + + if (type >= 0 && type < AWE_FX_END) { + DEBUG(2,printk("AWE32: effects (%d) %d %d\n", voice, type, val)); + if (mode == FX_FLAG_SET) + FX_SET(fx, type, val); + else if (mode == FX_FLAG_ADD) + FX_ADD(fx, type, val); + else + FX_UNSET(fx, type); + if (mode != FX_FLAG_OFF && parm_defs[type].realtime) { + DEBUG(2,printk("AWE32: fx_realtime (%d)\n", voice)); + awe_voice_change(voice, parm_defs[type].realtime); + } + } +} + + +/* change modulation wheel; voice is already mapped on multi2 mode */ +static void +awe_modwheel_change(int voice, int value) +{ + int i; + awe_chan_info *cinfo; + + cinfo = &channels[voice]; + i = value * ctrls[AWE_MD_MOD_SENSE] / 1200; + FX_ADD(&cinfo->fx, AWE_FX_LFO1_PITCH, i); + awe_voice_change(voice, awe_fx_fmmod); + FX_ADD(&cinfo->fx, AWE_FX_LFO2_PITCH, i); + awe_voice_change(voice, awe_fx_fm2frq2); +} + + /* voice pressure change */ static void awe_aftertouch(int dev, int voice, int pressure) @@ -2458,7 +2904,7 @@ awe_aftertouch(int dev, int voice, int pressure) break; case AWE_PLAY_MULTI2: note = (voice_alloc->map[voice] & 0xff) - 1; - awe_start_note(dev, voice, note + 0x80, pressure); + awe_key_pressure(dev, voice, note + 0x80, pressure); break; } } @@ -2468,7 +2914,6 @@ awe_aftertouch(int dev, int voice, int pressure) static void awe_controller(int dev, int voice, int ctrl_num, int value) { - int i; awe_chan_info *cinfo; if (! voice_in_range(voice)) @@ -2486,7 +2931,7 @@ awe_controller(int dev, int voice, int ctrl_num, int value) case CTL_BANK_SELECT: /* MIDI control #0 */ DEBUG(2,printk("AWE32: [bank(%d) %d]\n", voice, value)); if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) && - !misc_modes[AWE_MD_TOGGLE_DRUM_BANK]) + !ctrls[AWE_MD_TOGGLE_DRUM_BANK]) break; cinfo->bank = value; if (cinfo->bank == AWE_DRUM_BANK) @@ -2498,11 +2943,7 @@ awe_controller(int dev, int voice, int ctrl_num, int value) case CTL_MODWHEEL: /* MIDI control #1 */ DEBUG(2,printk("AWE32: [modwheel(%d) %d]\n", voice, value)); - i = value * misc_modes[AWE_MD_MOD_SENSE] / 1200; - FX_ADD(&cinfo->fx, AWE_FX_LFO1_PITCH, i); - awe_voice_change(voice, awe_fx_fmmod); - FX_ADD(&cinfo->fx, AWE_FX_LFO2_PITCH, i); - awe_voice_change(voice, awe_fx_fm2frq2); + awe_modwheel_change(voice, value); break; case CTRL_PITCH_BENDER: /* SEQ1 V2 contorl */ @@ -2533,7 +2974,7 @@ awe_controller(int dev, int voice, int ctrl_num, int value) DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, value)); /* (0-127) -> signed 8bit */ cinfo->panning = value * 2 - 128; - if (misc_modes[AWE_MD_REALTIME_PAN]) + if (ctrls[AWE_MD_REALTIME_PAN]) awe_voice_change(voice, awe_set_pan); break; @@ -2557,14 +2998,12 @@ awe_controller(int dev, int voice, int ctrl_num, int value) FX_SET(&cinfo->fx, AWE_FX_CHORUS, value * 2); break; -#ifdef AWE_ACCEPT_ALL_SOUNDS_CONTROLL case 120: /* all sounds off */ awe_note_off_all(FALSE); break; case 123: /* all notes off */ awe_note_off_all(TRUE); break; -#endif case CTL_SUSTAIN: /* MIDI control #64 */ cinfo->sustained = value; @@ -2605,7 +3044,7 @@ awe_panning(int dev, int voice, int value) cinfo = &channels[voice]; cinfo->panning = value; DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, cinfo->panning)); - if (misc_modes[AWE_MD_REALTIME_PAN]) + if (ctrls[AWE_MD_REALTIME_PAN]) awe_voice_change(voice, awe_set_pan); } @@ -2714,6 +3153,12 @@ awe_load_patch(int dev, int format, const char *addr, case AWE_MAP_PRESET: rc = awe_load_map(&patch, addr, count); break; + /* case AWE_PROBE_INFO: + rc = awe_probe_info(&patch, addr, count); + break;*/ + case AWE_PROBE_DATA: + rc = awe_probe_data(&patch, addr, count); + break; case AWE_LOAD_CHORUS_FX: rc = awe_load_chorus_fx(&patch, addr, count); break; @@ -2740,45 +3185,135 @@ awe_create_sf(int type, char *name) /* terminate sounds */ awe_reset(0); if (current_sf_id >= max_sfs) { +#ifndef AWE_DYNAMIC_BUFFER + return 1; +#else int newsize = max_sfs + AWE_MAX_SF_LISTS; - sf_list *newlist = my_realloc(sflists, sizeof(sf_list)*max_sfs, - sizeof(sf_list)*newsize); + sf_list *newlist = realloc_block(sflists, sizeof(sf_list)*max_sfs, + sizeof(sf_list)*newsize); if (newlist == NULL) return 1; sflists = newlist; max_sfs = newsize; +#endif /* dynamic buffer */ } rec = &sflists[current_sf_id]; rec->sf_id = current_sf_id + 1; rec->type = type; if (current_sf_id == 0 || (type & AWE_PAT_LOCKED) != 0) locked_sf_id = current_sf_id + 1; - /* - if (name) - MEMCPY(rec->name, name, AWE_PATCH_NAME_LEN); - else - BZERO(rec->name, AWE_PATCH_NAME_LEN); - */ rec->num_info = awe_free_info(); rec->num_sample = awe_free_sample(); rec->mem_ptr = awe_free_mem_ptr(); rec->infos = -1; rec->samples = -1; +#ifdef AWE_ALLOW_SAMPLE_SHARING + rec->shared = 0; + if (name) + memcpy(rec->name, name, AWE_PATCH_NAME_LEN); + else + strcpy(rec->name, "*TEMPORARY*"); + if (current_sf_id > 0 && name && (type & AWE_PAT_SHARED) != 0) { + /* is the current font really a shared font? */ + if (is_shared_sf(rec->name)) { + /* check if the shared font is already installed */ + int i; + for (i = current_sf_id; i > 0; i--) { + if (is_identical_name(rec->name, i)) { + rec->shared = i; + break; + } + } + } + } +#endif /* allow sharing */ + current_sf_id++; + return 0; } +#ifdef AWE_ALLOW_SAMPLE_SHARING + +/* check if the given name is a valid shared name */ +#define ASC_TO_KEY(c) ((c) - 'A' + 1) +static int is_shared_sf(unsigned char *name) +{ + static unsigned char id_head[6] = { + ASC_TO_KEY('A'), ASC_TO_KEY('W'), ASC_TO_KEY('E'), + AWE_MAJOR_VERSION, + AWE_MINOR_VERSION, + AWE_TINY_VERSION, + }; + if (MEMCMP(name, id_head, 6) == 0) + return TRUE; + return FALSE; +} + +/* check if the given name matches to the existing list */ +static int is_identical_name(unsigned char *name, int sf) +{ + char *id = sflists[sf-1].name; + if (is_shared_sf(id) && MEMCMP(id, name, AWE_PATCH_NAME_LEN) == 0) + return TRUE; + return FALSE; +} + +/* check if the given voice info exists */ +static int info_duplicated(awe_voice_list *rec) +{ + int j, sf_id; + sf_list *sf; + + /* search for all sharing lists */ + for (sf_id = rec->v.sf_id; sf_id > 0; sf_id = sf->shared) { + sf = &sflists[sf_id - 1]; + for (j = sf->infos; j >= 0; j = infos[j].next) { + awe_voice_list *p = &infos[j]; + if (p->type == V_ST_NORMAL && + p->bank == rec->bank && + p->instr == rec->instr && + p->v.low == rec->v.low && + p->v.high == rec->v.high && + p->v.sample == rec->v.sample) + return TRUE; + } + } + return FALSE; +} + +#endif /* AWE_ALLOW_SAMPLE_SHARING */ + + /* open patch; create sf list and set opened flag */ static int awe_open_patch(awe_patch_info *patch, const char *addr, int count) { awe_open_parm parm; + int shared; + COPY_FROM_USER(&parm, addr, AWE_PATCH_INFO_SIZE, sizeof(parm)); - if (awe_create_sf(parm.type, parm.name)) { - printk("AWE32: can't open: failed to alloc new list\n"); - return RET_ERROR(ENOSPC); + shared = FALSE; + +#ifdef AWE_ALLOW_SAMPLE_SHARING + if (current_sf_id > 0 && (parm.type & AWE_PAT_SHARED) != 0) { + /* is the previous font the same font? */ + if (is_identical_name(parm.name, current_sf_id)) { + /* then append to the previous */ + shared = TRUE; + awe_reset(0); + if (parm.type & AWE_PAT_LOCKED) + locked_sf_id = current_sf_id; + } + } +#endif /* allow sharing */ + if (! shared) { + if (awe_create_sf(parm.type, parm.name)) { + printk("AWE32: can't open: failed to alloc new list\n"); + return RET_ERROR(ENOSPC); + } } patch_opened = TRUE; return current_sf_id; @@ -2817,7 +3352,7 @@ awe_close_patch(awe_patch_info *patch, const char *addr, int count) static int awe_unload_patch(awe_patch_info *patch, const char *addr, int count) { - if (current_sf_id > 0) + if (current_sf_id > 0 && current_sf_id > locked_sf_id) awe_remove_samples(current_sf_id - 1); return 0; } @@ -2829,17 +3364,22 @@ static int alloc_new_info(int nvoices) awe_voice_list *newlist; free_info = awe_free_info(); if (free_info + nvoices >= max_infos) { +#ifndef AWE_DYNAMIC_BUFFER + printk("AWE32: can't alloc info table\n"); + return RET_ERROR(ENOSPC); +#else do { newsize = max_infos + AWE_MAX_INFOS; } while (free_info + nvoices >= newsize); - newlist = my_realloc(infos, sizeof(awe_voice_list)*max_infos, - sizeof(awe_voice_list)*newsize); + newlist = realloc_block(infos, sizeof(awe_voice_list)*max_infos, + sizeof(awe_voice_list)*newsize); if (newlist == NULL) { printk("AWE32: can't alloc info table\n"); return RET_ERROR(ENOSPC); } infos = newlist; max_infos = newsize; +#endif } return 0; } @@ -2851,16 +3391,21 @@ static int alloc_new_sample(void) awe_sample_list *newlist; free_sample = awe_free_sample(); if (free_sample >= max_samples) { +#ifndef AWE_DYNAMIC_BUFFER + printk("AWE32: can't alloc sample table\n"); + return RET_ERROR(ENOSPC); +#else newsize = max_samples + AWE_MAX_SAMPLES; - newlist = my_realloc(samples, - sizeof(awe_sample_list)*max_samples, - sizeof(awe_sample_list)*newsize); + newlist = realloc_block(samples, + sizeof(awe_sample_list)*max_samples, + sizeof(awe_sample_list)*newsize); if (newlist == NULL) { printk("AWE32: can't alloc sample table\n"); return RET_ERROR(ENOSPC); } samples = newlist; max_samples = newsize; +#endif } return 0; } @@ -2871,15 +3416,32 @@ awe_load_map(awe_patch_info *patch, const char *addr, int count) { awe_voice_map map; awe_voice_list *rec; - int free_info; + int p, free_info; + + /* get the link info */ + if (count < sizeof(map)) { + printk("AWE32 Error: invalid patch info length\n"); + return RET_ERROR(EINVAL); + } + COPY_FROM_USER(&map, addr, AWE_PATCH_INFO_SIZE, sizeof(map)); + + /* check if the identical mapping already exists */ + p = awe_search_instr(map.map_bank, map.map_instr); + for (; p >= 0; p = infos[p].next_instr) { + if (p >= 0 && infos[p].type == V_ST_MAPPED && + infos[p].v.low == map.map_key && + infos[p].v.start == map.src_instr && + infos[p].v.end == map.src_bank && + infos[p].v.fixkey == map.src_key) + return 0; /* already present! */ + } if (check_patch_opened(AWE_PAT_TYPE_MAP, NULL) < 0) return RET_ERROR(ENOSPC); + if (alloc_new_info(1) < 0) return RET_ERROR(ENOSPC); - COPY_FROM_USER(&map, addr, AWE_PATCH_INFO_SIZE, sizeof(map)); - free_info = awe_free_info(); rec = &infos[free_info]; rec->bank = map.map_bank; @@ -2901,6 +3463,54 @@ awe_load_map(awe_patch_info *patch, const char *addr, int count) return 0; } +#if 0 +/* probe preset in the current list -- nothing to be loaded */ +static int +awe_probe_info(awe_patch_info *patch, const char *addr, int count) +{ +#ifdef AWE_ALLOW_SAMPLE_SHARING + awe_voice_map map; + int p; + + if (! patch_opened) + return RET_ERROR(EINVAL); + + /* get the link info */ + if (count < sizeof(map)) { + printk("AWE32 Error: invalid patch info length\n"); + return RET_ERROR(EINVAL); + } + COPY_FROM_USER(&map, addr, AWE_PATCH_INFO_SIZE, sizeof(map)); + + /* check if the identical mapping already exists */ + p = awe_search_instr(map.src_bank, map.src_instr); + for (; p >= 0; p = infos[p].next_instr) { + if (p >= 0 && infos[p].type == V_ST_NORMAL && + is_identical_id(infos[p].v.sf_id, current_sf_id) && + infos[p].v.low <= map.src_key && + infos[p].v.high >= map.src_key) + return 0; /* already present! */ + } +#endif /* allow sharing */ + return RET_ERROR(EINVAL); +} +#endif + +/* probe sample in the current list -- nothing to be loaded */ +static int +awe_probe_data(awe_patch_info *patch, const char *addr, int count) +{ +#ifdef AWE_ALLOW_SAMPLE_SHARING + if (! patch_opened) + return RET_ERROR(EINVAL); + + /* search the specified sample by optarg */ + if (search_sample_index(current_sf_id, patch->optarg, 0) >= 0) + return 0; +#endif /* allow sharing */ + return RET_ERROR(EINVAL); +} + /* load voice information data */ static int awe_load_info(awe_patch_info *patch, const char *addr, int count) @@ -2965,6 +3575,12 @@ awe_load_info(awe_patch_info *patch, const char *addr, int count) COPY_FROM_USER(&infos[rec].v, addr, offset, AWE_VOICE_INFO_SIZE); offset += AWE_VOICE_INFO_SIZE; infos[rec].v.sf_id = current_sf_id; +#ifdef AWE_ALLOW_SAMPLE_SHARING + if (sflists[current_sf_id-1].shared) { + if (info_duplicated(&infos[rec])) + continue; + } +#endif /* allow sharing */ if (infos[rec].v.mode & AWE_MODE_INIT_PARM) awe_init_voice_parm(&infos[rec].v.parm); awe_set_sample(&infos[rec].v); @@ -2975,32 +3591,45 @@ awe_load_info(awe_patch_info *patch, const char *addr, int count) return 0; } + /* load wave sample data */ static int awe_load_data(awe_patch_info *patch, const char *addr, int count) { int offset, size; int rc, free_sample; - awe_sample_info *rec; + awe_sample_info tmprec, *rec; if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0) return RET_ERROR(ENOSPC); - if (alloc_new_sample() < 0) - return RET_ERROR(ENOSPC); - - free_sample = awe_free_sample(); - rec = &samples[free_sample].v; - size = (count - AWE_SAMPLE_INFO_SIZE) / 2; offset = AWE_PATCH_INFO_SIZE; - COPY_FROM_USER(rec, addr, offset, AWE_SAMPLE_INFO_SIZE); + COPY_FROM_USER(&tmprec, addr, offset, AWE_SAMPLE_INFO_SIZE); offset += AWE_SAMPLE_INFO_SIZE; - if (size != rec->size) { + if (size != tmprec.size) { printk("AWE32: load: sample size differed (%d != %d)\n", - rec->size, size); + tmprec.size, size); + return RET_ERROR(EINVAL); + } + + if (search_sample_index(current_sf_id, tmprec.sample, 0) >= 0) { +#ifdef AWE_ALLOW_SAMPLE_SHARING + /* if shared sample, skip this data */ + if (sflists[current_sf_id-1].type & AWE_PAT_SHARED) + return 0; +#endif /* allow sharing */ + DEBUG(1,printk("AWE32: sample data %d already present\n", tmprec.sample)); return RET_ERROR(EINVAL); } + + if (alloc_new_sample() < 0) + return RET_ERROR(ENOSPC); + + free_sample = awe_free_sample(); + rec = &samples[free_sample].v; + *rec = tmprec; + if (rec->size > 0) if ((rc = awe_write_wave_data(addr, offset, rec, -1)) != 0) return rc; @@ -3078,7 +3707,7 @@ awe_replace_data(awe_patch_info *patch, const char *addr, int count) static const char *readbuf_addr; static int readbuf_offs; static int readbuf_flags; -#ifdef __FreeBSD__ +#ifdef MALLOC_LOOP_DATA static unsigned short *readbuf_loop; static int readbuf_loopstart, readbuf_loopend; #endif @@ -3087,7 +3716,7 @@ static int readbuf_loopstart, readbuf_loopend; static int readbuf_init(const char *addr, int offset, awe_sample_info *sp) { -#ifdef __FreeBSD__ +#ifdef MALLOC_LOOP_DATA readbuf_loop = NULL; readbuf_loopstart = sp->loopstart; readbuf_loopend = sp->loopend; @@ -3121,7 +3750,7 @@ readbuf_word(int pos) } if (readbuf_flags & AWE_SAMPLE_UNSIGNED) c ^= 0x8000; /* unsigned -> signed */ -#ifdef __FreeBSD__ +#ifdef MALLOC_LOOP_DATA /* write on cache for reverse loop */ if (readbuf_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) { if (pos >= readbuf_loopstart && pos < readbuf_loopend) @@ -3131,7 +3760,7 @@ readbuf_word(int pos) return c; } -#ifdef __FreeBSD__ +#ifdef MALLOC_LOOP_DATA /* read from cache */ static unsigned short readbuf_word_cache(int pos) @@ -3184,7 +3813,7 @@ awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int chann if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) truesize += BLANK_LOOP_SIZE; if (awe_free_mem_ptr() + truesize >= awe_mem_size/2) { - printk("AWE32 Error: Sample memory full\n"); + DEBUG(-1,printk("AWE32 Error: Sample memory full\n")); return RET_ERROR(ENOSPC); } @@ -3418,7 +4047,7 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag) /* scale_freq, scale_factor, volume, and fractions not implemented */ /* append to the tail of the list */ - infos[free_info].bank = misc_modes[AWE_MD_GUS_BANK]; + infos[free_info].bank = ctrls[AWE_MD_GUS_BANK]; infos[free_info].instr = patch.instr_no; infos[free_info].disabled = FALSE; infos[free_info].type = V_ST_NORMAL; @@ -3443,7 +4072,7 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag) static void add_sf_info(int rec) { int sf_id = infos[rec].v.sf_id; - if (sf_id == 0) return; + if (sf_id <= 0) return; sf_id--; if (sflists[sf_id].infos < 0) sflists[sf_id].infos = rec; @@ -3462,7 +4091,7 @@ static void add_sf_info(int rec) static void add_sf_sample(int rec) { int sf_id = samples[rec].v.sf_id; - if (sf_id == 0) return; + if (sf_id <= 0) return; sf_id--; samples[rec].next = sflists[sf_id].samples; sflists[sf_id].samples = rec; @@ -3481,12 +4110,12 @@ static void purge_old_list(int rec, int next) for (cur = next; cur >= 0; cur = infos[cur].next_instr) { if (infos[cur].v.low == low && infos[cur].v.high == high && - infos[cur].v.sf_id != infos[rec].v.sf_id) + ! is_identical_id(infos[cur].v.sf_id, infos[rec].v.sf_id)) *prevp = infos[cur].next_instr; prevp = &infos[cur].next_instr; } } else { - if (infos[next].v.sf_id != infos[rec].v.sf_id) + if (! is_identical_id(infos[next].v.sf_id, infos[rec].v.sf_id)) infos[rec].next_instr = -1; } } @@ -3495,12 +4124,15 @@ static void purge_old_list(int rec, int next) static void add_info_list(int rec) { int *prevp, cur; - int instr = infos[rec].instr; - int bank = infos[rec].bank; + int instr; + int bank; if (infos[rec].disabled) return; + instr = infos[rec].instr; + bank = infos[rec].bank; + limitvalue(instr, 0, AWE_MAX_PRESETS-1); prevp = &preset_table[instr]; cur = *prevp; while (cur >= 0) { @@ -3555,27 +4187,72 @@ static void rebuild_preset_list(void) } } +/* compare the given sf_id pair */ +static int is_identical_id(int id1, int id2) +{ + if (id1 == id2) + return TRUE; + if (id1 <= 0 || id2 <= 0) /* this must not happen.. */ + return FALSE; +#ifdef AWE_ALLOW_SAMPLE_SHARING + { + /* compare with the sharing id */ + int i; + if (id1 < id2) { /* make sure id1 > id2 */ + int tmp; tmp = id1; id1 = id2; id2 = tmp; + } + for (i = sflists[id1-1].shared; i > 0; i = sflists[i-1].shared) { + if (i == id2) + return TRUE; + } + } +#endif /* allow sharing */ + return FALSE; +} + +/* search the sample index matching with the given sample id */ +static int search_sample_index(int sf, int sample, int level) +{ + int i; + + if (sf <= 0 || sf > current_sf_id) + return -1; /* this must not happen */ + + for (i = sflists[sf-1].samples; i >= 0; i = samples[i].next) { + if (samples[i].v.sample == sample) + return i; + } +#ifdef AWE_ALLOW_SAMPLE_SHARING + if (sflists[sf-1].shared) { /* search recursively */ + if (level > current_sf_id) + return -1; /* strange sharing loop.. quit */ + return search_sample_index(sflists[sf-1].shared, sample, level + 1); + } +#endif + return -1; +} + /* search the specified sample */ static short awe_set_sample(awe_voice_info *vp) { int i; + vp->index = -1; - for (i = sflists[vp->sf_id-1].samples; i >= 0; i = samples[i].next) { - if (samples[i].v.sample == vp->sample) { - /* set the actual sample offsets */ - vp->start += samples[i].v.start; - vp->end += samples[i].v.end; - vp->loopstart += samples[i].v.loopstart; - vp->loopend += samples[i].v.loopend; - /* copy mode flags */ - vp->mode = samples[i].v.mode_flags; - /* set index */ - vp->index = i; - return i; - } - } - return -1; + if ((i = search_sample_index(vp->sf_id, vp->sample, 0)) < 0) + return -1; + + /* set the actual sample offsets */ + vp->start += samples[i].v.start; + vp->end += samples[i].v.end; + vp->loopstart += samples[i].v.loopstart; + vp->loopend += samples[i].v.loopend; + /* copy mode flags */ + vp->mode = samples[i].v.mode_flags; + /* set index */ + vp->index = i; + + return i; } @@ -3682,13 +4359,22 @@ static int search_best_voice(int condition) { int i, time, best; + int vtarget = 0xffff, min_vtarget = 0xffff; + best = -1; time = current_alloc_time + 1; for (i = 0; i < awe_max_voices; i++) { - if ((voices[i].state & condition) && - (best < 0 || voices[i].time < time)) { + if (! (voices[i].state & condition)) + continue; +#ifdef AWE_CHECK_VTARGET + /* get current volume */ + vtarget = (awe_peek_dw(AWE_VTFT(i)) >> 16) & 0xffff; +#endif + if (best < 0 || vtarget < min_vtarget || + (vtarget == min_vtarget && voices[i].time < time)) { best = i; time = voices[i].time; + min_vtarget = vtarget; } } /* clear voice */ @@ -3718,8 +4404,7 @@ awe_clear_voice(void) if ((best = search_best_voice(AWE_ST_SUSTAINED)) >= 0) return best; -#ifdef AWE_LOOKUP_MIDI_PRIORITY - if (MULTI_LAYER_MODE() && misc_modes[AWE_MD_CHN_PRIOR]) { + if (MULTI_LAYER_MODE() && ctrls[AWE_MD_CHN_PRIOR]) { int ch = -1; int time = current_alloc_time + 1; int i; @@ -3735,7 +4420,6 @@ awe_clear_voice(void) } } } -#endif if (best < 0) best = search_best_voice(~AWE_ST_MARK); @@ -3823,10 +4507,35 @@ awe_setup_voice(int dev, int voice, int chn) * AWE32 mixer device control *================================================================*/ +static int awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg); + +static int my_mixerdev = -1; + +static struct mixer_operations awe_mixer_operations = { +#ifndef __FreeBSD__ + "AWE32", +#endif + "AWE32 Equalizer", + awe_mixer_ioctl, +}; + +static void attach_mixer(void) +{ + if ((my_mixerdev = sound_alloc_mixerdev()) >= 0) { + mixer_devs[my_mixerdev] = &awe_mixer_operations; + } +} + +static void unload_mixer(void) +{ + if (my_mixerdev >= 0) + sound_unload_mixerdev(my_mixerdev); +} + static int awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { - int i, level; + int i, level, value; if (((cmd >> 8) & 0xff) != 'M') return RET_ERROR(EINVAL); @@ -3838,38 +4547,43 @@ awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) if (IO_WRITE_CHECK(cmd)) { switch (cmd & 0xff) { case SOUND_MIXER_BASS: - awe_bass_level = level * 12 / 100; - if (awe_bass_level >= 12) - awe_bass_level = 11; - awe_equalizer(awe_bass_level, awe_treble_level); + value = level * 12 / 100; + if (value >= 12) + value = 11; + ctrls[AWE_MD_BASS_LEVEL] = value; + awe_update_equalizer(); break; case SOUND_MIXER_TREBLE: - awe_treble_level = level * 12 / 100; - if (awe_treble_level >= 12) - awe_treble_level = 11; - awe_equalizer(awe_bass_level, awe_treble_level); + value = level * 12 / 100; + if (value >= 12) + value = 11; + ctrls[AWE_MD_TREBLE_LEVEL] = value; + awe_update_equalizer(); break; case SOUND_MIXER_VOLUME: level = level * 127 / 100; if (level >= 128) level = 127; - init_atten = vol_table[level]; - for (i = 0; i < awe_max_voices; i++) - awe_set_voice_vol(i, TRUE); + atten_relative = FALSE; + atten_offset = vol_table[level]; + awe_update_volume(); break; } } switch (cmd & 0xff) { case SOUND_MIXER_BASS: - level = awe_bass_level * 100 / 24; + level = ctrls[AWE_MD_BASS_LEVEL] * 100 / 24; level = (level << 8) | level; break; case SOUND_MIXER_TREBLE: - level = awe_treble_level * 100 / 24; + level = ctrls[AWE_MD_TREBLE_LEVEL] * 100 / 24; level = (level << 8) | level; break; case SOUND_MIXER_VOLUME: + value = atten_offset; + if (atten_relative) + value += ctrls[AWE_MD_ZERO_ATTEN]; for (i = 127; i > 0; i--) { - if (init_atten <= vol_table[i]) + if (value <= vol_table[i]) break; } level = i * 100 / 127; @@ -4168,8 +4882,10 @@ awe_open_dram_for_write(int offset, int channels) for (i = 0; i < AWE_NORMAL_VOICES; i++) vidx[i] = i; } else { - for (i = 0; i < channels; i++) + for (i = 0; i < channels; i++) { vidx[i] = awe_clear_voice(); + voices[vidx[i]].state = AWE_ST_MARK; + } } /* use all channels for DMA transfer */ @@ -4201,7 +4917,7 @@ awe_open_dram_for_write(int offset, int channels) if (awe_peek_dw(AWE_SMALW) & 0x80000000) { for (i = 0; i < channels; i++) { awe_poke_dw(AWE_CCCA(vidx[i]), 0); - voices[i].state = AWE_ST_OFF; + voices[vidx[i]].state = AWE_ST_OFF; } return RET_ERROR(ENOSPC); } @@ -4265,14 +4981,14 @@ awe_close_dram(void) static int awe_detect_base(int addr) { - awe_base = addr; + setup_ports(addr, 0, 0); if ((awe_peek(AWE_U1) & 0x000F) != 0x000C) return 0; if ((awe_peek(AWE_HWCF1) & 0x007E) != 0x0058) return 0; if ((awe_peek(AWE_HWCF2) & 0x0003) != 0x0003) return 0; - DEBUG(0,printk("AWE32 found at %x\n", awe_base)); + DEBUG(0,printk("AWE32 found at %x\n", addr)); return 1; } @@ -4280,13 +4996,22 @@ static int awe_detect(void) { int base; - if (awe_base == 0) { + + if (port_setuped) /* already initialized by PnP */ + return 1; + + if (awe_port) /* use default i/o port value */ + setup_ports(awe_port, 0, 0); + else { /* probe it */ for (base = 0x620; base <= 0x680; base += 0x20) if (awe_detect_base(base)) return 1; DEBUG(0,printk("AWE32 not found\n")); return 0; } + if (memsize >= 0) /* given by config file or module option */ + awe_mem_size = memsize * 1024; /* convert to Kbytes */ + return 1; } @@ -4300,13 +5025,11 @@ awe_detect(void) #define UNIQUE_ID2 0x4321 #define UNIQUE_ID3 0xFFFF -static int +static void awe_check_dram(void) { - if (awe_mem_size > 0) { - awe_mem_size *= 1024; /* convert to Kbytes */ - return awe_mem_size; - } + if (awe_mem_size >= 0) /* already initialized */ + return; awe_open_dram_for_check(); @@ -4318,7 +5041,7 @@ awe_check_dram(void) awe_poke(AWE_SMLD, UNIQUE_ID2); while (awe_mem_size < AWE_MAX_DRAM_SIZE) { - awe_wait(2); + awe_wait(5); /* read a data on the DRAM start address */ awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET); awe_peek(AWE_SMLD); /* discard stale data */ @@ -4326,7 +5049,7 @@ awe_check_dram(void) break; if (awe_peek(AWE_SMLD) != UNIQUE_ID2) break; - awe_mem_size += 32; /* increment 32 Kbytes */ + awe_mem_size += 512; /* increment 512kbytes */ /* Write a unique data on the test address; * if the address is out of range, the data is written on * 0x200000(=AWE_DRAM_OFFSET). Then the two id words are @@ -4334,7 +5057,7 @@ awe_check_dram(void) */ awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + awe_mem_size*512L); awe_poke(AWE_SMLD, UNIQUE_ID3); - awe_wait(2); + awe_wait(5); /* read a data on the just written DRAM address */ awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + awe_mem_size*512L); awe_peek(AWE_SMLD); /* discard stale data */ @@ -4347,7 +5070,6 @@ awe_check_dram(void) /* convert to Kbytes */ awe_mem_size *= 1024; - return awe_mem_size; } @@ -4398,7 +5120,12 @@ awe_set_chorus_mode(int effect) awe_poke_dw(AWE_HWCF5, chorus_parm[effect].lfo_freq); awe_poke_dw(AWE_HWCF6, 0x8000); awe_poke_dw(AWE_HWCF7, 0x0000); - chorus_mode = effect; +} + +static void +awe_update_chorus_mode(void) +{ + awe_set_chorus_mode(ctrls[AWE_MD_CHORUS_MODE]); } /*----------------------------------------------------------------*/ @@ -4497,7 +5224,12 @@ awe_set_reverb_mode(int effect) for (i = 0; i < 28; i++) awe_poke(reverb_cmds[i].cmd, reverb_cmds[i].port, reverb_parm[effect].parms[i]); - reverb_mode = effect; +} + +static void +awe_update_reverb_mode(void) +{ + awe_set_reverb_mode(ctrls[AWE_MD_REVERB_MODE]); } /*================================================================ @@ -4545,8 +5277,6 @@ awe_equalizer(int bass, int treble) if (bass < 0 || bass > 11 || treble < 0 || treble > 11) return; - awe_bass_level = bass; - awe_treble_level = treble; awe_poke(AWE_INIT4(0x01), bass_parm[bass][0]); awe_poke(AWE_INIT4(0x11), bass_parm[bass][1]); awe_poke(AWE_INIT3(0x11), treble_parm[treble][0]); @@ -4562,20 +5292,968 @@ awe_equalizer(int bass, int treble) awe_poke(AWE_INIT4(0x1D), (unsigned short)(w + 0x8362)); } +static void awe_update_equalizer(void) +{ + awe_equalizer(ctrls[AWE_MD_BASS_LEVEL], ctrls[AWE_MD_TREBLE_LEVEL]); +} + -#endif /* CONFIG_AWE32_SYNTH */ +#ifdef CONFIG_AWE32_MIDIEMU -#ifdef MODULE -int init_module(void) +/*================================================================ + * Emu8000 MIDI Emulation + *================================================================*/ + +/*================================================================ + * midi queue record + *================================================================*/ + +/* queue type */ +enum { Q_NONE, Q_VARLEN, Q_READ, Q_SYSEX, }; + +#define MAX_MIDIBUF 64 + +/* midi status */ +typedef struct MidiStatus { + int queue; /* queue type */ + int qlen; /* queue length */ + int read; /* chars read */ + int status; /* current status */ + int chan; /* current channel */ + unsigned char buf[MAX_MIDIBUF]; +} MidiStatus; + +/* MIDI mode type */ +enum { MODE_GM, MODE_GS, MODE_XG, }; + +/* NRPN / CC -> Emu8000 parameter converter */ +typedef struct { + int control; + int awe_effect; + unsigned short (*convert)(int val); +} ConvTable; + + +/*================================================================ + * prototypes + *================================================================*/ + +static int awe_midi_open(int dev, int mode, void (*input)(int,unsigned char), void (*output)(int)); +static void awe_midi_close(int dev); +static int awe_midi_ioctl(int dev, unsigned cmd, caddr_t arg); +static int awe_midi_outputc(int dev, unsigned char midi_byte); + +static void init_midi_status(MidiStatus *st); +static void clear_rpn(void); +static void get_midi_char(MidiStatus *st, int c); +/*static void queue_varlen(MidiStatus *st, int c);*/ +static void special_event(MidiStatus *st, int c); +static void queue_read(MidiStatus *st, int c); +static void midi_note_on(MidiStatus *st); +static void midi_note_off(MidiStatus *st); +static void midi_key_pressure(MidiStatus *st); +static void midi_channel_pressure(MidiStatus *st); +static void midi_pitch_wheel(MidiStatus *st); +static void midi_program_change(MidiStatus *st); +static void midi_control_change(MidiStatus *st); +static void midi_select_bank(MidiStatus *st, int val); +static void midi_nrpn_event(MidiStatus *st); +static void midi_rpn_event(MidiStatus *st); +static void midi_detune(int chan, int coarse, int fine); +static void midi_system_exclusive(MidiStatus *st); +static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val); +static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val); +static int xg_control_change(MidiStatus *st, int cmd, int val); + +#define numberof(ary) (sizeof(ary)/sizeof(ary[0])) + + +/*================================================================ + * OSS Midi device record + *================================================================*/ + +static struct midi_operations awe_midi_operations = +{ + {"AWE Midi Emu", 0, 0, SNDCARD_SB}, + NULL /*&std_midi_synth*/, + {0}, /* input_info */ + awe_midi_open, /*open*/ + awe_midi_close, /*close*/ + awe_midi_ioctl, /*ioctl*/ + awe_midi_outputc, /*outputc*/ + NULL /*start_read*/, + NULL /*end_read*/, + NULL, /* kick */ + NULL, /* command */ +}; + +static int my_mididev = -1; + +static void attach_midiemu(void) { - attach_awe(); - SOUND_LOCK; - return 0; + if ((my_mididev = sound_alloc_mididev()) < 0) + printk ("Sound: Too many midi devices detected\n"); + else + midi_devs[my_mididev] = &awe_midi_operations; } -void cleanup_module(void) +static void unload_midiemu(void) { - unload_awe(); - SOUND_LOCK_END; + if (my_mididev >= 0) + sound_unload_mididev(my_mididev); +} + + +/*================================================================ + * open/close midi device + *================================================================*/ + +static int midi_opened = FALSE; + +static int midi_mode; +static int coarsetune = 0, finetune = 0; + +static int xg_mapping = TRUE; +static int xg_bankmode = 0; + +/* effect sensitivity */ + +#define FX_CUTOFF 0 +#define FX_RESONANCE 1 +#define FX_ATTACK 2 +#define FX_RELEASE 3 +#define FX_VIBRATE 4 +#define FX_VIBDEPTH 5 +#define FX_VIBDELAY 6 +#define FX_NUMS 7 + +#define DEF_FX_CUTOFF 170 +#define DEF_FX_RESONANCE 6 +#define DEF_FX_ATTACK 50 +#define DEF_FX_RELEASE 50 +#define DEF_FX_VIBRATE 30 +#define DEF_FX_VIBDEPTH 4 +#define DEF_FX_VIBDELAY 1500 + +/* effect sense: */ +static int gs_sense[] = +{ + DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE, + DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY +}; +static int xg_sense[] = +{ + DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE, + DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY +}; + + +/* current status */ +static MidiStatus curst; + + +static int +awe_midi_open (int dev, int mode, + void (*input)(int,unsigned char), + void (*output)(int)) +{ + if (midi_opened) + return -EBUSY; + + midi_opened = TRUE; + + midi_mode = MODE_GM; + + curst.queue = Q_NONE; + curst.qlen = 0; + curst.read = 0; + curst.status = 0; + curst.chan = 0; + BZERO(curst.buf, sizeof(curst.buf)); + + init_midi_status(&curst); + + return 0; +} + +static void +awe_midi_close (int dev) +{ + midi_opened = FALSE; +} + + +static int +awe_midi_ioctl (int dev, unsigned cmd, caddr_t arg) +{ + return -EPERM; +} + +static int +awe_midi_outputc (int dev, unsigned char midi_byte) +{ + if (! midi_opened) + return 1; + + /* force to change playing mode */ + playing_mode = AWE_PLAY_MULTI; + + get_midi_char(&curst, midi_byte); + return 1; +} + + +/*================================================================ + * initialize + *================================================================*/ + +static void init_midi_status(MidiStatus *st) +{ + clear_rpn(); + coarsetune = 0; + finetune = 0; +} + + +/*================================================================ + * RPN & NRPN + *================================================================*/ + +#define MAX_MIDI_CHANNELS 16 + +/* RPN & NRPN */ +static unsigned char nrpn[MAX_MIDI_CHANNELS]; /* current event is NRPN? */ +static int msb_bit; /* current event is msb for RPN/NRPN */ +/* RPN & NRPN indeces */ +static unsigned char rpn_msb[MAX_MIDI_CHANNELS], rpn_lsb[MAX_MIDI_CHANNELS]; +/* RPN & NRPN values */ +static int rpn_val[MAX_MIDI_CHANNELS]; + +static void clear_rpn(void) +{ + int i; + for (i = 0; i < MAX_MIDI_CHANNELS; i++) { + nrpn[i] = 0; + rpn_msb[i] = 127; + rpn_lsb[i] = 127; + rpn_val[i] = 0; + } + msb_bit = 0; +} + + +/*================================================================ + * process midi queue + *================================================================*/ + +/* status event types */ +typedef void (*StatusEvent)(MidiStatus *st); +static struct StatusEventList { + StatusEvent process; + int qlen; +} status_event[8] = { + {midi_note_off, 2}, + {midi_note_on, 2}, + {midi_key_pressure, 2}, + {midi_control_change, 2}, + {midi_program_change, 1}, + {midi_channel_pressure, 1}, + {midi_pitch_wheel, 2}, + {NULL, 0}, +}; + + +/* read a char from fifo and process it */ +static void get_midi_char(MidiStatus *st, int c) +{ + if (c == 0xfe) { + /* ignore active sense */ + st->queue = Q_NONE; + return; + } + + switch (st->queue) { + /* case Q_VARLEN: queue_varlen(st, c); break;*/ + case Q_READ: + case Q_SYSEX: + queue_read(st, c); + break; + case Q_NONE: + st->read = 0; + if ((c & 0xf0) == 0xf0) { + special_event(st, c); + } else if (c & 0x80) { /* status change */ + st->status = (c >> 4) & 0x07; + st->chan = c & 0x0f; + st->queue = Q_READ; + st->qlen = status_event[st->status].qlen; + if (st->qlen == 0) + st->queue = Q_NONE; + } + break; + } +} + +/* 0xfx events */ +static void special_event(MidiStatus *st, int c) +{ + switch (c) { + case 0xf0: /* system exclusive */ + st->queue = Q_SYSEX; + st->qlen = 0; + break; + case 0xf1: /* MTC quarter frame */ + case 0xf3: /* song select */ + st->queue = Q_READ; + st->qlen = 1; + break; + case 0xf2: /* song position */ + st->queue = Q_READ; + st->qlen = 2; + break; + } +} + +#if 0 +/* read variable length value */ +static void queue_varlen(MidiStatus *st, int c) +{ + st->qlen += (c & 0x7f); + if (c & 0x80) { + st->qlen <<= 7; + return; + } + if (st->qlen <= 0) { + st->qlen = 0; + st->queue = Q_NONE; + } + st->queue = Q_READ; + st->read = 0; } #endif + + +/* read a char */ +static void queue_read(MidiStatus *st, int c) +{ + if (st->read < MAX_MIDIBUF) { + if (st->queue != Q_SYSEX) + c &= 0x7f; + st->buf[st->read] = (unsigned char)c; + } + st->read++; + if (st->queue == Q_SYSEX && c == 0xf7) { + midi_system_exclusive(st); + st->queue = Q_NONE; + } else if (st->queue == Q_READ && st->read >= st->qlen) { + if (status_event[st->status].process) + status_event[st->status].process(st); + st->queue = Q_NONE; + } +} + + +/*================================================================ + * status events + *================================================================*/ + +/* note on */ +static void midi_note_on(MidiStatus *st) +{ + DEBUG(2,printk("midi: note_on (%d) %d %d\n", st->chan, st->buf[0], st->buf[1])); + if (st->buf[1] == 0) + midi_note_off(st); + else + awe_start_note(0, st->chan, st->buf[0], st->buf[1]); +} + +/* note off */ +static void midi_note_off(MidiStatus *st) +{ + DEBUG(2,printk("midi: note_off (%d) %d %d\n", st->chan, st->buf[0], st->buf[1])); + awe_kill_note(0, st->chan, st->buf[0], st->buf[1]); +} + +/* key pressure change */ +static void midi_key_pressure(MidiStatus *st) +{ + awe_key_pressure(0, st->chan, st->buf[0], st->buf[1]); +} + +/* channel pressure change */ +static void midi_channel_pressure(MidiStatus *st) +{ + channels[st->chan].chan_press = st->buf[0]; + awe_modwheel_change(st->chan, st->buf[0]); +} + +/* pitch wheel change */ +static void midi_pitch_wheel(MidiStatus *st) +{ + int val = (int)st->buf[1] * 128 + st->buf[0]; + awe_bender(0, st->chan, val); +} + +/* program change */ +static void midi_program_change(MidiStatus *st) +{ + int preset; + preset = st->buf[0]; + if (midi_mode == MODE_GS && IS_DRUM_CHANNEL(st->chan) && preset == 127) + preset = 0; + else if (midi_mode == MODE_XG && xg_mapping && IS_DRUM_CHANNEL(st->chan)) + preset += 64; + + awe_set_instr(0, st->chan, preset); +} + +#define send_effect(chan,type,val) awe_send_effect(chan,-1,type,val) +#define add_effect(chan,type,val) awe_send_effect(chan,-1,(type)|0x80,val) +#define unset_effect(chan,type) awe_send_effect(chan,-1,(type)|0x40,0) + +/* midi control change */ +static void midi_control_change(MidiStatus *st) +{ + int cmd = st->buf[0]; + int val = st->buf[1]; + + DEBUG(2,printk("midi: control (%d) %d %d\n", st->chan, cmd, val)); + if (midi_mode == MODE_XG) { + if (xg_control_change(st, cmd, val)) + return; + } + + /* controls #31 - #64 are LSB of #0 - #31 */ + msb_bit = 1; + if (cmd >= 0x20 && cmd < 0x40) { + msb_bit = 0; + cmd -= 0x20; + } + + switch (cmd) { + case CTL_SOFT_PEDAL: + if (val == 127) + add_effect(st->chan, AWE_FX_CUTOFF, -160); + else + unset_effect(st->chan, AWE_FX_CUTOFF); + break; + + case CTL_BANK_SELECT: + midi_select_bank(st, val); + break; + + /* set RPN/NRPN parameter */ + case CTL_REGIST_PARM_NUM_MSB: + nrpn[st->chan]=0; rpn_msb[st->chan]=val; + break; + case CTL_REGIST_PARM_NUM_LSB: + nrpn[st->chan]=0; rpn_lsb[st->chan]=val; + break; + case CTL_NONREG_PARM_NUM_MSB: + nrpn[st->chan]=1; rpn_msb[st->chan]=val; + break; + case CTL_NONREG_PARM_NUM_LSB: + nrpn[st->chan]=1; rpn_lsb[st->chan]=val; + break; + + /* send RPN/NRPN entry */ + case CTL_DATA_ENTRY: + if (msb_bit) + rpn_val[st->chan] = val * 128; + else + rpn_val[st->chan] |= val; + if (nrpn[st->chan]) + midi_nrpn_event(st); + else + midi_rpn_event(st); + break; + + /* increase/decrease data entry */ + case CTL_DATA_INCREMENT: + rpn_val[st->chan]++; + midi_rpn_event(st); + break; + case CTL_DATA_DECREMENT: + rpn_val[st->chan]--; + midi_rpn_event(st); + break; + + /* default */ + default: + awe_controller(0, st->chan, cmd, val); + break; + } +} + +/* tone bank change */ +static void midi_select_bank(MidiStatus *st, int val) +{ + if (midi_mode == MODE_XG && msb_bit) { + xg_bankmode = val; + /* XG MSB value; not normal bank selection */ + switch (val) { + case 127: /* remap to drum channel */ + awe_controller(0, st->chan, CTL_BANK_SELECT, 128); + break; + default: /* remap to normal channel */ + awe_controller(0, st->chan, CTL_BANK_SELECT, val); + break; + } + return; + } else if (midi_mode == MODE_GS && !msb_bit) + /* ignore LSB bank in GS mode (used for mapping) */ + return; + + /* normal bank controls; accept both MSB and LSB */ + if (! IS_DRUM_CHANNEL(st->chan)) { + if (midi_mode == MODE_XG) { + if (xg_bankmode) return; + if (val == 64 || val == 126) + val = 0; + } else if (midi_mode == MODE_GS && val == 127) + val = 0; + awe_controller(0, st->chan, CTL_BANK_SELECT, val); + } +} + + +/*================================================================ + * RPN events + *================================================================*/ + +static void midi_rpn_event(MidiStatus *st) +{ + int type; + type = (rpn_msb[st->chan]<<8) | rpn_lsb[st->chan]; + switch (type) { + case 0x0000: /* Pitch bend sensitivity */ + /* MSB only / 1 semitone per 128 */ + if (msb_bit) { + channels[st->chan].bender_range = + rpn_val[st->chan] * 100 / 128; + } + break; + + case 0x0001: /* fine tuning: */ + /* MSB/LSB, 8192=center, 100/8192 cent step */ + finetune = rpn_val[st->chan] - 8192; + midi_detune(st->chan, coarsetune, finetune); + break; + + case 0x0002: /* coarse tuning */ + /* MSB only / 8192=center, 1 semitone per 128 */ + if (msb_bit) { + coarsetune = rpn_val[st->chan] - 8192; + midi_detune(st->chan, coarsetune, finetune); + } + break; + + case 0x7F7F: /* "lock-in" RPN */ + break; + } +} + + +/* tuning: + * coarse = -8192 to 8192 (100 cent per 128) + * fine = -8192 to 8192 (max=100cent) + */ +static void midi_detune(int chan, int coarse, int fine) +{ + /* 4096 = 1200 cents in AWE parameter */ + int val; + val = coarse * 4096 / (12 * 128); + val += fine / 24; + if (val) + send_effect(chan, AWE_FX_INIT_PITCH, val); + else + unset_effect(chan, AWE_FX_INIT_PITCH); +} + + +/*================================================================ + * system exclusive message + * GM/GS/XG macros are accepted + *================================================================*/ + +static void midi_system_exclusive(MidiStatus *st) +{ + /* GM on */ + static unsigned char gm_on_macro[] = { + 0x7e,0x7f,0x09,0x01, + }; + /* XG on */ + static unsigned char xg_on_macro[] = { + 0x43,0x10,0x4c,0x00,0x00,0x7e,0x00, + }; + /* GS prefix + * drum channel: XX=0x1?(channel), YY=0x15, ZZ=on/off + * reverb mode: XX=0x01, YY=0x30, ZZ=0-7 + * chorus mode: XX=0x01, YY=0x38, ZZ=0-7 + */ + static unsigned char gs_pfx_macro[] = { + 0x41,0x10,0x42,0x12,0x40,/*XX,YY,ZZ*/ + }; + +#if 0 + /* SC88 system mode set + * single module mode: XX=1 + * double module mode: XX=0 + */ + static unsigned char gs_mode_macro[] = { + 0x41,0x10,0x42,0x12,0x00,0x00,0x7F,/*ZZ*/ + }; + /* SC88 display macro: XX=01:bitmap, 00:text + */ + static unsigned char gs_disp_macro[] = { + 0x41,0x10,0x45,0x12,0x10,/*XX,00*/ + }; +#endif + + /* GM on */ + if (MEMCMP(st->buf, gm_on_macro, sizeof(gm_on_macro)) == 0) { + if (midi_mode != MODE_GS && midi_mode != MODE_XG) + midi_mode = MODE_GM; + init_midi_status(st); + } + + /* GS macros */ + else if (MEMCMP(st->buf, gs_pfx_macro, sizeof(gs_pfx_macro)) == 0) { + if (midi_mode != MODE_GS && midi_mode != MODE_XG) + midi_mode = MODE_GS; + + if (st->buf[5] == 0x00 && st->buf[6] == 0x7f && st->buf[7] == 0x00) { + /* GS reset */ + init_midi_status(st); + } + + else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x15) { + /* drum pattern */ + int p = st->buf[5] & 0x0f; + if (p == 0) p = 9; + else if (p < 10) p--; + if (st->buf[7] == 0) + DRUM_CHANNEL_OFF(p); + else + DRUM_CHANNEL_ON(p); + + } else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x21) { + /* program */ + int p = st->buf[5] & 0x0f; + if (p == 0) p = 9; + else if (p < 10) p--; + if (! IS_DRUM_CHANNEL(p)) + awe_set_instr(0, p, st->buf[7]); + + } else if (st->buf[5] == 0x01 && st->buf[6] == 0x30) { + /* reverb mode */ + awe_set_reverb_mode(st->buf[7]); + + } else if (st->buf[5] == 0x01 && st->buf[6] == 0x38) { + /* chorus mode */ + awe_set_chorus_mode(st->buf[7]); + + } else if (st->buf[5] == 0x00 && st->buf[6] == 0x04) { + /* master volume */ + awe_change_master_volume(st->buf[7]); + + } + } + + /* XG on */ + else if (MEMCMP(st->buf, xg_on_macro, sizeof(xg_on_macro)) == 0) { + midi_mode = MODE_XG; + xg_mapping = TRUE; + xg_bankmode = 0; + } +} + + +/*================================================================ + * convert NRPN/control values + *================================================================*/ + +static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val) +{ + int i, cval; + for (i = 0; i < num_tables; i++) { + if (table[i].control == type) { + cval = table[i].convert(val); + send_effect(st->chan, table[i].awe_effect, cval); + return TRUE; + } + } + return FALSE; +} + +static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val) +{ + int i, cval; + for (i = 0; i < num_tables; i++) { + if (table[i].control == type) { + cval = table[i].convert(val); + add_effect(st->chan, table[i].awe_effect|0x80, cval); + return TRUE; + } + } + return FALSE; +} + + +/*---------------------------------------------------------------- + * AWE32 NRPN effects + *----------------------------------------------------------------*/ + +static unsigned short fx_delay(int val); +static unsigned short fx_attack(int val); +static unsigned short fx_hold(int val); +static unsigned short fx_decay(int val); +static unsigned short fx_the_value(int val); +static unsigned short fx_twice_value(int val); +static unsigned short fx_conv_pitch(int val); +static unsigned short fx_conv_Q(int val); + +/* function for each NRPN */ /* [range] units */ +#define fx_env1_delay fx_delay /* [0,5900] 4msec */ +#define fx_env1_attack fx_attack /* [0,5940] 1msec */ +#define fx_env1_hold fx_hold /* [0,8191] 1msec */ +#define fx_env1_decay fx_decay /* [0,5940] 4msec */ +#define fx_env1_release fx_decay /* [0,5940] 4msec */ +#define fx_env1_sustain fx_the_value /* [0,127] 0.75dB */ +#define fx_env1_pitch fx_the_value /* [-127,127] 9.375cents */ +#define fx_env1_cutoff fx_the_value /* [-127,127] 56.25cents */ + +#define fx_env2_delay fx_delay /* [0,5900] 4msec */ +#define fx_env2_attack fx_attack /* [0,5940] 1msec */ +#define fx_env2_hold fx_hold /* [0,8191] 1msec */ +#define fx_env2_decay fx_decay /* [0,5940] 4msec */ +#define fx_env2_release fx_decay /* [0,5940] 4msec */ +#define fx_env2_sustain fx_the_value /* [0,127] 0.75dB */ + +#define fx_lfo1_delay fx_delay /* [0,5900] 4msec */ +#define fx_lfo1_freq fx_twice_value /* [0,127] 84mHz */ +#define fx_lfo1_volume fx_twice_value /* [0,127] 0.1875dB */ +#define fx_lfo1_pitch fx_the_value /* [-127,127] 9.375cents */ +#define fx_lfo1_cutoff fx_twice_value /* [-64,63] 56.25cents */ + +#define fx_lfo2_delay fx_delay /* [0,5900] 4msec */ +#define fx_lfo2_freq fx_twice_value /* [0,127] 84mHz */ +#define fx_lfo2_pitch fx_the_value /* [-127,127] 9.375cents */ + +#define fx_init_pitch fx_conv_pitch /* [-8192,8192] cents */ +#define fx_chorus fx_the_value /* [0,255] -- */ +#define fx_reverb fx_the_value /* [0,255] -- */ +#define fx_cutoff fx_twice_value /* [0,127] 62Hz */ +#define fx_filterQ fx_conv_Q /* [0,127] -- */ + +static unsigned short fx_delay(int val) +{ + return (unsigned short)calc_parm_delay(val); +} + +static unsigned short fx_attack(int val) +{ + return (unsigned short)calc_parm_attack(val); +} + +static unsigned short fx_hold(int val) +{ + return (unsigned short)calc_parm_hold(val); +} + +static unsigned short fx_decay(int val) +{ + return (unsigned short)calc_parm_decay(val); +} + +static unsigned short fx_the_value(int val) +{ + return (unsigned short)(val & 0xff); +} + +static unsigned short fx_twice_value(int val) +{ + return (unsigned short)((val * 2) & 0xff); +} + +static unsigned short fx_conv_pitch(int val) +{ + return (short)(val * 4096 / 1200); +} + +static unsigned short fx_conv_Q(int val) +{ + return (unsigned short)((val / 8) & 0xff); +} + + +static ConvTable awe_effects[] = +{ + { 0, AWE_FX_LFO1_DELAY, fx_lfo1_delay}, + { 1, AWE_FX_LFO1_FREQ, fx_lfo1_freq}, + { 2, AWE_FX_LFO2_DELAY, fx_lfo2_delay}, + { 3, AWE_FX_LFO2_FREQ, fx_lfo2_freq}, + + { 4, AWE_FX_ENV1_DELAY, fx_env1_delay}, + { 5, AWE_FX_ENV1_ATTACK,fx_env1_attack}, + { 6, AWE_FX_ENV1_HOLD, fx_env1_hold}, + { 7, AWE_FX_ENV1_DECAY, fx_env1_decay}, + { 8, AWE_FX_ENV1_SUSTAIN, fx_env1_sustain}, + { 9, AWE_FX_ENV1_RELEASE, fx_env1_release}, + + {10, AWE_FX_ENV2_DELAY, fx_env2_delay}, + {11, AWE_FX_ENV2_ATTACK, fx_env2_attack}, + {12, AWE_FX_ENV2_HOLD, fx_env2_hold}, + {13, AWE_FX_ENV2_DECAY, fx_env2_decay}, + {14, AWE_FX_ENV2_SUSTAIN, fx_env2_sustain}, + {15, AWE_FX_ENV2_RELEASE, fx_env2_release}, + + {16, AWE_FX_INIT_PITCH, fx_init_pitch}, + {17, AWE_FX_LFO1_PITCH, fx_lfo1_pitch}, + {18, AWE_FX_LFO2_PITCH, fx_lfo2_pitch}, + {19, AWE_FX_ENV1_PITCH, fx_env1_pitch}, + {20, AWE_FX_LFO1_VOLUME, fx_lfo1_volume}, + {21, AWE_FX_CUTOFF, fx_cutoff}, + {22, AWE_FX_FILTERQ, fx_filterQ}, + {23, AWE_FX_LFO1_CUTOFF, fx_lfo1_cutoff}, + {24, AWE_FX_ENV1_CUTOFF, fx_env1_cutoff}, + {25, AWE_FX_CHORUS, fx_chorus}, + {26, AWE_FX_REVERB, fx_reverb}, +}; + +static int num_awe_effects = numberof(awe_effects); + + +/*---------------------------------------------------------------- + * GS(SC88) NRPN effects; still experimental + *----------------------------------------------------------------*/ + +/* cutoff: quarter semitone step, max=255 */ +static unsigned short gs_cutoff(int val) +{ + return (val - 64) * gs_sense[FX_CUTOFF] / 50; +} + +/* resonance: 0 to 15(max) */ +static unsigned short gs_filterQ(int val) +{ + return (val - 64) * gs_sense[FX_RESONANCE] / 50; +} + +/* attack: */ +static unsigned short gs_attack(int val) +{ + return -(val - 64) * gs_sense[FX_ATTACK] / 50; +} + +/* decay: */ +static unsigned short gs_decay(int val) +{ + return -(val - 64) * gs_sense[FX_RELEASE] / 50; +} + +/* release: */ +static unsigned short gs_release(int val) +{ + return -(val - 64) * gs_sense[FX_RELEASE] / 50; +} + +/* vibrato freq: 0.042Hz step, max=255 */ +static unsigned short gs_vib_rate(int val) +{ + return (val - 64) * gs_sense[FX_VIBRATE] / 50; +} + +/* vibrato depth: max=127, 1 octave */ +static unsigned short gs_vib_depth(int val) +{ + return (val - 64) * gs_sense[FX_VIBDEPTH] / 50; +} + +/* vibrato delay: -0.725msec step */ +static unsigned short gs_vib_delay(int val) +{ + return -(val - 64) * gs_sense[FX_VIBDELAY] / 50; +} + +static ConvTable gs_effects[] = +{ + {32, AWE_FX_CUTOFF, gs_cutoff}, + {33, AWE_FX_FILTERQ, gs_filterQ}, + {99, AWE_FX_ENV2_ATTACK, gs_attack}, + {100, AWE_FX_ENV2_DECAY, gs_decay}, + {102, AWE_FX_ENV2_RELEASE, gs_release}, + {8, AWE_FX_LFO1_FREQ, gs_vib_rate}, + {9, AWE_FX_LFO1_VOLUME, gs_vib_depth}, + {10, AWE_FX_LFO1_DELAY, gs_vib_delay}, +}; + +static int num_gs_effects = numberof(gs_effects); + + +/*================================================================ + * NRPN events: accept as AWE32/SC88 specific controls + *================================================================*/ + +static void midi_nrpn_event(MidiStatus *st) +{ + if (rpn_msb[st->chan] == 127 && rpn_lsb[st->chan] <= 26) { + if (! msb_bit) /* both MSB/LSB necessary */ + send_converted_effect(awe_effects, num_awe_effects, + st, rpn_lsb[st->chan], + rpn_val[st->chan] - 8192); + } else if (rpn_msb[st->chan] == 1) { + if (msb_bit) /* only MSB is valid */ + add_converted_effect(gs_effects, num_gs_effects, + st, rpn_lsb[st->chan], + rpn_val[st->chan] / 128); + } +} + + +/*---------------------------------------------------------------- + * XG control effects; still experimental + *----------------------------------------------------------------*/ + +/* cutoff: quarter semitone step, max=255 */ +static unsigned short xg_cutoff(int val) +{ + return (val - 64) * xg_sense[FX_CUTOFF] / 64; +} + +/* resonance: 0(open) to 15(most nasal) */ +static unsigned short xg_filterQ(int val) +{ + return (val - 64) * xg_sense[FX_RESONANCE] / 64; +} + +/* attack: */ +static unsigned short xg_attack(int val) +{ + return -(val - 64) * xg_sense[FX_ATTACK] / 64; +} + +/* release: */ +static unsigned short xg_release(int val) +{ + return -(val - 64) * xg_sense[FX_RELEASE] / 64; +} + +static ConvTable xg_effects[] = +{ + {71, AWE_FX_CUTOFF, xg_cutoff}, + {74, AWE_FX_FILTERQ, xg_filterQ}, + {72, AWE_FX_ENV2_RELEASE, xg_release}, + {73, AWE_FX_ENV2_ATTACK, xg_attack}, +}; + +static int num_xg_effects = numberof(xg_effects); + +static int xg_control_change(MidiStatus *st, int cmd, int val) +{ + return add_converted_effect(xg_effects, num_xg_effects, st, cmd, val); +} + +#endif /* CONFIG_AWE32_MIDIEMU */ + +#endif /* CONFIG_AWE32_SYNTH */ diff --git a/drivers/sound/midibuf.c b/drivers/sound/midibuf.c index 7adfeb89c5fb..b1c9763e50b5 100644 --- a/drivers/sound/midibuf.c +++ b/drivers/sound/midibuf.c @@ -40,7 +40,7 @@ struct midi_buf struct midi_parms { - int prech_timeout; /* + long prech_timeout; /* * Timeout before the first ch */ }; @@ -282,8 +282,14 @@ int MIDIbuf_write(int dev, struct file *file, const char *buf, int count) n = SPACE_AVAIL(midi_out_buf[dev]); if (n == 0) { /* - * No space just now. We have to sleep + * No space just now. */ + + if (file->f_flags & O_NONBLOCK) { + restore_flags(flags); + return -EAGAIN; + } + interruptible_sleep_on(&midi_sleeper[dev]); if (signal_pending(current)) { @@ -322,6 +328,10 @@ int MIDIbuf_read(int dev, struct file *file, char *buf, int count) if (!DATA_AVAIL(midi_in_buf[dev])) { /* * No data yet, wait */ + if (file->f_flags & O_NONBLOCK) { + restore_flags(flags); + return -EAGAIN; + } interruptible_sleep_on_timeout(&input_sleeper[dev], parms[dev].prech_timeout); diff --git a/drivers/sound/msnd.h b/drivers/sound/msnd.h index 1dbdedf37c8c..ae7a952add15 100644 --- a/drivers/sound/msnd.h +++ b/drivers/sound/msnd.h @@ -24,13 +24,13 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd.h,v 1.32 1998/10/09 19:54:39 andrewtv Exp $ + * $Id: msnd.h,v 1.33 1998/11/05 20:26:18 andrewtv Exp $ * ********************************************************************/ #ifndef __MSND_H #define __MSND_H -#define VERSION "0.8.2.1" +#define VERSION "0.8.2.2" #define DEFSAMPLERATE DSP_DEFAULT_SPEED #define DEFSAMPLESIZE AFMT_U8 diff --git a/drivers/sound/msnd_pinnacle.c b/drivers/sound/msnd_pinnacle.c index 8f0b6de86cfe..9109658d456b 100644 --- a/drivers/sound/msnd_pinnacle.c +++ b/drivers/sound/msnd_pinnacle.c @@ -29,7 +29,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd_pinnacle.c,v 1.66 1998/10/09 19:54:39 andrewtv Exp $ + * $Id: msnd_pinnacle.c,v 1.73 1998/12/04 14:41:02 andrewtv Exp $ * ********************************************************************/ @@ -67,7 +67,7 @@ #endif #ifndef CONFIG_MSND_WRITE_NDELAY -# define CONFIG_MSND_WRITE_NDELAY 0 +# define CONFIG_MSND_WRITE_NDELAY 1 #endif #define get_play_delay_jiffies(size) ((size) * HZ * \ @@ -379,14 +379,14 @@ static int mixer_get(int d) switch (d) { case SOUND_MIXER_VOLUME: - case SOUND_MIXER_SYNTH: case SOUND_MIXER_PCM: case SOUND_MIXER_LINE: + case SOUND_MIXER_IMIX: + case SOUND_MIXER_LINE1: #ifndef MSND_CLASSIC case SOUND_MIXER_MIC: + case SOUND_MIXER_SYNTH: #endif - case SOUND_MIXER_IMIX: - case SOUND_MIXER_LINE1: return (dev.left_levels[d] >> 8) * 100 / 0xff | (((dev.right_levels[d] >> 8) * 100 / 0xff) << 8); default: @@ -394,16 +394,30 @@ static int mixer_get(int d) } } -#define update_vol(a,b,s) \ - writew(dev.left_levels[a] * readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff / s, \ - dev.SMA + SMA_##b##Left); \ - writew(dev.right_levels[a] * readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff / s, \ +#define update_volm(a,b) \ + writew((dev.left_levels[a] >> 1) * \ + readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff, \ + dev.SMA + SMA_##b##Left); \ + writew((dev.right_levels[a] >> 1) * \ + readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff, \ dev.SMA + SMA_##b##Right); -#define update_pot(d,s,ar) \ - writeb(dev.left_levels[d] >> 8, dev.SMA + SMA_##s##Left); \ - writeb(dev.right_levels[d] >> 8, dev.SMA + SMA_##s##Right); \ - if (msnd_send_word(&dev, 0, 0, ar) == 0) \ +#define update_potm(d,s,ar) \ + writeb((dev.left_levels[d] >> 8) * \ + readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff, \ + dev.SMA + SMA_##s##Left); \ + writeb((dev.right_levels[d] >> 8) * \ + readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff, \ + dev.SMA + SMA_##s##Right); \ + if (msnd_send_word(&dev, 0, 0, ar) == 0) \ + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); + +#define update_pot(d,s,ar) \ + writeb(dev.left_levels[d] >> 8, \ + dev.SMA + SMA_##s##Left); \ + writeb(dev.right_levels[d] >> 8, \ + dev.SMA + SMA_##s##Right); \ + if (msnd_send_word(&dev, 0, 0, ar) == 0) \ chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); static int mixer_set(int d, int value) @@ -412,6 +426,7 @@ static int mixer_set(int d, int value) int right = (value & 0x0000ff00) >> 8; int bLeft, bRight; int wLeft, wRight; + int updatemaster = 0; if (d > 31) return -EINVAL; @@ -426,66 +441,66 @@ static int mixer_set(int d, int value) dev.right_levels[d] = wRight; switch (d) { - case SOUND_MIXER_VOLUME: /* master volume */ - writew(wLeft / 2, dev.SMA + SMA_wCurrMastVolLeft); - writew(wRight / 2, dev.SMA + SMA_wCurrMastVolRight); - break; - - /* pot controls */ - case SOUND_MIXER_LINE: /* aux pot control */ + /* master volume unscaled controls */ + case SOUND_MIXER_LINE: /* line pot control */ + /* scaled by IMIX in digital mix */ writeb(bLeft, dev.SMA + SMA_bInPotPosLeft); writeb(bRight, dev.SMA + SMA_bInPotPosRight); if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0) chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); break; - #ifndef MSND_CLASSIC case SOUND_MIXER_MIC: /* mic pot control */ + /* scaled by IMIX in digital mix */ writeb(bLeft, dev.SMA + SMA_bMicPotPosLeft); writeb(bRight, dev.SMA + SMA_bMicPotPosRight); if (msnd_send_word(&dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0) chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); break; #endif + case SOUND_MIXER_VOLUME: /* master volume */ + writew(wLeft, dev.SMA + SMA_wCurrMastVolLeft); + writew(wRight, dev.SMA + SMA_wCurrMastVolRight); + /* fall through */ - case SOUND_MIXER_LINE1: /* line pot control */ - writeb(bLeft, dev.SMA + SMA_bAuxPotPosLeft); - writeb(bRight, dev.SMA + SMA_bAuxPotPosRight); - if (msnd_send_word(&dev, 0, 0, HDEXAR_AUX_SET_POTS) == 0) - chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); - break; + case SOUND_MIXER_LINE1: /* aux pot control */ + /* scaled by master volume */ + /* fall through */ /* digital controls */ case SOUND_MIXER_SYNTH: /* synth vol (dsp mix) */ case SOUND_MIXER_PCM: /* pcm vol (dsp mix) */ case SOUND_MIXER_IMIX: /* input monitor (dsp mix) */ + /* scaled by master volume */ + updatemaster = 1; break; default: return 0; } - /* update digital controls for master volume */ - update_vol(SOUND_MIXER_PCM, wCurrPlayVol, 1); - update_vol(SOUND_MIXER_IMIX, wCurrInVol, 1); + if (updatemaster) { + /* update master volume scaled controls */ + update_volm(SOUND_MIXER_PCM, wCurrPlayVol); + update_volm(SOUND_MIXER_IMIX, wCurrInVol); #ifndef MSND_CLASSIC - update_vol(SOUND_MIXER_SYNTH, wCurrMHdrVol, 1); + update_volm(SOUND_MIXER_SYNTH, wCurrMHdrVol); #endif - + update_potm(SOUND_MIXER_LINE1, bAuxPotPos, HDEXAR_AUX_SET_POTS); + } + return mixer_get(d); } static void mixer_setup(void) { update_pot(SOUND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS); + update_potm(SOUND_MIXER_LINE1, bAuxPotPos, HDEXAR_AUX_SET_POTS); + update_volm(SOUND_MIXER_PCM, wCurrPlayVol); + update_volm(SOUND_MIXER_IMIX, wCurrInVol); #ifndef MSND_CLASSIC update_pot(SOUND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS); -#endif - update_pot(SOUND_MIXER_LINE1, bAuxPotPos, HDEXAR_AUX_SET_POTS); - update_vol(SOUND_MIXER_PCM, wCurrPlayVol, 1); - update_vol(SOUND_MIXER_IMIX, wCurrInVol, 1); -#ifndef MSND_CLASSIC - update_vol(SOUND_MIXER_SYNTH, wCurrMHdrVol, 1); + update_volm(SOUND_MIXER_SYNTH, wCurrMHdrVol); #endif } @@ -501,7 +516,7 @@ static unsigned long set_recsrc(unsigned long recsrc) dev.recsrc ^= recsrc; #ifndef MSND_CLASSIC - if (dev.recsrc & SOUND_MASK_LINE) { + if (dev.recsrc & SOUND_MASK_IMIX) { if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0) chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); } @@ -518,7 +533,7 @@ static unsigned long set_recsrc(unsigned long recsrc) /* Select no input (?) */ dev.recsrc = 0; #else - dev.recsrc = SOUND_MASK_LINE; + dev.recsrc = SOUND_MASK_IMIX; if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0) chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); #endif @@ -545,13 +560,15 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg) set_mixer_info(); info.modify_counter = dev.mixer_mod_count; return copy_to_user((void *)arg, &info, sizeof(info)); - } - else if (cmd == SOUND_OLD_MIXER_INFO) { + } else if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; set_mixer_info(); return copy_to_user((void *)arg, &info, sizeof(info)); - } - else if (((cmd >> 8) & 0xff) == 'M') { + } else if (cmd == SOUND_MIXER_PRIVATE1) { + dev.nresets = 0; + dsp_full_reset(); + return 0; + } else if (((cmd >> 8) & 0xff) == 'M') { int val = 0; if (_SIOC_DIR(cmd) & _SIOC_WRITE) { @@ -570,8 +587,7 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg) } ++dev.mixer_mod_count; return put_user(val, (int *)arg); - } - else { + } else { switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: val = dev.recsrc; @@ -579,21 +595,22 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg) case SOUND_MIXER_DEVMASK: case SOUND_MIXER_STEREODEVS: - val = SOUND_MASK_VOLUME | + val = SOUND_MASK_PCM | + SOUND_MASK_LINE | + SOUND_MASK_IMIX | + SOUND_MASK_LINE1 | #ifndef MSND_CLASSIC - SOUND_MASK_SYNTH | SOUND_MASK_MIC | + SOUND_MASK_SYNTH | #endif - SOUND_MASK_PCM | - SOUND_MASK_LINE | - SOUND_MASK_IMIX; + SOUND_MASK_VOLUME; break; case SOUND_MIXER_RECMASK: #ifdef MSND_CLASSIC val = 0; #else - val = SOUND_MASK_LINE | + val = SOUND_MASK_IMIX | SOUND_MASK_SYNTH; if (test_bit(F_HAVEDIGITAL, &dev.flags)) val |= SOUND_MASK_DIGITAL1; @@ -639,7 +656,9 @@ static void dsp_write_flush(void) if (!(dev.mode & FMODE_WRITE) || !test_bit(F_WRITING, &dev.flags)) return; set_bit(F_WRITEFLUSH, &dev.flags); - interruptible_sleep_on_timeout(&dev.writeflush, get_play_delay_jiffies(dev.DAPF.len) + HZ / 8); + interruptible_sleep_on_timeout( + &dev.writeflush, + get_play_delay_jiffies(dev.DAPF.len)); clear_bit(F_WRITEFLUSH, &dev.flags); if (!signal_pending(current)) { current->state = TASK_INTERRUPTIBLE; @@ -727,6 +746,16 @@ static void set_default_audio_parameters(void) set_default_rec_audio_parameters(); } +static void mod_inc_ref(void) +{ + MOD_INC_USE_COUNT; +} + +static void mod_dec_ref(void) +{ + MOD_DEC_USE_COUNT; +} + static int dev_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); @@ -760,7 +789,7 @@ static int dev_open(struct inode *inode, struct file *file) err = -EINVAL; if (err >= 0) - MOD_INC_USE_COUNT; + mod_inc_ref(); return err; } @@ -791,7 +820,7 @@ static int dev_release(struct inode *inode, struct file *file) if (err >= 0) #endif - MOD_DEC_USE_COUNT; + mod_dec_ref(); #ifndef LINUX20 return err; @@ -919,7 +948,9 @@ static int dsp_read(char *buf, size_t len) if (count > 0) { set_bit(F_READBLOCK, &dev.flags); - if (!interruptible_sleep_on_timeout(&dev.readblock, get_rec_delay_jiffies(DAR_BUFF_SIZE))) + if (!interruptible_sleep_on_timeout( + &dev.readblock, + get_rec_delay_jiffies(DAR_BUFF_SIZE))) clear_bit(F_READING, &dev.flags); clear_bit(F_READBLOCK, &dev.flags); if (signal_pending(current)) @@ -960,7 +991,9 @@ static int dsp_write(const char *buf, size_t len) if (count > 0) { set_bit(F_WRITEBLOCK, &dev.flags); - interruptible_sleep_on_timeout(&dev.writeblock, get_play_delay_jiffies(DAP_BUFF_SIZE)); + interruptible_sleep_on_timeout( + &dev.writeblock, + get_play_delay_jiffies(DAP_BUFF_SIZE)); clear_bit(F_WRITEBLOCK, &dev.flags); if (signal_pending(current)) return -EINTR; @@ -1054,7 +1087,8 @@ static __inline__ void eval_dsp_msg(register WORD wMessage) break; default: -/* printk(KERN_DEBUG LOGNAME ": DSP message %d 0x%02x\n", LOBYTE(wMessage), LOBYTE(wMessage)); */ +/* printk(KERN_DEBUG LOGNAME ": DSP message %d 0x%02x\n", + LOBYTE(wMessage), LOBYTE(wMessage)); */ break; } break; @@ -1150,11 +1184,9 @@ __initfunc(static int probe_multisound(void)) return -ENODEV; } - printk(KERN_INFO LOGNAME ": DSP reset successful\n"); - #ifdef MSND_CLASSIC dev.name = "Classic/Tahiti/Monterey"; - printk(KERN_INFO LOGNAME ": Turtle Beach %s, " + printk(KERN_INFO LOGNAME ": %s, " #else switch (dev.info >> 4) { case 0xf: xv = "<= 1.15"; break; @@ -1177,7 +1209,7 @@ __initfunc(static int probe_multisound(void)) dev.name = pinfiji; break; } - printk(KERN_INFO LOGNAME ": Turtle Beach %s revision %s, Xilinx version %s, " + printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, " #endif /* MSND_CLASSIC */ "I/O 0x%x-0x%x, IRQ %d, memory mapped to 0x%p-0x%p\n", dev.name, @@ -1275,26 +1307,20 @@ static int init_sma(void) __initfunc(static int calibrate_adc(WORD srate)) { - if (!dev.calibrate_signal) { - printk(KERN_INFO LOGNAME ": ADC calibration to board ground "); + writew(srate, dev.SMA + SMA_wCalFreqAtoD); + if (dev.calibrate_signal == 0) writew(readw(dev.SMA + SMA_wCurrHostStatusFlags) | 0x0001, dev.SMA + SMA_wCurrHostStatusFlags); - } else { - printk(KERN_INFO LOGNAME ": ADC calibration to signal ground "); + else writew(readw(dev.SMA + SMA_wCurrHostStatusFlags) & ~0x0001, dev.SMA + SMA_wCurrHostStatusFlags); - } - - writew(srate, dev.SMA + SMA_wCalFreqAtoD); - if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 && chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ / 3); - printk("successful\n"); return 0; } - printk("failed\n"); + printk(KERN_WARNING LOGNAME ": ADC calibration failed\n"); return -EIO; } @@ -1302,11 +1328,7 @@ __initfunc(static int calibrate_adc(WORD srate)) static int upload_dsp_code(void) { outb(HPBLKSEL_0, dev.io + HP_BLKS); - -#ifdef HAVE_DSPCODEH - printk(KERN_INFO LOGNAME ": Using resident Turtle Beach DSP code\n"); -#else - printk(KERN_INFO LOGNAME ": Loading Turtle Beach DSP code\n"); +#ifndef HAVE_DSPCODEH INITCODESIZE = mod_firmware_load(INITCODEFILE, &INITCODE); if (!INITCODE) { printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE); @@ -1325,6 +1347,11 @@ static int upload_dsp_code(void) printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n"); return -ENODEV; } +#ifdef HAVE_DSPCODEH + printk(KERN_INFO LOGNAME ": DSP firmware uploaded (resident)\n"); +#else + printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n"); +#endif #ifndef HAVE_DSPCODEH vfree(INITCODE); @@ -1365,9 +1392,7 @@ static int initialize(void) if ((err = upload_dsp_code()) < 0) { printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n"); return err; - - } else - printk(KERN_INFO LOGNAME ": DSP upload successful\n"); + } timeout = 200; while (readw(dev.base)) { @@ -1390,8 +1415,8 @@ static int dsp_full_reset(void) if (test_bit(F_RESETTING, &dev.flags) || ++dev.nresets > 10) return 0; - printk(KERN_INFO LOGNAME ": Resetting DSP\n"); set_bit(F_RESETTING, &dev.flags); + printk(KERN_INFO LOGNAME ": DSP reset\n"); dsp_halt(NULL); /* Unconditionally halt */ if ((rv = initialize())) printk(KERN_WARNING LOGNAME ": DSP reset failed\n"); @@ -1441,13 +1466,11 @@ __initfunc(static int attach_multisound(void)) free_irq(dev.irq, &dev); return dev.mixer_minor; } - printk(KERN_INFO LOGNAME ": Using DSP minor %d, mixer minor %d\n", dev.dsp_minor, dev.mixer_minor); disable_irq(dev.irq); calibrate_adc(dev.play_sample_rate); #ifndef MSND_CLASSIC - printk(KERN_INFO LOGNAME ": Setting initial recording source to Line In\n"); - force_recsrc(SOUND_MASK_LINE); + force_recsrc(SOUND_MASK_IMIX); #endif return 0; @@ -1464,16 +1487,6 @@ static void unload_multisound(void) } #endif -static void mod_inc_ref(void) -{ - MOD_INC_USE_COUNT; -} - -static void mod_dec_ref(void) -{ - MOD_DEC_USE_COUNT; -} - #ifndef MSND_CLASSIC /* Pinnacle/Fiji Logical Device Configuration */ @@ -1896,14 +1909,10 @@ __initfunc(int msnd_pinnacle_init(void)) clear_bit(F_DISABLE_WRITE_NDELAY, &dev.flags); else set_bit(F_DISABLE_WRITE_NDELAY, &dev.flags); - #ifndef MSND_CLASSIC - if (digital) { + if (digital) set_bit(F_HAVEDIGITAL, &dev.flags); - printk(KERN_INFO LOGNAME ": Digital I/O access enabled\n"); - } #endif - init_waitqueue(&dev.writeblock); init_waitqueue(&dev.readblock); init_waitqueue(&dev.writeflush); @@ -1912,9 +1921,7 @@ __initfunc(int msnd_pinnacle_init(void)) #ifndef LINUX20 spin_lock_init(&dev.lock); #endif - - printk(KERN_INFO LOGNAME ": Using %u byte digital audio FIFOs (x2)\n", dev.fifosize); - + printk(KERN_INFO LOGNAME ": %u byte audio FIFOs (x2)\n", dev.fifosize); if ((err = msnd_fifo_alloc(&dev.DAPF, dev.fifosize)) < 0) { printk(KERN_ERR LOGNAME ": Couldn't allocate write FIFO\n"); return err; @@ -1946,10 +1953,7 @@ __initfunc(int msnd_pinnacle_init(void)) #ifdef MODULE void cleanup_module(void) { - printk(KERN_INFO LOGNAME ": Unloading\n"); - unload_multisound(); - msnd_fifo_free(&dev.DAPF); msnd_fifo_free(&dev.DARF); } diff --git a/drivers/sound/opl3sa2.c b/drivers/sound/opl3sa2.c index d9d95c2783cc..05823f689ed2 100644 --- a/drivers/sound/opl3sa2.c +++ b/drivers/sound/opl3sa2.c @@ -5,6 +5,10 @@ * * Scott Murray, Jun 14, 1998 * + * + * Changes + * Paul J.Y. Lahaie Changed probing / attach code order + * */ /* Based on the CS4232 driver: @@ -196,12 +200,14 @@ int init_module(void) { return -ENODEV; } + + if (probe_opl3sa2_mss(&mss_cfg) == 0) + { + return -ENODEV; + } + attach_opl3sa2(&cfg); - if (probe_opl3sa2_mss(&mss_cfg) == 0) - { - return -ENODEV; - } attach_opl3sa2_mss(&mss_cfg); #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c index 701be528918e..1fa943741bf5 100644 --- a/drivers/sound/pss.c +++ b/drivers/sound/pss.c @@ -135,7 +135,7 @@ static void pss_write(pss_confdata *devc, int data) * loops. */ - for (i = 0; i < 5000000 && jiffies < limit; i++) + for (i = 0; i < 5000000 && time_before(jiffies, limit); i++) { if (inw(REG(PSS_STATUS)) & PSS_WRITE_EMPTY) { @@ -285,7 +285,7 @@ static int pss_download_boot(pss_confdata * devc, unsigned char *block, int size outw(0x00fe, REG(PSS_DATA)); limit = jiffies + HZ/10; - for (i = 0; i < 32768 && jiffies < limit; i++) + for (i = 0; i < 32768 && time_before(jiffies, limit); i++) if (inw(REG(PSS_DATA)) == 0x5500) break; diff --git a/drivers/sound/sb_audio.c b/drivers/sound/sb_audio.c index b14924e4e68c..889f57b01252 100644 --- a/drivers/sound/sb_audio.c +++ b/drivers/sound/sb_audio.c @@ -91,6 +91,14 @@ static void sb_audio_close(int dev) { sb_devc *devc = audio_devs[dev]->devc; + /* if we did dma juggling put the right dmap in the right place */ + if(devc->duplex && audio_devs[dev]->dmap_out->dma != devc->dma8) + { + struct dma_buffparms *dmap_temp; + dmap_temp = audio_devs[dev]->dmap_out; + audio_devs[dev]->dmap_out = audio_devs[dev]->dmap_in; + audio_devs[dev]->dmap_in = dmap_temp; + } audio_devs[dev]->dmap_out->dma = devc->dma8; audio_devs[dev]->dmap_in->dma = ( devc->duplex ) ? devc->dma16 : devc->dma8; @@ -1136,6 +1144,12 @@ sb16_copy_from_user(int dev, } } +static void +sb16_audio_mmap(int dev) +{ + sb_devc *devc = audio_devs[dev]->devc; + devc->fullduplex = 0; +} static struct audio_driver sb1_audio_driver = /* SB1.x */ { @@ -1254,7 +1268,10 @@ static struct audio_driver sb16_audio_driver = /* SB16 */ sb16_audio_trigger, sb16_audio_set_speed, sb16_audio_set_bits, - sbpro_audio_set_channels + sbpro_audio_set_channels, + NULL, + NULL, + sb16_audio_mmap }; static struct audio_driver ess_audio_driver = /* ESS ES688/1688 */ diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c index 34f82ff701db..bb8063ab5efa 100644 --- a/drivers/sound/sb_common.c +++ b/drivers/sound/sb_common.c @@ -975,9 +975,11 @@ void sb_dsp_unload(struct address_info *hw_config, int sbmpu) if (devc->dma16 >= 0) sound_free_dma(devc->dma16); } - if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && devc->irq > 0) + if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI)) { - free_irq(devc->irq, devc); + if (devc->irq > 0); + free_irq(devc->irq, devc); + sound_unload_mixerdev(devc->my_mixerdev); /* We don't have to do this bit any more the UART401 is its own master -- Krzysztof Halasa */ diff --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c index b5cb59cdf15f..5e9407d23573 100644 --- a/drivers/sound/sequencer.c +++ b/drivers/sound/sequencer.c @@ -82,7 +82,7 @@ static volatile int iqhead = 0, iqtail = 0, iqlen = 0; static volatile int seq_playing = 0; static volatile int sequencer_busy = 0; static int output_threshold; -static int pre_event_timeout; +static long pre_event_timeout; static unsigned synth_open_mask; static int seq_queue(unsigned char *note, char nonblock); diff --git a/drivers/sound/sound_calls.h b/drivers/sound/sound_calls.h index 8c91cb72d1b7..d05369d7c0dd 100644 --- a/drivers/sound/sound_calls.h +++ b/drivers/sound/sound_calls.h @@ -205,6 +205,11 @@ void attach_sscape (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); +/* From ad1816.c */ +void unload_ad1816(struct address_info *hw_info); +int probe_ad1816 (struct address_info *hw_config); +void attach_ad1816 (struct address_info *hw_config); + /* From aedsp16.c */ int InitAEDSP16_SBPRO(struct address_info *hw_config); int InitAEDSP16_MSS(struct address_info *hw_config); @@ -281,29 +286,10 @@ void attach_vidc(struct address_info *hw_config); int probe_vidc(struct address_info *hw_config); void unload_vidc(struct address_info *hw_config); -/* From wavefront.c */ -void attach_wavefront (struct address_info *hw_config); -int probe_wavefront (struct address_info *hw_config); -void unload_wavefront (struct address_info *hw_config); - -/* From wf_midi.c */ -void attach_wf_mpu(struct address_info * hw_config); -int probe_wf_mpu(struct address_info *hw_config); -void unload_wf_mpu(struct address_info *hw_config); -int virtual_midi_enable (int mididev, struct address_info *); -void virtual_midi_disable (int mididev); - -/* From wavefront.c */ -void attach_wavefront (struct address_info *hw_config); -int probe_wavefront (struct address_info *hw_config); -void unload_wavefront (struct address_info *hw_config); - -/* From wf_midi.c */ -void attach_wf_mpu(struct address_info * hw_config); -int probe_wf_mpu(struct address_info *hw_config); -void unload_wf_mpu(struct address_info *hw_config); -int virtual_midi_enable (int mididev, struct address_info *); -void virtual_midi_disable (int mididev); +/* From waveartist.c */ +void attach_waveartist(struct address_info *hw_config); +int probe_waveartist(struct address_info *hw_config); +void unload_waveartist(struct address_info *hw_config); /* From wavefront.c */ void attach_wavefront (struct address_info *hw_config); diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index b830afdd2f17..aca163bb74ec 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -760,6 +760,9 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) dmap->mapping_flags |= DMA_MAP_MAPPED; + if( audio_devs[dev]->d->mmap) + audio_devs[dev]->d->mmap(dev); + memset(dmap->raw_buf, dmap->neutral_byte, dmap->bytes_in_use); diff --git a/drivers/sound/vidc.c b/drivers/sound/vidc.c index c33ed9beb7c9..36a4eafb1c42 100644 --- a/drivers/sound/vidc.c +++ b/drivers/sound/vidc.c @@ -6,32 +6,50 @@ * Copyright (C) 1997 by Russell King */ +#include +#include + #include #include #include "sound_config.h" +#include "soundmodule.h" #include "vidc.h" int vidc_busy; -void vidc_update_filler(int bits, int channels) +void vidc_update_filler(int format, int channels) { - int filltype; + int fillertype; + +#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3)) - filltype = bits + channels; - switch (filltype) + fillertype = TYPE(format, channels); +printk("filler type: %X\n", fillertype); + switch (fillertype) { default: - case 9: - vidc_filler = vidc_fill_1x8; + case TYPE(AFMT_U8, 1): + vidc_filler = vidc_fill_1x8_u; break; - case 10: - vidc_filler = vidc_fill_2x8; + + case TYPE(AFMT_U8, 2): + vidc_filler = vidc_fill_2x8_u; break; - case 17: - vidc_filler = vidc_fill_1x16; + + case TYPE(AFMT_S8, 1): + vidc_filler = vidc_fill_1x8_s; break; - case 18: - vidc_filler = vidc_fill_2x16; + + case TYPE(AFMT_S8, 2): + vidc_filler = vidc_fill_2x8_s; + break; + + case TYPE(AFMT_S16_LE, 1): + vidc_filler = vidc_fill_1x16_s; + break; + + case TYPE(AFMT_S16_LE, 2): + vidc_filler = vidc_fill_2x16_s; break; } } @@ -55,12 +73,12 @@ void attach_vidc(struct address_info *hw_config) printk(KERN_ERR "VIDCsound: can't allocate virtual DMA channel\n"); return; } - if (request_irq(hw_config->irq, vidc_sound_dma_irq, 0, "VIDCsound", NULL)) + if (request_irq(hw_config->irq, vidc_sound_dma_irq, 0, "VIDCsound", &dma_start)) { printk(KERN_ERR "VIDCsound: can't allocate DMA interrupt\n"); return; } - vidc_synth_init(hw_config); +// vidc_synth_init(hw_config); vidc_audio_init(hw_config); vidc_mixer_init(hw_config); } @@ -76,6 +94,32 @@ int probe_vidc(struct address_info *hw_config) void unload_vidc(struct address_info *hw_config) { + int i; + free_irq(hw_config->irq, NULL); sound_free_dma(hw_config->dma); + + for (i = 0; i < 2; i++) + free_page(dma_buf[i]); +} + +#ifdef MODULE +static struct address_info config; + +int init_module(void) +{ + if (probe_vidc(&config) == 0) + return -ENODEV; + printk("VIDC 16-bit serial sound\n"); + SOUND_LOCK; + attach_vidc(&config); + return 0; } + +void cleanup_module(void) +{ + unload_vidc(&config); + SOUND_LOCK_END; +} + +#endif diff --git a/drivers/sound/vidc.h b/drivers/sound/vidc.h index 33625f3929d6..a79bdc85d6eb 100644 --- a/drivers/sound/vidc.h +++ b/drivers/sound/vidc.h @@ -16,14 +16,18 @@ extern int vidc_busy; * Filler routines for different channels and sample sizes */ -extern unsigned long vidc_fill_1x8(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); -extern unsigned long vidc_fill_2x8(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); -extern unsigned long vidc_fill_1x16(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); -extern unsigned long vidc_fill_2x16(unsigned long ibuf, unsigned long iend, - unsigned long obuf, int mask); +extern unsigned long vidc_fill_1x8_u(unsigned long ibuf, unsigned long iend, + unsigned long obuf, int mask); +extern unsigned long vidc_fill_2x8_u(unsigned long ibuf, unsigned long iend, + unsigned long obuf, int mask); +extern unsigned long vidc_fill_1x8_s(unsigned long ibuf, unsigned long iend, + unsigned long obuf, int mask); +extern unsigned long vidc_fill_2x8_s(unsigned long ibuf, unsigned long iend, + unsigned long obuf, int mask); +extern unsigned long vidc_fill_1x16_s(unsigned long ibuf, unsigned long iend, + unsigned long obuf, int mask); +extern unsigned long vidc_fill_2x16_s(unsigned long ibuf, unsigned long iend, + unsigned long obuf, int mask); /* * DMA Interrupt handler diff --git a/drivers/sound/vidc_audio.c b/drivers/sound/vidc_audio.c index a59a077f386b..7aa2750847eb 100644 --- a/drivers/sound/vidc_audio.c +++ b/drivers/sound/vidc_audio.c @@ -8,6 +8,8 @@ #include #include +#include + #include "sound_config.h" #include "vidc.h" @@ -22,7 +24,7 @@ static int vidc_adev; static int vidc_audio_volume; static int vidc_audio_rate; -static char vidc_audio_bits; +static char vidc_audio_format; static char vidc_audio_channels; extern void vidc_update_filler(int bits, int channels); @@ -38,23 +40,25 @@ int vidc_audio_set_volume(int newvol) return vidc_audio_volume; } -static int vidc_audio_set_bits(int bits) +static int vidc_audio_set_bits(int fmt) { - switch (bits) +printk("setting format: %d\n", fmt); + switch (fmt) { case AFMT_QUERY: break; case AFMT_U8: + case AFMT_S8: case AFMT_S16_LE: - vidc_audio_bits = bits; - vidc_update_filler(vidc_audio_bits, vidc_audio_channels); + vidc_audio_format = fmt; + vidc_update_filler(vidc_audio_format, vidc_audio_channels); break; default: - vidc_audio_bits = 16; - vidc_update_filler(vidc_audio_bits, vidc_audio_channels); + vidc_audio_format = AFMT_S16_LE; + vidc_update_filler(vidc_audio_format, vidc_audio_channels); break; } - return vidc_audio_bits; + return vidc_audio_format; } static int vidc_audio_set_rate(int rate) @@ -68,8 +72,8 @@ static int vidc_audio_set_rate(int rate) vidc_audio_rate = 3; if (vidc_audio_rate > 255) vidc_audio_rate = 255; - outl((vidc_audio_rate - 2) | 0xb0000000, VIDC_BASE); - outl(0xb1000003, VIDC_BASE); + outl((vidc_audio_rate - 2) | 0xb0000000, IO_VIDC_BASE); + outl(0xb1000003, IO_VIDC_BASE); newsize = (10000 / vidc_audio_rate) & ~3; if (newsize < 208) newsize = 208; @@ -92,11 +96,11 @@ static int vidc_audio_set_channels(int channels) case 1: case 2: vidc_audio_channels = channels; - vidc_update_filler(vidc_audio_bits, vidc_audio_channels); + vidc_update_filler(vidc_audio_format, vidc_audio_channels); break; default: vidc_audio_channels = 2; - vidc_update_filler(vidc_audio_bits, vidc_audio_channels); + vidc_update_filler(vidc_audio_format, vidc_audio_channels); break; } return vidc_audio_channels; @@ -110,7 +114,6 @@ static int vidc_audio_set_channels(int channels) * * Called when opening the DMAbuf (dmabuf.c:259) */ - static int vidc_audio_open(int dev, int mode) { if (vidc_busy) @@ -133,7 +136,6 @@ static int vidc_audio_open(int dev, int mode) * Called when closing the DMAbuf (dmabuf.c:477) * after halt_xfer */ - static void vidc_audio_close(int dev) { vidc_busy = 0; @@ -205,23 +207,23 @@ static int vidc_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) * 2. (dmabuf.c:1504) * 3. A new buffer needs to be sent to the device (dmabuf.c:1579) */ - -static void vidc_audio_dma_interrupt(void) -{ - DMAbuf_outputintr(vidc_adev, 1); -} - static void vidc_audio_output_block(int dev, unsigned long buf, int total_count, int intrflag) { - dma_start = buf; + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_out; + + dma_start = buf - (unsigned long)dmap->raw_buf_phys + (unsigned long)dmap->raw_buf; dma_count = total_count; - if (!intrflag) + if (!(adev->flags & DMA_ACTIVE)) { - dma_interrupt = vidc_audio_dma_interrupt; + unsigned long flags; +printk("kicking output: %lX+%lX [%lX]\n", dma_start, dma_count, *(unsigned long *)dma_start); + save_flags_cli(flags); vidc_sound_dma_irq(0, NULL, NULL); - outb(DMA_CR_D | DMA_CR_E, IOMD_SD0CR); + outb(DMA_CR_E | 0x10, IOMD_SD0CR); + restore_flags(flags); } } @@ -235,6 +237,11 @@ static int vidc_audio_prepare_for_input(int dev, int bsize, int bcount) return -EINVAL; } +static void vidc_audio_dma_interrupt(void) +{ + DMAbuf_outputintr(vidc_adev, 1); +} + /* * Prepare for outputting samples to `dev' * @@ -246,34 +253,27 @@ static int vidc_audio_prepare_for_input(int dev, int bsize, int bcount) * 2. We get a write buffer without dma_mode setup (dmabuf.c:1152) * 3. We restart a transfer (dmabuf.c:1324) */ - static int vidc_audio_prepare_for_output(int dev, int bsize, int bcount) { + audio_devs[dev]->dmap_out->flags |= DMA_NODMA; + dma_interrupt = vidc_audio_dma_interrupt; return 0; } -static void vidc_audio_reset(int dev) -{ -} - /* - * Halt a DMA transfer to `dev' - * - * Called when: - * 1. We close the DMAbuf (dmabuf.c:476) - * 2. We run out of output buffers to output to the device. (dmabuf.c:1456) - * 3. We run out of output buffers and we're closing down. (dmabuf.c:1546) - * 4. We run out of input buffers in AUTOMODE. (dmabuf.c:1651) + * Stop our current operation. */ - -static void vidc_audio_halt_xfer(int dev) +static void vidc_audio_reset(int dev) { - dma_count = 0; + /* stop interrupts. Our real interrupt routine + * will close DMA down for us + */ + dma_interrupt = NULL; } static int vidc_audio_local_qlen(int dev) { - return dma_count != 0; + return /*dma_count !=*/ 0; } static struct audio_driver vidc_audio_driver = @@ -286,35 +286,28 @@ static struct audio_driver vidc_audio_driver = vidc_audio_prepare_for_input, /* prepare_for_input */ vidc_audio_prepare_for_output, /* prepare_for_output */ vidc_audio_reset, /* reset */ - vidc_audio_halt_xfer, /* halt_xfer */ vidc_audio_local_qlen, /*+local_qlen */ NULL, /*+copy_from_user */ NULL, /*+halt_input */ - NULL, /*+halt_output */ + NULL, /* halt_output */ NULL, /*+trigger */ NULL, /*+set_speed */ NULL, /*+set_bits */ NULL, /*+set_channels */ }; -static struct audio_operations vidc_audio_operations = -{ - "VIDCsound", - 0, - AFMT_U8 | AFMT_S16_LE, - NULL, - &vidc_audio_driver -}; - void vidc_audio_init(struct address_info *hw_config) { vidc_audio_volume = 100 | (100 << 8); - if ((vidc_adev = sound_alloc_audiodev())!=-1) + + if ((vidc_adev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, + "VIDCsound", &vidc_audio_driver, + sizeof(struct audio_driver), + DMA_AUTOMODE, AFMT_U8 | AFMT_S8 | AFMT_S16_LE, + NULL, hw_config->dma, hw_config->dma2)) >= 0) { - audio_devs[vidc_adev] = &vidc_audio_operations; audio_devs[vidc_adev]->min_fragment = 10; /* 1024 bytes => 64 buffers */ audio_devs[vidc_adev]->mixer_dev = num_mixers; - audio_devs[vidc_adev]->flags |= 0; } else printk(KERN_ERR "VIDCsound: Too many PCM devices available\n"); } diff --git a/drivers/sound/vidc_fill.S b/drivers/sound/vidc_fill.S index 841fe5b96e36..b8b1e6620e7a 100644 --- a/drivers/sound/vidc_fill.S +++ b/drivers/sound/vidc_fill.S @@ -12,11 +12,12 @@ .text -ENTRY(vidc_fill_1x8) +ENTRY(vidc_fill_1x8_u) mov ip, #0xff00 1: cmp r0, r1 bge SYMBOL_NAME(vidc_clear) ldrb r4, [r0], #1 + eor r4, r4, #0x80 and r4, ip, r4, lsl #8 orr r4, r4, r4, lsl #16 str r4, [r2], #4 @@ -24,7 +25,7 @@ ENTRY(vidc_fill_1x8) blt 1b mov pc, lr -ENTRY(vidc_fill_2x8) +ENTRY(vidc_fill_2x8_u) mov ip, #0xff00 1: cmp r0, r1 bge SYMBOL_NAME(vidc_clear) @@ -38,7 +39,33 @@ ENTRY(vidc_fill_2x8) blt 1b mov pc, lr -ENTRY(vidc_fill_1x16) +ENTRY(vidc_fill_1x8_s) + mov ip, #0xff00 +1: cmp r0, r1 + bge SYMBOL_NAME(vidc_clear) + ldrb r4, [r0], #1 + and r4, ip, r4, lsl #8 + orr r4, r4, r4, lsl #16 + str r4, [r2], #4 + cmp r2, r3 + blt 1b + mov pc, lr + +ENTRY(vidc_fill_2x8_s) + mov ip, #0xff00 +1: cmp r0, r1 + bge SYMBOL_NAME(vidc_clear) + ldr r4, [r0], #2 + and r5, r4, ip + and r4, ip, r4, lsl #8 + orr r4, r4, r5, lsl #16 + orr r4, r4, r4, lsr #8 + str r4, [r2], #4 + cmp r2, r3 + blt 1b + mov pc, lr + +ENTRY(vidc_fill_1x16_s) mov ip, #0xff00 orr ip, ip, ip, lsr #8 1: cmp r0, r1 @@ -56,7 +83,7 @@ ENTRY(vidc_fill_1x16) blt 1b mov pc, lr -ENTRY(vidc_fill_2x16) +ENTRY(vidc_fill_2x16_s) mov ip, #0xff00 orr ip, ip, ip, lsr #8 1: cmp r0, r1 @@ -103,26 +130,26 @@ ENTRY(vidc_clear) */ ENTRY(vidc_sound_dma_irq) - stmfd sp!, {r4 - r9, lr} - ldr r9, =SYMBOL_NAME(dma_start) - ldmia r9, {r0, r1, r2, r3, r4, r5} + stmfd sp!, {r4 - r8, lr} + ldr r8, =SYMBOL_NAME(dma_start) + ldmia r8, {r0, r1, r2, r3, r4, r5} teq r1, #0 adreq r4, SYMBOL_NAME(vidc_fill_noaudio) - moveq r8, #1 << 31 - movne r8, #0 + moveq r7, #1 << 31 + movne r7, #0 mov ip, #IOMD_BASE & 0xff000000 orr ip, ip, #IOMD_BASE & 0x00ff0000 - ldrb r7, [ip, #IOMD_SD0ST] - tst r7, #DMA_ST_OFL @ Check for overrun - eorne r7, r7, #DMA_ST_AB - tst r7, #DMA_ST_AB + ldrb r6, [ip, #IOMD_SD0ST] + tst r6, #DMA_ST_OFL @ Check for overrun + eorne r6, r6, #DMA_ST_AB + tst r6, #DMA_ST_AB moveq r2, r3 @ DMAing A, update B add r3, r2, r5 @ End of DMA buffer add r1, r1, r0 @ End of virtual DMA buffer mov lr, pc - mov pc, r4 @ Call fill routine + mov pc, r4 @ Call fill routine (uses r4, ip) sub r1, r1, r0 @ Remaining length - stmia r9, {r0, r1} + stmia r8, {r0, r1} mov r0, #0 tst r2, #4 @ Round buffer up to 4 words strne r0, [r2], #4 @@ -133,29 +160,31 @@ ENTRY(vidc_sound_dma_irq) mov r2, r2, lsl #20 movs r2, r2, lsr #20 orreq r2, r2, #1 << 30 @ Set L bit - orr r2, r2, r8 - ldmdb r9, {r3, r4, r5} - tst r7, #DMA_ST_AB + orr r2, r2, r7 + ldmdb r8, {r3, r4, r5} + tst r6, #DMA_ST_AB mov ip, #IOMD_BASE & 0xff000000 orr ip, ip, #IOMD_BASE & 0x00ff0000 streq r4, [ip, #IOMD_SD0CURB] strne r5, [ip, #IOMD_SD0CURA] streq r2, [ip, #IOMD_SD0ENDB] strne r2, [ip, #IOMD_SD0ENDA] - ldr r6, [ip, #IOMD_SD0ST] - tst r6, #DMA_ST_OFL + ldr lr, [ip, #IOMD_SD0ST] + tst lr, #DMA_ST_OFL bne 1f - tst r7, #DMA_ST_AB + tst r6, #DMA_ST_AB strne r4, [ip, #IOMD_SD0CURB] streq r5, [ip, #IOMD_SD0CURA] strne r2, [ip, #IOMD_SD0ENDB] streq r2, [ip, #IOMD_SD0ENDA] -1: teq r8, #0 +1: teq r7, #0 mov r0, #0x10 strneb r0, [ip, #IOMD_SD0CR] - teqeq r1, #0 - ldmfd sp!, {r4 - r9, lr} - moveq pc, r3 @ Call interrupt routine + ldmfd sp!, {r4 - r8, lr} + teq r1, #0 @ If we have no more + movne pc, lr + teq r3, #0 + movne pc, r3 @ Call interrupt routine mov pc, lr .data diff --git a/drivers/sound/vidc_mixer.c b/drivers/sound/vidc_mixer.c index 1bdb1e88e588..01be4925cab1 100644 --- a/drivers/sound/vidc_mixer.c +++ b/drivers/sound/vidc_mixer.c @@ -47,13 +47,15 @@ static int vidc_default_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) break; case SOUND_MIXER_READ_SYNTH: - ret = vidc_synth_get_volume(); +// ret = vidc_synth_get_volume(); + ret = 0; break; case SOUND_MIXER_WRITE_SYNTH: if (get_user(ret, (int *) arg)) return -EINVAL; - ret = vidc_synth_set_volume(ret); +// ret = vidc_synth_set_volume(ret); + ret = 0; break; case SOUND_MIXER_READ_PCM: diff --git a/drivers/sound/vidc_synth.c b/drivers/sound/vidc_synth.c index 7e6797e8ee3c..ba94f0bc6dbb 100644 --- a/drivers/sound/vidc_synth.c +++ b/drivers/sound/vidc_synth.c @@ -8,7 +8,7 @@ #include "sound_config.h" #include "vidc.h" - +#if 0 static struct synth_info vidc_info = { "VIDCsound", /* name */ @@ -42,31 +42,32 @@ static void vidc_synth_close(int dev) static struct synth_operations vidc_synth_operations = { - &vidc_info, /* info */ - 0, /* midi_dev */ - SYNTH_TYPE_SAMPLE, /* synth_type */ - /*SAMPLE_TYPE_XXX */ 0, - /* SAMPLE_TYPE GUS *//* synth_subtype */ - vidc_synth_open, /* open */ - vidc_synth_close, /* close */ - NULL, /* ioctl */ - NULL, /* kill_note */ - NULL, /* start_note */ - NULL, /* set_instr */ - NULL, /* reset */ - NULL, /* hw_control */ - NULL, /* load_patch */ - NULL, /* aftertouch */ - NULL, /* controller */ - NULL, /* panning */ - NULL, /* volume_method */ - NULL, /* patchmgr */ - NULL, /* bender */ - NULL, /* alloc */ - NULL, /* setup_voice */ - NULL, /* send_sysex */ - /* alloc */ - /* chn_info[16] */ + "VIDC Synth", /* name */ + &vidc_info, /* info */ + 0, /* midi_dev */ + SYNTH_TYPE_SAMPLE, /* synth_type */ + /*SAMPLE_TYPE_XXX */ 0, /* synth_subtype */ + vidc_synth_open, /* open */ + vidc_synth_close, /* close */ + NULL, /* ioctl */ + NULL, /* kill_note */ + NULL, /* start_note */ + NULL, /* set_instr */ + NULL, /* reset */ + NULL, /* hw_control */ + NULL, /* load_patch */ + NULL, /* aftertouch */ + NULL, /* controller */ + NULL, /* panning */ + NULL, /* volume_method */ + NULL, /* bender */ + NULL, /* alloc_voice */ + NULL, /* setup_voice */ + NULL, /* send_sysex */ + /* alloc */ + /* chn_info[16] */ + /* syex_buf */ + /* syex_ptr */ }; int vidc_synth_get_volume(void) @@ -87,3 +88,4 @@ void vidc_synth_init(struct address_info *hw_config) else printk(KERN_ERR "VIDCsound: Too many synthesizers\n"); } +#endif diff --git a/fs/ChangeLog b/fs/ChangeLog index 056d07a8637e..caea148966a5 100644 --- a/fs/ChangeLog +++ b/fs/ChangeLog @@ -8,3 +8,67 @@ Thu Oct 20 23:44:22 1994 Theodore Y. Ts'o (tytso@rt-11) * fcntl.c (sys_fcntl): Add more of a security check to the F_SETOWN fcntl(). +[Tons of changes missed, indeed. This list is worth restarting since +at least some fixes WILL break third-party filesystems. Sorry, but +there was no other way to fix rmdir/rename deadlock, for one.] + +Wed Dec 2 (Linus, fill the rest, please) + + * namei.c (do_rmdir) and rmdir method in filesystems: + Locking of directory we remove was taken to VFS. + See comments in do_rmdir(). Unfixed filesystems + will bloody likely deadlock in rmdir(). + +Thu Dec 3 17:25:31 1998 Al Viro (viro@math.psu.edu) + + * namei.c (do_rmdir): + Reject non-directories here. + Two (probably) obsolete checks moved here too: we fail if + the directory we remove is the same as parent (BUG: we + serve mountpoints later) or if it lives on a different + device. + * sysvfs/namei.c (sysv_rmdir): + Bugectomy: old check for victim being busy (inode->i_count) + wasn't replaced (with checking dentry->d_count) and escaped + Linus in the last round of changes. Shot and buried. + +Fri Dec 4 00:54:12 1998 AV + + * namei.c (check_sticky): New function check_sticky(dir, inode). + If dir is sticky check whether we can unlink/rmdir/rename + the inode. Returns 1 if we can't. If dir isn't sticky - + return 0 (i.e. no objections). Some filesystems require + suser() here; some are fine with CAP_FOWNER. The later + seems more reasonable. + * namei.c (do_rmdir): + Moved the check for sticky bit here. + * affs/{inode,namei}.c: + All AFFS directories have sticky semantics (i.e. non-owner + having write permisssions on directory can unlink/rmdir/rename + only the files he owns), but AFFS didn't set S_ISVTX on them. + Fixed. NB: maybe this behaviour should be controlled by mount + option. Obvious values being 'sticky' (current behaviour), + 'nonsticky' (normal behaviour) and maybe some play on 'D' + permissions bit. FIXME. + * qnx4/namei.c (qnx4_rmdir): + Plugged inode leak. + * ufs/namei.c (ufs_rmdir): + Changed handling of busy directory to new scheme. + +Fri Dec 4 10:30:58 1998 AV + + * namei.c (VFS_rmdir): New function. It gets inode of the parent and + dentry of the victim, does all checks and applies fs-specific + rmdir() method. It should be called with semaphores down + on both the victim and its parent and with bumped d_count on + victim (see comments in do_rmdir). + * include/linux/fs.h: Added VFS_rmdir + * kernel/ksyms.c: Added VFS_rmdir to export list (for NFSD). + * nfsd/vfs.c: Fixed rmdir handling. + + Remaining problems with rmdir: + UMSDOS_rename is broken. Call it with the dest. existing and + being an empty directory and you've got EBUSY. At least it + doesn't do any harm, so that will wait several days till rename + cleanup. + TODO: unlink handling in NFSD does no tests. diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 55243ab83f5e..80aad129c8d6 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -170,8 +170,11 @@ affs_read_inode(struct inode *inode) } else { inode->i_op = &affs_file_inode_operations; } - } else if (S_ISDIR(inode->i_mode)) + } else if (S_ISDIR(inode->i_mode)) { + /* Maybe it should be controlled by mount parameter? */ + inode->i_mode |= S_ISVTX; inode->i_op = &affs_dir_inode_operations; + } else if (S_ISLNK(inode->i_mode)) inode->i_op = &affs_symlink_inode_operations; } diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 22540a57b79b..6114e1414db2 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -319,7 +319,7 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode) error = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR); if (error) goto out_iput; - inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask); + inode->i_mode = S_IFDIR | S_ISVTX | (mode & 0777 & ~current->fs->umask); inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); d_instantiate(dentry,inode); mark_inode_dirty(inode); @@ -360,17 +360,6 @@ affs_rmdir(struct inode *dir, struct dentry *dentry) if (!(bh = affs_find_entry(dir,dentry,&ino))) goto rmdir_done; - retval = -EPERM; - if (current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) - goto rmdir_done; - if (inode->i_dev != dir->i_dev) - goto rmdir_done; - if (inode == dir) /* we may not delete ".", but "../dir" is ok */ - goto rmdir_done; - retval = -ENOTDIR; - if (!S_ISDIR(inode->i_mode)) - goto rmdir_done; /* * Make sure the directory is empty and the dentry isn't busy. */ diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index c191d60a9856..540d4ca7cfde 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -643,21 +643,7 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry) inode = dentry->d_inode; DQUOT_INIT(inode); - retval = -EPERM; - if ((dir->i_mode & S_ISVTX) && - current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) - goto end_rmdir; - if (inode == dir) /* we may not delete ".", but "../dir" is ok */ - goto end_rmdir; - - retval = -ENOTDIR; - if (!S_ISDIR(inode->i_mode)) - goto end_rmdir; - retval = -EIO; - if (inode->i_dev != dir->i_dev) - goto end_rmdir; if (le32_to_cpu(de->inode) != inode->i_ino) goto end_rmdir; diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 4ef71500da55..f8d89227d3bf 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -337,9 +337,6 @@ int hfs_rmdir(struct inode * parent, struct dentry *dentry) struct hfs_cat_key key; int error; - if (parent == inode) /* can't delete . */ - return -EPERM; - if (build_key(&key, parent, dentry->d_name.name, dentry->d_name.len)) return -EPERM; diff --git a/fs/minix/namei.c b/fs/minix/namei.c index ad2211d2522d..3735fbd16df7 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -429,21 +429,8 @@ int minix_rmdir(struct inode * dir, struct dentry *dentry) retval = -ENOENT; if (!bh) goto end_rmdir; - retval = -EPERM; inode = dentry->d_inode; - if ((dir->i_mode & S_ISVTX) && - current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) - goto end_rmdir; - if (inode->i_dev != dir->i_dev) - goto end_rmdir; - if (inode == dir) /* we may not delete ".", but "../dir" is ok */ - goto end_rmdir; - if (!S_ISDIR(inode->i_mode)) { - retval = -ENOTDIR; - goto end_rmdir; - } if (!empty_dir(inode)) { retval = -ENOTEMPTY; goto end_rmdir; diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index 7d18237e7274..cff800a43a04 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -439,11 +439,6 @@ int msdos_rmdir(struct inode *dir, struct dentry *dentry) &bh, &de, &ino); if (res < 0) goto rmdir_done; - res = -ENOTDIR; - if (!S_ISDIR(inode->i_mode)) - goto rmdir_done; - if (dir->i_dev != inode->i_dev || dir == inode) - printk("msdos_rmdir: impossible condition\n"); /* * Check whether the directory is empty, then prune * any child dentries and make sure it's not in use. diff --git a/fs/namei.c b/fs/namei.c index 84208808a4dd..66c92c87c7ab 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -865,58 +865,67 @@ static inline void double_unlock(struct dentry *d1, struct dentry *d2) dput(d2); } -static inline int do_rmdir(const char * name) -{ - int error; - struct dentry *dir; - struct dentry *dentry; - - dentry = lookup_dentry(name, NULL, 0); - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) - goto exit; +/* + * It's inline, so penalty for filesystems that don't use sticky bit is + * minimal. + */ - dir = dget(dentry->d_parent); +static inline int check_sticky(struct inode *dir, struct inode *inode) +{ + if (!(dir->i_mode & S_ISVTX)) + return 0; + if (inode->i_uid == current->fsuid) + return 0; + if (dir->i_uid == current->fsuid) + return 0; + return !capable(CAP_FOWNER); +} - error = -ENOENT; - if (!dentry->d_inode) - goto exit; - /* - * The dentry->d_count stuff confuses d_delete() enough to - * not kill the inode from under us while it is locked. This - * wouldn't be needed, except the dentry semaphore is really - * in the inode, not in the dentry.. - */ - dentry->d_count++; - double_lock(dir, dentry); - if (dentry->d_parent != dir) - goto exit_lock; +int VFS_rmdir(struct inode *dir, struct dentry *dentry) +{ + int error; - error = -EROFS; - if (IS_RDONLY(dir->d_inode)) - goto exit_lock; + if (IS_RDONLY(dir)) + return -EROFS; - error = permission(dir->d_inode,MAY_WRITE | MAY_EXEC); + error = permission(dir,MAY_WRITE | MAY_EXEC); if (error) - goto exit_lock; + return error; /* * A subdirectory cannot be removed from an append-only directory. */ - error = -EPERM; - if (IS_APPEND(dir->d_inode)) - goto exit_lock; + if (IS_APPEND(dir)) + return -EPERM; + /* + * Check the sticky bit. + */ + if (check_sticky(dir, dentry->d_inode)) + return -EPERM; /* Disallow removals of mountpoints. */ - error = -EBUSY; if (dentry->d_mounts != dentry->d_covers) - goto exit_lock; - - error = -EPERM; - if (!dir->d_inode->i_op || !dir->d_inode->i_op->rmdir) - goto exit_lock; + return -EBUSY; - DQUOT_INIT(dir->d_inode); + if (!dir->i_op || !dir->i_op->rmdir) + return -EPERM; + /* + * I suspect that these two checks are atavisms copied from minixfs + * and it looks like they can be dropped. Anyway, it will be simpler + * to drop them from here and even if those checks are needed they + * belong to VFS. + */ + if (dir == dentry->d_inode) + return -EPERM; + if (dir->i_dev != dentry->d_inode->i_dev) + return -EPERM; + /* + * Non-directories can't be rmdir'd. It may confuse the heck of + * NFS and CODA. Testing it in VFS is the Right Thing (tm), anyway. + */ + if (!S_ISDIR(dentry->d_inode->i_mode)) + return -ENOTDIR; + DQUOT_INIT(dir); /* * We try to drop the dentry early: we should have @@ -942,11 +951,44 @@ static inline int do_rmdir(const char * name) d_drop(dentry); } - error = dir->d_inode->i_op->rmdir(dir->d_inode, dentry); + error = dir->i_op->rmdir(dir, dentry); + + return error; +} + +static inline int do_rmdir(const char * name) +{ + int error; + struct dentry *dir; + struct dentry *dentry; + + dentry = lookup_dentry(name, NULL, 0); + error = PTR_ERR(dentry); + if (IS_ERR(dentry)) + goto exit; + + error = -ENOENT; + if (!dentry->d_inode) + goto exit_dput; + /* + * The dentry->d_count stuff confuses d_delete() enough to + * not kill the inode from under us while it is locked. This + * wouldn't be needed, except the dentry semaphore is really + * in the inode, not in the dentry.. + */ + dentry->d_count++; + dir = dget(dentry->d_parent); + double_lock(dir, dentry); + + /* + * Check that dentry still sits where it did and do the real stuff. + */ + if (dentry->d_parent == dir) + error = VFS_rmdir(dir->d_inode, dentry); -exit_lock: - dentry->d_count--; double_unlock(dentry, dir); +exit_dput: + dput(dentry); exit: return error; } diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index b1dee7366949..fd3a72e2c6f3 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -718,6 +718,9 @@ out: * * We update inode->i_nlink and free the inode prior to the operation * to avoid possible races if the server reuses the inode. + * + * FIXME! We don't do it anymore (2.1.131) - it interacts badly with + * new rmdir(). -- AV */ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) { diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index d11c20ab67e5..6b4e344339bc 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -749,52 +749,45 @@ nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) goto out_changed; + inode->i_mode = fattr->mode; + inode->i_nlink = fattr->nlink; + inode->i_uid = fattr->uid; + inode->i_gid = fattr->gid; + + inode->i_blocks = fattr->blocks; + inode->i_atime = fattr->atime.seconds; + inode->i_ctime = fattr->ctime.seconds; + /* - * If we have pending write-back entries, we don't want - * to look at the size the server sends us too closely.. - * In particular, ignore the server if it tells us that - * the file is smaller or older than we locally think it - * is.. + * Update the read time so we don't revalidate too often. */ - if (NFS_WRITEBACK(inode)) { - if (inode->i_size > fattr->size) - fattr->size = inode->i_size; - if (inode->i_mtime > fattr->mtime.seconds) - fattr->mtime.seconds = inode->i_mtime; - } + NFS_READTIME(inode) = jiffies; + error = 0; /* - * If the size or mtime changed from outside, we want - * to invalidate the local caches immediately. + * If we have pending write-back entries, we don't want + * to look at the size or the mtime the server sends us + * too closely, as we're in the middle of modifying them. */ + if (NFS_WRITEBACK(inode)) + goto out; + if (inode->i_size != fattr->size) { #ifdef NFS_DEBUG_VERBOSE printk("NFS: size change on %x/%ld\n", inode->i_dev, inode->i_ino); #endif + inode->i_size = fattr->size; invalid = 1; } + if (inode->i_mtime != fattr->mtime.seconds) { #ifdef NFS_DEBUG_VERBOSE printk("NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino); #endif + inode->i_mtime = fattr->mtime.seconds; invalid = 1; } - inode->i_mode = fattr->mode; - inode->i_nlink = fattr->nlink; - inode->i_uid = fattr->uid; - inode->i_gid = fattr->gid; - - inode->i_size = fattr->size; - inode->i_blocks = fattr->blocks; - inode->i_atime = fattr->atime.seconds; - inode->i_mtime = fattr->mtime.seconds; - inode->i_ctime = fattr->ctime.seconds; - /* - * Update the read time so we don't revalidate too often. - */ - NFS_READTIME(inode) = jiffies; - error = 0; if (invalid) goto out_invalid; out: @@ -810,6 +803,7 @@ inode->i_ino, inode->i_mode, fattr->mode); #endif fattr->mode = inode->i_mode; /* save mode */ make_bad_inode(inode); + nfs_inval(inode); inode->i_mode = fattr->mode; /* restore mode */ /* * No need to worry about unhashing the dentry, as the @@ -824,12 +818,9 @@ out_invalid: #ifdef NFS_DEBUG_VERBOSE printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages); #endif - if (!S_ISDIR(inode->i_mode)) { - /* This sends off all dirty pages off to the server. - * Note that this function must not sleep. */ - nfs_inval(inode); + if (!S_ISDIR(inode->i_mode)) invalidate_inode_pages(inode); - } else + else nfs_invalidate_dircache(inode); NFS_CACHEINV(inode); NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 72d67a13ae5c..87810f32c614 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1076,25 +1076,49 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, * FIXME!! * * This should do a double-lock on both rdentry and the parent + * + * Moreover, it should do checks *both* for unlink and rmdir + * cases. AV */ - err = fh_lock_parent(fhp, rdentry); - if (err) - goto out; + if (type != S_IFDIR) { + /* It's UNLINK */ + err = fh_lock_parent(fhp, rdentry); + if (err) + goto out; - DQUOT_INIT(dirp); - if (type == S_IFDIR) { - err = -ENOTDIR; - if (dirp->i_op && dirp->i_op->rmdir) - err = dirp->i_op->rmdir(dirp, rdentry); - } else { + DQUOT_INIT(dirp); err = -EPERM; if (dirp->i_op && dirp->i_op->unlink) err = dirp->i_op->unlink(dirp, rdentry); + DQUOT_DROP(dirp); + fh_unlock(fhp); + + dput(rdentry); + + } else { + /* It's RMDIR */ + /* See comments in fs/namei.c:do_rmdir */ + rdentry->d_count++; + nfsd_double_down(&dirp->i_sem, &rdentry->d_inode->i_sem); + if (!fhp->fh_pre_mtime) + fhp->fh_pre_mtime = dirp->i_mtime; + fhp->fh_locked = 1; + /* CHECKME: Should we do something with the child? */ + + err = -ENOENT; + if (rdentry->d_parent->d_inode == dirp) + err = VFS_rmdir(dirp, rdentry); + + rdentry->d_count--; + DQUOT_DROP(dirp); + if (!fhp->fh_post_version) + fhp->fh_post_version = dirp->i_version; + fhp->fh_locked = 0; + nfsd_double_up(&dirp->i_sem, &rdentry->d_inode->i_sem); + + dput(rdentry); } - DQUOT_DROP(dirp); - fh_unlock(fhp); - dput(rdentry); if (err) goto out_nfserr; if (EX_ISSYNC(fhp->fh_export)) diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c index 9c6617f50dd8..5479bf8e1bb9 100644 --- a/fs/qnx4/namei.c +++ b/fs/qnx4/namei.c @@ -168,29 +168,9 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry) if (bh == NULL) { return -ENOENT; } - if ((inode = iget(dir->i_sb, ino)) == NULL) { - QNX4DEBUG(("qnx4: lookup->iget -> NULL\n")); - retval = -EACCES; - goto end_rmdir; - } - retval = -EPERM; - if ((dir->i_mode & S_ISVTX) && - current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) { - QNX4DEBUG(("qnx4: rmdir->capabilities\n")); - goto end_rmdir; - } - if (inode->i_dev != dir->i_dev) { - QNX4DEBUG(("qnx4: rmdir->different devices\n")); - goto end_rmdir; - } - if (inode == dir) { /* we may not delete ".", but "../dir" is ok */ - QNX4DEBUG(("qnx4: inode==dir\n")); - goto end_rmdir; - } - if (!S_ISDIR(inode->i_mode)) { - QNX4DEBUG(("qnx4: rmdir->not a directory\n")); - retval = -ENOTDIR; + inode = dentry->d_inode; + if (inode->i_ino != ino) { + retval = -EIO; goto end_rmdir; } #if 0 diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index f2ba59c4f9d0..30138872ba25 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -469,10 +469,6 @@ smb_rmdir(struct inode *dir, struct dentry *dentry) struct inode *inode = dentry->d_inode; int error; - error = -ENOTDIR; - if (!S_ISDIR(inode->i_mode)) - goto out; - /* * Close the directory if it's open. */ diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index fdae5c38c5a6..0fcc9292064c 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -416,21 +416,8 @@ int sysv_rmdir(struct inode * dir, struct dentry * dentry) retval = -ENOENT; if (!bh) goto end_rmdir; - retval = -EPERM; inode = dentry->d_inode; - if ((dir->i_mode & S_ISVTX) && - current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) - goto end_rmdir; - if (inode->i_dev != dir->i_dev) - goto end_rmdir; - if (inode == dir) /* we may not delete ".", but "../dir" is ok */ - goto end_rmdir; - if (!S_ISDIR(inode->i_mode)) { - retval = -ENOTDIR; - goto end_rmdir; - } if (!empty_dir(inode)) { retval = -ENOTEMPTY; goto end_rmdir; @@ -439,7 +426,7 @@ int sysv_rmdir(struct inode * dir, struct dentry * dentry) retval = -ENOENT; goto end_rmdir; } - if (inode->i_count > 1) { + if (!list_empty(&dentry->d_hash)) { retval = -EBUSY; goto end_rmdir; } diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 130d53bb5c85..76d0ef8e019f 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -683,46 +683,15 @@ int ufs_rmdir (struct inode * dir, struct dentry *dentry) if (inode->i_sb->dq_op) inode->i_sb->dq_op->initialize (inode, -1); - retval = -EPERM; - if ((dir->i_mode & S_ISVTX) && - current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid && !fsuser()) - goto end_rmdir; - if (inode == dir) /* we may not delete ".", but "../dir" is ok */ - goto end_rmdir; - - retval = -ENOTDIR; - if (!S_ISDIR(inode->i_mode)) - goto end_rmdir; - retval = -EIO; - if (inode->i_dev != dir->i_dev) - goto end_rmdir; if (SWAB32(de->d_ino) != inode->i_ino) goto end_rmdir; - /* - * Prune any child dentries so that this dentry becomes negative. - */ - if (dentry->d_count > 1) { - ufs_warning (sb, "ufs_rmdir", "d_count=%d, pruning\n", dentry->d_count); - shrink_dcache_parent(dentry); - } if (!ufs_empty_dir (inode)) retval = -ENOTEMPTY; else if (SWAB32(de->d_ino) != inode->i_ino) retval = -ENOENT; else { - if (dentry->d_count > 1) { - /* - * Are we deleting the last instance of a busy directory? - * Better clean up if so. - * - * Make directory empty (it will be truncated when finally - * dereferenced). This also inhibits ufs_add_entry. - */ - inode->i_size = 0; - } retval = ufs_delete_entry (dir, de, bh); dir->i_version = ++event; } @@ -739,6 +708,7 @@ int ufs_rmdir (struct inode * dir, struct dentry *dentry) inode->i_nlink); inode->i_version = ++event; inode->i_nlink = 0; + inode->i_size = 0; mark_inode_dirty(inode); dir->i_nlink--; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c index 831802dcfa43..8e7780395a89 100644 --- a/fs/umsdos/namei.c +++ b/fs/umsdos/namei.c @@ -1011,14 +1011,6 @@ int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry) if (!list_empty(&dentry->d_hash)) goto out; - /* check the sticky bit */ - ret = -EPERM; - if (is_sticky(dir, dentry->d_inode->i_uid)) { -printk("umsdos_rmdir: %s/%s is sticky\n", -dentry->d_parent->d_name.name, dentry->d_name.name); - goto out; - } - /* check whether the EMD is empty */ ret = -ENOTEMPTY; empty = umsdos_isempty (dentry); diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index bf558a4f7da8..18dc5c2941b7 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -1416,12 +1416,6 @@ static int vfat_rmdir_free_ino(struct inode *dir,struct buffer_head *bh, struct super_block *sb = dir->i_sb; int res; - if (!S_ISDIR(dentry->d_inode->i_mode)) { - return -ENOTDIR; - } - if (dir->i_dev != dentry->d_inode->i_dev || dir == dentry->d_inode) { - return -EBUSY; - } if (!list_empty(&dentry->d_hash)) return -EBUSY; diff --git a/include/asm-alpha/dma.h b/include/asm-alpha/dma.h index 441e0abc8220..6e2828e36610 100644 --- a/include/asm-alpha/dma.h +++ b/include/asm-alpha/dma.h @@ -342,5 +342,13 @@ extern void free_dma(unsigned int dmanr); /* release it again */ #define KERNEL_HAVE_CHECK_DMA extern int check_dma(unsigned int dmanr); +/* From PCI */ + +#ifdef CONFIG_PCI_QUIRKS +extern int isa_dma_bridge_buggy; +#else +#define isa_dma_bridge_buggy (0) +#endif + #endif /* _ASM_DMA_H */ diff --git a/include/asm-alpha/termios.h b/include/asm-alpha/termios.h index a16407c8eaba..015e2debbc1c 100644 --- a/include/asm-alpha/termios.h +++ b/include/asm-alpha/termios.h @@ -77,6 +77,8 @@ struct termio { #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ +#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #ifdef __KERNEL__ /* eof=^D eol=\0 eol2=\0 erase=del diff --git a/include/asm-arm/termios.h b/include/asm-arm/termios.h index 2510a5b0eba9..5e05c1754b5b 100644 --- a/include/asm-arm/termios.h +++ b/include/asm-arm/termios.h @@ -58,6 +58,8 @@ struct termio { #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ +#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #ifdef __KERNEL__ diff --git a/include/asm-i386/dma.h b/include/asm-i386/dma.h index 748e331675e8..35aed55a7aad 100644 --- a/include/asm-i386/dma.h +++ b/include/asm-i386/dma.h @@ -8,6 +8,7 @@ #ifndef _ASM_DMA_H #define _ASM_DMA_H +#include #include /* need byte IO */ #include /* And spinlocks */ #include @@ -284,5 +285,12 @@ static __inline__ int get_dma_residue(unsigned int dmanr) extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ extern void free_dma(unsigned int dmanr); /* release it again */ +/* From PCI */ + +#ifdef CONFIG_PCI_QUIRKS +extern int isa_dma_bridge_buggy; +#else +#define isa_dma_bridge_buggy (0) +#endif #endif /* _ASM_DMA_H */ diff --git a/include/asm-i386/termios.h b/include/asm-i386/termios.h index cf6b5cd67677..6c860006004d 100644 --- a/include/asm-i386/termios.h +++ b/include/asm-i386/termios.h @@ -50,6 +50,8 @@ struct termio { #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ +#define N_IRDA 11 /* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #ifdef __KERNEL__ diff --git a/include/asm-m68k/termios.h b/include/asm-m68k/termios.h index b17fed223804..a65484efb84f 100644 --- a/include/asm-m68k/termios.h +++ b/include/asm-m68k/termios.h @@ -58,6 +58,8 @@ struct termio { #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ +#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #ifdef __KERNEL__ diff --git a/include/asm-mips/termios.h b/include/asm-mips/termios.h index 4a6553c176ff..62e3882a3cb6 100644 --- a/include/asm-mips/termios.h +++ b/include/asm-mips/termios.h @@ -96,6 +96,8 @@ struct termio { #define N_MASC 8 /* Reserved fo Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ +#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #ifdef __KERNEL__ diff --git a/include/asm-ppc/termios.h b/include/asm-ppc/termios.h index c6385d4a7a91..13b3591b81b3 100644 --- a/include/asm-ppc/termios.h +++ b/include/asm-ppc/termios.h @@ -182,6 +182,8 @@ struct termio { #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ +#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #ifdef __KERNEL__ diff --git a/include/asm-sparc/termios.h b/include/asm-sparc/termios.h index aeefe28e4696..d00d6558c643 100644 --- a/include/asm-sparc/termios.h +++ b/include/asm-sparc/termios.h @@ -66,6 +66,8 @@ struct winsize { #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ +#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #ifdef __KERNEL__ diff --git a/include/asm-sparc64/termios.h b/include/asm-sparc64/termios.h index 767722d4c989..607ad1440310 100644 --- a/include/asm-sparc64/termios.h +++ b/include/asm-sparc64/termios.h @@ -66,6 +66,8 @@ struct winsize { #define N_MASC 8 /* Reserved for Mobitex module */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ +#define N_IRDA 11 /* Linux IrDa - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #ifdef __KERNEL__ diff --git a/include/linux/awe_voice.h b/include/linux/awe_voice.h index aa131313141b..95fc207da025 100644 --- a/include/linux/awe_voice.h +++ b/include/linux/awe_voice.h @@ -2,10 +2,10 @@ * sound/awe_voice.h * * Voice information definitions for the low level driver for the - * AWE32/Sound Blaster 32 wave table synth. - * version 0.4.2c; Oct. 7, 1997 + * AWE32/SB32/AWE64 wave table synth. + * version 0.4.3; Mar. 1, 1998 * - * Copyright (C) 1996,1997 Takashi Iwai + * Copyright (C) 1996-1998 Takashi Iwai * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -55,6 +55,8 @@ typedef struct awe_patch_info { #define AWE_UNLOAD_PATCH 4 /* none */ #define AWE_REPLACE_DATA 5 /* awe_sample_info (optarg=#channels)*/ #define AWE_MAP_PRESET 6 /* awe_voice_map */ +/*#define AWE_PROBE_INFO 7*/ /* awe_voice_map (pat only) */ +#define AWE_PROBE_DATA 8 /* optarg=sample */ #define AWE_LOAD_CHORUS_FX 0x10 /* awe_chorus_fx_rec (optarg=mode) */ #define AWE_LOAD_REVERB_FX 0x11 /* awe_reverb_fx_rec (optarg=mode) */ @@ -88,6 +90,7 @@ typedef struct _awe_open_parm { #define AWE_PAT_TYPE_MAP 7 #define AWE_PAT_LOCKED 0x100 /* lock the samples */ +#define AWE_PAT_SHARED 0x200 /* sample is shared */ short reserved; char name[AWE_PATCH_NAME_LEN]; @@ -126,6 +129,30 @@ typedef struct _awe_voice_parm { unsigned short reserved[4]; /* not used */ } awe_voice_parm; +typedef struct _awe_voice_parm_block { + unsigned short moddelay; /* modulation delay (0x8000) */ + unsigned char modatk, modhld; + unsigned char moddcy, modsus; + unsigned short modrel, moddummy; + short modkeyhold, modkeydecay; /* envelope change per key (not used) */ + unsigned short voldelay; /* volume delay (0x8000) */ + unsigned char volatk, volhld; + unsigned char voldcy, volsus; + unsigned char volrel, voldummy; + short volkeyhold, volkeydecay; /* envelope change per key (not used) */ + unsigned short lfo1delay; /* LFO1 delay (0x8000) */ + unsigned short lfo2delay; /* LFO2 delay (0x8000) */ + unsigned char env1fc, env1pit; + unsigned char lfo1fc, lfo1pit; + unsigned char lfo1freq, lfo1vol; + unsigned char lfo2freq, lfo2pit; + 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_block; + #define AWE_VOICE_PARM_SIZE 48 @@ -419,7 +446,7 @@ enum { /* 0*/ AWE_MD_EXCLUSIVE_OFF, /* obsolete */ /* 1*/ AWE_MD_EXCLUSIVE_ON, /* obsolete */ /* 2*/ AWE_MD_VERSION, /* read only */ -/* 3*/ AWE_MD_EXCLUSIVE_SOUND, /* ignored */ +/* 3*/ AWE_MD_EXCLUSIVE_SOUND, /* 0/1: exclusive note on (default=1) */ /* 4*/ AWE_MD_REALTIME_PAN, /* 0/1: do realtime pan change (default=1) */ /* 5*/ AWE_MD_GUS_BANK, /* bank number for GUS patches (default=0) */ /* 6*/ AWE_MD_KEEP_EFFECT, /* 0/1: keep effect values, (default=0) */ @@ -430,6 +457,13 @@ enum { /*11*/ AWE_MD_DEF_BANK, /* integer: default bank number (def=0) */ /*12*/ AWE_MD_DEF_DRUM, /* integer: default drumset number (def=0) */ /*13*/ AWE_MD_TOGGLE_DRUM_BANK, /* 0/1: toggle drum flag with bank# (def=0) */ +/*14*/ AWE_MD_NEW_VOLUME_CALC, /* 0/1: volume calculation mode (def=1) */ +/*15*/ AWE_MD_CHORUS_MODE, /* integer: chorus mode (def=2) */ +/*16*/ AWE_MD_REVERB_MODE, /* integer: chorus mode (def=4) */ +/*17*/ AWE_MD_BASS_LEVEL, /* integer: bass level (def=5) */ +/*18*/ AWE_MD_TREBLE_LEVEL, /* integer: treble level (def=9) */ +/*19*/ AWE_MD_DEBUG_MODE, /* integer: debug level (def=0) */ +/*20*/ AWE_MD_PAN_EXCHANGE, /* 0/1: exchange panning direction (def=0) */ AWE_MD_END, }; diff --git a/include/linux/fs.h b/include/linux/fs.h index 3a5adf06e51f..686044e24794 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -776,6 +776,7 @@ extern int get_write_access(struct inode *inode); extern void put_write_access(struct inode *inode); extern struct dentry * open_namei(const char * pathname, int flag, int mode); extern struct dentry * do_mknod(const char * filename, int mode, dev_t dev); +extern int VFS_rmdir(struct inode *dir, struct dentry *dentry); extern int do_pipe(int *); /* fs/dcache.c -- generic fs support functions */ diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index 31bab91a4104..30d8b8f0a314 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -65,6 +65,7 @@ #define ARPHRD_HIPPI 780 /* High Performance Parallel Interface */ #define ARPHRD_ASH 781 /* Nexus 64Mbps Ash */ #define ARPHRD_ECONET 782 /* Acorn Econet */ +#define ARPHRD_IRDA 783 /* Linux/IR */ /* ARP protocol opcodes. */ #define ARPOP_REQUEST 1 /* ARP request */ diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 68213c539098..3fae9a9def44 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -73,6 +73,8 @@ #define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/ #define ETH_P_TR_802_2 0x0011 /* 802.2 frames */ #define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */ +#define ETH_P_CONTROL 0x0016 /* Card specific control frames */ +#define ETH_P_IRDA 0x0017 /* Linux/IR */ /* * This is an Ethernet frame header. diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 925e70d20cc0..308ad56167eb 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -43,7 +43,8 @@ enum { CYCLADES_BH, CM206_BH, JS_BH, - MACSERIAL_BH + MACSERIAL_BH, + ISICOM_BH }; #include diff --git a/include/linux/isicom.h b/include/linux/isicom.h new file mode 100644 index 000000000000..e61aa08388fd --- /dev/null +++ b/include/linux/isicom.h @@ -0,0 +1,301 @@ +#ifndef _LINUX_ISICOM_H +#define _LINUX_ISICOM_H + +/*#define ISICOM_DEBUG*/ +/*#define ISICOM_DEBUG_DTR_RTS*/ + + +/* + * Firmware Loader definitions ... + */ + +#define __MultiTech ('M'<<8) +#define MIOCTL_LOAD_FIRMWARE (__MultiTech | 0x01) +#define MIOCTL_READ_FIRMWARE (__MultiTech | 0x02) +#define MIOCTL_XFER_CTRL (__MultiTech | 0x03) +#define MIOCTL_RESET_CARD (__MultiTech | 0x04) + +#define DATA_SIZE 16 + +typedef struct { + unsigned short exec_segment; + unsigned short exec_addr; +} exec_record; + +typedef struct { + int board; /* Board to load */ + unsigned short addr; + unsigned short count; +} bin_header; + +typedef struct { + int board; /* Board to load */ + unsigned short addr; + unsigned short count; + unsigned short segment; + unsigned char bin_data[DATA_SIZE]; +} bin_frame; + +#ifdef __KERNEL__ + +#define YES 1 +#define NO 0 + +#define ISILOAD_MISC_MINOR 155 /* /dev/isctl */ +#define ISILOAD_NAME "ISILoad" + +/* + * ISICOM Driver definitions ... + * + */ + +#define ISICOM_NAME "ISICom" + +/* + * These are now officially allocated numbers + */ + +#define ISICOM_NMAJOR 112 /* normal */ +#define ISICOM_CMAJOR 113 /* callout */ +#define ISICOM_MAGIC (('M' << 8) | 'T') + +#define WAKEUP_CHARS 256 /* hard coded for now */ +#define TX_SIZE 254 + +#define BOARD_COUNT 4 +#define PORT_COUNT (BOARD_COUNT*16) + +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 + +/* character sizes */ + +#define ISICOM_CS5 0x0000 +#define ISICOM_CS6 0x0001 +#define ISICOM_CS7 0x0002 +#define ISICOM_CS8 0x0003 + +/* stop bits */ + +#define ISICOM_1SB 0x0000 +#define ISICOM_2SB 0x0004 + +/* parity */ + +#define ISICOM_NOPAR 0x0000 +#define ISICOM_ODPAR 0x0008 +#define ISICOM_EVPAR 0x0018 + +/* flow control */ + +#define ISICOM_CTSRTS 0x03 +#define ISICOM_INITIATE_XONXOFF 0x04 +#define ISICOM_RESPOND_XONXOFF 0x08 + +#define InterruptTheCard(base) (outw(0,(base)+0xc)) +#define ClearInterrupt(base) (inw((base)+0x0a)) + +#define BOARD(line) (((line) >> 4) & 0x3) +#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) + + /* isi kill queue bitmap */ + +#define ISICOM_KILLTX 0x01 +#define ISICOM_KILLRX 0x02 + + /* isi_board status bitmap */ + +#define FIRMWARE_LOADED 0x0001 +#define BOARD_ACTIVE 0x0002 + + /* isi_port status bitmap */ + +#define ISI_CTS 0x1000 +#define ISI_DSR 0x2000 +#define ISI_RI 0x4000 +#define ISI_DCD 0x8000 +#define ISI_DTR 0x0100 +#define ISI_RTS 0x0200 + + +#define ISI_TXOK 0x0001 + +struct isi_board { + unsigned short base; + unsigned char irq; + unsigned char port_count; + unsigned short status; + unsigned short port_status; /* each bit represents a single port */ + unsigned short shift_count; + struct isi_port * ports; + signed char count; +}; + +struct isi_port { + unsigned short magic; + unsigned int flags; + int count; + int blocked_open; + int close_delay; + unsigned short channel; + unsigned short status; + unsigned short closing_wait; + long session; + long pgrp; + struct isi_board * card; + struct tty_struct * tty; + struct wait_queue * close_wait; + struct wait_queue * open_wait; + struct tq_struct hangup_tq; + struct tq_struct bh_tqueue; + unsigned char * xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + struct termios normal_termios; + struct termios callout_termios; +}; + + +/* + * ISI Card specific ops ... + */ + +extern inline void raise_dtr(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + short wait=300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + printk(KERN_WARNING "ISICOM: Card found busy in raise_dtr.\n"); + return; + } +#ifdef ISICOM_DEBUG_DTR_RTS + printk(KERN_DEBUG "ISICOM: raise_dtr.\n"); +#endif + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0504, base); + InterruptTheCard(base); + port->status |= ISI_DTR; +} + +extern inline void drop_dtr(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + short wait=300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + printk(KERN_WARNING "ISICOM: Card found busy in drop_dtr.\n"); + return; + } +#ifdef ISICOM_DEBUG_DTR_RTS + printk(KERN_DEBUG "ISICOM: drop_dtr.\n"); +#endif + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0404, base); + InterruptTheCard(base); + port->status &= ~ISI_DTR; +} +extern inline void raise_rts(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + short wait=300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + printk(KERN_WARNING "ISICOM: Card found busy in raise_rts.\n"); + return; + } +#ifdef ISICOM_DEBUG_DTR_RTS + printk(KERN_DEBUG "ISICOM: raise_rts.\n"); +#endif + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0a04, base); + InterruptTheCard(base); + port->status |= ISI_RTS; +} +extern inline void drop_rts(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + short wait=300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + printk(KERN_WARNING "ISICOM: Card found busy in drop_rts.\n"); + return; + } +#ifdef ISICOM_DEBUG_DTR_RTS + printk(KERN_DEBUG "ISICOM: drop_rts.\n"); +#endif + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0804, base); + InterruptTheCard(base); + port->status &= ~ISI_RTS; +} +extern inline void raise_dtr_rts(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + short wait=300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + printk(KERN_WARNING "ISICOM: Card found busy in raise_dtr_rts.\n"); + return; + } +#ifdef ISICOM_DEBUG_DTR_RTS + printk(KERN_DEBUG "ISICOM: raise_dtr_rts.\n"); +#endif + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0f04, base); + InterruptTheCard(base); + port->status |= (ISI_DTR | ISI_RTS); +} +extern inline void drop_dtr_rts(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + short wait=300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + printk(KERN_WARNING "ISICOM: Card found busy in drop_dtr_rts.\n"); + return; + } +#ifdef ISICOM_DEBUG_DTR_RTS + printk(KERN_DEBUG "ISICOM: drop_dtr_rts.\n"); +#endif + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0c04, base); + InterruptTheCard(base); + port->status &= ~(ISI_RTS | ISI_DTR); +} + +extern inline void kill_queue(struct isi_port * port, short queue) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + short wait=300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + printk(KERN_WARNING "ISICOM: Card found busy in kill_queue.\n"); + return; + } +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: kill_queue 0x%x.\n", queue); +#endif + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw((queue << 8) | 0x06, base); + InterruptTheCard(base); +} + +#endif /* __KERNEL__ */ + +#endif /* ISICOM_H */ \ No newline at end of file diff --git a/include/linux/socket.h b/include/linux/socket.h index de7a1dbe3d12..ef3963ba3e6c 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -166,6 +166,7 @@ struct ucred { #define AF_ECONET 19 /* Acorn Econet */ #define AF_ATMSVC 20 /* ATM SVCs */ #define AF_SNA 22 /* Linux SNA Project (nutters!) */ +#define AF_IRDA 23 /* IRDA sockets */ #define AF_MAX 32 /* For now.. */ /* Protocol families, same as address families. */ @@ -193,6 +194,7 @@ struct ucred { #define PF_ECONET AF_ECONET #define PF_ATMSVC AF_ATMSVC #define PF_SNA AF_SNA +#define PF_IRDA AF_IRDA #define PF_MAX AF_MAX @@ -206,6 +208,7 @@ struct ucred { #define MSG_OOB 1 #define MSG_PEEK 2 #define MSG_DONTROUTE 4 +#define MSG_TRYHARD 4 /* Synonym for MSG_DONTROUTE for DECnet */ #define MSG_CTRUNC 8 #define MSG_PROXY 0x10 /* Supply or ask second address. */ #define MSG_TRUNC 0x20 diff --git a/include/linux/videodev.h b/include/linux/videodev.h index 7fe9f2d84de2..ce043b96cf68 100644 --- a/include/linux/videodev.h +++ b/include/linux/videodev.h @@ -136,9 +136,9 @@ struct video_audio char name[16]; #define VIDEO_SOUND_MONO 1 #define VIDEO_SOUND_STEREO 2 -#define VIDEO_SOUND_LANG1 3 -#define VIDEO_SOUND_LANG2 4 - __u16 mode; +#define VIDEO_SOUND_LANG1 4 +#define VIDEO_SOUND_LANG2 8 + __u16 mode; /* detected audio carriers or one to set */ __u16 balance; /* Stereo balance */ __u16 step; /* Step actual volume uses */ }; diff --git a/kernel/ksyms.c b/kernel/ksyms.c index d567240e6ac6..b249985cb566 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -172,6 +172,7 @@ EXPORT_SYMBOL(shrink_dcache_parent); EXPORT_SYMBOL(find_inode_number); EXPORT_SYMBOL(is_subdir); EXPORT_SYMBOL(get_unused_fd); +EXPORT_SYMBOL(VFS_rmdir); #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE) EXPORT_SYMBOL(do_nfsservctl); diff --git a/mm/filemap.c b/mm/filemap.c index 227bcd5a9ce7..b48cde1052e4 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -198,10 +198,9 @@ int shrink_mmap(int priority, int gfp_mask) static unsigned long clock = 0; unsigned long limit = num_physpages; struct page * page; - int count_max, count_min; + int count; - count_max = limit; - count_min = (limit<<2) >> (priority); + count = (limit<<1) >> (priority); page = mem_map + clock; do { @@ -213,24 +212,13 @@ int shrink_mmap(int priority, int gfp_mask) if (shrink_one_page(page, gfp_mask)) return 1; - count_max--; - /* - * If the page we looked at was recyclable but we didn't - * reclaim it (presumably due to PG_referenced), don't - * count it as scanned. This way, the more referenced - * page cache pages we encounter, the more rapidly we - * will age them. - */ - if (atomic_read(&page->count) != 1 || - (!page->inode && !page->buffers)) - count_min--; page++; clock++; if (clock >= max_mapnr) { clock = 0; page = mem_map; } - } while (count_max > 0 && count_min > 0); + } while (--count >= 0); return 0; } diff --git a/mm/vmscan.c b/mm/vmscan.c index c5efa52a2050..f053210e5a9d 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -424,35 +424,21 @@ out: */ static int do_try_to_free_page(int gfp_mask) { - static int state = 0; int i=6; /* Always trim SLAB caches when memory gets low. */ kmem_cache_reap(gfp_mask); - if (buffer_over_borrow() || pgcache_over_borrow()) - state = 0; - - switch (state) { - do { - case 0: - if (shrink_mmap(i, gfp_mask)) - return 1; - state = 1; - case 1: - if (shm_swap(i, gfp_mask)) - return 1; - state = 2; - case 2: - if (swap_out(i, gfp_mask)) - return 1; - state = 3; - case 3: - shrink_dcache_memory(i, gfp_mask); - state = 0; + do { + if (shrink_mmap(i, gfp_mask)) + return 1; + if (shm_swap(i, gfp_mask)) + return 1; + if (swap_out(i, gfp_mask)) + return 1; + shrink_dcache_memory(i, gfp_mask); i--; - } while (i >= 0); - } + } while (i >= 0); return 0; } diff --git a/net/802/tr.c b/net/802/tr.c index f708fe881508..a8f77970efb0 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -154,10 +154,12 @@ int tr_rebuild_header(struct sk_buff *skb) return 0; } +#ifdef CONFIG_INET if(arp_find(trh->daddr, skb)) { return 1; } else +#endif { tr_source_route(skb,trh,dev); return 0; -- 2.39.5