diff -u --recursive --new-file v2.1.93/linux/CREDITS linux/CREDITS --- v2.1.93/linux/CREDITS Wed Apr 1 20:11:46 1998 +++ linux/CREDITS Wed Apr 8 17:31:27 1998 @@ -895,6 +895,10 @@ E: rfkoenig@immd4.informatik.uni-erlangen.de D: The Linux Support Team Erlangen +N: Andreas Koensgen +E: ajk@iehk.rwth-aachen.de +D: 6pack driver for AX.25 + N: Andi Kleen E: ak@muc.de D: network hacker, syncookies @@ -1254,6 +1258,14 @@ S: FIN-00330 Helsingfors S: Finland +N: Matija Nalis +E: mnalis@jagor.srce.hr +E: mnalis@voyager.hr +D: Maintainer of the Umsdos file system +S: Listopadska 7 +S: 10000 Zagreb +S: Croatia + N: Jonathan Naylor E: g4klx@g4klx.demon.co.uk E: g4klx@amsat.org @@ -1407,7 +1419,7 @@ N: Joerg Reuter E: jreuter@poboxes.com -W: http://www.rat.de/jr/ +W: http://poboxes.com/jreuter/ W: http://qsl.net/dl1bke/ D: Generic Z8530 driver, AX.25 DAMA slave implementation D: Several AX.25 hacks @@ -1865,6 +1877,14 @@ S: Hernesaarenkatu 15 A 2 S: Fin-00150 Helsinki S: Finland + +N: Jonathan Woithe +E: jwoithe@physics.adelaide.edu.au +W: http://www.physics.adelaide.edu.au/~jwoithe +D: ALS-007 soundcard extensions to Sound Blaster driver +S: 4/36 Trevelyan St +S: Wayville SA 5034 +S: Australia N: Roger E. Wolff E: R.E.Wolff@BitWizard.nl diff -u --recursive --new-file v2.1.93/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.93/linux/Documentation/Configure.help Mon Apr 6 17:40:59 1998 +++ linux/Documentation/Configure.help Wed Apr 8 17:31:27 1998 @@ -1089,7 +1089,7 @@ want to say Y here. Information about ELF is on the WWW at http://www.sjc.ox.ac.uk/users/barlow/elf-howto.html (To browse the WWW, you need to have access to a machine on the Internet that has a - programs like lynx or netscape). If you find that after upgrading + program like lynx or netscape). If you find that after upgrading from Linux kernel 1.2 and saying Y here, you still can't run any ELF binaries (they just crash), then you'll have to install the newest ELF runtime libraries, including ld.so (check the file @@ -1208,7 +1208,7 @@ the line "SMP=1" is not commented out and read Documentation/smp and Documentation/IO-APIC.txt and the SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ (to browse the WWW, you - need to have access to a machine on the Internet that has a programs + need to have access to a machine on the Internet that has a program like lynx or netscape). People using multiprocessor machines should also say Y to "Enhanced Real Time Clock Support", below. If you want to compile a kernel that should work on both single @@ -1243,7 +1243,7 @@ extensive information about drivers for many devices attaching to the parallel port see http://www.torque.net/linux-pp.html on the WWW (To browse the WWW, you need to have access to a machine on the - Internet that has a programs like lynx or netscape). It is possible + Internet that has a program like lynx or netscape). It is possible to share a single parallel port among several devices and it is safe to compile all the corresponding drivers into the kernel. If you want to compile parallel port support as a module ( = code which can @@ -1295,72 +1295,6 @@ themselves when requested. Say Y to enable this feature, or M to compile it as a module (parport_ieee1284.o). If in doubt, say N. -Plug and Play subsystem (EXPERIMENTAL) -CONFIG_PNP_DRV - This enables support for the new Plug-and-Play (or PnP) Linux - subsystems. This support is required for PnP ISA support, and for PnP - Legacy support. User-mode utilities for this support may be found at - http://www.lpsg.demon.co.uk/pnp-linux.html. - -PnP resource management -CONFIG_KERNEL_PNP_RESOURCE - This option will cause the new PnP generic resource management - routines to be used instead of the old routines request_xxx and - free_xxx. Emulation routines are put in place to support the old - calling style. This code support masks for IO decoding (required for - Plug and Play devices). There is no need to enable this option unless - you want to - these features will still be used where they are needed. - However, enabling it will reduce your kernel size slightly, and also - allow you to test this code more extensively. - -Support for boot-loaded PnP configuration (RECOMMENDED) -CONFIG_PNP_BLDCONFIG - This will enable support for preloading data about the configuration - of any Plug-and-Play devices in the system into the kernel at boot - time, which means that any devices required at boot can be configured - at this time manually. Say Y unless you have a reason not to. - -PnP ISA support -CONFIG_PNP_ISA - This option is required to allow the Linux PnP subsystem to handle - Plug and Play ISA devices. This includes full support for PnP ISA, - including the I/O range check feature. - -PnP ISA backwards-compatibility support -CONFIG_PNP_ISA_COMPAT - This option will enable partial backwards compatibility with drivers - written using older versions (up to the last 0.2.x) of the PnP driver - written by Tom Lees . - -PnP Legacy device support -CONFIG_PNP_LEGACY - Before PnP ISA was standardized, several "jumperless", or - "soft-configurable" boards were finding their way onto the market. - These cards used somewhat proprietary mechanisms for configuring - IRQs, DMAs, IO addresses, and memory ranges. These devices (mainly - network cards, but also some sound cards) can be configured as any - other PnP device can by saying Y here, if appropriate drivers - for these devices are available. - -PnP sysctl support (RECOMMENDED) -CONFIG_PNP_SYSCTL - This option enables support for the user-mode interface to the - kernel-mode PnP systems. It requires that you said Y to "Sysctl - support" above. The only reason you might want to switch this off - is if you aren't going to use user-mode utilities to configure PnP, - and you want to save a couple of kilobytes of kernel space. Answer Y - unless you know what you are doing. User-mode utilities and a - library for accessing this interface may be found at - http://www.lpsg.demon.co.uk/pnp-linux.html. - -PnP auto-configures all devices on startup -CONFIG_PNP_BOOTINIT - This option will allow the PnP subsystem to automatically configure - all the PnP devices it finds upon system startup (or at least - attempt to). This is useful if you have older drivers which do not use - the Linux-PnP system to configure PnP devices, and which you need - to be configured by PnP before you can use them. - Enable loadable module support CONFIG_MODULES Kernel modules are small pieces of compiled code which can be @@ -3560,6 +3494,14 @@ whenever you want), say M here and read Documentation/modules.txt. The module will be called mkiss.o. +Serial port 6PACK driver for AX.25 +CONFIG_6PACK +6pack is a protocol that attaches a TNC connected to a serial interface +to be used as a network device. 6pack can be used as an alternative to KISS, +but has some extended functionality. Note that this driver is still +experimental and might cause problems. For details about the features +and the usage of the driver, read Documentation/networking/6pack.txt. + PLIP (parallel port) support CONFIG_PLIP PLIP (Parallel Line Internet Protocol) is used to create a @@ -6700,7 +6642,7 @@ fashion. (They should also Documentation/smp and Documentation/IO-APIC.txt and the SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ (to browse the WWW, you - need to have access to a machine on the Internet that has a programs + need to have access to a machine on the Internet that has a program like lynx or netscape)). If you think you have a use for such a device (such as periodic data sampling), then say Y here, and go read the file @@ -6801,6 +6743,16 @@ why they still haven't released any documentation. [http://204.200.238.31/cgi-bin/link.pl?co=i&cl=/ts/ibm/contact.html] +Are you using the IBM Mwave "emulation" of SB ? +CONFIG_SB_MWAVE + The IBM Mwave can do whats loosely describable as emulation of an 8bit + soundblaster if you load the right firmware from DOS warm boot and pray + and your machine happens to like you. Say Y if you are doing this as the + IRQ test normally fails on the mwave emulation. If you'd like real MWAVE + support phone IBM (425-556-8822) and ask them why they still haven't + released any documentation. + [http://204.200.238.31/cgi-bin/link.pl?co=i&cl=/ts/ibm/contact.html] + Generic OPL2/OPL3 FM synthesizer support CONFIG_ADLIB Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). @@ -6898,6 +6850,15 @@ manufacturers such as Turtle Beach (Tropez), Reveal (some models) and Diamond (latest ones). +Support MIDI in older MAD16 based cards (requires SB) +CONFIG_MAD16_OLDCARD + Answer Y (or M) if you have an older card based on the C928 + or Mozart chipset and you want to have MIDI support. If you + enable this option you also need to enable support for SoundBlaster. + + If you answer Y here you will + also need to enable the SoundBlaster driver. + Support for Crystal CS4232 based (PnP) cards CONFIG_CS4232 Say Y here if you have a card based on the Crystal CS4232 chip set, @@ -7854,6 +7815,11 @@ inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. + +SAA5249 Teletext processor +CONFIG_VIDEO_SAA5249 + Support for I2C bus based teletext using the SAA5249 chip. At the moment + this is only useful on some european WinTV cards. Quickcam BW Video For Linux CONFIG_VIDEO_BWQCAM diff -u --recursive --new-file v2.1.93/linux/Documentation/filesystems/umsdos.txt linux/Documentation/filesystems/umsdos.txt --- v2.1.93/linux/Documentation/filesystems/umsdos.txt Mon Jan 30 23:39:02 1995 +++ linux/Documentation/filesystems/umsdos.txt Wed Apr 8 11:39:45 1998 @@ -1,7 +1,13 @@ +Firstly, let me say that UMSDOS is going through some major code changes, +and has some KNOWN BUGS (and quite a few unknown :-). Please read +fs/umsdos/README-WIP.txt for more information on current status. Thanks. + +---------------------------------------------------------------------------- Very short explanation for the impatient!!! Umsdos is a file system driver that run on top the MSDOS fs driver. It is written by Jacques Gelinas (jacques@solucorp.qc.ca) +and is currently maintained by Matija Nalis (mnalis@jagor.srce.hr) Umsdos is not a file system per se, but a twist to make a boring one into a useful one. diff -u --recursive --new-file v2.1.93/linux/Documentation/joystick.txt linux/Documentation/joystick.txt --- v2.1.93/linux/Documentation/joystick.txt Sat Nov 29 10:33:18 1997 +++ linux/Documentation/joystick.txt Wed Apr 8 15:31:03 1998 @@ -41,7 +41,13 @@ select `M' for this driver in the kernel configuration and insert the module: -insmod js.o js=0xXX,0xYY +insmod joystick.o js=0xXX,0xYY + + To enable autoloading/-unloading of the joystick module, you have to add +these lines to /etc/conf.modules: + +alias char-major-15 joystick +options joystick js=0xXX,0xYY To enable the user space programs to read the joystick device, you have to create the device files using mknod (man mknod for more info): diff -u --recursive --new-file v2.1.93/linux/Documentation/networking/6pack.txt linux/Documentation/networking/6pack.txt --- v2.1.93/linux/Documentation/networking/6pack.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/6pack.txt Wed Apr 8 17:31:27 1998 @@ -0,0 +1,175 @@ +This is the 6pack-mini-HOWTO, written by + +Andreas Könsgen DG3KQ +Internet: ajk@iehk.rwth-aachen.de +AMPR-net: dg3kq@db0pra.ampr.org +AX.25: dg3kq@db0ach.#nrw.deu.eu + +Last update: April 7, 1998 + +1. What is 6pack, and what are the advantages to KISS? + +6pack is a transmission protocol for the data exchange between the PC and +the TNC over a serial line. It can be used as an alternative to KISS. + +6pack has two major advantages: +- The PC is given the full control over the radio + channel. Special control data is exchanged between the PC and the TNC so + that the PC knows at any time if the TNC is receiving data, if an TNC + buffer underrun or overrun has occured, if the PTT is + set and so on. This control data is processed at a higher priority than + normal data, so a data stream can be interrupted at any time to issue an + important event. This helps to improve the channel access and timing algorithms + as everything is computed in the PC. It would even be possible to experiment with + something completely different than the known CSMA and DAMA channel access + methods. + This kind of real-time control is especially important to supply several + TNCs that are connected between each other and the PC by a daisy chain + (however, this feature is not supported yet by the Linux 6pack driver). + +- Each packet transferred over the serial line is supplied with a checksum, + so it is easy to detect errors due to problems on the serial line. + Received packets that are corrupt are not passed on to the AX.25 layer. + Damaged packets that the TNC has received from the PC are not transmitted. + +More details about 6pack are described in the file 6pack.ps that is located +in the doc directory of the AX.25 utilities package. + +2. Who has developed the 6pack protocol? + +The 6pack protocol has been developed by Ekki Plicht DF4OR, Henning Rech +DF9IC and Gunter Jost DK7WJ. A driver for 6pack, written by Gunter Jost and +Matthias Welwarsky DG2FEF, comes along with the PC version of FlexNet. +They have also written a firmware for TNCs to perform the 6pack +protocol (see section 4 below). + +3. Where can I get the latest version of 6pack for LinuX? + +At the moment, the 6pack stuff can obtained via anonymous ftp from +db0bm.automation.fh-aachen.de. In the directory /incoming/dg3kq, +there is a file named 6pack.tgz. + +4. Preparing the TNC for 6pack operation + +To be able to use 6pack, a special firmware for the TNC is needed. The EPROM +of a newly bought TNC does not contain 6pack, so you will have to +program an EPROM yourself. The image file for 6pack EPROMs should be +available on any packet radio box where PC/FlexNet can be found. The name of +the file is 6pack.bin. This file is copyrighted and maintainend by the FlexNet +team. It can be used under the terms of the license that comes along +with PC/FlexNet. Please do not ask me about the internals of this file as I +don't know anything about it. I used a textual description of the 6pack +protocol to program the Linux driver. + +TNCs contain a 64kByte EPROM, the lower half of which is used for +TheFirmware/KISS. The upper half is either empty or is sometimes +programmed with a software called TAPR. In the latter case, the TNC +is supplied with a DIP switch so you can easily change between the +two systems. When programming a new EPROM, one of the systems is replaced +by 6pack. It is useful to replace TAPR, as this software is rarely used +nowadays. If your TNC is not equipped with the switch mentioned above, you +can build in one yourself that switches over the highest address pin +of the EPROM between HIGH and LOW level. After having inserted the new EPROM +and switched to 6pack, apply power to the TNC for a first test. The connect +and the status LED are lit for about a second if the firmware initialises +the TNC correctly. + +5. Building and installing the 6pack driver + +The driver has been tested with kernel version 2.1.90. Using with older +kernels may lead to a compilation error because the interface to a kernel +function has been changed in the 2.1.8x kernels. + +How to turn on 6pack support: + +- In the linux kernel configuration program, select the code maturity level + options menu and turn on the prompting for development drivers. + +- Select the amateur radio support menu and turn on the serial port 6pack + driver. + +- Compile and install the kernel and the modules. + +To use the driver, the kissattach program delivered with the AX.25 utilities +has to be modified. + +- Do a cd to the directory that keeps the kissattach sources. Edit the + kissattach.c file. At the top, insert the following lines: + + #ifndef N_6PACK + #define N_6PACK (N_AX25+1) + #endif + + Then find the line + + int disc = N_AX25; + + and replace N_AX25 by N_6PACK. + +- Recompile kissattach. Rename it to spattach to avoid confusions. + +Installing the driver: + +- Do an insmod 6pack. Look at your + /var/log/messages file to check if the module has printed its initialization message. + +- Do a spattach as you would launch kissattach when starting a KISS port. + Check if the kernel prints the message '6pack: TNC found'. + +- From here, everything should work as if you were setting up a KISS port. + The only difference is that the network device that represents + the 6pack port is called sp instead of sl or ax. So, sp0 would be the + first 6pack port. + +Although the driver has been tested on various platforms, I still declare it +ALPHA. BE CAREFUL! Sync your disks before insmoding the 6pack module +and spattaching. Watch out if your computer behaves strangely. Read section +6 of this file about known problems. + +Note that the connect and status LEDs of the TNC are controlled in a +different way than they are when the TNC is used with PC/FlexNet. When using +FlexNet, the connect LED is on if there is a connection; the status LED is +on if there is data in the buffer of the PC's AX.25 engine that has to be +transmitted. Under LinuX, the 6pack layer is beyond the AX.25 layer, +so the 6pack driver doesn't know anything about connects or data that +has not yet been transmitted. Therefore the LEDs are controlled +as they are in KISS mode: The connect LED is turned on if data is transferred +from the PC to the TNC over the serial line, the status LED if data is +sent to the PC. + +6. Known problems + +When testing the driver with 2.0.3x kernels and +operating with data rates on the radio channel of 9600 Baud or higher, +the driver may, on certain systems, sometimes print the message '6pack: +bad checksum', which is due to data loss if the other station sends two +or more subsequent packets. I have been told that this is due tu a problem +with the serial driver of 2.0.3x kernels. I don't know yet if the problem +still exists with 2.1.x kernels, as I have heard that the serial driver +code has been changed with 2.1.x. + +When shutting down the sp interface with ifconfig, the kernel crashes if +there is still an AX.25 connection left over which an IP connection was +running, even if that IP connection is already closed. The problem does not +occur when there is a bare AX.25 connection still running. I don't know if +this is a problem of the 6pack driver or something else in the kernel. + +The driver has been tested as a module, not yet as a kernel-builtin driver. + +The 6pack protocol supports daisy-chaining of TNCs in a token ring, which is +connected to one serial port of the PC. This feature is not implemented +and at least at the moment I won't be able to do it because I do not have +the opportunity to build a TNC daisy-chain and test it. + +Some of the comments in the source code are inaccurate. They are left from +the SLIP/KISS driver, from which the 6pack driver has been derived. +I haven't modified or removed them yet -- sorry! The code itself needs +some cleaning and optimizing. This will be done in a later release. + +If you encounter a bug or if you have a question or suggestion concerning the +driver, feel free to mail me, using the adresses given at the beginning of +this file. + +Have fun! + +Andreas diff -u --recursive --new-file v2.1.93/linux/Documentation/sound/AWE32 linux/Documentation/sound/AWE32 --- v2.1.93/linux/Documentation/sound/AWE32 Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sound/AWE32 Wed Apr 8 15:34:23 1998 @@ -0,0 +1,63 @@ +From: Nicola Bernardelli + + In order to load SB-AWE related drivers on recent kernels (tested +with 2.1.86 and 2.1.88) with modularized sound support these lines can +be issued (of course with the suitable values for the parameters) +after PNP setup: + +insmod sound.o +insmod uart401.o +insmod sb.o io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330 +insmod awe_wave.o + + Alternatively, in order to also have automatic load on demand +(not of the awe support, which would anyway most likely also require a +call to sfxload), these lines can be added to /etc/conf.modules, of +course with the suitable values for the parameters): + +alias char-major-14 sb +post-install sb modprobe "-k" "adlib_card" +options sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330 +options adlib_card io=0x388 # FM synthetiser + +and then these two commands can be issued: + +modprobe sb +insmod awe_wave + +------------------------------------------------------------------------------ + +After picking up the second approach, you may want to put these lines +on an ossfreeOn script: + + ----- +#!/bin/sh + +modprobe sb +insmod awe_wave + +# A call to 'aumix -L' (attention to what the home dir is at boot +# time, you may put a link /.aumixrc -> /home//.aumixrc) to +# restore mixer device levels and a call to 'sfxload ' may be added in a customized ossfreeSetup script: + +if [ -x /usr/local/sbin/ossfreeSetup ] ; then + /usr/local/sbin/ossfreeSetup +fi + ----- + +And these lines in an ossfreeOff script: + + ----- +#!/bin/sh + +# NOT set -e, maybe not all of them are currently loaded. + +rmmod awe_wave +rmmod adlib_card +rmmod opl3 +rmmod sb +rmmod uart401 +rmmod sound + ----- + diff -u --recursive --new-file v2.1.93/linux/Documentation/sound/MAD16 linux/Documentation/sound/MAD16 --- v2.1.93/linux/Documentation/sound/MAD16 Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sound/MAD16 Wed Apr 8 15:34:23 1998 @@ -0,0 +1,25 @@ +From: Shaw Carruthers + +I have been using mad16 sound for some time now with no problems, current +kernel 2.1.89 + +lsmod shows: + +mad16 5176 0 +sb 22044 0 [mad16] +uart401 5576 0 [mad16 sb] +ad1848 14176 1 [mad16] +sound 61928 0 [mad16 sb uart401 ad1848] + +.config has: + +CONFIG_SOUND=m +CONFIG_ADLIB=m +CONFIG_MAD16=m +CONFIG_YM3812=m + +modules.conf has: + +alias char-major-14 mad16 +options sb mad16=1 +options mad16 io=0x530 irq=7 dma=0 dma16=1 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0 diff -u --recursive --new-file v2.1.93/linux/Documentation/sound/Opti linux/Documentation/sound/Opti --- v2.1.93/linux/Documentation/sound/Opti Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sound/Opti Wed Apr 8 15:34:23 1998 @@ -0,0 +1,216 @@ +Support for the OPTi 82C931 chip +-------------------------------- +Note: parts of this README file apply also to other +cards that use the mad16 driver. + +Some items in this README file are based on features +added to the sound driver after Linux-2.1.91 was out. +By the time of writing this I do not know which official +kernel release will include these features. +Please do not report inconsistencies on older Linux +kernels. + +The OPTi 82C931 is supported in its non PnP mode. +Usually you do not need to set jumpers etc... The sound driver +will check the card status and if it is required it will +force the card into a mode in which it can be programmed. + +If you have another OS installed on your computer it is recommended +that Linux and the other OS use the same resources. + +Also, it is recommended that resources specified in /etc/conf.modules +and resources specified in /etc/isapnp.conf agree. + +Compiling the sound driver +-------------------------- +I highly recommend that you build a modularized sound driver. +This document does not cover sound-driver which is built in +the kernel. + +Sound card support should be enabled as a module (chose m). +Answer 'm' for these items: + Generic OPL2/OPL3 FM synthesizer support (CONFIG_ADLIB) + Microsoft Sound System support (CONFIG_MSS) + Support for OPTi MAD16 and/or Mozart based cards (CONFIG_MAD16) + FM synthesizer (YM3812/OPL-3) support (CONFIG_YM3812) + +The configuration menu may ask for addresses, irq lines or dma +channels. If the card is used as a module the module loading +options will override these values. + +For the OPTi 931 you can answer 'n' to: + Support MIDI in older MAD16 based cards (requires SB) (CONFIG_MAD16_OLDCARD) +If you do need MIDI support in a Mozart or C928 based card you +need to answer 'm' to the above question. In that case you will +also need to answer 'm' to: + '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' (CONFIG_SB) + +Go on and compile your kernel and modules. Install the modules. Run depmod -a. + +Using isapnptools +----------------- +In most systems with a PnP bios you do not need to use isapnp. The +initialization provided by the bios is sufficient for the driver +to pick up the card and continue initialization. + +If that fails, or if you have other PnP cards, you need to use isapnp +to initialize the card. +This was tested with isapnptools-1.11 but I recommend that you use +isapnptools-1.13 (or newer). Run pnpdump to dump the information +about your PnP cards. Then edit the resulting file and select +the options of your choice. This file is normally installed as +/etc/isapnp.conf. + +The driver had one limitation WRT io port resources. +IO3 base should be 0x0E0C. Isapnp allows other io ports but this +address is hard-coded into the driver. + +Using kmod and autoloading the sound driver +------------------------------------------- +Comment: as of linux-2.1.90 kmod is replacing kerneld. +The config file '/etc/conf.modules' is used as before. + +This is the sound part of my /etc/conf.modules file. +Following that I will explain each line. + +alias mixer0 mad16 +alias audio0 mad16 +alias midi0 mad16 +alias synth0 opl3 +options sb mad16=1 +options mad16 irq=10 dma=0 dma16=1 io=0x530 joystick=1 cdtype=0 +options opl3 io=0x388 +post-install mad16 /sbin/ad1848_mixer_reroute 14 8 15 3 16 6 + +Explain: + +alias mixer0 mad16 +alias audio0 mad16 +alias midi0 mad16 +alias synth0 opl3 + +When any sound device is opened the kernel requests auto-loading +of char-major-14. There is a built-in alias that translates this +request to loading the main sound module. The main sound module +contains only common code which is needed by all the sound drivers, +and the driver for /dev/sndstat. + +The sound module in it's turn will request loading of a sub-driver +for mixer, audio, midi or synthesizer device. The first 3 are +supported by the mad16 driver. The synth device is supported +by the opl3 driver. + +There is currently no way to autoload the sound device driver +if more than one card is installed. + +options sb mad16=1 + +This is left for historical reason. If you enable the +config option 'Support MIDI in older MAD16 based cards (requires SB)' +or if you use an older mad16 driver it will force loading of the +SoundBlaster driver. This option tells the SB driver not to look +for a SB card but to wait for the mad16 driver. + +options mad16 irq=10 dma=0 dma16=1 io=0x530 joystick=1 cdtype=0 +options opl3 io=0x388 + +post-install mad16 /sbin/ad1848_mixer_reroute 14 8 15 3 16 6 + +This sets resources and options for the mad16 and opl3 drivers. +I use 2 dma channels (only one is required) to enable full duplex. +joystick=1 enables the joystick port. cdtype=0 disables the cd port. +You can also set mpu_io and mpu_irq in the mad16 options for the +uart401 driver. + +This tells modprobe to run /sbin/ad1848_mixer_reroute after +mad16 is successfully loaded and initialized. The source +for ad1848_mixer_reroute is appended to the end of this readme +file. It is impossible for the sound driver to know the actual +connections to the mixer. The 3 inputs intended for cd, synth +and line-in are mapped to the generic inputs line1, line2 and +line3. This program reroutes these mixer channels to their +right names (note the right mapping depends on the actual sound +card that you use). +The numeric parameters mean: + 14=line1 8=cd - reroute line1 to the CD input. + 15=line2 3=synth - reroute line2 to the synthesizer input. + 16=line3 6=line - reroute line3 to the line input. +For reference on other input names look at the file +/usr/include/linux/soundcard.h. + +Using a joystick +----------------- +You must enable a joystick in the mad16 options. (also +in /etc/isapnp.conf if you use it). +Tested with regular analog joysticks. + +A CDROM drive connected to the sound card +----------------------------------------- +The 82C931 chip has support only for secondary ATAPI cdrom. +(cdtype=8). Loading the mad16 driver resets the C931 chip +and if a cdrom was already mounted it may cause a complete +system hang. Do not use the sound card if you have an alternative. +If you do use the sound card it is important that you load +the mad16 driver (use "modprobe mad16" to prevent auto-unloading) +before the cdrom is accessed the first time. + +Using the sound driver built-in the kernel may help here. but... +Most new systems have a PnP bios and also two IDE controllers. +The IDE controller on the sound card may be needed only on older +systems (which have only one IDE controller) but these systems +also do not have a PnP bios - requiring isapnptoosl and a modularized +driver. + +Known problems +-------------- +1. See the section on "A CDROM drive connected to the sound card". + +2. On my system the codec cannot capture companded sound samples. + (eg., recording from /dev/audio). When any companded capture is + requested I get a stereo-16 bit samples instead. Playback of + companded samples work well. Apparently this problem is not common + to all C931 based cards. I do not know how to identify cards that + have this problem. + +Source for ad1848_mixer_reroute.c +--------------------------------- +#include +#include +#include + +static char *mixer_names[SOUND_MIXER_NRDEVICES] = + SOUND_DEVICE_LABELS; + +int +main(int argc, char **argv) { + int val, from, to; + int i, fd; + + fd = open("/dev/mixer", O_RDWR); + if(fd < 0) { + perror("/dev/mixer"); + return 1; + } + + for(i = 2; i < argc; i += 2) { + from = atoi(argv[i-1]); + to = atoi(argv[i]); + + if(to == SOUND_MIXER_NONE) + fprintf(stderr, "%s: turning off mixer %s\n", + argv[0], mixer_names[to]); + else + fprintf(stderr, "%s: rerouting mixer %s to %s\n", + argv[0], mixer_names[from], mixer_names[to]); + + val = from << 8 | to; + + if(ioctl(fd, SOUND_MIXER_PRIVATE2, &val)) { + perror("AD1848 mixer reroute"); + return 1; + } + } + + return 0; +} + diff -u --recursive --new-file v2.1.93/linux/Documentation/sound/mwave linux/Documentation/sound/mwave --- v2.1.93/linux/Documentation/sound/mwave Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sound/mwave Wed Apr 8 15:34:23 1998 @@ -0,0 +1,192 @@ + How to try and survive an IBM Mwave under Linux SB drivers + + +* IBM refuse to provide documentation. If anyone can ever find out what + MWD50430.EXE actually does to load firmware then this comedy could go + away. + +* If you'd like to ask IBM why they don't release Mwave information. + phone IBM (425-556-8822) and ask them why they still haven't + released any documentation. + [http://204.200.238.31/cgi-bin/link.pl?co=i&cl=/ts/ibm/contact.html] + +---------------------------------------------------------------------------- + +OK, First thing - the IRQ problem IS a problem, whether the test is bypassed or +not. And it is NOT a linux problem - it is an MWAVE problem that is fixed with +the latest MWAVE patches. So, in other words, DON'T bypass the test for MWAVES!! + +My config is Win 95 on HDA1, swap on HDA2, RH 5 on HDA3. + +The steps, then: + + Boot to Linux. + Mount Win95 file system (assume mount mount = /dos95) + mkdir /dos95/linux + mkdir /dos95/linux/boot + mkdir /dos95/linux/boot/parms + + Copy the kernel, any initrd image, and loadlin to /dos95/linux/boot + + Reboot to win 95 + + Edit C:/msdos.sys and add/change the following: + + Logo=0 + BootGUI=0 + + [Note msdos.sys IS a text file but it needs to be 'unhidden' and make + read-writable before it can be eddited] + + Edit Config .sys to have multiple config menus. I have one for win95, and + five for linux. Like this: +------------ +[menu] +menuitem=W95, Windows 95 +menuitem=LINTP, Linux - ThinkPad +menuitem=LINTP3, Linux - ThinkPad Console +menuitem=LINDOC, Linux - Docked +menuitem=LINDOC3, Linux - Docked Console +menuitem=LIN1, Linux - Single User Mode +REM menudefault=W95,10 + +[W95] + +[LINTP] + +[LINDOC] + +[LINTP3] + +[LINDOC3] + +[LIN1] + +[COMMON] +FILES=30 +REM Please read README.TXT in C:\MWW subdirectory before changing the DOS= statement. +DOS=HIGH,UMB +DEVICE=C:\MWW\MANAGER\MWD50430.EXE +SHELL=c:\command.com /e:2048 +------------------- + +The important things are the SHELL and DEVICE statements + + Then change Autoexec.bat. Basically everything in there originally should be + done ONLY when Win95 is booted. Then you add new things specifically for + Linux. Mine is as follows + +--------------- +@ECHO OFF +if "%CONFIG%" == "W95" goto W95 + +REM +REM Linux stuff +REM +SET MWPATH=C:\MWW\DLL;C:\MWW\MWGAMES;C:\MWW\DSP +SET BLASTER=A220 I5 D1 +SET MWROOT=C:\MWW +SET LIBPATH=C:\MWW\DLL +SET PATH=C:\WINDOWS;C:\MWW\DLL; +CALL MWAVE START NOSHOW +c:\linux\boot\loadlin.exe @c:\linux\boot\parms\%CONFIG%.par + +:W95 +REM +REM Windows 95 stuff +REM +c:\toolkit\guard +SET MSINPUT=C:\MSINPUT +SET MWPATH=C:\MWW\DLL;C:\MWW\MWGAMES;C:\MWW\DSP +REM The following is used by DOS games to recognize Sound Blaster hardware. +REM If hardware settings are changed, please change this line as well. +REM See the Mwave README file for instructions. +SET BLASTER=A220 I5 D1 +SET MWROOT=C:\MWW +SET LIBPATH=C:\MWW\DLL +SET PATH=C:\WINDOWS;C:\WINDOWS\COMMAND;E:\ORAWIN95\BIN;f:\msdev\bin;e:\v30\bin.dbg;v:\devt\v30\bin;c:\JavaSDK\Bin;C:\MWW\DLL; +SET INCLUDE=f:\MSDEV\INCLUDE;F:\MSDEV\MFC\INCLUDE +SET LIB=F:\MSDEV\LIB;F:\MSDEV\MFC\LIB +win + +------------------------ + +Now build a file in c:\linux\boot\parms for each linux config that you have. + +For example, my LINDOC3 config is for a docked Thinkpad at runlevel 3 with no +initrd image, and has a parm file named LINDOC3.PAR in c:\linux\boot\parms: + +----------------------- +# LOADLIN @param_file image=other_image root=/dev/other +# +# Linux Console in docking station +# +c:\linux\boot\zImage.krn # first value must be the filename of the Linux-kernel +root=/dev/hda3 # the device which gets mounted as root FS +ro # Other kernel agruments go here +apm=off +doc=yes +3 +----------------------- + +the doc=yes parm is an environment variable that my init scripts use, it is not +a kernel argument. + +However, the apm=off parm IS a kernel argument!!!!!!! APM, at least in my setup, +causes the kernel to crash when loaded via loadlin (but NOT when loaded via +LILO). The APM stuff COULD be forced out of the kernel via the kernel compile +options. BUT I, instead, got hold of an unofficial patch to the APM drivers that +allows them to be dynamically deactivated via kernel arguments. Whatever you +chose to document, APM, it seems, MUST be off for setups like mine. + +Now check the C:\MWW\MWCONFIG.REF looks like this: + +---------------------- +[NativeDOS] +Default=SB1.5 +SBInputSource=CD +SYNTH=FM +QSound=OFF +Reverb=OFF +Chorus=OFF +ReverbDepth=5 +ChorusDepth=5 +SBInputVolume=5 +SBMainVolume=10 +SBWaveVolume=10 +SBSynthVolume=10 +WaveTableVolume=10 +AudioPowerDriver=ON + +[FastCFG] +Show=No +HideOption=Off +----------------------------- + +OR the Default= line COULD be + +Default=SBPRO + +Reboot to Win95 and choose Linux. When booted, use sndconfig to configure the +sound modules and VOILA - ThinkPad sound with Linux. + +Now the gottchas - You can either have CD sound OR Mixers but not both. Thats a +problem with the SB1.5(CD sound) or SBPRO(Mixers) settings. No-one knows why +this is! + +And, for some reason MPEG3 files, when played through mpg123, sound like they +are playing at 1/8th speed - not very useful!!!!!!!!!!!! If you have ANY insight +on why this second thing might be happening I would be grateful. + +=========================================================== + _/ _/_/_/_/ + _/_/ _/_/ _/ + _/ _/_/ _/_/_/_/ Martin John Bartlett + _/ _/ _/ _/ (martin@nitram.demon.co.uk) +_/ _/_/_/_/ + _/ +_/ _/ + _/_/ +=========================================================== + + diff -u --recursive --new-file v2.1.93/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.93/linux/MAINTAINERS Tue Mar 17 22:18:13 1998 +++ linux/MAINTAINERS Wed Apr 8 17:31:27 1998 @@ -76,6 +76,12 @@ L: linux-net@vger.rutgers.edu S: Maintained +6PACK NETWORK DRIVER FOR AX.25 +P: Andreas Koensgen +M: ajk@iehk.rwth-aachen.de +L: linux-hams@vger.rutgers.edu +S: Maintained + 8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.] P: Paul Gortmaker M gpg109@rsphy1.anu.edu.au @@ -157,7 +163,7 @@ DAMA SLAVE for AX.25 P: Joerg Reuter M: jreuter@poboxes.com -W: http://www.rat.de/jr/ +W: http://poboxes.com/jreuter/ W: http://qsl.net/dl1bke/ L: linux-hams@vger.rutgers.edu S: Maintained @@ -313,6 +319,7 @@ JOYSTICK DRIVER P: Vojtech Pavlik M: vojtech@atrey.karlin.mff.cuni.cz +L: linux-joystick@atrey.karlin.mff.cuni.cz S: Maintained KERNEL AUTOMOUNTER (AUTOFS) @@ -461,9 +468,9 @@ PNP SUPPORT P: Tom Lees M: tom@lpsg.demon.co.uk -L: pnp-list@lpsg.demon.co.uk -L: pnp-list@redhat.com (maybe) -W: http://www.lpsg.demon.co.uk/pnp-linux.html +L: pnp-users@ferret.lmh.ox.ac.uk +L: pnp-devel@ferret.lmh.ox.ac.uk +W: http://www-jcr.lmh.ox.ac.uk/~pnp/ S: Maintained PPP PROTOCOL DRIVERS AND COMPRESSORS @@ -516,7 +523,7 @@ SOUND P: Alan Cox -M: Alan Cox@linux.org +M: Alan.Cox@linux.org S: Maintained SPARC: @@ -613,7 +620,7 @@ Z8530 DRIVER FOR AX.25 P: Joerg Reuter M: jreuter@poboxes.com -W: http://www.rat.de/jr/ +W: http://poboxes.com/jreuter/ W: http://qsl.net/dl1bke/ L: linux-hams@vger.rutgers.edu S: Maintained diff -u --recursive --new-file v2.1.93/linux/Makefile linux/Makefile --- v2.1.93/linux/Makefile Mon Apr 6 17:40:59 1998 +++ linux/Makefile Mon Apr 6 17:41:27 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 93 +SUBLEVEL = 94 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) diff -u --recursive --new-file v2.1.93/linux/Rules.make linux/Rules.make --- v2.1.93/linux/Rules.make Tue Jan 13 11:47:55 1998 +++ linux/Rules.make Wed Apr 8 15:36:26 1998 @@ -176,9 +176,21 @@ MODINCL = $(TOPDIR)/include/linux/modules # The -w option (enable warnings) for genksyms will return here in 2.1 +# So where has it gone ??? +# +# Added the SMP seperator to stop module accidents between uniproc/smp +# intel boxes - AC - from bits by Michael Chastain +# + +ifdef SMP + genksyms_smp_prefix := -p smp_ +else + genksyms_smp_prefix := +endif + $(MODINCL)/%.ver: %.c $(CC) $(CFLAGS) -E -D__GENKSYMS__ $<\ - | $(GENKSYMS) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp + | $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp mv $@.tmp $@ $(addprefix $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver)): $(TOPDIR)/include/linux/autoconf.h diff -u --recursive --new-file v2.1.93/linux/arch/alpha/boot/bootp.c linux/arch/alpha/boot/bootp.c --- v2.1.93/linux/arch/alpha/boot/bootp.c Wed Apr 1 20:11:47 1998 +++ linux/arch/alpha/boot/bootp.c Tue Apr 7 07:52:04 1998 @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.1.93/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.1.93/linux/arch/alpha/config.in Wed Apr 1 20:11:47 1998 +++ linux/arch/alpha/config.in Tue Apr 7 08:05:05 1998 @@ -12,7 +12,6 @@ unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION -unset CONFIG_ALPHA_SRM CONFIG_ALPHA_SRM_SETUP mainmenu_option next_comment comment 'Code maturity level options' diff -u --recursive --new-file v2.1.93/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.1.93/linux/arch/alpha/kernel/alpha_ksyms.c Tue Mar 17 22:18:13 1998 +++ linux/arch/alpha/kernel/alpha_ksyms.c Tue Apr 7 08:05:05 1998 @@ -27,7 +27,6 @@ #define __KERNEL_SYSCALLS__ #include -extern void bcopy (const char *src, char *dst, int len); extern struct hwrpb_struct *hwrpb; extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); @@ -134,7 +133,6 @@ * interface isn't gonna change any time soon now, so it's OK * to leave it out of version control. */ -# undef bcopy # undef memcpy # undef memset EXPORT_SYMBOL_NOVERS(__divl); @@ -147,7 +145,3 @@ EXPORT_SYMBOL_NOVERS(__remqu); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); - -#if CONFIG_PCI -EXPORT_SYMBOL(pci_devices); -#endif diff -u --recursive --new-file v2.1.93/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c --- v2.1.93/linux/arch/alpha/kernel/bios32.c Mon Apr 6 17:40:59 1998 +++ linux/arch/alpha/kernel/bios32.c Tue Apr 7 08:05:05 1998 @@ -560,15 +560,13 @@ } -unsigned long pcibios_init(unsigned long mem_start, - unsigned long mem_end) +void __init +pcibios_init(void) { printk("Alpha PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV); - #if !PCI_MODIFY printk("...NOT modifying existing (SRM) PCI configuration\n"); #endif - return mem_start; } /* @@ -1951,20 +1949,20 @@ extern void tga_console_init(void); #endif /* CONFIG_TGA_CONSOLE */ -unsigned long __init -pcibios_fixup(unsigned long mem_start, unsigned long mem_end) +void __init +pcibios_fixup(void) { struct pci_bus *cur; #ifdef CONFIG_ALPHA_MCPCIA /* must do massive setup for multiple PCI busses here... */ DBG_DEVS(("pcibios_fixup: calling mcpcia_fixup()...\n")); - mem_start = mcpcia_fixup(mem_start, mem_end); + mcpcia_fixup(); #endif /* MCPCIA */ #ifdef CONFIG_ALPHA_TSUNAMI /* must do massive setup for multiple PCI busses here... */ - /* mem_start = tsunami_fixup(mem_start, mem_end); */ + /* tsunami_fixup(); */ #endif /* TSUNAMI */ #if PCI_MODIFY && !defined(CONFIG_ALPHA_RUFFIAN) @@ -2030,8 +2028,6 @@ tga_console_init(); #endif #endif - - return mem_start; } diff -u --recursive --new-file v2.1.93/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S --- v2.1.93/linux/arch/alpha/kernel/head.S Wed Apr 1 20:11:47 1998 +++ linux/arch/alpha/kernel/head.S Tue Apr 7 07:52:04 1998 @@ -8,7 +8,6 @@ */ #define __ASSEMBLY__ -#include #include #define halt call_pal PAL_halt diff -u --recursive --new-file v2.1.93/linux/arch/alpha/kernel/mcpcia.c linux/arch/alpha/kernel/mcpcia.c --- v2.1.93/linux/arch/alpha/kernel/mcpcia.c Mon Apr 6 17:40:59 1998 +++ linux/arch/alpha/kernel/mcpcia.c Tue Apr 7 08:05:05 1998 @@ -962,8 +962,7 @@ } } -unsigned long mcpcia_fixup(unsigned long memory_start, - unsigned long memory_end) +void mcpcia_fixup(void) { struct linux_hose_info *hose; @@ -974,7 +973,5 @@ for (hose = mcpcia_root; hose; hose = hose->next) { mcpcia_probe(hose, &memory_start); } - - return memory_start; } #endif /* CONFIG_ALPHA_MCPCIA */ diff -u --recursive --new-file v2.1.93/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.1.93/linux/arch/alpha/kernel/setup.c Wed Apr 1 20:11:47 1998 +++ linux/arch/alpha/kernel/setup.c Tue Apr 7 08:05:05 1998 @@ -395,7 +395,7 @@ "BogoMIPS\t\t: %lu.%02lu\n" "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n" - "platform string\t: %s\n" + "platform string\t\t: %s\n" #ifdef __SMP__ "%s" #endif diff -u --recursive --new-file v2.1.93/linux/arch/alpha/kernel/smc37c669.c linux/arch/alpha/kernel/smc37c669.c --- v2.1.93/linux/arch/alpha/kernel/smc37c669.c Mon Apr 6 17:40:59 1998 +++ linux/arch/alpha/kernel/smc37c669.c Tue Apr 7 08:05:05 1998 @@ -994,7 +994,7 @@ ** and standard ISA IRQs. ** */ -static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table __initdata; +static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table __initdata = 0; /* ** The following definition is for the default IRQ @@ -1020,7 +1020,7 @@ ** ISA DMA channels. ** */ -static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table __initdata; +static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table __initdata = 0; /* ** The following definition is the default DRQ diff -u --recursive --new-file v2.1.93/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.1.93/linux/arch/alpha/kernel/smp.c Wed Apr 1 20:11:47 1998 +++ linux/arch/alpha/kernel/smp.c Tue Apr 7 07:52:04 1998 @@ -1,3 +1,4 @@ +#include #include #include #include diff -u --recursive --new-file v2.1.93/linux/arch/alpha/lib/memcpy.c linux/arch/alpha/lib/memcpy.c --- v2.1.93/linux/arch/alpha/lib/memcpy.c Sun Oct 6 22:55:45 1996 +++ linux/arch/alpha/lib/memcpy.c Tue Apr 7 08:05:05 1998 @@ -104,7 +104,7 @@ DO_REST_ALIGNED(d,s,n); } -void * __memcpy(void * dest, const void *src, size_t n) +void * memcpy(void * dest, const void *src, size_t n) { if (!(((unsigned long) dest ^ (unsigned long) src) & 7)) { __memcpy_aligned((unsigned long) dest, (unsigned long) src, n); @@ -114,22 +114,5 @@ return dest; } -/* - * Broken compiler uses "bcopy" to do internal - * assignments. Silly OSF/1 BSDism. - */ -char * bcopy(const char * src, char * dest, size_t n) -{ - __memcpy(dest, src, n); - return dest; -} - -/* - * gcc-2.7.1 and newer generate calls to memset and memcpy. So we - * need to define that here: - */ -#ifdef __ELF__ - asm (".weak memcpy; memcpy = __memcpy"); -#else - asm (".weakext memcpy, __memcpy"); -#endif +/* For backward modules compatibility, define __memcpy. */ +asm("__memcpy = memcpy; .globl __memcpy"); diff -u --recursive --new-file v2.1.93/linux/arch/arm/config.in linux/arch/arm/config.in --- v2.1.93/linux/arch/arm/config.in Wed Apr 1 20:11:47 1998 +++ linux/arch/arm/config.in Wed Apr 8 15:42:59 1998 @@ -105,6 +105,17 @@ # fi # endmenu +# Conditionally compile in the Uniform CD-ROM driver +if [ "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_BLK_DEV_SR" = "y" ]; then + define_bool CONFIG_CDROM y +else + if [ "$CONFIG_BLK_DEV_IDECD" = "m" -o "$CONFIG_BLK_DEV_SR" = "m" ]; then + define_bool CONFIG_CDROM m + else + define_bool CONFIG_CDROM n + fi +fi + source fs/Config.in source fs/nls/Config.in diff -u --recursive --new-file v2.1.93/linux/arch/arm/defconfig linux/arch/arm/defconfig --- v2.1.93/linux/arch/arm/defconfig Wed Apr 1 20:11:47 1998 +++ linux/arch/arm/defconfig Wed Apr 8 15:42:59 1998 @@ -169,6 +169,7 @@ CONFIG_ETHER1=m CONFIG_ETHER3=m CONFIG_ETHERH=m +CONFIG_CDROM=y # # Filesystems diff -u --recursive --new-file v2.1.93/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c --- v2.1.93/linux/arch/arm/kernel/armksyms.c Tue Mar 17 22:18:13 1998 +++ linux/arch/arm/kernel/armksyms.c Wed Apr 8 15:42:59 1998 @@ -12,6 +12,7 @@ #include #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(struct pt_regs *, struct user_fp_struct *); @@ -76,6 +77,10 @@ /* processor dependencies */ EXPORT_SYMBOL(processor); + +/* irq */ +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); /* io */ EXPORT_SYMBOL(outswb); diff -u --recursive --new-file v2.1.93/linux/arch/arm/kernel/calls.S linux/arch/arm/kernel/calls.S --- v2.1.93/linux/arch/arm/kernel/calls.S Tue Jan 20 16:39:41 1998 +++ linux/arch/arm/kernel/calls.S Wed Apr 8 15:42:59 1998 @@ -5,7 +5,7 @@ */ #ifndef NR_SYSCALLS #define NR_syscalls 256 -#define NR_SYSCALLS 182 +#define NR_SYSCALLS 184 #else /* 0 */ .long SYMBOL_NAME(sys_setup) @@ -190,5 +190,7 @@ .long SYMBOL_NAME(sys_rt_sigsuspend_wrapper) /* 180 */ .long SYMBOL_NAME(sys_pread) .long SYMBOL_NAME(sys_pwrite) - .space (NR_syscalls - 182) * 4 + .long SYMBOL_NAME(sys_xstat) + .long SYMBOL_NAME(sys_xmknod) + .space (NR_syscalls - 184) * 4 #endif diff -u --recursive --new-file v2.1.93/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c --- v2.1.93/linux/arch/arm/kernel/irq.c Mon Feb 23 18:12:01 1998 +++ linux/arch/arm/kernel/irq.c Wed Apr 8 15:42:59 1998 @@ -98,7 +98,7 @@ if (!action) continue; p += sprintf(p, "%3d: %10u %s", - i, kstat.interrupts[i], action->name); + i, kstat.irqs[0][i], action->name); for (action = action->next; action; action = action->next) { p += sprintf(p, ", %s", action->name); } @@ -126,7 +126,7 @@ cpu = smp_processor_id(); irq_enter(cpu, irq); - kstat.interrupts[irq]++; + kstat.irqs[0][irq]++; /* Return with this interrupt masked if no action */ status = 0; diff -u --recursive --new-file v2.1.93/linux/arch/arm/mm/fault-armo.c linux/arch/arm/mm/fault-armo.c --- v2.1.93/linux/arch/arm/mm/fault-armo.c Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/mm/fault-armo.c Wed Apr 8 15:42:59 1998 @@ -27,6 +27,50 @@ #define FAULT_CODE_WRITE 0x02 #define FAULT_CODE_USER 0x01 +struct pgtable_cache_struct quicklists; + +void __bad_pte(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); + set_pmd(pmd, mk_pmd(BAD_PAGETABLE)); +} + +pgd_t *get_pgd_slow(void) +{ + pgd_t *pgd = (pgd_t *) kmalloc(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL); + pgd_t *init; + + if (pgd) { + init = pgd_offset(&init_mm, 0); + memzero (pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); + memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR); + } + return pgd; +} + +pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *) kmalloc (PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR); + set_pmd(pmd, mk_pmd(pte)); + return pte + offset; + } + set_pmd(pmd, mk_pmd(BAD_PAGETABLE)); + return NULL; + } + kfree (pte); + if (pmd_bad(*pmd)) { + __bad_pte(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret); static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs, diff -u --recursive --new-file v2.1.93/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c --- v2.1.93/linux/arch/arm/mm/fault-armv.c Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/mm/fault-armv.c Wed Apr 8 15:42:59 1998 @@ -25,6 +25,81 @@ #define FAULT_CODE_READ 0x02 #define FAULT_CODE_USER 0x01 +struct pgtable_cache_struct quicklists; + +void __bad_pte(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); + set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); +} + +void __bad_pte_kernel(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); + set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); +} + +pgd_t *get_pgd_slow(void) +{ + /* + * need to get a 16k page for level 1 + */ + pgd_t *pgd = (pgd_t *) __get_free_pages(GFP_KERNEL,2); + pgd_t *init; + + if (pgd) { + init = pgd_offset(&init_mm, 0); + memzero ((void *)pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); + memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR); + } + return pgd; +} + +pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *) get_small_page(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR); + set_pmd(pmd, mk_user_pmd(pte)); + return pte + offset; + } + set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); + return NULL; + } + free_small_page ((unsigned long) pte); + if (pmd_bad(*pmd)) { + __bad_pte(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + +pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *) get_small_page(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR); + set_pmd(pmd, mk_kernel_pmd(pte)); + return pte + offset; + } + set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); + return NULL; + } + free_small_page ((unsigned long) pte); + if (pmd_bad(*pmd)) { + __bad_pte_kernel(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret); static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs, diff -u --recursive --new-file v2.1.93/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c --- v2.1.93/linux/arch/arm/mm/init.c Tue Jan 20 16:39:42 1998 +++ linux/arch/arm/mm/init.c Wed Apr 8 15:42:59 1998 @@ -30,7 +30,6 @@ pgd_t swapper_pg_dir[PTRS_PER_PGD]; -const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; extern char _etext, _stext, _edata, __bss_start, _end; extern char __init_begin, __init_end; diff -u --recursive --new-file v2.1.93/linux/arch/i386/Makefile linux/arch/i386/Makefile --- v2.1.93/linux/arch/i386/Makefile Wed Apr 1 20:11:47 1998 +++ linux/arch/i386/Makefile Wed Apr 8 18:05:55 1998 @@ -58,9 +58,6 @@ DRIVERS := $(DRIVERS) arch/i386/math-emu/math.a endif -memsize: dummy - @echo "__kernel_offset__ = (0x1000-$(CONFIG_MAX_MEMSIZE))*1024*1024;" > arch/i386/.kernel_offset.lds - arch/i386/kernel: dummy $(MAKE) linuxsubdirs SUBDIRS=arch/i386/kernel @@ -69,31 +66,30 @@ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot -zImage: memsize vmlinux +zImage: vmlinux @$(MAKEBOOT) zImage -bzImage: memsize vmlinux +bzImage: vmlinux @$(MAKEBOOT) bzImage compressed: zImage -zlilo: memsize vmlinux +zlilo: vmlinux @$(MAKEBOOT) BOOTIMAGE=zImage zlilo -bzlilo: memsize vmlinux +bzlilo: vmlinux @$(MAKEBOOT) BOOTIMAGE=bzImage zlilo -zdisk: memsize vmlinux +zdisk: vmlinux @$(MAKEBOOT) BOOTIMAGE=zImage zdisk -bzdisk: memsize vmlinux +bzdisk: vmlinux @$(MAKEBOOT) BOOTIMAGE=bzImage zdisk -install: memsize vmlinux +install: vmlinux @$(MAKEBOOT) BOOTIMAGE=bzImage install archclean: - rm -f .kernel_offset.lds @$(MAKEBOOT) clean archdep: diff -u --recursive --new-file v2.1.93/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.1.93/linux/arch/i386/config.in Wed Apr 1 20:11:47 1998 +++ linux/arch/i386/config.in Wed Apr 8 16:05:45 1998 @@ -17,7 +17,6 @@ Pentium/K5/5x86/6x86 CONFIG_M586 \ PPro/K6/6x86MX CONFIG_M686" Pentium bool 'Math emulation' CONFIG_MATH_EMULATION -int ' Max physical memory in MB' CONFIG_MAX_MEMSIZE 1024 endmenu mainmenu_option next_comment diff -u --recursive --new-file v2.1.93/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c --- v2.1.93/linux/arch/i386/kernel/bios32.c Mon Apr 6 17:40:59 1998 +++ linux/arch/i386/kernel/bios32.c Tue Apr 7 07:37:46 1998 @@ -125,42 +125,7 @@ int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned char *value) { - int res; - - res = access_pci->read_config_byte(bus, device_fn, where, value); - -#ifdef __SMP__ -/* - * IOAPICs can take PCI IRQs directly, lets first check the mptable: - * - * This can go away once nobody probes the irq this way, - * but uses the PCI tables instead. - */ - if (where == PCI_INTERRUPT_LINE) { - int irq; - char pin; - - /* - * get the PCI IRQ INT _physical pin_ for this device - */ - access_pci->read_config_byte(bus, device_fn, - PCI_INTERRUPT_PIN, &pin); - /* - * subtle, PCI pins are numbered starting from 1 ... - */ - pin--; - - irq = IO_APIC_get_PCI_irq_vector (bus,PCI_SLOT(device_fn),pin); - if (irq != -1) - *value = (unsigned char) irq; - - printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n", - bus,PCI_SLOT(device_fn), pin, irq); - - } -#endif - - return res; + return access_pci->read_config_byte(bus, device_fn, where, value); } int pcibios_read_config_word (unsigned char bus, diff -u --recursive --new-file v2.1.93/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S --- v2.1.93/linux/arch/i386/kernel/head.S Wed Apr 1 20:11:47 1998 +++ linux/arch/i386/kernel/head.S Wed Apr 8 16:07:16 1998 @@ -619,9 +619,6 @@ .fill 256,8,0 # idt is uninitialized /* - * This gdt setup gives the kernel a CONFIG_MAX_MEMSIZE sized address space at - * virtual address PAGE_OFFSET. - * * This contains up to 8192 quadwords depending on NR_TASKS - 64kB of * gdt entries. Ugh. * diff -u --recursive --new-file v2.1.93/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.1.93/linux/arch/i386/kernel/irq.c Thu Mar 26 15:57:02 1998 +++ linux/arch/i386/kernel/irq.c Tue Apr 7 07:48:54 1998 @@ -70,7 +70,9 @@ static unsigned int irq_events [NR_IRQS] = { -1, }; static int disabled_irq [NR_IRQS] = { 0, }; +#ifdef __SMP__ static int ipi_pending [NR_IRQS] = { 0, }; +#endif /* * Not all IRQs can be routed through the IO-APIC, eg. on certain (older) diff -u --recursive --new-file v2.1.93/linux/arch/i386/kernel/mca.c linux/arch/i386/kernel/mca.c --- v2.1.93/linux/arch/i386/kernel/mca.c Fri Jan 30 11:28:06 1998 +++ linux/arch/i386/kernel/mca.c Wed Apr 8 18:12:32 1998 @@ -62,7 +62,7 @@ /*--------------------------------------------------------------------*/ #ifdef CONFIG_PROC_FS -static long mca_do_proc_init( long memory_start, long memory_end ); +static void mca_do_proc_init( void ); static int mca_default_procfn( char* buf, int slot ); static ssize_t proc_mca_read( struct file*, char*, size_t, loff_t *); @@ -79,7 +79,7 @@ /*--------------------------------------------------------------------*/ -__initfunc(long mca_init(long memory_start, long memory_end)) +__initfunc(void mca_init(void)) { unsigned int i, j; int foundscsi = 0; @@ -96,21 +96,14 @@ */ if (!MCA_bus) - return memory_start; + return; cli(); /* * Allocate MCA_info structure (at address divisible by 8) */ - if( ((memory_start+7)&(~7)) > memory_end ) - { - /* uh oh */ - return memory_start; - } - - mca_info = (struct MCA_info*) ((memory_start+7)&(~7)); - memory_start = ((long)mca_info) + sizeof(struct MCA_info); + mca_info = kmalloc(sizeof(struct MCA_info), GFP_ATOMIC); /* * Make sure adapter setup is off @@ -194,10 +187,8 @@ request_region(0x100,0x08,"POS (MCA)"); #ifdef CONFIG_PROC_FS - memory_start = mca_do_proc_init( memory_start, memory_end ); + mca_do_proc_init(); #endif - - return memory_start; } /*--------------------------------------------------------------------*/ @@ -418,12 +409,12 @@ /*--------------------------------------------------------------------*/ -__initfunc(long mca_do_proc_init( long memory_start, long memory_end )) +__initfunc(void mca_do_proc_init( void )) { int i = 0; struct proc_dir_entry* node = 0; - if( mca_info == 0 ) return memory_start; /* never happens */ + if( mca_info == 0 ) return; /* never happens */ proc_register( &proc_mca, &(struct proc_dir_entry) { PROC_MCA_REGISTERS, 3, "pos", S_IFREG|S_IRUGO, @@ -439,11 +430,7 @@ mca_info->slot[i].dev = 0; if( ! mca_isadapter( i ) ) continue; - if( memory_start + sizeof(struct proc_dir_entry) > memory_end ) { - continue; - } - node = (struct proc_dir_entry*) memory_start; - memory_start += sizeof(struct proc_dir_entry); + node = kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC); if( i < MCA_MAX_SLOT_NR ) { node->low_ino = PROC_MCA_SLOT + i; @@ -464,7 +451,6 @@ proc_register( &proc_mca, node ); } - return memory_start; } /* mca_do_proc_init() */ /*--------------------------------------------------------------------*/ diff -u --recursive --new-file v2.1.93/linux/arch/i386/math-emu/poly.h linux/arch/i386/math-emu/poly.h --- v2.1.93/linux/arch/i386/math-emu/poly.h Sun Jul 31 22:19:14 1994 +++ linux/arch/i386/math-emu/poly.h Tue Apr 7 07:48:54 1998 @@ -83,7 +83,7 @@ /* Note: the constraints in the asm statement didn't always work properly with gcc 2.5.8. Changing from using edi to using ecx got around the problem, but keep fingers crossed! */ -extern inline int add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp) +extern inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp) { asm volatile ("movl %2,%%ecx; movl %3,%%esi; movl (%%esi),%%eax; addl %%eax,(%%ecx); diff -u --recursive --new-file v2.1.93/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.1.93/linux/arch/i386/mm/init.c Mon Apr 6 17:40:59 1998 +++ linux/arch/i386/mm/init.c Wed Apr 8 11:35:15 1998 @@ -293,8 +293,6 @@ } local_flush_tlb(); - printk("IO APIC ID: %d\n", *(int *)0xFEC00000); - printk("APIC ID: %d\n", *(int *)0xFEE00000); } #endif local_flush_tlb(); diff -u --recursive --new-file v2.1.93/linux/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds --- v2.1.93/linux/arch/i386/vmlinux.lds Tue Mar 17 22:18:14 1998 +++ linux/arch/i386/vmlinux.lds Wed Apr 8 18:01:53 1998 @@ -1,13 +1,12 @@ /* ld script to make i386 Linux kernel * Written by Martin Mares */ -INCLUDE arch/i386/.kernel_offset.lds OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(_start) SECTIONS { - . = __kernel_offset__ + 0x100000; + . = 0xC0000000 + 0x100000; _text = .; /* Text and read-only data */ .text : { *(.text) diff -u --recursive --new-file v2.1.93/linux/arch/m68k/amiga/amiga_ksyms.c linux/arch/m68k/amiga/amiga_ksyms.c --- v2.1.93/linux/arch/m68k/amiga/amiga_ksyms.c Thu Mar 26 15:57:02 1998 +++ linux/arch/m68k/amiga/amiga_ksyms.c Tue Apr 7 07:52:04 1998 @@ -1,4 +1,3 @@ -#include #include #include #include diff -u --recursive --new-file v2.1.93/linux/arch/m68k/atari/atari_ksyms.c linux/arch/m68k/atari/atari_ksyms.c --- v2.1.93/linux/arch/m68k/atari/atari_ksyms.c Thu Mar 26 15:57:02 1998 +++ linux/arch/m68k/atari/atari_ksyms.c Tue Apr 7 07:52:04 1998 @@ -1,4 +1,3 @@ -#include #include #include diff -u --recursive --new-file v2.1.93/linux/arch/m68k/mac/ksyms.c linux/arch/m68k/mac/ksyms.c --- v2.1.93/linux/arch/m68k/mac/ksyms.c Thu Mar 26 15:57:02 1998 +++ linux/arch/m68k/mac/ksyms.c Tue Apr 7 07:52:04 1998 @@ -1,4 +1,3 @@ -#include #include #include #include diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/block/Config.in linux/drivers/acorn/block/Config.in --- v2.1.93/linux/drivers/acorn/block/Config.in Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/block/Config.in Wed Apr 8 15:51:32 1998 @@ -16,6 +16,4 @@ bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT fi -bool 'ADFS partition support' CONFIG_BLK_DEV_PART - endmenu diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c --- v2.1.93/linux/drivers/acorn/block/mfmhd.c Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/block/mfmhd.c Wed Apr 8 15:51:32 1998 @@ -85,6 +85,8 @@ * card slots if someone tries this)! * * 17/1/97:RMK: Upgraded to 2.1 kernels. + * + * 4/3/98:RMK: Changed major number to 21. */ /* @@ -108,6 +110,9 @@ #include #include +#define MAJOR_NR MFM_ACORN_MAJOR +#include + #include #include #include @@ -117,12 +122,6 @@ #include #include -#define MFM_DISK_MAJOR 13 -#undef XT_DISK_MAJOR -#define XT_DISK_MAJOR -1 -#define MAJOR_NR MFM_DISK_MAJOR -#include "blk.h" - /* * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc */ @@ -231,9 +230,6 @@ static void mfm_specify (void); static void issue_request(int dev, unsigned int block, unsigned int nsect, struct request *req); - -#define mfm_init xd_init -#define mfm_setup xd_setup static unsigned int mfm_addr; /* Controller address */ static unsigned int mfm_IRQPollLoc; /* Address to read for IRQ information */ diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c --- v2.1.93/linux/drivers/acorn/net/ether1.c Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/net/ether1.c Wed Apr 8 15:51:32 1998 @@ -41,16 +41,16 @@ #include #include #include -#include -#include -#include -#include #include - +#include #include #include #include +#include +#include +#include +#include #include #define __ETHER1_C @@ -58,9 +58,6 @@ static unsigned int net_debug = NET_DEBUG; -#define struct ether1_priv *priv = (struct ether1_priv *)dev->priv \ - struct ether1_priv *priv = (struct ether1_priv *)dev->priv - #define BUFFER_SIZE 0x10000 #define TX_AREA_START 0x00100 #define TX_AREA_END 0x05000 @@ -87,7 +84,8 @@ #define ether1_inw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs) #define ether1_outw(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs) -static inline unsigned short ether1_inw_p (struct device *dev, int addr, int svflgs) +static inline unsigned short +ether1_inw_p (struct device *dev, int addr, int svflgs) { unsigned long flags; unsigned short ret; @@ -102,7 +100,8 @@ return ret; } -static inline void ether1_outw_p (struct device *dev, unsigned short val, int addr, int svflgs) +static inline void +ether1_outw_p (struct device *dev, unsigned short val, int addr, int svflgs) { unsigned long flags; @@ -124,8 +123,8 @@ * This routine is essentially an optimised memcpy from the card's * onboard RAM to kernel memory. */ - -static inline void *ether1_inswb (unsigned int addr, void *data, unsigned int len) +static inline void * +ether1_inswb (unsigned int addr, void *data, unsigned int len) { int used; @@ -161,13 +160,14 @@ 2: adds %3, %3, #1 ldreqb %0, [%1] streqb %0, [%2]" - : "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len) - : "1" (addr), "2" (data), "3" (len)); + : "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len) + : "1" (addr), "2" (data), "3" (len)); return data; } -static inline void *ether1_outswb (unsigned int addr, void *data, unsigned int len) +static inline void * +ether1_outswb (unsigned int addr, void *data, unsigned int len) { int used; @@ -203,28 +203,26 @@ 2: adds %3, %3, #1 ldreqb %0, [%2] streqb %0, [%1]" - : "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len) - : "1" (addr), "2" (data), "3" (len)); + : "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len) + : "1" (addr), "2" (data), "3" (len)); return data; } -static void ether1_writebuffer (struct device *dev, void *data, unsigned int start, unsigned int length) +static void +ether1_writebuffer (struct device *dev, void *data, unsigned int start, unsigned int length) { unsigned int page, thislen, offset; + offset = start & 4095; - for (page = start >> 12; length; page++) - { + for (page = start >> 12; length; page++) { outb (page, REG_PAGE); - if (offset + length > 4096) - { - length -= 4096 - offset; - thislen = 4096 - offset; - } - else - { + if (offset + length > 4096) { + length -= 4096 - offset; + thislen = 4096 - offset; + } else { thislen = length; length = 0; } @@ -234,23 +232,20 @@ } } -static void ether1_readbuffer (struct device *dev, void *data, unsigned int start, unsigned int length) +static void +ether1_readbuffer (struct device *dev, void *data, unsigned int start, unsigned int length) { unsigned int page, thislen, offset; offset = start & 4095; - for (page = start >> 12; length; page++) - { + for (page = start >> 12; length; page++) { outb (page, REG_PAGE); - if (offset + length > 4096) - { + if (offset + length > 4096) { length -= 4096 - offset; thislen = 4096 - offset; - } - else - { - thislen = length; + } else { + thislen = length; length = 0; } @@ -259,7 +254,8 @@ } } -static int ether1_ramtest (struct device *dev, unsigned char byte) +__initfunc(static int +ether1_ramtest (struct device *dev, unsigned char byte)) { unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL); int i, ret = BUFFER_SIZE; @@ -275,12 +271,9 @@ memset (buffer, byte ^ 0xff, BUFFER_SIZE); ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE); - for (i = 0; i < BUFFER_SIZE; i++) - { - if (buffer[i] != byte) - { - if (max_errors >= 0 && bad != buffer[i]) - { + for (i = 0; i < BUFFER_SIZE; i++) { + if (buffer[i] != byte) { + if (max_errors >= 0 && bad != buffer[i]) { if (bad != -1) printk ("\n"); printk (KERN_CRIT "%s: RAM failed with (%02X instead of %02X) at 0x%04X", @@ -290,12 +283,9 @@ bad = buffer[i]; bad_start = i; } - } - else - { - if (bad != -1) - { - if (bad_start == i - 1) + } else { + if (bad != -1) { + if (bad_start == i - 1) printk ("\n"); else printk (" - 0x%04X\n", i - 1); @@ -311,13 +301,15 @@ return ret; } -static int ether1_reset (struct device *dev) +static int +ether1_reset (struct device *dev) { outb (CTRL_RST|CTRL_ACK, REG_CONTROL); return BUS_16; } -static int ether1_init_2 (struct device *dev) +__initfunc(static int +ether1_init_2 (struct device *dev)) { int i; dev->mem_start = 0; @@ -328,7 +320,7 @@ i = ether1_ramtest (dev, 0x1e); if (i <= 0) - return -ENODEV; + return -ENODEV; dev->mem_end = i; return 0; @@ -340,12 +332,9 @@ */ /* at 0x0100 */ - #define NOP_ADDR (TX_AREA_START) #define NOP_SIZE (0x06) - -static nop_t init_nop = -{ +static nop_t init_nop = { 0, CMD_NOP, NOP_ADDR @@ -364,8 +353,7 @@ /* at 0x002e */ #define MC_ADDR (0x002e) #define MC_SIZE (0x0c) -static mc_t init_mc = -{ +static mc_t init_mc = { 0, CMD_SETMULTICAST, TDR_ADDR, @@ -447,7 +435,7 @@ }; #define RBD_SIZE (0x0a) -static rbd_t init_rbd = { +static rbd_t init_rbd = { 0, 0, 0, @@ -458,7 +446,8 @@ #define TX_SIZE (0x08) #define TBD_SIZE (0x08) -static int ether1_init_for_open (struct device *dev) +static int +ether1_init_for_open (struct device *dev) { struct ether1_priv *priv = (struct ether1_priv *)dev->priv; int i, status, addr, next, next2; @@ -479,8 +468,7 @@ ether1_writebuffer (dev, &init_tdr, TDR_ADDR, TDR_SIZE); ether1_writebuffer (dev, &init_nop, NOP_ADDR, NOP_SIZE); - if (ether1_inw (dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) - { + if (ether1_inw (dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) { printk (KERN_ERR "%s: detected either RAM fault or compiler bug\n", dev->name); return 1; @@ -492,21 +480,16 @@ * First rfd is linked to scp, first rbd is linked to first * rfd. Last rbd has a suspend command. */ - addr = RX_AREA_START; - - do - { + do { next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10; next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10; - if (next2 >= RX_AREA_END) - { + if (next2 >= RX_AREA_END) { next = RX_AREA_START; init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND; priv->rx_tail = addr; - } - else + } else init_rfd.rfd_command = 0; if (addr == RX_AREA_START) init_rfd.rfd_rbdoffset = addr + RFD_SIZE; @@ -519,8 +502,7 @@ ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE); ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE); addr = next; - } - while (next2 < RX_AREA_END); + } while (next2 < RX_AREA_END); priv->tx_link = NOP_ADDR; priv->tx_head = NOP_ADDR + NOP_SIZE; @@ -536,10 +518,8 @@ /* 586 should now unset iscp.busy */ i = jiffies + HZ/2; - while (ether1_inw (dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) - { - if (jiffies > i) - { + while (ether1_inw (dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) { + if (jiffies > i) { printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name); return 1; } @@ -547,32 +527,30 @@ /* check status of commands that we issued */ i += HZ/10; - while (((status = ether1_inw (dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) - { - if (jiffies-i<0) + while (((status = ether1_inw (dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS)) + & STAT_COMPLETE) == 0) { + if (jiffies > i) break; } - if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) - { + if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) { printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status); printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, - ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), - ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), - ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), - ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); + ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); failures += 1; } i += HZ/10; - while (((status = ether1_inw (dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) - { - if (jiffies-i<0) + while (((status = ether1_inw (dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS)) + & STAT_COMPLETE) == 0) { + if (jiffies > i) break; } - if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) - { + if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) { printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status); printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), @@ -583,14 +561,13 @@ } i += HZ/10; - while (((status = ether1_inw (dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) - { - if (jiffies-i < 0) + while (((status = ether1_inw (dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS)) + & STAT_COMPLETE) == 0) { + if (jiffies > i) break; } - if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) - { + if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) { printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status); printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), @@ -601,33 +578,29 @@ } i += HZ; - while (((status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) - { - if (jiffies-i <0) + while (((status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS)) + & STAT_COMPLETE) == 0) { + if (jiffies > i) break; } - if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) - { + if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) { printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name); printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); - } - else - { + } else { status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS); if (status & TDR_XCVRPROB) printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name); - else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) - { + else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) { #ifdef FANCY printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name, status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10, (status & TDR_TIME) % 10); -#else +#else printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name, status & TDR_SHORT ? "short" : "open", (status & TDR_TIME)); #endif @@ -639,7 +612,8 @@ return failures ? 1 : 0; } -static int ether1_probe1 (struct device *dev) +__initfunc(static int +ether1_probe1 (struct device *dev)) { static unsigned int version_printed = 0; struct ether1_priv *priv; @@ -649,13 +623,12 @@ dev->priv = kmalloc (sizeof (struct ether1_priv), GFP_KERNEL); if (!dev->priv) - return 1; + return 1; priv = (struct ether1_priv *)dev->priv; memset (priv, 0, sizeof (struct ether1_priv)); - if ((priv->bus_type = ether1_reset (dev)) == 0) - { + if ((priv->bus_type = ether1_reset (dev)) == 0) { kfree (dev->priv); return 1; } @@ -672,15 +645,14 @@ for (i = 0; i < 6; i++) printk (i==0?" %02x":i==5?":%02x\n":":%02x", dev->dev_addr[i]); - if (ether1_init_2 (dev)) - { + if (ether1_init_2 (dev)) { kfree (dev->priv); return 1; } - dev->open = ether1_open; - dev->stop = ether1_close; - dev->hard_start_xmit= ether1_sendpacket; + dev->open = ether1_open; + dev->stop = ether1_close; + dev->hard_start_xmit = ether1_sendpacket; dev->get_stats = ether1_getstats; dev->set_multicast_list = ether1_setmulticastlist; @@ -688,8 +660,7 @@ ether_setup (dev); #ifndef CLAIM_IRQ_AT_OPEN - if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) - { + if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) { kfree (dev->priv); return -EAGAIN; } @@ -699,7 +670,8 @@ /* ------------------------------------------------------------------------- */ -static void ether1_addr (struct device *dev) +__initfunc(static void +ether1_addr (struct device *dev)) { int i; @@ -707,7 +679,8 @@ dev->dev_addr[i] = inb (IDPROM_ADDRESS + i); } -int ether1_probe (struct device *dev) +__initfunc(int +ether1_probe (struct device *dev)) { #ifndef MODULE struct expansion_card *ec; @@ -723,6 +696,7 @@ dev->irq = ec->irq; ecard_claim (ec); + #endif ether1_addr (dev); @@ -733,36 +707,36 @@ /* ------------------------------------------------------------------------- */ -static int ether1_txalloc (struct device *dev, int size) +static int +ether1_txalloc (struct device *dev, int size) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; int start, tail; size = (size + 1) & ~1; tail = priv->tx_tail; - if (priv->tx_head + size > TX_AREA_END) - { + if (priv->tx_head + size > TX_AREA_END) { if (tail > priv->tx_head) return -1; start = TX_AREA_START; if (start + size > tail) return -1; priv->tx_head = start + size; - } - else - { + } else { if (priv->tx_head < tail && (priv->tx_head + size) > tail) return -1; start = priv->tx_head; priv->tx_head += size; } + return start; } -static void ether1_restart (struct device *dev, char *reason) +static void +ether1_restart (struct device *dev, char *reason) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; priv->stats.tx_errors ++; if (reason) @@ -781,9 +755,10 @@ dev->start = 1; } -static int ether1_open (struct device *dev) +static int +ether1_open (struct device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; #ifdef CLAIM_IRQ_AT_OPEN if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) return -EAGAIN; @@ -792,8 +767,7 @@ memset (&priv->stats, 0, sizeof (struct enet_statistics)); - if (ether1_init_for_open (dev)) - { + if (ether1_init_for_open (dev)) { #ifdef CLAIM_IRQ_AT_OPEN free_irq (dev->irq, dev); #endif @@ -808,15 +782,15 @@ return 0; } -static int ether1_sendpacket (struct sk_buff *skb, struct device *dev) +static int +ether1_sendpacket (struct sk_buff *skb, struct device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; if (priv->restart) ether1_restart (dev, NULL); - if (dev->tbusy) - { + if (dev->tbusy) { /* * If we get here, some higher level has decided that we are broken. * There should really be a "kick me" function call instead. @@ -835,11 +809,9 @@ * Block a timer-based transmit from overlapping. This could better be * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit (0, (void *)&dev->tbusy) != 0) printk (KERN_WARNING "%s: transmitter access conflict.\n", dev->name); - else - { + else { int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr; unsigned long flags; @@ -890,14 +862,15 @@ if (tst != -1) dev->tbusy = 0; } - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return 0; } -static void ether1_xmit_done (struct device *dev) +static void +ether1_xmit_done (struct device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; nop_t nop; int caddr, tst; @@ -906,57 +879,52 @@ again: ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); - switch (nop.nop_command & CMD_MASK) - { - case CMD_TDR: - /* special case */ - if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS) != (unsigned short)I82586_NULL) - { - ether1_outw (dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t, - scb_command, NORMALIRQS); - outb (CTRL_CA, REG_CONTROL); - } - priv->tx_tail = NOP_ADDR; - return; + switch (nop.nop_command & CMD_MASK) { + case CMD_TDR: + /* special case */ + if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS) + != (unsigned short)I82586_NULL) { + ether1_outw(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t, + scb_command, NORMALIRQS); + outb (CTRL_CA, REG_CONTROL); + } + priv->tx_tail = NOP_ADDR; + return; - case CMD_NOP: - if (nop.nop_link == caddr) - { - if (priv->initialising == 0) - printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name); - else - priv->initialising = 0; - return; - } - if (caddr == nop.nop_link) - return; - caddr = nop.nop_link; - goto again; - - case CMD_TX: - if (nop.nop_status & STAT_COMPLETE) - break; - printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name); - priv->restart = 1; + case CMD_NOP: + if (nop.nop_link == caddr) { + if (priv->initialising == 0) + printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name); + else + priv->initialising = 0; return; - - default: - printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name, - nop.nop_command & CMD_MASK, caddr); - priv->restart = 1; + } + if (caddr == nop.nop_link) return; + caddr = nop.nop_link; + goto again; + + case CMD_TX: + if (nop.nop_status & STAT_COMPLETE) + break; + printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name); + priv->restart = 1; + return; + + default: + printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name, + nop.nop_command & CMD_MASK, caddr); + priv->restart = 1; + return; } - while (nop.nop_status & STAT_COMPLETE) - { - if (nop.nop_status & STAT_OK) - { + while (nop.nop_status & STAT_COMPLETE) { + if (nop.nop_status & STAT_OK) { priv->stats.tx_packets ++; priv->stats.collisions += (nop.nop_status & STAT_COLLISIONS); - } - else - { + } else { priv->stats.tx_errors ++; + if (nop.nop_status & STAT_COLLAFTERTX) priv->stats.collisions ++; if (nop.nop_status & STAT_NOCARRIER) @@ -968,16 +936,15 @@ if (nop.nop_status & STAT_COLLEXCESSIVE) priv->stats.collisions += 16; } - if (nop.nop_link == caddr) - { + + if (nop.nop_link == caddr) { printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name); break; } caddr = nop.nop_link; ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); - if ((nop.nop_command & CMD_MASK) != CMD_NOP) - { + if ((nop.nop_command & CMD_MASK) != CMD_NOP) { printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name); break; } @@ -987,8 +954,7 @@ caddr = nop.nop_link; ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); - if ((nop.nop_command & CMD_MASK) != CMD_TX) - { + if ((nop.nop_command & CMD_MASK) != CMD_TX) { printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name); break; } @@ -1004,15 +970,15 @@ mark_bh (NET_BH); } -static void ether1_recv_done (struct device *dev) +static void +ether1_recv_done (struct device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; int status; int nexttail, rbdaddr; rbd_t rbd; - do - { + do { status = ether1_inw (dev, priv->rx_head, rfd_t, rfd_status, NORMALIRQS); if ((status & RFD_COMPLETE) == 0) break; @@ -1020,16 +986,14 @@ rbdaddr = ether1_inw (dev, priv->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS); ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE); - if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) - { + if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) { int length = rbd.rbd_status & RBD_ACNT; struct sk_buff *skb; length = (length + 1) & ~1; skb = dev_alloc_skb (length + 2); - if (skb) - { + if (skb) { skb->dev = dev; skb_reserve (skb, 2); @@ -1038,13 +1002,10 @@ skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); priv->stats.rx_packets ++; - } - else + } else priv->stats.rx_dropped ++; - } - else - { - printk (KERN_WARNING "%s: %s\n", dev->name, + } else { + printk(KERN_WARNING "%s: %s\n", dev->name, (rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid"); priv->stats.rx_dropped ++; } @@ -1052,7 +1013,7 @@ nexttail = ether1_inw (dev, priv->rx_tail, rfd_t, rfd_link, NORMALIRQS); /* nexttail should be rx_head */ if (nexttail != priv->rx_head) - printk (KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n", + printk(KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n", dev->name, nexttail, priv->rx_head); ether1_outw (dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS); ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_command, NORMALIRQS); @@ -1061,86 +1022,85 @@ priv->rx_tail = nexttail; priv->rx_head = ether1_inw (dev, priv->rx_head, rfd_t, rfd_link, NORMALIRQS); - } - while (1); + } while (1); } -static void ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs) +static void +ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs) { struct device *dev = (struct device *)dev_id; - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; int status; dev->interrupt = 1; status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS); - if (status) - { - ether1_outw (dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX), - SCB_ADDR, scb_t, scb_command, NORMALIRQS); + if (status) { + ether1_outw(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX), + SCB_ADDR, scb_t, scb_command, NORMALIRQS); outb (CTRL_CA | CTRL_ACK, REG_CONTROL); - if (status & SCB_STCX) + if (status & SCB_STCX) { ether1_xmit_done (dev); - if (status & SCB_STCNA) - { + } + if (status & SCB_STCNA) { if (priv->resetting == 0) printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name); else priv->resetting += 1; - if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS) != (unsigned short)I82586_NULL) - { + if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS) + != (unsigned short)I82586_NULL) { ether1_outw (dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS); outb (CTRL_CA, REG_CONTROL); } if (priv->resetting == 2) priv->resetting = 0; } - if (status & SCB_STFR) + if (status & SCB_STFR) { ether1_recv_done (dev); - - if (status & SCB_STRNR) - { - if (ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) - { + } + if (status & SCB_STRNR) { + if (ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) { printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name); ether1_outw (dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS); outb (CTRL_CA, REG_CONTROL); priv->stats.rx_dropped ++; /* we suspended due to lack of buffer space */ - } - else - printk (KERN_WARNING "%s: RU went not ready: %04X\n", dev->name, - ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS)); - printk (KERN_WARNING "RU ptr = %04X\n", ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset,NORMALIRQS)); + } else + printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name, + ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS)); + printk (KERN_WARNING "RU ptr = %04X\n", ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, + NORMALIRQS)); } - } - else - outb (CTRL_ACK, REG_CONTROL); + } else + outb (CTRL_ACK, REG_CONTROL); dev->interrupt = 0; } -static int ether1_close (struct device *dev) +static int +ether1_close (struct device *dev) { #ifdef CLAIM_IRQ_AT_OPEN free_irq (dev->irq, dev); #endif - ether1_reset (dev); + ether1_reset (dev); + dev->start = 0; dev->tbusy = 0; + MOD_DEC_USE_COUNT; return 0; } -static struct enet_statistics *ether1_getstats (struct device *dev) +static struct enet_statistics * +ether1_getstats (struct device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; return &priv->stats; } - /* * Set or clear the multicast filter for this adaptor. * num_addrs == -1 Promiscuous mode, receive all packets. @@ -1148,8 +1108,8 @@ * num_addrs > 0 Multicast mode, receive normal and MC packets, and do * best-effort filtering. */ - -static void ether1_setmulticastlist (struct device *dev) +static void +ether1_setmulticastlist (struct device *dev) { } @@ -1161,12 +1121,12 @@ static struct device *my_ethers[MAX_ECARDS]; static struct expansion_card *ec[MAX_ECARDS]; -int init_module (void) +int +init_module (void) { int i; - for (i = 0; i < MAX_ECARDS; i++) - { + for (i = 0; i < MAX_ECARDS; i++) { my_ethers[i] = NULL; ec[i] = NULL; strcpy (ethernames[i], " "); @@ -1174,10 +1134,9 @@ i = 0; - ecard_startfind(); + ecard_startfind (); - do - { + do { if ((ec[i] = ecard_find(0, ether1_cids)) == NULL) break; @@ -1191,17 +1150,13 @@ ecard_claim (ec[i]); - if (register_netdev (my_ethers[i]) != 0) - { - for (i = 0; i < 4; i++) - { - if (my_ethers[i]) - { + if (register_netdev (my_ethers[i]) != 0) { + for (i = 0; i < 4; i++) { + if (my_ethers[i]) { kfree (my_ethers[i]); my_ethers[i] = NULL; } - if (ec[i]) - { + if (ec[i]) { ecard_release (ec[i]); ec[i] = NULL; } @@ -1209,20 +1164,18 @@ return -EIO; } i++; - } - while (i < MAX_ECARDS); + } while (i < MAX_ECARDS); return i != 0 ? 0 : -ENODEV; } -void cleanup_module (void) +void +cleanup_module (void) { int i; - for (i = 0; i < MAX_ECARDS; i++) - { - if (my_ethers[i]) - { + for (i = 0; i < MAX_ECARDS; i++) { + if (my_ethers[i]) { unregister_netdev (my_ethers[i]); release_region (my_ethers[i]->base_addr, 16); release_region (my_ethers[i]->base_addr + 0x800, 4096); @@ -1231,8 +1184,7 @@ #endif my_ethers[i] = NULL; } - if (ec[i]) - { + if (ec[i]) { ecard_release (ec[i]); ec[i] = NULL; } diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/net/ether3.c linux/drivers/acorn/net/ether3.c --- v2.1.93/linux/drivers/acorn/net/ether3.c Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/net/ether3.c Wed Apr 8 15:51:32 1998 @@ -7,29 +7,30 @@ * By Russell King, with some suggestions from borris@ant.co.uk * * Changelog: - * 1.04 RMK 29/02/1996 Won't pass packets that are from our ethernet - * address up to the higher levels - they're - * silently ignored. I/F can now be put into - * multicast mode. Receiver routine optimised. - * 1.05 RMK 30/02/1996 Now claims interrupt at open when part of - * the kernel rather than when a module. - * 1.06 RMK 02/03/1996 Various code cleanups - * 1.07 RMK 13/10/1996 Optimised interrupt routine and transmit - * routines. - * 1.08 RMK 14/10/1996 Fixed problem with too many packets, - * prevented the kernel message about dropped - * packets appearing too many times a second. - * Now does not disable all IRQs, only the IRQ - * used by this card. - * 1.09 RMK 10/11/1996 Only enables TX irq when buffer space is low, - * but we still service the TX queue if we get a - * RX interrupt. - * 1.10 RMK 15/07/1997 Fixed autoprobing of NQ8004. - * 1.11 RMK 16/11/1997 Fixed autoprobing of NQ8005A. - * 1.12 RMK 31/12/1997 Removed reference to dev_tint for Linux 2.1. + * 1.04 RMK 29/02/1996 Won't pass packets that are from our ethernet + * address up to the higher levels - they're + * silently ignored. I/F can now be put into + * multicast mode. Receiver routine optimised. + * 1.05 RMK 30/02/1996 Now claims interrupt at open when part of + * the kernel rather than when a module. + * 1.06 RMK 02/03/1996 Various code cleanups + * 1.07 RMK 13/10/1996 Optimised interrupt routine and transmit + * routines. + * 1.08 RMK 14/10/1996 Fixed problem with too many packets, + * prevented the kernel message about dropped + * packets appearing too many times a second. + * Now does not disable all IRQs, only the IRQ + * used by this card. + * 1.09 RMK 10/11/1996 Only enables TX irq when buffer space is low, + * but we still service the TX queue if we get a + * RX interrupt. + * 1.10 RMK 15/07/1997 Fixed autoprobing of NQ8004. + * 1.11 RMK 16/11/1997 Fixed autoprobing of NQ8005A. + * 1.12 RMK 31/12/1997 Removed reference to dev_tint for Linux 2.1. * * TODO: * When we detect a fatal error on the interface, we should restart it. + * Reap transmit packets after some time even if the buffer never filled. */ static char *version = "ether3 ethernet driver (c) 1995-1998 R.M.King v1.12\n"; @@ -49,6 +50,7 @@ #include #include #include +#include #include #include @@ -64,25 +66,20 @@ #endif static unsigned int net_debug = NET_DEBUG; - -static const card_ids ether3_cids[] = -{ - {MANU_ANT2, PROD_ANT_ETHER3}, - {MANU_ANT, PROD_ANT_ETHER3}, - {MANU_ANT, PROD_ANT_ETHERB}, /* trial - will etherb work? */ - {0xffff, 0xffff} +static const card_ids ether3_cids[] = { + { MANU_ANT2, PROD_ANT_ETHER3 }, + { MANU_ANT, PROD_ANT_ETHER3 }, + { MANU_ANT, PROD_ANT_ETHERB }, /* trial - will etherb work? */ + { 0xffff, 0xffff } }; static void ether3_setmulticastlist(struct device *dev); -static int ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt); +static int ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt); static void ether3_tx(struct device *dev, struct dev_priv *priv); extern int inswb(int reg, void *buffer, int len); extern int outswb(int reg, void *buffer, int len); -#define struct dev_priv *priv = (struct dev_priv *)dev->priv \ - struct dev_priv *priv = (struct dev_priv *)dev->priv - #define BUS_16 2 #define BUS_8 1 #define BUS_UNKNOWN 0 @@ -91,9 +88,7 @@ * I'm not sure what address we should default to if the internal one * is corrupted... */ - -unsigned char def_eth_addr[6] = -{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; +unsigned char def_eth_addr[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; /* --------------------------------------------------------------------------- */ @@ -102,16 +97,17 @@ buffer_read } buffer_rw_t; -static int ether3_setbuffer(struct device *dev, buffer_rw_t read, int start) +static int +ether3_setbuffer(struct device *dev, buffer_rw_t read, int start) { - struct dev_priv *priv = (struct dev_priv *) dev->priv; + struct dev_priv *priv = (struct dev_priv *)dev->priv; int timeout = 1000; outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND); while ((inw(REG_STATUS) & STAT_FIFOEMPTY) == 0) { if (!timeout--) { - printk(KERN_ERR "%s: setbuffer broken\n", dev->name); + printk("%s: setbuffer broken\n", dev->name); priv->broken = 1; return 1; } @@ -131,47 +127,49 @@ * write data to the buffer memory */ #define ether3_writebuffer(dev,data,length) \ - outswb (REG_BUFWIN, (data), (length)) + outswb(REG_BUFWIN, (data), (length)) #define ether3_writeword(dev,data) \ - outw ((data), REG_BUFWIN) + outw((data), REG_BUFWIN) #define ether3_writelong(dev,data) { \ unsigned long reg_bufwin = REG_BUFWIN; \ - outw ((data), reg_bufwin); \ - outw ((data) >> 16, reg_bufwin); \ + outw((data), reg_bufwin); \ + outw((data) >> 16, reg_bufwin); \ } /* * read data from the buffer memory */ #define ether3_readbuffer(dev,data,length) \ - inswb (REG_BUFWIN, (data), (length)) + inswb(REG_BUFWIN, (data), (length)) #define ether3_readword(dev) \ - inw (REG_BUFWIN) + inw(REG_BUFWIN) #define ether3_readlong(dev) \ - inw (REG_BUFWIN) | (inw (REG_BUFWIN) << 16) + inw(REG_BUFWIN) | (inw(REG_BUFWIN) << 16) /* * Switch LED off... */ -static void ether3_ledoff(unsigned long data) +static void +ether3_ledoff(unsigned long data) { - struct device *dev = (struct device *) data; - struct dev_priv *priv = (struct dev_priv *) dev->priv; + struct device *dev = (struct device *)data; + struct dev_priv *priv = (struct dev_priv *)dev->priv; outw(priv->regs.config2 |= CFG2_CTRLO, REG_CONFIG2); } /* * switch LED on... */ -static inline void ether3_ledon(struct device *dev, struct dev_priv *priv) +static inline void +ether3_ledon(struct device *dev, struct dev_priv *priv) { del_timer(&priv->timer); - priv->timer.expires = jiffies + HZ / 50; /* leave on for 1/50th second */ - priv->timer.data = (unsigned long) dev; + priv->timer.expires = jiffies + HZ / 50; /* leave on for 1/50th second */ + priv->timer.data = (unsigned long)dev; priv->timer.function = ether3_ledoff; add_timer(&priv->timer); if (priv->regs.config2 & CFG2_CTRLO) @@ -182,30 +180,36 @@ * Read the ethernet address string from the on board rom. * This is an ascii string!!! */ -static void ether3_addr(char *addr, struct expansion_card *ec) +__initfunc(static void +ether3_addr(char *addr, struct expansion_card *ec)) { struct in_chunk_dir cd; char *s; - + if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) { int i; - for (i = 0; i < 6; i++) { + for (i = 0; i<6; i++) { addr[i] = simple_strtoul(s + 1, &s, 0x10); - if (*s != (i == 5 ? ')' : ':')) + if (*s != (i==5?')' : ':' )) break; } if (i == 6) return; } + /* I wonder if we should even let the user continue in this case + * - no, it would be better to disable the device + */ + printk(KERN_ERR "ether3: Couldn't read a valid MAC address from card.\n"); memcpy(addr, def_eth_addr, 6); } /* --------------------------------------------------------------------------- */ -static int ether3_ramtest(struct device *dev, unsigned char byte) +__initfunc(static int +ether3_ramtest(struct device *dev, unsigned char byte)) { unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL); - int i, ret = 0; + int i,ret = 0; int max_errors = 4; int bad = -1; @@ -234,7 +238,7 @@ } } else { if (bad != -1) { - if (bad != i - 1) + if (bad != i - 1) printk(" - 0x%04X", i - 1); printk("\n"); bad = -1; @@ -250,13 +254,14 @@ /* ------------------------------------------------------------------------------- */ -static int ether3_init_2(struct device *dev) +__initfunc(static int +ether3_init_2(struct device *dev)) { - struct dev_priv *priv = (struct dev_priv *) dev->priv; + struct dev_priv *priv = (struct dev_priv *)dev->priv; int i; - priv->regs.config1 = CFG1_RECVCOMPSTAT0 | CFG1_DMABURST8; - priv->regs.config2 = CFG2_CTRLO | CFG2_RECVCRC | CFG2_ERRENCRC; + priv->regs.config1 = CFG1_RECVCOMPSTAT0|CFG1_DMABURST8; + priv->regs.config2 = CFG2_CTRLO|CFG2_RECVCRC|CFG2_ERRENCRC; priv->regs.command = 0; /* * Set up our hardware address @@ -273,12 +278,12 @@ priv->regs.config1 |= CFG1_RECVSPECBROAD; /* - * There is a problem with the NQ8005 in that it occasionally losses the - * last two bytes. To get round this problem, we receive the CRC as well. - * That way, if we do loose the last two, then it doesn't matter + * There is a problem with the NQ8005 in that it occasionally loses the + * last two bytes. To get round this problem, we receive the CRC as + * well. That way, if we do loose the last two, then it doesn't matter. */ outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1); - outw((TX_END >> 8) - 1, REG_BUFWIN); + outw((TX_END>>8) - 1, REG_BUFWIN); outw(priv->rx_head, REG_RECVPTR); outw(0, REG_TRANSMITPTR); outw(priv->rx_head >> 8, REG_RECVEND); @@ -287,10 +292,10 @@ outw(priv->regs.command, REG_COMMAND); i = ether3_ramtest(dev, 0x5A); - if (i) + if(i) return i; i = ether3_ramtest(dev, 0x1E); - if (i) + if(i) return i; ether3_setbuffer(dev, buffer_write, 0); @@ -298,29 +303,30 @@ return 0; } -static void ether3_init_for_open(struct device *dev) +static void +ether3_init_for_open(struct device *dev) { - struct dev_priv *priv = (struct dev_priv *) dev->priv; + struct dev_priv *priv = (struct dev_priv *)dev->priv; int i; memset(&priv->stats, 0, sizeof(struct enet_statistics)); priv->regs.command = 0; - outw(CMD_RXOFF | CMD_TXOFF, REG_COMMAND); - while (inw(REG_STATUS) & (STAT_RXON | STAT_TXON)); + outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND); + while (inw(REG_STATUS) & (STAT_RXON|STAT_TXON)); outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1); for (i = 0; i < 6; i++) outb(dev->dev_addr[i], REG_BUFWIN); - priv->tx_used = 0; - priv->tx_head = 0; - priv->tx_tail = 0; + priv->tx_used = 0; + priv->tx_head = 0; + priv->tx_tail = 0; priv->regs.config2 |= CFG2_CTRLO; - priv->rx_head = RX_START; + priv->rx_head = RX_START; outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1); - outw((TX_END >> 8) - 1, REG_BUFWIN); + outw((TX_END>>8) - 1, REG_BUFWIN); outw(priv->rx_head, REG_RECVPTR); outw(priv->rx_head >> 8, REG_RECVEND); outw(0, REG_TRANSMITPTR); @@ -337,20 +343,22 @@ /* * This is the real probe routine. */ -static int ether3_probe1(struct device *dev) +__initfunc(static int +ether3_probe1(struct device *dev)) { static unsigned version_printed = 0; struct dev_priv *priv; unsigned int i, bus_type, error = ENODEV; - if (net_debug && version_printed++ == 0) + if (net_debug && version_printed++ == 0) printk(version); if (!dev->priv) { - dev->priv = kmalloc(sizeof(struct dev_priv), GFP_KERNEL); + dev->priv = kmalloc(sizeof (struct dev_priv), GFP_KERNEL); if (!dev->priv) return -ENOMEM; } + priv = (struct dev_priv *) dev->priv; memset(priv, 0, sizeof(struct dev_priv)); @@ -374,6 +382,7 @@ else if (inw(REG_RECVPTR) == 0x101) bus_type = BUS_16; } + switch (bus_type) { case BUS_UNKNOWN: printk(KERN_ERR "%s: unable to identify podule bus width\n", dev->name); @@ -407,7 +416,8 @@ #endif return 0; } - failed: + +failed: kfree(dev->priv); dev->priv = NULL; release_region(dev->base_addr, 128); @@ -415,7 +425,8 @@ } #ifndef MODULE -int ether3_probe(struct device *dev) +__initfunc(int +ether3_probe(struct device *dev)) { struct expansion_card *ec; @@ -445,7 +456,8 @@ * registers that "should" only need to be set once at boot, so that * there is non-reboot way to recover if something goes wrong. */ -static int ether3_open(struct device *dev) +static int +ether3_open(struct device *dev) { ether3_init_for_open(dev); @@ -453,7 +465,7 @@ #ifdef CLAIM_IRQ_AT_OPEN if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev)) { - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; return -EAGAIN; } #endif @@ -467,18 +479,19 @@ /* * The inverse routine to ether3_open(). */ -static int ether3_close(struct device *dev) +static int +ether3_close(struct device *dev) { - struct dev_priv *priv = (struct dev_priv *) dev->priv; + struct dev_priv *priv = (struct dev_priv *)dev->priv; dev->tbusy = 1; dev->start = 0; disable_irq(dev->irq); - outw(CMD_RXOFF | CMD_TXOFF, REG_COMMAND); + outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND); priv->regs.command = 0; - while (inw(REG_STATUS) & (STAT_RXON | STAT_TXON)); + while (inw(REG_STATUS) & (STAT_RXON|STAT_TXON)); outb(0x80, REG_CONFIG2 + 1); outw(0, REG_COMMAND); @@ -492,12 +505,12 @@ } /* - * Get the current statistics. This may be called with the card open or + * Get the current statistics. This may be called with the card open or * closed. */ static struct enet_statistics *ether3_getstats(struct device *dev) { - struct dev_priv *priv = (struct dev_priv *) dev->priv; + struct dev_priv *priv = (struct dev_priv *)dev->priv; return &priv->stats; } @@ -509,14 +522,15 @@ */ static void ether3_setmulticastlist(struct device *dev) { - struct dev_priv *priv = (struct dev_priv *) dev->priv; + struct dev_priv *priv = (struct dev_priv *)dev->priv; priv->regs.config1 &= ~CFG1_RECVPROMISC; if (dev->flags & IFF_PROMISC) { /* promiscuous mode */ priv->regs.config1 |= CFG1_RECVPROMISC; - } else if (dev->flags & IFF_ALLMULTI) { + } else + if (dev->flags & IFF_ALLMULTI) { priv->regs.config1 |= CFG1_RECVSPECBRMULTI; } else priv->regs.config1 |= CFG1_RECVSPECBROAD; @@ -527,15 +541,16 @@ /* * Transmit a packet */ -static int ether3_sendpacket(struct sk_buff *skb, struct device *dev) +static int +ether3_sendpacket(struct sk_buff *skb, struct device *dev) { - struct dev_priv *priv = (struct dev_priv *) dev->priv; - retry: + struct dev_priv *priv = (struct dev_priv *)dev->priv; +retry: if (!dev->tbusy) { /* Block a timer-based transmit from overlapping. This could better be * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (!test_and_set_bit(0, (void *) &dev->tbusy)) { + if (!test_and_set_bit(0, (void *)&dev->tbusy)) { unsigned long flags; unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned int ptr, nextptr; @@ -543,17 +558,18 @@ length = (length + 1) & ~1; if (priv->broken) { - dev_kfree_skb(skb, FREE_WRITE); - priv->stats.tx_dropped++; + dev_kfree_skb(skb); + priv->stats.tx_dropped ++; dev->tbusy = 0; return 0; } + ptr = priv->tx_head; nextptr = ptr + 0x600; if (nextptr >= TX_END) nextptr = 0; if (nextptr == priv->tx_tail) - return 1; /* unable to queue */ + return 1; /* unable to queue */ priv->tx_head = nextptr; save_flags_cli(flags); @@ -562,13 +578,13 @@ ether3_setbuffer(dev, buffer_write, ptr + 4); ether3_writebuffer(dev, skb->data, length); ether3_writeword(dev, htons(nextptr)); - ether3_writeword(dev, (TXHDR_TRANSMIT | TXHDR_CHAINCONTINUE) >> 16); + ether3_writeword(dev, (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE) >> 16); ether3_setbuffer(dev, buffer_write, ptr); #define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS) ether3_writeword(dev, htons(ptr + length + 4)); ether3_writeword(dev, (TXHDR_FLAGS >> 16)); ether3_ledon(dev, priv); - priv->tx_used++; + priv->tx_used ++; if (priv->tx_used < MAX_TX_BUFFERED) dev->tbusy = 0; if (priv->tx_used >= (MAX_TX_BUFFERED * 3 / 4)) { @@ -578,7 +594,7 @@ restore_flags(flags); dev->trans_start = jiffies; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); if (!(inw(REG_STATUS) & STAT_TXON)) { outw(ptr, REG_TRANSMITPTR); outw(priv->regs.command | CMD_TXON, REG_COMMAND); @@ -599,24 +615,25 @@ printk("%s: transmit timed out, network cable problem?\n", dev->name); dev->tbusy = 0; priv->regs.config2 |= CFG2_CTRLO; - outw(priv->regs.config2, REG_CONFIG2); + outw(priv->regs.config2 , REG_CONFIG2); dev->trans_start = jiffies; goto retry; } } -static void ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void +ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct device *dev = (struct device *) dev_id; + struct device *dev = (struct device *)dev_id; struct dev_priv *priv; unsigned int status; #if NET_DEBUG > 1 - if (net_debug & DEBUG_INT) + if(net_debug & DEBUG_INT) printk("eth3irq: %d ", irq); #endif - priv = (struct dev_priv *) dev->priv; + priv = (struct dev_priv *)dev->priv; dev->interrupt = 1; status = inw(REG_STATUS); @@ -625,12 +642,13 @@ * mostly empty, if we happen to get a RX interrupt, we might as * well handle the TX packets as well. */ - if (status & STAT_INTTX) { /* Packets transmitted */ + if (status & STAT_INTTX) { /* Packets transmitted */ outw(CMD_ACKINTTX | priv->regs.command, REG_COMMAND); ether3_tx(dev, priv); } + status = inw(REG_STATUS); - if (status & STAT_INTRX && ether3_rx(dev, priv, 12)) { /* Got packet(s). */ + if (status & STAT_INTRX && ether3_rx(dev, priv, 12)) { /* Got packet(s). */ /* * We only acknowledge the interrupt if we have received all packets * in the buffer or else we run out of memory. This is to allow the @@ -646,7 +664,7 @@ dev->interrupt = 0; #if NET_DEBUG > 1 - if (net_debug & DEBUG_INT) + if(net_debug & DEBUG_INT) printk("done\n"); #endif } @@ -654,7 +672,8 @@ /* * If we have a good packet(s), get it/them out of the buffers. */ -static int ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt) +static int +ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt) { unsigned int next_ptr = priv->rx_head, received = 0; ether3_ledon(dev, priv); @@ -681,16 +700,17 @@ next_ptr = ntohs(temp_ptr); } ether3_setbuffer(dev, buffer_read, this_ptr); - ether3_readbuffer(dev, addrs + 2, 12); + ether3_readbuffer(dev, addrs+2, 12); /* - * ignore our own packets... - */ - if (!(*(unsigned long *) &dev->dev_addr[0] ^ *(unsigned long *) &addrs[2 + 6]) && - !(*(unsigned short *) &dev->dev_addr[4] ^ *(unsigned short *) &addrs[2 + 10])) { - maxcnt++; /* compensate for loopedback packet */ + * ignore our own packets... + */ + if (!(*(unsigned long *)&dev->dev_addr[0] ^ *(unsigned long *)&addrs[2+6]) && + !(*(unsigned short *)&dev->dev_addr[4] ^ *(unsigned short *)&addrs[2+10])) { + maxcnt ++; /* compensate for loopedback packet */ outw(next_ptr >> 8, REG_RECVEND); - } else if (!(status & (RXSTAT_OVERSIZE | RXSTAT_CRCERROR | RXSTAT_DRIBBLEERROR | RXSTAT_SHORTPACKET))) { + } else + if (!(status & (RXSTAT_OVERSIZE|RXSTAT_CRCERROR|RXSTAT_DRIBBLEERROR|RXSTAT_SHORTPACKET))) { unsigned int length = next_ptr - this_ptr; struct sk_buff *skb; @@ -706,32 +726,28 @@ buf = skb_put(skb, length); ether3_readbuffer(dev, buf + 12, length - 12); outw(next_ptr >> 8, REG_RECVEND); - *(unsigned short *) (buf + 0) = *(unsigned short *) (addrs + 2); - *(unsigned long *) (buf + 2) = *(unsigned long *) (addrs + 4); - *(unsigned long *) (buf + 6) = *(unsigned long *) (addrs + 8); - *(unsigned short *) (buf + 10) = *(unsigned short *) (addrs + 12); + *(unsigned short *)(buf + 0) = *(unsigned short *)(addrs + 2); + *(unsigned long *)(buf + 2) = *(unsigned long *)(addrs + 4); + *(unsigned long *)(buf + 6) = *(unsigned long *)(addrs + 8); + *(unsigned short *)(buf + 10) = *(unsigned short *)(addrs + 12); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - received++; + received ++; } else goto dropping; } else { struct enet_statistics *stats = &priv->stats; outw(next_ptr >> 8, REG_RECVEND); - if (status & RXSTAT_OVERSIZE) - stats->rx_length_errors++; - if (status & RXSTAT_CRCERROR) - stats->rx_crc_errors++; - if (status & RXSTAT_DRIBBLEERROR) - stats->rx_fifo_errors++; - if (status & RXSTAT_SHORTPACKET) - stats->rx_length_errors++; + if (status & RXSTAT_OVERSIZE) stats->rx_length_errors ++; + if (status & RXSTAT_CRCERROR) stats->rx_crc_errors ++; + if (status & RXSTAT_DRIBBLEERROR) stats->rx_fifo_errors ++; + if (status & RXSTAT_SHORTPACKET) stats->rx_length_errors ++; stats->rx_errors++; } } - while (--maxcnt); + while (-- maxcnt); - done: +done: priv->stats.rx_packets += received; priv->rx_head = next_ptr; /* @@ -739,42 +755,44 @@ * have dropped at least one packet. */ if (!(inw(REG_STATUS) & STAT_RXON)) { - priv->stats.rx_dropped++; - outw(next_ptr, REG_RECVPTR); + priv->stats.rx_dropped ++; + outw(next_ptr, REG_RECVPTR); outw(priv->regs.command | CMD_RXON, REG_COMMAND); } + return maxcnt; - dropping:{ - static unsigned long last_warned; +dropping:{ + static unsigned long last_warned; - outw(next_ptr >> 8, REG_RECVEND); - /* - * Don't print this message too many times... - */ - if (jiffies - last_warned > 30 * HZ) { - last_warned = jiffies; - printk("%s: memory squeeze, dropping packet.\n", dev->name); - } - priv->stats.rx_dropped++; - goto done; + outw(next_ptr >> 8, REG_RECVEND); + /* + * Don't print this message too many times... + */ + if (jiffies - last_warned > 30 * HZ) { + last_warned = jiffies; + printk("%s: memory squeeze, dropping packet.\n", dev->name); + } + priv->stats.rx_dropped ++; + goto done; } } /* * Update stats for the transmitted packet(s) */ -static void ether3_tx(struct device *dev, struct dev_priv *priv) +static void +ether3_tx(struct device *dev, struct dev_priv *priv) { unsigned int tx_tail = priv->tx_tail; do { - unsigned long status; - /* - * Read the packet header - */ - ether3_setbuffer(dev, buffer_read, tx_tail); - status = ether3_readlong(dev); + unsigned long status; + /* + * Read the packet header + */ + ether3_setbuffer(dev, buffer_read, tx_tail); + status = ether3_readlong(dev); /* * Check to see if this packet has been transmitted @@ -788,11 +806,9 @@ if (!(status & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS))) priv->stats.tx_packets++; else { - priv->stats.tx_errors++; - if (status & TXSTAT_16COLLISIONS) - priv->stats.collisions += 16; - if (status & TXSTAT_BABBLED) - priv->stats.tx_fifo_errors++; + priv->stats.tx_errors ++; + if (status & TXSTAT_16COLLISIONS) priv->stats.collisions += 16; + if (status & TXSTAT_BABBLED) priv->stats.tx_fifo_errors ++; } /* @@ -824,11 +840,12 @@ static struct device *my_ethers[MAX_ECARDS]; static struct expansion_card *ec[MAX_ECARDS]; -int init_module(void) +int +init_module(void) { int i; - for (i = 0; i < MAX_ECARDS; i++) { + for(i = 0; i < MAX_ECARDS; i++) { my_ethers[i] = NULL; ec[i] = NULL; strcpy(ethernames[i], " "); @@ -842,11 +859,11 @@ if ((ec[i] = ecard_find(0, ether3_cids)) == NULL) break; - my_ethers[i] = (struct device *) kmalloc(sizeof(struct device), GFP_KERNEL); + my_ethers[i] = (struct device *)kmalloc(sizeof(struct device), GFP_KERNEL); memset(my_ethers[i], 0, sizeof(struct device)); my_ethers[i]->irq = ec[i]->irq; - my_ethers[i]->base_addr = ecard_address(ec[i], ECARD_MEMC, 0); + my_ethers[i]->base_addr= ecard_address(ec[i], ECARD_MEMC, 0); my_ethers[i]->init = ether3_probe1; my_ethers[i]->name = ethernames[i]; @@ -854,13 +871,13 @@ ecard_claim(ec[i]); - if (register_netdev(my_ethers[i]) != 0) { + if(register_netdev(my_ethers[i]) != 0) { for (i = 0; i < 4; i++) { - if (my_ethers[i]) { + if(my_ethers[i]) { kfree(my_ethers[i]); my_ethers[i] = NULL; } - if (ec[i]) { + if(ec[i]) { ecard_release(ec[i]); ec[i] = NULL; } @@ -869,28 +886,25 @@ } i++; } - while (i < MAX_ECARDS); + while(i < MAX_ECARDS); return i != 0 ? 0 : -ENODEV; } -void cleanup_module(void) +void +cleanup_module(void) { - if (MOD_IN_USE) { - printk("ether3: device busy, remove delayed\n"); - } else { - int i; - for (i = 0; i < MAX_ECARDS; i++) { - if (my_ethers[i]) { - release_region(my_ethers[i]->base_addr, 128); - unregister_netdev(my_ethers[i]); - my_ethers[i] = NULL; - } - if (ec[i]) { - ecard_release(ec[i]); - ec[i] = NULL; - } + int i; + for (i = 0; i < MAX_ECARDS; i++) { + if (my_ethers[i]) { + release_region(my_ethers[i]->base_addr, 128); + unregister_netdev(my_ethers[i]); + my_ethers[i] = NULL; + } + if (ec[i]) { + ecard_release(ec[i]); + ec[i] = NULL; } } } -#endif /* MODULE */ +#endif /* MODULE */ diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/net/etherh.c linux/drivers/acorn/net/etherh.c --- v2.1.93/linux/drivers/acorn/net/etherh.c Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/net/etherh.c Wed Apr 8 15:51:32 1998 @@ -41,7 +41,7 @@ #include #include -#include "8390.h" +#include "../../net/8390.h" #define NET_DEBUG 0 #define DEBUG_INIT 2 diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/cumana_1.c linux/drivers/acorn/scsi/cumana_1.c --- v2.1.93/linux/drivers/acorn/scsi/cumana_1.c Tue Mar 10 10:03:31 1998 +++ linux/drivers/acorn/scsi/cumana_1.c Wed Apr 8 15:51:32 1998 @@ -33,7 +33,13 @@ */ /* - * $Log: cumana_NCR5380.c,v $ + * $Log: cumana_1.c,v $ + * Revision 1.2 1998/03/08 05:49:46 davem + * Merge to 2.1.89 + * + * Revision 1.1 1998/02/23 02:45:22 davem + * Merge to 2.1.88 + * */ #include diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/cumana_1.h linux/drivers/acorn/scsi/cumana_1.h --- v2.1.93/linux/drivers/acorn/scsi/cumana_1.h Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/scsi/cumana_1.h Wed Apr 8 15:51:32 1998 @@ -23,7 +23,10 @@ */ /* - * $Log: cumana_NCR5380.h,v $ + * $Log: cumana_1.h,v $ + * Revision 1.1 1998/02/23 02:45:22 davem + * Merge to 2.1.88 + * */ #ifndef CUMANA_NCR5380_H diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/cumana_2.c linux/drivers/acorn/scsi/cumana_2.c --- v2.1.93/linux/drivers/acorn/scsi/cumana_2.c Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/scsi/cumana_2.c Wed Apr 8 15:51:32 1998 @@ -114,7 +114,7 @@ unsigned long word; - if (inb (REG0_STATUS(&info->info)) & STATUS_INT) + if (inb (REG_STAT(&info->info)) & STAT_INT) goto end; if (!(inb (info->cstatus) & CSTATUS_DRQ)) @@ -131,7 +131,7 @@ else { if (transfer && (transfer & 255)) { while (length >= 256) { - if (inb (REG0_STATUS(&info->info)) & STATUS_INT) + if (inb (REG_STAT(&info->info)) & STAT_INT) goto end; if (!(inb (info->cstatus) & CSTATUS_DRQ)) @@ -146,7 +146,7 @@ while (length > 0) { unsigned long word; - if (inb (REG0_STATUS(&info->info)) & STATUS_INT) + if (inb (REG_STAT(&info->info)) & STAT_INT) goto end; if (!(inb (info->cstatus) & CSTATUS_DRQ)) diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/ecoscsi.c linux/drivers/acorn/scsi/ecoscsi.c --- v2.1.93/linux/drivers/acorn/scsi/ecoscsi.c Tue Mar 10 10:03:31 1998 +++ linux/drivers/acorn/scsi/ecoscsi.c Wed Apr 8 15:51:32 1998 @@ -32,7 +32,13 @@ */ /* - * $Log: ecoscsi_NCR5380.c,v $ + * $Log: ecoscsi.c,v $ + * Revision 1.2 1998/03/08 05:49:47 davem + * Merge to 2.1.89 + * + * Revision 1.1 1998/02/23 02:45:24 davem + * Merge to 2.1.88 + * */ #include diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/ecoscsi.h linux/drivers/acorn/scsi/ecoscsi.h --- v2.1.93/linux/drivers/acorn/scsi/ecoscsi.h Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/scsi/ecoscsi.h Wed Apr 8 15:51:32 1998 @@ -19,7 +19,10 @@ */ /* - * $Log: ecoscsi_NCR5380.h,v $ + * $Log: ecoscsi.h,v $ + * Revision 1.1 1998/02/23 02:45:24 davem + * Merge to 2.1.88 + * */ #ifndef ECOSCSI_NCR5380_H diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/fas216.c linux/drivers/acorn/scsi/fas216.c --- v2.1.93/linux/drivers/acorn/scsi/fas216.c Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/scsi/fas216.c Wed Apr 8 15:51:32 1998 @@ -37,8 +37,8 @@ #define FAS216_C -#include "scsi.h" -#include "hosts.h" +#include "../../scsi/scsi.h" +#include "../../scsi/hosts.h" #include "fas216.h" #define VER_MAJOR 0 @@ -104,7 +104,7 @@ if (value < 4) value = 4; - else if value > 35) + else if (value > 35) value = 35; return value & 31; @@ -1269,6 +1269,46 @@ *SCpntp2 = NULL; } +/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt) + * Purpose : abort this command + * Params : SCpnt - command to abort + * Returns : FAILED if unable to abort + */ +int fas216_eh_abort(Scsi_Cmnd *SCpnt) +{ + return FAILED; +} + +/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt) + * Purpose : Reset the device associated with this command + * Params : SCpnt - command specifing device to reset + * Returns : FAILED if unable to reset + */ +int fas216_eh_device_reset(Scsi_Cmnd *SCpnt) +{ + return FAILED; +} + +/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt) + * Purpose : Reset the complete bus associated with this command + * Params : SCpnt - command specifing bus to reset + * Returns : FAILED if unable to reset + */ +int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt) +{ + return FAILED; +} + +/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt) + * Purpose : Reset the host associated with this command + * Params : SCpnt - command specifing host to reset + * Returns : FAILED if unable to reset + */ +int fas216_eh_host_reset(Scsi_Cmnd *SCpnt) +{ + return FAILED; +} + /* Function: int fas216_abort (Scsi_Cmnd *SCpnt) * Purpose : abort a command if something horrible happens. * Params : SCpnt - Command that is believed to be causing a problem. @@ -1352,7 +1392,7 @@ #else info->device[i].disconnect_ok = 0; #endif - info->device[i].stp = fas216_syncperiod(info->ifcfg.asyncperiod); + info->device[i].stp = fas216_syncperiod(info, info->ifcfg.asyncperiod); info->device[i].sof = 0; #ifdef SCSI2SYNC info->device[i].negstate = syncneg_start; @@ -1374,7 +1414,7 @@ outb(info->scsi.cfg[2], REG_CNTL3(info)); outb(info->ifcfg.select_timeout, REG_STIM(info)); outb(0, REG_SOF(info)); - outb(fas216_syncperiod(info->ifcfg.asyncperiod), REG_STP(info)); + outb(fas216_syncperiod(info, info->ifcfg.asyncperiod), REG_STP(info)); outb(info->scsi.cfg[0], REG_CNTL1(info)); } @@ -1465,7 +1505,7 @@ info->host = instance; info->scsi.cfg[0] = instance->this_id; info->scsi.cfg[1] = CNTL2_ENF | CNTL2_S2FE; - info->scsi.cfg[2] = CNTL3_ADDIDCHK | CNTL3_G2CB | CNTL3_FASTSCSI | CNTL3_FASTCLK; + info->scsi.cfg[2] = CNTL3_ADIDCHK | CNTL3_G2CB | CNTL3_FASTSCSI | CNTL3_FASTCLK; info->scsi.type = "unknown"; info->SCpnt = NULL; fas216_reset_state(info); @@ -1500,7 +1540,7 @@ } - outb(CNTL3_IDENABLE, REG_CNTL3(info)); + outb(CNTL3_ADIDCHK, REG_CNTL3(info)); outb(0, REG_CNTL3(info)); outb(CMD_RESETCHIP, REG_CMD(info)); @@ -1562,6 +1602,11 @@ EXPORT_SYMBOL(fas216_command); EXPORT_SYMBOL(fas216_intr); EXPORT_SYMBOL(fas216_release); +EXPORT_SYMBOL(fas216_eh_abort); +EXPORT_SYMBOL(fas216_eh_device_reset); +EXPORT_SYMBOL(fas216_eh_bus_reset); +EXPORT_SYMBOL(fas216_eh_host_reset); + #ifdef MODULE int init_module (void) diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/fas216.h linux/drivers/acorn/scsi/fas216.h --- v2.1.93/linux/drivers/acorn/scsi/fas216.h Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/scsi/fas216.h Wed Apr 8 15:51:32 1998 @@ -196,7 +196,7 @@ typedef enum { syncneg_start, /* Negociate with device for Sync xfers */ syncneg_sent, /* Sync Xfer negociation sent */ - syncnsg_complete /* Sync Xfer complete */ + syncneg_complete /* Sync Xfer complete */ } syncneg_t; typedef struct { @@ -277,81 +277,82 @@ int internal_done; /* flag to indicate request done */ } FAS216_Info; -/* - * Function: int fas216_init (struct Scsi_Host *instance) - * +/* Function: int fas216_init (struct Scsi_Host *instance) * Purpose : initialise FAS/NCR/AMD SCSI ic. - * * Params : instance - a driver-specific filled-out structure - * * Returns : 0 on success */ extern int fas216_init (struct Scsi_Host *instance); -/* - * Function: int fas216_abort (Scsi_Cmnd *SCpnt) - * +/* Function: int fas216_abort (Scsi_Cmnd *SCpnt) * Purpose : abort a command if something horrible happens. - * * Params : SCpnt - Command that is believed to be causing a problem. - * * Returns : one of SCSI_ABORT_ macros. */ extern int fas216_abort (Scsi_Cmnd *); -/* - * Function: int fas216_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) - * +/* Function: int fas216_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) * Purpose : resets the adapter if something horrible happens. - * * Params : SCpnt - Command that is believed to be causing a problem. * reset_flags - flags indicating reset type that is believed to be required. - * * Returns : one of SCSI_RESET_ macros, or'd with the SCSI_RESET_*_RESET macros. */ extern int fas216_reset (Scsi_Cmnd *, unsigned int); -/* - * Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) - * +/* Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) * Purpose : queue a command for adapter to process. - * * Params : SCpnt - Command to queue * done - done function to call once command is complete - * * Returns : 0 - success, else error */ extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -/* - * Function: int fas216_command (Scsi_Cmnd *SCpnt) - * +/* Function: int fas216_command (Scsi_Cmnd *SCpnt) * Purpose : queue a command for adapter to process. - * * Params : SCpnt - Command to queue - * * Returns : scsi result code */ extern int fas216_command (Scsi_Cmnd *); -/* - * Function: void fas216_intr (struct Scsi_Host *instance) - * +/* Function: void fas216_intr (struct Scsi_Host *instance) * Purpose : handle interrupts from the interface to progress a command - * * Params : instance - interface to service */ extern void fas216_intr (struct Scsi_Host *instance); -/* - * Function: int fas216_release (struct Scsi_Host *instance) - * +/* Function: int fas216_release (struct Scsi_Host *instance) * Purpose : release all resources and put everything to bed for FAS/NCR/AMD SCSI ic. - * * Params : instance - a driver-specific filled-out structure - * * Returns : 0 on success */ extern int fas216_release (struct Scsi_Host *instance); + +/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt) + * Purpose : abort this command + * Params : SCpnt - command to abort + * Returns : FAILED if unable to abort + */ +extern int fas216_eh_abort(Scsi_Cmnd *SCpnt); + +/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt) + * Purpose : Reset the device associated with this command + * Params : SCpnt - command specifing device to reset + * Returns : FAILED if unable to reset + */ +extern int fas216_eh_device_reset(Scsi_Cmnd *SCpnt); + +/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt) + * Purpose : Reset the complete bus associated with this command + * Params : SCpnt - command specifing bus to reset + * Returns : FAILED if unable to reset + */ +extern int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt); + +/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt) + * Purpose : Reset the host associated with this command + * Params : SCpnt - command specifing host to reset + * Returns : FAILED if unable to reset + */ +extern int fas216_eh_host_reset(Scsi_Cmnd *SCpnt); #endif /* FAS216_H */ diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/oak.c linux/drivers/acorn/scsi/oak.c --- v2.1.93/linux/drivers/acorn/scsi/oak.c Tue Mar 10 10:03:31 1998 +++ linux/drivers/acorn/scsi/oak.c Wed Apr 8 15:51:32 1998 @@ -33,6 +33,12 @@ /* * $Log: oak.c,v $ + * Revision 1.2 1998/03/08 05:49:48 davem + * Merge to 2.1.89 + * + * Revision 1.1 1998/02/23 02:45:27 davem + * Merge to 2.1.88 + * */ #include diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/oak.h linux/drivers/acorn/scsi/oak.h --- v2.1.93/linux/drivers/acorn/scsi/oak.h Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/scsi/oak.h Wed Apr 8 15:51:32 1998 @@ -23,7 +23,10 @@ */ /* - * $Log: oak_NCR5380.h,v $ + * $Log: oak.h,v $ + * Revision 1.1 1998/02/23 02:45:27 davem + * Merge to 2.1.88 + * */ #ifndef OAK_NCR5380_H diff -u --recursive --new-file v2.1.93/linux/drivers/acorn/scsi/powertec.h linux/drivers/acorn/scsi/powertec.h --- v2.1.93/linux/drivers/acorn/scsi/powertec.h Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/scsi/powertec.h Wed Apr 8 15:51:32 1998 @@ -53,7 +53,13 @@ this_id: SCSI_ID, /* scsi host id */ \ sg_tablesize: SG_ALL, /* sg_tablesize */ \ cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \ -use_clustering: ENABLE_CLUSTERING \ +use_clustering: ENABLE_CLUSTERING, \ +eh_strategy_handler: NULL, \ +eh_host_reset_handler: fas216_eh_host_reset, \ +eh_bus_reset_handler: fas216_eh_bus_reset, \ +eh_device_reset_handler: fas216_eh_device_reset, \ +eh_abort_handler: fas216_eh_abort, \ +use_new_eh_code: 0 \ } #ifndef HOSTS_C diff -u --recursive --new-file v2.1.93/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c --- v2.1.93/linux/drivers/block/ide-proc.c Mon Apr 6 17:40:59 1998 +++ linux/drivers/block/ide-proc.c Tue Apr 7 07:48:54 1998 @@ -254,11 +254,13 @@ static int proc_ide_read_config (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_hwif_t *hwif = (ide_hwif_t *)data; char *out = page; - int len, reg = 0; + int len; #ifdef CONFIG_BLK_DEV_IDEPCI + ide_hwif_t *hwif = (ide_hwif_t *)data; + int reg = 0; + struct pci_dev *dev = hwif->pci_dev; out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n", diff -u --recursive --new-file v2.1.93/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.1.93/linux/drivers/char/Config.in Tue Mar 17 22:18:14 1998 +++ linux/drivers/char/Config.in Wed Apr 8 17:24:48 1998 @@ -117,6 +117,13 @@ dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV 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 + if [ "$CONFIG_VIDEO_SAA5249" != "n" ]; then + define_bool CONFIG_BUS_I2C $CONFIG_VIDEO_SAA5249 + fi + if [ "$CONFIG_VIDEO_BT848" != "n" ]; then + define_bool CONFIG_BUS_I2C $CONFIG_VIDEO_BT848 + fi fi tristate '/dev/nvram support' CONFIG_NVRAM tristate 'PC joystick support' CONFIG_JOYSTICK diff -u --recursive --new-file v2.1.93/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.1.93/linux/drivers/char/Makefile Mon Apr 6 17:40:59 1998 +++ linux/drivers/char/Makefile Wed Apr 8 17:24:48 1998 @@ -302,11 +302,27 @@ endif endif +ifeq ($(CONFIG_BUS_I2C),y) + LX_OBJS += i2c.o +else + ifeq ($(CONFIG_BUS_I2C),m) + MX_OBJS += i2c.o + endif +endif + ifeq ($(CONFIG_VIDEO_BT848),y) -L_OBJS += bttv.o +L_OBJS += bttv.o msp3400.o tuner.o else ifeq ($(CONFIG_VIDEO_BT848),m) - M_OBJS += bttv.o + M_OBJS += bttv.o msp3400.o tuner.o + endif +endif + +ifeq ($(CONFIG_VIDEO_SAA5249),y) +L_OBJS += saa5249.o +else + ifeq ($(CONFIG_VIDEO_SAA5249),m) + M_OBJS += saa5249.o endif endif @@ -330,7 +346,7 @@ L_OBJS += pms.o else ifeq ($(CONFIG_VIDEO_PMS),m) - M_OBJS += pms.o + M_OBJS += pms.o endif endif diff -u --recursive --new-file v2.1.93/linux/drivers/char/bt848.h linux/drivers/char/bt848.h --- v2.1.93/linux/drivers/char/bt848.h Sat Nov 29 10:33:19 1997 +++ linux/drivers/char/bt848.h Wed Apr 8 17:24:48 1998 @@ -1,7 +1,7 @@ /* bt848.h - Bt848 register offsets - Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,13 +22,15 @@ #define _BT848_H_ #ifndef PCI_VENDOR_ID_BROOKTREE -#define PCI_VENDOR_ID_BROOKTREE 0x109e +#define PCI_VENDOR_ID_BROOKTREE 0x109e #endif #ifndef PCI_DEVICE_ID_BT848 -#define PCI_DEVICE_ID_BT848 0x350 +#define PCI_DEVICE_ID_BT848 0x350 +#endif +#ifndef PCI_DEVICE_ID_BT849 +#define PCI_DEVICE_ID_BT849 0x351 #endif -#define RISCMEM_LEN 131040 /* Brooktree 848 registers */ diff -u --recursive --new-file v2.1.93/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.1.93/linux/drivers/char/bttv.c Mon Feb 23 18:12:04 1998 +++ linux/drivers/char/bttv.c Wed Apr 8 17:24:48 1998 @@ -1,7 +1,8 @@ /* bttv - Bt848 frame grabber driver - Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,10 +21,20 @@ Modified to put the RISC code writer in the kernel and to fit a common (and I hope safe) kernel interface. When we have an X extension all will now be really sweet. + + TODO: + + * think of some good ioctls for Video4Linux to handle + YUV, planar YUV, ... grabs and sell them to AC :-) + * move norm from tuner to channel struct!? + composite source from a satellite tuner can deliver different norms + depending on tuned channel + * mmap VBI data? */ #include #include +#include #include #include #include @@ -39,21 +50,31 @@ #include #include #include -#include +#include +#include #include #include +#include "i2c.h" #include "bttv.h" #include "tuner.h" #define DEBUG(x) /* Debug driver */ -#define IDEBUG(x) /* Debug interrupt handler */ +#define IDEBUG(x) /* Debug interrupt handler */ -static unsigned int remap=0; -static unsigned int vidmem=0; -static unsigned int tuner=0; /* Default tuner */ -MODULE_PARM(tuner,"i"); +static unsigned int remap=0; /* remap Bt848 */ +static unsigned int vidmem=0; /* manually set video mem address */ +static int triton1=0; +static int radio=0; + +static unsigned int card=0; + +MODULE_PARM(remap,"i"); +MODULE_PARM(vidmem,"i"); +MODULE_PARM(triton1,"i"); +MODULE_PARM(radio,"i"); +MODULE_PARM(card,"i"); static int find_vga(void); static void bt848_set_risc_jmps(struct bttv *btv); @@ -61,17 +82,21 @@ /* Anybody who uses more than four? */ #define BTTV_MAX 4 -static int bttv_num; +static int bttv_num; /* number of Bt848s in use */ static struct bttv bttvs[BTTV_MAX]; #define I2C_TIMING (0x7<<4) #define I2C_COMMAND (I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA) +#define I2C_DELAY 10 +#define I2C_SET(CTRL,DATA) \ + { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); } +#define I2C_GET() (btread(BT848_I2C)&1) + #define AUDIO_MUTE_DELAY 10000 #define FREQ_CHANGE_DELAY 20000 #define EEPROM_WRITE_DELAY 20000 - /*******************************/ /* Memory management functions */ /*******************************/ @@ -79,56 +104,137 @@ /* convert virtual user memory address to physical address */ /* (virt_to_phys only works for kmalloced kernel memory) */ -static inline ulong uvirt_to_phys(ulong adr) +static inline unsigned long uvirt_to_phys(unsigned long adr) { pgd_t *pgd; pmd_t *pmd; pte_t *ptep, pte; -/* printk("adr: 0x%08x\n",adr);*/ pgd = pgd_offset(current->mm, adr); -/* printk("pgd: 0x%08x\n",pgd);*/ if (pgd_none(*pgd)) return 0; pmd = pmd_offset(pgd, adr); -/* printk("pmd: 0x%08x\n",pmd); */ if (pmd_none(*pmd)) return 0; - ptep = pte_offset(pmd, adr&(~PGDIR_MASK)); + ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/); pte = *ptep; if(pte_present(pte)) - return (pte_page(pte)|(adr&(PAGE_SIZE-1))); + return + virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1)))); return 0; } +static inline unsigned long uvirt_to_bus(unsigned long adr) +{ + /* printk("adr: 0x%8x, ",adr); + printk("phys: 0x%8x, ",(uvirt_to_phys(adr))); + printk("bus: 0x%8x\n",virt_to_bus(phys_to_virt(uvirt_to_phys(adr)))); + */ + return virt_to_bus(phys_to_virt(uvirt_to_phys(adr))); +} + /* convert virtual kernel memory address to physical address */ /* (virt_to_phys only works for kmalloced kernel memory) */ -static inline ulong kvirt_to_phys(ulong adr) +static inline unsigned long kvirt_to_phys(unsigned long adr) { return uvirt_to_phys(VMALLOC_VMADDR(adr)); } -static inline ulong kvirt_to_bus(ulong adr) +static inline unsigned long kvirt_to_bus(unsigned long adr) { - return virt_to_bus(phys_to_virt(kvirt_to_phys(adr))); + return uvirt_to_bus(VMALLOC_VMADDR(adr)); } +static void * rvmalloc(unsigned long size) +{ + void * mem; + unsigned long adr, page; + + mem=vmalloc(size); + if (mem) + { + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_phys(adr); + mem_map_reserve(MAP_NR(phys_to_virt(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} -/*****************/ -/* I2C functions */ -/*****************/ +static void rvfree(void * mem, unsigned long size) +{ + unsigned long adr, page; + + if (mem) + { + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_phys(adr); + mem_map_unreserve(MAP_NR(phys_to_virt(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } +} -static int I2CRead(struct bttv *btv, int addr) +/* + * Create the giant waste of buffer space we need for now + * until we get DMA to user space sorted out (probably 2.3.x) + * + * We only create this as and when someone uses mmap + */ + +static int fbuffer_alloc(struct bttv *btv) +{ + if(!btv->fbuffer) + btv->fbuffer=(unsigned char *) rvmalloc(2*0x144000); + else + printk(KERN_ERR "bttv: Double alloc of fbuffer!\n"); + if(!btv->fbuffer) + return -ENOBUFS; + return 0; +} + + +/* ----------------------------------------------------------------------- */ +/* I2C functions */ + +/* software I2C functions */ + +static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data) +{ + struct bttv *btv = (struct bttv*)bus->data; + btwrite((ctrl<<1)|data, BT848_I2C); + udelay(I2C_DELAY); +} + +static int i2c_getdataline(struct i2c_bus *bus) +{ + struct bttv *btv = (struct bttv*)bus->data; + return btread(BT848_I2C)&1; +} + +/* hardware I2C functions */ + +/* read I2C */ +static int I2CRead(struct i2c_bus *bus, unsigned char addr) { u32 i; u32 stat; + struct bttv *btv = (struct bttv*)bus->data; /* clear status bit ; BT848_INT_RACK is ro */ btwrite(BT848_INT_I2CDONE, BT848_INT_STAT); btwrite(((addr & 0xff) << 24) | I2C_COMMAND, BT848_I2C); - + /* * Timeout for I2CRead is 1 second (this should be enough, really!) */ @@ -136,11 +242,12 @@ { stat=btread(BT848_INT_STAT); if (stat & BT848_INT_I2CDONE) - break; - udelay(1000); /* 1ms, as I2C is 1kHz (?) */ + break; + udelay(1000); } - if (!i) { + if (!i) + { printk(KERN_DEBUG "bttv: I2CRead timeout\n"); return -1; } @@ -153,12 +260,13 @@ /* set both to write both bytes, reset it to write only b1 */ -static int I2CWrite(struct bttv *btv, unchar addr, unchar b1, - unchar b2, int both) +static int I2CWrite(struct i2c_bus *bus, unsigned char addr, unsigned char b1, + unsigned char b2, int both) { u32 i; u32 data; u32 stat; + struct bttv *btv = (struct bttv*)bus->data; /* clear status bit; BT848_INT_RACK is ro */ btwrite(BT848_INT_I2CDONE, BT848_INT_STAT); @@ -172,15 +280,16 @@ btwrite(data, BT848_I2C); - for (i=1000; i; i--) + for (i=0x1000; i; i--) { stat=btread(BT848_INT_STAT); if (stat & BT848_INT_I2CDONE) break; - udelay(1000); + udelay(1000); } - if (!i) { + if (!i) + { printk(KERN_DEBUG "bttv: I2CWrite timeout\n"); return -1; } @@ -190,19 +299,20 @@ return 0; } -static void readee(struct bttv *btv, unchar *eedata) +/* read EEPROM */ +static void readee(struct i2c_bus *bus, unsigned char *eedata) { int i, k; - - if (I2CWrite(btv, 0xa0, 0, -1, 0)<0) + + if (I2CWrite(bus, 0xa0, 0, -1, 0)<0) { printk(KERN_WARNING "bttv: readee error\n"); return; } - + for (i=0; i<256; i++) { - k=I2CRead(btv, 0xa1); + k=I2CRead(bus, 0xa1); if (k<0) { printk(KERN_WARNING "bttv: readee error\n"); @@ -212,13 +322,14 @@ } } -static void writeee(struct bttv *btv, unchar *eedata) +/* write EEPROM */ +static void writeee(struct i2c_bus *bus, unsigned char *eedata) { int i; for (i=0; i<256; i++) { - if (I2CWrite(btv, 0xa0, i, eedata[i], 1)<0) + if (I2CWrite(bus, 0xa0, i, eedata[i], 1)<0) { printk(KERN_WARNING "bttv: writeee error (%d)\n", i); break; @@ -227,28 +338,91 @@ } } +void attach_inform(struct i2c_bus *bus, int id) +{ + struct bttv *btv = (struct bttv*)bus->data; + int tunertype; + + switch (id) + { + case I2C_DRIVERID_MSP3400: + btv->have_msp3400 = 1; + break; + case I2C_DRIVERID_TUNER: + btv->have_tuner = 1; + if (btv->type == BTTV_MIRO) + { + tunertype=((btread(BT848_GPIO_DATA)>>10)-1)&7; + i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER, + TUNER_SET_TYPE,&tunertype); + } + break; + } +} + +void detach_inform(struct i2c_bus *bus, int id) +{ + struct bttv *btv = (struct bttv*)bus->data; + + switch (id) + { + case I2C_DRIVERID_MSP3400: + btv->have_msp3400 = 0; + break; + case I2C_DRIVERID_TUNER: + btv->have_tuner = 0; + break; + } +} + +static struct i2c_bus bttv_i2c_bus_template = +{ + "bt848", + I2C_BUSID_BT848, + NULL, + + SPIN_LOCK_UNLOCKED, + + attach_inform, + detach_inform, + + i2c_setlines, + i2c_getdataline, + I2CRead, + I2CWrite, +}; + +/* ----------------------------------------------------------------------- */ + /* - * Tuner, internal, external and mute + * Tuner, Radio, internal, external and mute */ -static unchar audiomuxs[][4] = +static unsigned char audiomuxs[][5] = { - { 0x00, 0x00, 0x00, 0x00}, /* unknown */ - { 0x02, 0x00, 0x00, 0x0a}, /* MIRO */ - { 0x00, 0x02, 0x03, 0x04}, /* Hauppauge */ - { 0x04, 0x02, 0x03, 0x01}, /* STB */ - { 0x01, 0x02, 0x03, 0x04}, /* Intel??? */ - { 0x01, 0x02, 0x03, 0x04}, /* Diamond DTV2000??? */ + { 0x00, 0x00, 0x00, 0x00, 0x00}, /* unknown */ + { 0x02, 0x00, 0x00, 0x00, 0x0a}, /* MIRO */ + { 0x00, 0x01, 0x02, 0x03, 0x04}, /* Hauppauge */ + { 0x04, 0x00, 0x02, 0x03, 0x01}, /* STB */ + { 0x00, 0x01, 0x02, 0x03, 0x04}, /* Intel??? */ + { 0x00, 0x01, 0x02, 0x03, 0x04}, /* Diamond DTV2000 */ + { 0x0c, 0x00, 0x0b, 0x0b, 0x00}, /* AVerMedia TVPhone */ }; static void audio(struct bttv *btv, int mode) { + /* enable least significant GPIO output nibble */ btwrite(0x0f, BT848_GPIO_OUT_EN); + + /* select direct input */ btwrite(0x00, BT848_GPIO_REG_INP); switch (mode) { - case AUDIO_UNMUTE: + case AUDIO_MUTE: + btv->audio|=AUDIO_MUTE; + break; + case AUDIO_UNMUTE: btv->audio&=~AUDIO_MUTE; mode=btv->audio; break; @@ -263,8 +437,12 @@ btv->audio|=mode; break; } - if ((btv->audio&AUDIO_MUTE) || !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)) - mode=AUDIO_OFF; + /* if audio mute or not in H-lock, turn audio off */ + if ((btv->audio&AUDIO_MUTE) || + (!btv->radio && !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))) + mode=AUDIO_OFF; + if ((mode == 0) && (btv->radio)) + mode = 1; btaor(audiomuxs[btv->type][mode] , ~0x0f, BT848_GPIO_DATA); } @@ -319,11 +497,19 @@ #define VBIBUF_SIZE 65536 +/* Maximum sample number per VBI line is 2044, can NTSC deliver this? + Note that we write 2048-aligned to keep alignment to memory pages +*/ +#define VBI_SPL 2044 + +/* RISC command to write one VBI data line */ +#define VBI_RISC BT848_RISC_WRITE|VBI_SPL|BT848_RISC_EOL|BT848_RISC_SOL + static void make_vbitab(struct bttv *btv) { int i; - dword *po=(dword *) btv->vbi_odd; - dword *pe=(dword *) btv->vbi_even; + unsigned int *po=(unsigned int *) btv->vbi_odd; + unsigned int *pe=(unsigned int *) btv->vbi_even; DEBUG(printk(KERN_DEBUG "vbiodd: 0x%08x\n",(int)btv->vbi_odd)); DEBUG(printk(KERN_DEBUG "vbievn: 0x%08x\n",(int)btv->vbi_even)); @@ -333,8 +519,8 @@ *(po++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(po++)=0; for (i=0; i<16; i++) { - *(po++)=BT848_RISC_WRITE|2044|BT848_RISC_EOL|BT848_RISC_SOL|(13<<20); - *(po++)=kvirt_to_bus((ulong)btv->vbibuf+i*2048); + *(po++)=VBI_RISC; + *(po++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048); } *(po++)=BT848_RISC_JUMP; *(po++)=virt_to_bus(btv->risc_jmp+4); @@ -342,11 +528,129 @@ *(pe++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(pe++)=0; for (i=16; i<32; i++) { - *(pe++)=BT848_RISC_WRITE|2044|BT848_RISC_EOL|BT848_RISC_SOL; - *(pe++)=kvirt_to_bus((ulong)btv->vbibuf+i*2048); + *(pe++)=VBI_RISC; + *(pe++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048); } *(pe++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16); *(pe++)=virt_to_bus(btv->risc_jmp+10); + DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po)); + DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe)); +} + +int fmtbppx2[16] = { + 8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0 +}; + +static int make_vrisctab(struct bttv *btv, unsigned int *ro, unsigned int *re, + unsigned int *vbuf, unsigned short width, unsigned short height, unsigned short fmt) +{ + unsigned long line; + unsigned long bpl; /* bytes per line */ + unsigned long bl; + unsigned long todo; + unsigned int **rp; + int inter; + unsigned long vadr=(unsigned long) vbuf; + + inter = (height>btv->win.cropheight/2) ? 1 : 0; + bpl=width*fmtbppx2[fmt&0xf]/2; + + *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0; + *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0; + + for (line=0; line < (height<<(1^inter)); line++) + { + if (inter) + rp= (line&1) ? &re : &ro; + else + rp= (line>height) ? &re : &ro; + + bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr); + if (bpl<=bl) + { + *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL| + BT848_RISC_EOL|bpl; + *((*rp)++)=kvirt_to_bus(vadr); + vadr+=bpl; + } + else + { + todo=bpl; + *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL|bl; + *((*rp)++)=kvirt_to_bus(vadr); + vadr+=bl; + todo-=bl; + while (todo>PAGE_SIZE) + { + *((*rp)++)=BT848_RISC_WRITE|PAGE_SIZE; + *((*rp)++)=kvirt_to_bus(vadr); + vadr+=PAGE_SIZE; + todo-=PAGE_SIZE; + } + *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_EOL|todo; + *((*rp)++)=kvirt_to_bus(vadr); + vadr+=todo; + } + } + + *(ro++)=BT848_RISC_JUMP; + *(ro++)=btv->bus_vbi_even; + *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16); + *(re++)=btv->bus_vbi_odd; + + return 0; +} + +/* does this really make a difference ???? */ +#define BURST_MAX 4096 + +static inline void write_risc_segment(unsigned int **rp, unsigned long line_adr, unsigned int command, + int *x, uint dx, uint bpp, uint width) +{ + unsigned int flags, len; + + if (!dx) + return; + len=dx*bpp; + +#ifdef LIMIT_DMA + if (command==BT848_RISC_WRITEC) + { + unsigned int dx2=BURST_MAX/bpp; + while (len>BURST_MAX) + { + write_risc_segment(rp, line_adr, command, + &x,dx2, bpp, width); + dx-=dx2; + len=dx*bpp; + } + } +#endif + + /* mask upper 8 bits for 24+8 bit overlay modes */ + flags = ((bpp==4) ? BT848_RISC_BYTE3 : 0); + + if (*x==0) + { + if (command==BT848_RISC_SKIP) + { + if (dx>8, BT848_E_HSCALE_HI+off); + btwrite(hscale&0xff, BT848_E_HSCALE_LO+off); + btaor((vscale>>8), 0xc0, BT848_E_VSCALE_HI+off); + btwrite(vscale&0xff, BT848_E_VSCALE_LO+off); + btwrite(hactive&0xff, BT848_E_HACTIVE_LO+off); + btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off); + btwrite(vactive&0xff, BT848_E_VACTIVE_LO+off); + btwrite(vdelay&0xff, BT848_E_VDELAY_LO+off); + btwrite(crop, BT848_E_CROP+off); +} + + +static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt) { - u16 vscale, hscale; + u16 vscale, hscale; u32 xsf, sr; u16 hdelay, vdelay; u16 hactive, vactive; u16 inter; - u8 crop; - - /* - * No window , no try... - */ - - if (!btv->win.width) - return; - if (!btv->win.height) - return; - - inter=(btv->win.interlace&1)^1; + u8 crop, vtc; + struct tvnorm *tvn; + + if (!width || !height) + return; - switch (btv->win.bpp) - { - /* - * RGB8 seems to be a 9x5x5 GRB color cube starting at color 16 - * Why the h... can't they even mention this in the datasheet??? - */ - case 1: - btwrite(BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT); - btand(~0x10, BT848_CAP_CTL); /* Dithering looks much better in this mode */ - break; - case 2: - btwrite(BT848_COLOR_FMT_RGB16, BT848_COLOR_FMT); - btor(0x10, BT848_CAP_CTL); - break; - case 3: - btwrite(BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT); - btor(0x10, BT848_CAP_CTL); - break; - case 4: - btwrite(BT848_COLOR_FMT_RGB32, BT848_COLOR_FMT); - btor(0x10, BT848_CAP_CTL); - break; - } + tvn=&tvnorms[btv->win.norm]; - /* - * Set things up according to the final picture width. - */ - - hactive=btv->win.width; - if (hactive < 193) - { - btwrite (2, BT848_E_VTC); - btwrite (2, BT848_O_VTC); - } - else if (hactive < 385) - { - btwrite (1, BT848_E_VTC); - btwrite (1, BT848_O_VTC); - } - else - { - btwrite (0, BT848_E_VTC); - btwrite (0, BT848_O_VTC); - } + if (btv->win.cropwidth>tvn->cropwidth) + btv->win.cropwidth=tvn->cropwidth; + if (btv->win.cropheight>tvn->cropheight) + btv->win.cropheight=tvn->cropheight; + + if (width>btv->win.cropwidth) + width=btv->win.cropwidth; + if (height>btv->win.cropheight) + height=btv->win.cropheight; + + btwrite(tvn->adelay, BT848_ADELAY); + btwrite(tvn->bdelay, BT848_BDELAY); + btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM); + + btwrite(fmt, BT848_COLOR_FMT); + hactive=width; + + vtc=0; + /* Some people say interpolation looks bad ... */ + /* vtc = (hactive < 193) ? 2 : ((hactive < 385) ? 1 : 0); */ + + btv->win.interlace = (height>btv->win.cropheight/2) ? 1 : 0; + inter=(btv->win.interlace&1)^1; + xsf = (hactive*tvn->scaledtwidth)/btv->win.cropwidth; + hscale = ((tvn->totalwidth*4096UL)/xsf-4096); + vdelay=btv->win.cropy+tvn->vdelay; + + hdelay=(tvn->hdelayx1*tvn->scaledtwidth)/tvn->totalwidth; + hdelay=((hdelay+btv->win.cropx)*hactive)/btv->win.cropwidth; + hdelay&=0x3fe; - /* - * Ok are we doing Never The Same Color or PAL ? - */ - - if (btv->win.norm==1) - { - btv->win.cropwidth=640; - btv->win.cropheight=480; - btwrite(0x68, BT848_ADELAY); - btwrite(0x5d, BT848_BDELAY); - btaor(BT848_IFORM_NTSC, ~7, BT848_IFORM); - btaor(BT848_IFORM_XT0, ~0x18, BT848_IFORM); - xsf = (btv->win.width*365625UL)/300000UL; - hscale = ((910UL*4096UL)/xsf-4096); - vdelay=btv->win.cropy+0x16; - hdelay=((hactive*135)/754+btv->win.cropx)&0x3fe; - } - else - { - btv->win.cropwidth=768; - btv->win.cropheight=576; - if (btv->win.norm==0) - { - btwrite(0x7f, BT848_ADELAY); - btwrite(0x72, BT848_BDELAY); - btaor(BT848_IFORM_PAL_BDGHI, ~BT848_IFORM_NORM, BT848_IFORM); - } - else - { - btwrite(0x7f, BT848_ADELAY); - btwrite(0x00, BT848_BDELAY); - btaor(BT848_IFORM_SECAM, ~BT848_IFORM_NORM, BT848_IFORM); - } - btaor(BT848_IFORM_XT1, ~0x18, BT848_IFORM); - xsf = (btv->win.width*36875UL)/30000UL; - hscale = ((1135UL*4096UL)/xsf-4096); - vdelay=btv->win.cropy+0x20; - hdelay=((hactive*186)/922+btv->win.cropx)&0x3fe; - } - sr=((btv->win.cropheight>>inter)*512)/btv->win.height-512; + sr=((btv->win.cropheight>>inter)*512)/height-512; vscale=(0x10000UL-sr)&0x1fff; vactive=btv->win.cropheight; + crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)| + ((vactive>>4)&0x30)|((vdelay>>2)&0xc0); + vscale|= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0; + + bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, vactive, + hdelay, vdelay, crop); + bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive, + hdelay, vdelay, crop); + +} -#if 0 - printk("bttv: hscale=0x%04x, ",hscale); - printk("bttv: vscale=0x%04x\n",vscale); - - printk("bttv: hdelay =0x%04x\n",hdelay); - printk("bttv: hactive=0x%04x\n",hactive); - printk("bttv: vdelay =0x%04x\n",vdelay); - printk("bttv: vactive=0x%04x\n",vactive); -#endif - /* - * Interlace is set elsewhere according to the final image - * size we desire - */ - - if (btv->win.interlace) - { - btor(BT848_VSCALE_INT, BT848_E_VSCALE_HI); - btor(BT848_VSCALE_INT, BT848_O_VSCALE_HI); - } - else +int bpp2fmt[4] = { + BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, + BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 +}; + +static void bt848_set_winsize(struct bttv *btv) +{ + unsigned short format; + int bpp; + + bpp=fmtbppx2[btv->win.color_fmt&0x0f]/2; + if (btv->win.bpp == 0) { - btand(~BT848_VSCALE_INT, BT848_E_VSCALE_HI); - btand(~BT848_VSCALE_INT, BT848_O_VSCALE_HI); + btv->win.bpp=bpp; + format=btv->win.color_fmt; } - - /* - * Load her up + else if (btv->win.bpp!=bpp) + btv->win.color_fmt=format=bpp2fmt[(btv->win.bpp-1)&3]; + else + format=btv->win.color_fmt; + + /* RGB8 seems to be a 9x5x5 GRB color cube starting at + * color 16. Why the h... can't they even mention this in the + * datasheet??? [AC - because its a standard format so I guess + * it never occured them] + * Enable dithering in this mode */ - - btwrite(hscale>>8, BT848_E_HSCALE_HI); - btwrite(hscale>>8, BT848_O_HSCALE_HI); - btwrite(hscale&0xff, BT848_E_HSCALE_LO); - btwrite(hscale&0xff, BT848_O_HSCALE_LO); - - btwrite((vscale>>8)|(btread(BT848_E_VSCALE_HI)&0xe0), BT848_E_VSCALE_HI); - btwrite((vscale>>8)|(btread(BT848_O_VSCALE_HI)&0xe0), BT848_O_VSCALE_HI); - btwrite(vscale&0xff, BT848_E_VSCALE_LO); - btwrite(vscale&0xff, BT848_O_VSCALE_LO); - - btwrite(hactive&0xff, BT848_E_HACTIVE_LO); - btwrite(hactive&0xff, BT848_O_HACTIVE_LO); - btwrite(hdelay&0xff, BT848_E_HDELAY_LO); - btwrite(hdelay&0xff, BT848_O_HDELAY_LO); - - btwrite(vactive&0xff, BT848_E_VACTIVE_LO); - btwrite(vactive&0xff, BT848_O_VACTIVE_LO); - btwrite(vdelay&0xff, BT848_E_VDELAY_LO); - btwrite(vdelay&0xff, BT848_O_VDELAY_LO); + if (format==BT848_COLOR_FMT_RGB8) + btand(~0x10, BT848_CAP_CTL); + else + btor(0x10, BT848_CAP_CTL); - crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)| - ((vactive>>4)&0x30)|((vdelay>>2)&0xc0); - btwrite(crop, BT848_E_CROP); - btwrite(crop, BT848_O_CROP); + bt848_set_geo(btv,btv->win.width, btv->win.height, format); } - -/* - * The floats in the tuner struct are computed at compile time - * by gcc and cast back to integers. Thus we don't violate the - * "no float in kernel" rule. - */ - -static struct tunertype tuners[] = { - {"Temic PAL", TEMIC, PAL, - 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2, 623}, - {"Philips PAL_I", Philips, PAL_I, - 16*140.25,16*463.25,0x00,0x00,0x00,0x00,0x00, 623}, - {"Philips NTSC", Philips, NTSC, - 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0, 732}, - {"Philips SECAM", Philips, SECAM, - 16*168.25,16*447.25,0xA3,0x93,0x33,0x8e,0xc0, 623}, - {"NoTuner", NoTuner, NOTUNER, - 0 ,0 ,0x00,0x00,0x00,0x00,0x00, 0}, - {"Philips PAL", Philips, PAL, - 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0, 623}, - {"Temic NTSC", TEMIC, NTSC, - 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2, 732}, - {"TEMIC PAL_I", TEMIC, PAL_I, - 0 ,0 ,0x00,0x00,0x00,0x00,0xc2, 623}, -}; - /* * Set TSA5522 synthesizer frequency in 1/16 Mhz steps */ -static void set_freq(struct bttv *btv, ushort freq) +static void set_freq(struct bttv *btv, unsigned short freq) { - u8 config; - u16 div; - struct tunertype *tun=&tuners[btv->tuner]; + int fixme = freq; /* XXX */ int oldAudio = btv->audio; - + audio(btv, AUDIO_MUTE); udelay(AUDIO_MUTE_DELAY); - - if (freq < tun->thresh1) - config = tun->VHF_L; - else if (freq < tun->thresh2) - config = tun->VHF_H; - else - config = tun->UHF; - if(freq < tun->thresh1) - config = tun->VHF_L; - else if(freq < tun->thresh2) - config = tun->VHF_H; - else - config=tun->UHF; - - div=freq+tun->IFPCoff; - - div&=0x7fff; + if (btv->radio) + { + if (btv->have_tuner) + i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER, + TUNER_SET_RADIOFREQ,&fixme); - if (I2CWrite(btv, btv->tuneradr, (div>>8)&0x7f, div&0xff, 1)<0) - return; - I2CWrite(btv, btv->tuneradr, tun->config, config, 1); - if (!(oldAudio & AUDIO_MUTE)) + if (btv->have_msp3400) { + i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, + MSP_SET_RADIO,0); + i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, + MSP_NEWCHANNEL,0); + } + } + else { + if (btv->have_tuner) + i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER, + TUNER_SET_TVFREQ,&fixme); + + if (btv->have_msp3400) { + i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, + MSP_SET_TVNORM,&(btv->win.norm)); + i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, + MSP_NEWCHANNEL,0); + } + } + + if (!(oldAudio & AUDIO_MUTE)) { udelay(FREQ_CHANGE_DELAY); audio(btv, AUDIO_UNMUTE); } } + + +/* + * Grab into virtual memory. + * Currently only does double buffering. Do we need more? + */ + +static int vgrab(struct bttv *btv, struct video_mmap *mp) +{ + unsigned int *ro, *re; + unsigned int *vbuf; + + if(btv->fbuffer==NULL) + { + if(fbuffer_alloc(btv)) + return -ENOBUFS; + } + + /* + * No grabbing past the end of the buffer! + */ + + if(mp->frame>1 || mp->frame <0) + return -EINVAL; + + if(mp->height <0 || mp->width <0) + return -EINVAL; + + if(mp->height>480 || mp->width>640) + return -EINVAL; + + /* + * FIXME: Check the format of the grab here. This is probably + * also less restrictive than the normal overlay grabs. Stuff + * like QCIF has meaning as a capture. + */ + + /* + * Ok load up the BT848 + */ + + vbuf=(unsigned int *)(btv->fbuffer+0x144000*mp->frame); + if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)) + return -EAGAIN; + ro=btv->grisc+(((btv->grabcount++)&1) ? 2048 :0); + re=ro+1024; + btv->gwidth=mp->width; + btv->gheight=mp->height; + btv->gfmt=mp->format; + make_vrisctab(btv, ro, re, vbuf, btv->gwidth, btv->gheight, btv->gfmt); + /* bt848_set_risc_jmps(btv); */ + btor(3, BT848_CAP_CTL); + btor(3, BT848_GPIO_DMA_CTL); + btv->gro=virt_to_bus(ro); + btv->gre=virt_to_bus(re); + if (!(btv->grabbing++)) + btv->risc_jmp[12]=BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ; + /* interruptible_sleep_on(&btv->capq); */ + return 0; +} static long bttv_write(struct video_device *v, const char *buf, unsigned long count, int nonblock) { @@ -608,7 +939,6 @@ todo-=q; buf+=q; -/* btv->vbip=0; */ cli(); if (todo && q==VBIBUF_SIZE-btv->vbip) { @@ -659,14 +989,17 @@ users+=bttvs[i].user; if (users==1) find_vga(); + btv->fbuffer=NULL; + if (!btv->fbuffer) + btv->fbuffer=(unsigned char *) rvmalloc(2*0x144000); + if (!btv->fbuffer) + { + btv->user--; + return -EINVAL; + } break; case 1: break; - case 2: - btv->vbip=VBIBUF_SIZE; - btv->cap|=0x0c; - bt848_set_risc_jmps(btv); - break; } MOD_INC_USE_COUNT; return 0; @@ -679,17 +1012,15 @@ btv->user--; audio(btv, AUDIO_MUTE); btv->cap&=~3; -#if 0 /* FIXME */ - if(minor&0x20) - { - btv->cap&=~0x0c; - } -#endif bt848_set_risc_jmps(btv); + if(btv->fbuffer) + rvfree((void *) btv->fbuffer, 2*0x144000); + btv->fbuffer=0; MOD_DEC_USE_COUNT; } + /***********************************/ /* ioctls and supporting functions */ /***********************************/ @@ -714,7 +1045,7 @@ btaor(conthi, ~4, BT848_O_CONTROL); } -extern inline void bt848_sat_u(struct bttv *btv, ulong data) +extern inline void bt848_sat_u(struct bttv *btv, unsigned long data) { u32 datahi; @@ -724,7 +1055,7 @@ btaor(datahi, ~2, BT848_O_CONTROL); } -static inline void bt848_sat_v(struct bttv *btv, ulong data) +static inline void bt848_sat_v(struct bttv *btv, unsigned long data) { u32 datahi; @@ -734,6 +1065,7 @@ btaor(datahi, ~1, BT848_O_CONTROL); } + /* * Cliprect -> risc table. * @@ -772,15 +1104,17 @@ } first2.next=NULL; - rmem[rpo++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; rmem[rpo++]=0; + rmem[rpo++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1|(0xf<<20); + rmem[rpo++]=0; - rmem2[rpe++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; rmem2[rpe++]=0; + rmem2[rpe++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; + rmem2[rpe++]=0; /* * 32bit depth frame buffers need extra flags setting */ - + if (depth==4) mask=BT848_RISC_BYTE3; else @@ -842,7 +1176,7 @@ * here, but the overlap might be partial */ - /* add rect to second (x-sorted) list if rect.y == y */ + /* add rect to second (x-sorted) list if rect.y == y */ if ((cur=first.next)) { while ((cur) && (cur->y == y)) @@ -953,8 +1287,9 @@ { /* Skip the line : write a SKIP + start/end of line marks */ (*rp)--; - rpp[(*rp)-1]=BT848_RISC_SKIP|(btv->win.width*depth)| - BT848_RISC_EOL|BT848_RISC_SOL; + rpp[(*rp)-1]=BT848_RISC_SKIP| + (btv->win.width*depth)| + BT848_RISC_EOL|BT848_RISC_SOL; } } /* @@ -988,15 +1323,15 @@ vw->clipcount++; } + /* * ioctl routine */ + static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { unsigned char eedata[256]; -/* unsigned long data;*/ -/* static ushort creg;*/ struct bttv *btv=(struct bttv *)dev; static int lastchan=0; @@ -1092,10 +1427,14 @@ /* Only channel 0 has a tuner */ if(v.tuner!=0 || lastchan) return -EINVAL; - if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC) + if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC + &&v.mode!=VIDEO_MODE_SECAM) return -EOPNOTSUPP; + /* FIXME: norm should be in video_channel struct + composite source can have different norms too + */ btv->win.norm = v.mode; - bt848_set_size(btv); + bt848_set_winsize(btv); return 0; } case VIDIOCGPICT: @@ -1109,6 +1448,7 @@ p.palette=VIDEO_PALETTE_RGB24; if(btv->win.bpp==4) p.palette=VIDEO_PALETTE_RGB32; + if(copy_to_user(arg, &p, sizeof(p))) return -EFAULT; return 0; @@ -1155,7 +1495,7 @@ on=(btv->cap&3)?1:0; bt848_cap(btv,0); - bt848_set_size(btv); + bt848_set_winsize(btv); if(vw.clipcount>256) return -EDOM; /* Too many! */ @@ -1188,7 +1528,7 @@ */ write_risc_data(btv,vcp, vw.clipcount); vfree(vcp); - if(on) + if(on && btv->win.vidadr!=0) bt848_cap(btv,1); return 0; } @@ -1213,14 +1553,15 @@ int v; if(copy_from_user(&v, arg,sizeof(v))) return -EFAULT; - if(btv->win.vidadr==0 || btv->win.width==0 || btv->win.height==0) - return -EINVAL; if(v==0) { bt848_cap(btv,0); } else { + if(btv->win.vidadr==0 || btv->win.width==0 + || btv->win.height==0) + return -EINVAL; bt848_cap(btv,1); } return 0; @@ -1247,7 +1588,13 @@ return -EFAULT; if(v.depth!=8 && v.depth!=16 && v.depth!=24 && v.depth!=32) return -EINVAL; - btv->win.vidadr=(int)v.base; + if (v.base) + /* also handle virtual base addresses */ + if ((unsigned int)v.base>=0xe0000000UL) + btv->win.vidadr=(uint)v.base; + else + btv->win.vidadr=PAGE_OFFSET| + uvirt_to_bus((uint)v.base); btv->win.sheight=v.height; btv->win.swidth=v.width; btv->win.bpp=v.depth/8; @@ -1255,7 +1602,7 @@ DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n", v.base, v.width,v.height, btv->win.bpp, btv->win.bpl)); - bt848_set_size(btv); + bt848_set_winsize(btv); return 0; } case VIDIOCKEY: @@ -1287,6 +1634,17 @@ v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE); v.flags|=VIDEO_AUDIO_MUTABLE; strcpy(v.name,"TV"); + if (btv->have_msp3400) + { + v.flags|=VIDEO_AUDIO_VOLUME; + i2c_control_device(&(btv->i2c), + I2C_DRIVERID_MSP3400, + MSP_GET_VOLUME,&(v.volume)); + i2c_control_device(&(btv->i2c), + I2C_DRIVERID_MSP3400, + MSP_GET_STEREO,&(v.mode)); + } + else v.mode = VIDEO_SOUND_MONO; if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; @@ -1296,28 +1654,55 @@ struct video_audio v; if(copy_from_user(&v,arg, sizeof(v))) return -EFAULT; - if(v.audio!=0) - return -EINVAL; if(v.flags&VIDEO_AUDIO_MUTE) audio(btv, AUDIO_MUTE); + if(v.audio<0||v.audio>2) + return -EINVAL; + bt848_muxsel(btv,v.audio); if(!(v.flags&VIDEO_AUDIO_MUTE)) audio(btv, AUDIO_UNMUTE); + if (btv->have_msp3400) + { + i2c_control_device(&(btv->i2c), + I2C_DRIVERID_MSP3400, + MSP_SET_VOLUME,&(v.volume)); + i2c_control_device(&(btv->i2c), + I2C_DRIVERID_MSP3400, + MSP_SET_STEREO,&(v.mode)); + } btv->audio_dev=v; return 0; } - case BTTV_WRITEEE: + case VIDIOCSYNC: + if (btv->grabbing && btv->grab==btv->lastgrab) + interruptible_sleep_on(&btv->capq); + btv->lastgrab=btv->grab; + return 0; + + case BTTV_WRITEE: + if(!suser()) + return -EPERM; if(copy_from_user((void *) eedata, (void *) arg, 256)) return -EFAULT; - writeee(btv, eedata); - break; + writeee(&(btv->i2c), eedata); + return 0; case BTTV_READEE: - readee(btv, eedata); + if(!suser()) + return -EPERM; + readee(&(btv->i2c), eedata); if(copy_to_user((void *) arg, (void *) eedata, 256)) return -EFAULT; break; + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) + return -EFAULT; + return vgrab(btv, &vm); + } default: return -ENOIOCTLCMD; } @@ -1329,6 +1714,41 @@ return 0; } +/* + * This maps the vmalloced and reserved fbuffer to user space. + * + * FIXME: + * - PAGE_READONLY should suffice!? + * - remap_page_range is kind of inefficient for page by page remapping. + * But e.g. pte_alloc() does not work in modules ... :-( + */ + +static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size) +{ + struct bttv *btv=(struct bttv *)dev; + unsigned long start=(unsigned long) adr; + unsigned long page,pos; + + if (size>2*0x144000) + return -EINVAL; + if (!btv->fbuffer) + { + if(fbuffer_alloc(btv)) + return -EINVAL; + } + pos=(unsigned long) btv->fbuffer; + while (size > 0) + { + page = kvirt_to_phys(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start+=PAGE_SIZE; + pos+=PAGE_SIZE; + size-=PAGE_SIZE; + } + return 0; +} + static struct video_device bttv_template= { "UNSET", @@ -1339,6 +1759,96 @@ bttv_read, bttv_write, bttv_ioctl, + bttv_mmap, + bttv_init_done, + NULL, + 0, + 0 +}; + + +static long vbi_read(struct video_device *v, char *buf, unsigned long count, + int nonblock) +{ + struct bttv *btv=(struct bttv *)(v-2); + int q,todo; + + todo=count; + while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) + { + if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q)) + return -EFAULT; + todo-=q; + buf+=q; + + cli(); + if (todo && q==VBIBUF_SIZE-btv->vbip) + { + if(nonblock) + { + sti(); + if(count==todo) + return -EWOULDBLOCK; + return count-todo; + } + interruptible_sleep_on(&btv->vbiq); + sti(); + if(signal_pending(current)) + { + if(todo==count) + return -EINTR; + else + return count-todo; + } + } + } + if (todo) + { + if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo)) + return -EFAULT; + btv->vbip+=todo; + } + return count; +} + +static int vbi_open(struct video_device *dev, int flags) +{ + struct bttv *btv=(struct bttv *)(dev-2); + + btv->vbip=VBIBUF_SIZE; + btv->cap|=0x0c; + bt848_set_risc_jmps(btv); + + MOD_INC_USE_COUNT; + return 0; +} + +static void vbi_close(struct video_device *dev) +{ + struct bttv *btv=(struct bttv *)(dev-2); + + btv->cap&=~0x0c; + bt848_set_risc_jmps(btv); + + MOD_DEC_USE_COUNT; +} + + +static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + return -EINVAL; +} + +static struct video_device vbi_template= +{ + "bttv vbi", + VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, + VID_HARDWARE_BT848, + vbi_open, + vbi_close, + vbi_read, + bttv_write, + vbi_ioctl, NULL, /* no mmap yet */ bttv_init_done, NULL, @@ -1346,9 +1856,106 @@ 0 }; + +static int radio_open(struct video_device *dev, int flags) +{ + struct bttv *btv = (struct bttv *)(dev-1); + + if (btv->user) + return -EBUSY; + btv->user++; + set_freq(btv,400*16); + btv->radio = 1; + bt848_muxsel(btv,0); + audio(btv, AUDIO_UNMUTE); + + MOD_INC_USE_COUNT; + return 0; +} + +static void radio_close(struct video_device *dev) +{ + struct bttv *btv=(struct bttv *)(dev-1); + + btv->user--; + btv->radio = 0; + audio(btv, AUDIO_MUTE); + MOD_DEC_USE_COUNT; +} + +static long radio_read(struct video_device *v, char *buf, unsigned long count, int nonblock) +{ + return -EINVAL; +} + +static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct bttv *btv=(struct bttv *)(dev-1); + static int lastchan=0; + switch (cmd) { + case VIDIOCGCAP: + /* XXX */ + break; + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v,arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner||lastchan) /* Only tuner 0 */ + return -EINVAL; + strcpy(v.name, "Radio"); + v.rangelow=(int)(87.5*16); + v.rangehigh=(int)(108.0*16); + v.flags= 0; /* XXX */ + v.mode = 0; /* XXX */ + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + /* Only channel 0 has a tuner */ + if(v.tuner!=0 || lastchan) + return -EINVAL; + /* XXX anything to do ??? */ + return 0; + } + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + bttv_ioctl((struct video_device *)btv,cmd,arg); + break; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static struct video_device radio_template= +{ + "bttv radio", + VID_TYPE_TUNER, + VID_HARDWARE_BT848, + radio_open, + radio_close, + radio_read, /* just returns -EINVAL */ + bttv_write, /* just returns -EINVAL */ + radio_ioctl, + NULL, /* no mmap */ + bttv_init_done, /* just returns 0 */ + NULL, + 0, + 0 +}; + + struct vidbases { - ushort vendor, device; + unsigned short vendor, device; char *name; uint badr; }; @@ -1386,7 +1993,7 @@ static int find_vga(void) { unsigned int devfn, class, vendev; - ushort vendor, device, badr; + unsigned short vendor, device, badr; int found=0, bus=0, i, tga_type; unsigned int vidadr=0; @@ -1470,6 +2077,8 @@ return found; } + + #define TRITON_PCON 0x50 #define TRITON_BUS_CONCURRENCY (1<<0) #define TRITON_STREAMING (1<<1) @@ -1480,28 +2089,27 @@ { int index; + /* Just in case some nut set this to something dangerous */ + if (triton1) + triton1=BT848_INT_ETBF; + for (index = 0; index < 8; index++) { unsigned char bus, devfn; - unsigned char b, bo; + unsigned char b; /* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */ - if (!pcibios_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, index, &bus, &devfn)) + if (!pcibios_find_device(PCI_VENDOR_ID_SI, + PCI_DEVICE_ID_SI_496, + index, &bus, &devfn)) { printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n"); } - if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, - index, &bus, &devfn)) - { - pcibios_read_config_byte(bus, devfn, 0x53, &b); - DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, ")); - DEBUG(printk("bufcon=0x%02x\n",b)); - } - - if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, - index, &bus, &devfn)) + if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82441, + index, &bus, &devfn)) { pcibios_read_config_byte(bus, devfn, 0x53, &b); DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, ")); @@ -1512,139 +2120,176 @@ index, &bus, &devfn)) { printk(KERN_INFO "bttv: Host bridge 82437FX Triton PIIX\n"); - pcibios_read_config_byte(bus, devfn, TRITON_PCON, &b); - bo=b; - DEBUG(printk(KERN_DEBUG "bttv: 82437FX: PCON: 0x%x\n",b)); - + triton1=BT848_INT_ETBF; + +#if 0 + /* The ETBF bit SHOULD make all this unnecessary */ /* 430FX (Triton I) freezes with bus concurrency on -> switch it off */ - if(!(b & TRITON_BUS_CONCURRENCY)) - { - printk(KERN_WARNING "bttv: 82437FX: disabling bus concurrency\n"); - b |= TRITON_BUS_CONCURRENCY; - } + { + unsigned char bo; - /* still freezes on other boards -> switch off even more */ - if(b & TRITON_PEER_CONCURRENCY) - { - printk(KERN_WARNING "bttv: 82437FX: disabling peer concurrency\n"); - b &= ~TRITON_PEER_CONCURRENCY; - } - if(!(b & TRITON_STREAMING)) - { - printk(KERN_WARNING "bttv: 82437FX: disabling streaming\n"); - b |= TRITON_STREAMING; - } + pcibios_read_config_byte(bus, devfn, TRITON_PCON, &b); + bo=b; + DEBUG(printk(KERN_DEBUG "bttv: 82437FX: PCON: 0x%x\n",b)); - if (b!=bo) - { - pcibios_write_config_byte(bus, devfn, TRITON_PCON, b); - printk(KERN_DEBUG "bttv: 82437FX: PCON changed to: 0x%x\n",b); + if(!(b & TRITON_BUS_CONCURRENCY)) + { + printk(KERN_WARNING "bttv: 82437FX: disabling bus concurrency\n"); + b |= TRITON_BUS_CONCURRENCY; + } + + if(b & TRITON_PEER_CONCURRENCY) + { + printk(KERN_WARNING "bttv: 82437FX: disabling peer concurrency\n"); + b &= ~TRITON_PEER_CONCURRENCY; + } + if(!(b & TRITON_STREAMING)) + { + printk(KERN_WARNING "bttv: 82437FX: disabling streaming\n"); + b |= TRITON_STREAMING; + } + + if (b!=bo) + { + pcibios_write_config_byte(bus, devfn, TRITON_PCON, b); + printk(KERN_DEBUG "bttv: 82437FX: PCON changed to: 0x%x\n",b); + } } +#endif } } } -static void init_tda9850(struct bttv *btv) + +static void init_tda9850(struct i2c_bus *bus) { - I2CWrite(btv, I2C_TDA9850, TDA9850_CON3, 0, 1); + I2CWrite(bus, I2C_TDA9850, TDA9850_CON1, 0x08, 1); /* noise threshold st */ + I2CWrite(bus, I2C_TDA9850, TDA9850_CON2, 0x08, 1); /* noise threshold sap */ + I2CWrite(bus, I2C_TDA9850, TDA9850_CON3, 0x40, 1); /* stereo mode */ + I2CWrite(bus, I2C_TDA9850, TDA9850_CON4, 0x07, 1); /* 0 dB input gain?*/ + I2CWrite(bus, I2C_TDA9850, TDA9850_ALI1, 0x10, 1); /* wideband alignment? */ + I2CWrite(bus, I2C_TDA9850, TDA9850_ALI2, 0x10, 1); /* spectral alignment? */ + I2CWrite(bus, I2C_TDA9850, TDA9850_ALI3, 0x03, 1); } + + /* Figure out card and tuner type */ static void idcard(struct bttv *btv) { - int i; - + int tunertype; btwrite(0, BT848_GPIO_OUT_EN); DEBUG(printk(KERN_DEBUG "bttv: GPIO: 0x%08x\n", btread(BT848_GPIO_DATA))); - btv->type=BTTV_MIRO; - btv->tuner=tuner; - - if (I2CRead(btv, I2C_HAUPEE)>=0) - btv->type=BTTV_HAUPPAUGE; - else if (I2CRead(btv, I2C_STBEE)>=0) - btv->type=BTTV_STB; - - for (i=0xc0; i<0xd0; i+=2) + /* Default the card to the user-selected one. */ + btv->type=card; + + /* If we were asked to auto-detect, then do so! + Right now this will only recognize Miro, Hauppauge or STB + */ + if (btv->type == BTTV_UNKNOWN) { - if (I2CRead(btv, i)>=0) - { - btv->tuneradr=i; - break; - } + btv->type=BTTV_MIRO; + + if (I2CRead(&(btv->i2c), I2C_HAUPEE)>=0) + btv->type=BTTV_HAUPPAUGE; + else + if (I2CRead(&(btv->i2c), I2C_STBEE)>=0) + btv->type=BTTV_STB; } - btv->dbx = I2CRead(btv, I2C_TDA9850) ? 0 : 1; + btv->dbx = I2CRead(&(btv->i2c), I2C_TDA9850) ? 0 : 1; if (btv->dbx) - init_tda9850(btv); + init_tda9850(&(btv->i2c)); /* How do I detect the tuner type for other cards but Miro ??? */ printk(KERN_INFO "bttv: model: "); switch (btv->type) { case BTTV_MIRO: - btv->tuner=((btread(BT848_GPIO_DATA)>>10)-1)&7; - printk("MIRO"); + printk("MIRO\n"); + if (btv->have_tuner) + { + tunertype=((btread(BT848_GPIO_DATA)>>10)-1)&7; + i2c_control_device(&(btv->i2c), + I2C_DRIVERID_TUNER, + TUNER_SET_TYPE,&tunertype); + } strcpy(btv->video_dev.name,"BT848(Miro)"); break; case BTTV_HAUPPAUGE: - printk("HAUPPAUGE"); + printk("HAUPPAUGE\n"); strcpy(btv->video_dev.name,"BT848(Hauppauge)"); break; case BTTV_STB: - printk("STB"); + printk("STB\n"); strcpy(btv->video_dev.name,"BT848(STB)"); break; case BTTV_INTEL: - printk("Intel"); + printk("Intel\n"); strcpy(btv->video_dev.name,"BT848(Intel)"); break; case BTTV_DIAMOND: - printk("Diamond"); + printk("Diamond\n"); strcpy(btv->video_dev.name,"BT848(Diamond)"); break; + case BTTV_AVERMEDIA: + printk("AVerMedia\n"); + strcpy(btv->video_dev.name,"BT848(AVerMedia)"); + break; } - printk(" (%s @ 0x%02x)\n", tuners[btv->tuner].name, btv->tuneradr); audio(btv, AUDIO_MUTE); } + static void bt848_set_risc_jmps(struct bttv *btv) { int flags=btv->cap; - + + /* Sync to start of odd field */ btv->risc_jmp[0]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE; btv->risc_jmp[1]=0; - btv->risc_jmp[2]=BT848_RISC_JUMP; + /* Jump to odd vbi sub */ + btv->risc_jmp[2]=BT848_RISC_JUMP|(0x5<<20); if (flags&8) btv->risc_jmp[3]=virt_to_bus(btv->vbi_odd); else btv->risc_jmp[3]=virt_to_bus(btv->risc_jmp+4); - btv->risc_jmp[4]=BT848_RISC_JUMP; + /* Jump to odd sub */ + btv->risc_jmp[4]=BT848_RISC_JUMP|(0x6<<20); if (flags&2) btv->risc_jmp[5]=virt_to_bus(btv->risc_odd); else btv->risc_jmp[5]=virt_to_bus(btv->risc_jmp+6); + + /* Sync to start of even field */ btv->risc_jmp[6]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO; btv->risc_jmp[7]=0; + /* Jump to even vbi sub */ btv->risc_jmp[8]=BT848_RISC_JUMP; if (flags&4) btv->risc_jmp[9]=virt_to_bus(btv->vbi_even); else btv->risc_jmp[9]=virt_to_bus(btv->risc_jmp+10); - btv->risc_jmp[10]=BT848_RISC_JUMP; + /* Jump to even sub */ + btv->risc_jmp[10]=BT848_RISC_JUMP|(8<<20); if (flags&1) btv->risc_jmp[11]=virt_to_bus(btv->risc_even); else - btv->risc_jmp[11]=virt_to_bus(btv->risc_jmp); + btv->risc_jmp[11]=virt_to_bus(btv->risc_jmp+12); + + btv->risc_jmp[12]=BT848_RISC_JUMP; + btv->risc_jmp[13]=virt_to_bus(btv->risc_jmp); + /* enable cpaturing and DMA */ btaor(flags, ~0x0f, BT848_CAP_CTL); if (flags&0x0f) bt848_dma(btv, 3); @@ -1653,12 +2298,15 @@ } -static int init_bt848(struct bttv *btv) +static int init_bt848(int i) { - /* reset the bt848 */ - btwrite(0,BT848_SRESET); + struct bttv *btv = &bttvs[i]; + btv->user=0; + /* reset the bt848 */ + btwrite(0, BT848_SRESET); + DEBUG(printk(KERN_DEBUG "bttv: bt848_mem: 0x%08x\n",(unsigned int) btv->bt848_mem)); /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */ @@ -1674,43 +2322,66 @@ btv->win.cropx=0; btv->win.cropy=0; btv->win.bpp=2; + btv->win.color_fmt=BT848_COLOR_FMT_RGB16; btv->win.bpl=1024*btv->win.bpp; btv->win.swidth=1024; btv->win.sheight=768; btv->cap=0; - if (!(btv->risc_odd=(dword *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + btv->gmode=0; + btv->risc_odd=0; + btv->risc_even=0; + btv->risc_jmp=0; + btv->vbibuf=0; + btv->grisc=0; + btv->grabbing=0; + btv->grabcount=0; + btv->grab=0; + btv->lastgrab=0; + + /* i2c */ + memcpy(&(btv->i2c),&bttv_i2c_bus_template,sizeof(struct i2c_bus)); + sprintf(btv->i2c.name,"bt848-%d",i); + btv->i2c.data = btv; + + if (!(btv->risc_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) return -1; - if (!(btv->risc_even=(dword *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + if (!(btv->risc_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) return -1; - if (!(btv->risc_jmp =(dword *) kmalloc(2048, GFP_KERNEL))) + if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL))) return -1; - btv->vbi_odd=btv->risc_jmp+12; + DEBUG(printk(KERN_DEBUG "risc_jmp: %p\n",btv->risc_jmp)); + btv->vbi_odd=btv->risc_jmp+16; btv->vbi_even=btv->vbi_odd+256; - btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp); + btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp+12); btv->bus_vbi_even=virt_to_bus(btv->risc_jmp+6); btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD); - btv->vbibuf=(unchar *) vmalloc(VBIBUF_SIZE); + btv->vbibuf=(unsigned char *) vmalloc(VBIBUF_SIZE); if (!btv->vbibuf) return -1; + if (!(btv->grisc=(unsigned int *) kmalloc(16384, GFP_KERNEL))) + return -1; + + btv->fbuffer=NULL; bt848_muxsel(btv, 1); - bt848_set_size(btv); + bt848_set_winsize(btv); /* btwrite(0, BT848_TDEC); */ btwrite(0x10, BT848_COLOR_CTL); btwrite(0x00, BT848_CAP_CTL); + btwrite(0xfc, BT848_GPIO_DMA_CTL); btwrite(0x0ff, BT848_VBI_PACK_SIZE); btwrite(1, BT848_VBI_PACK_DEL); - btwrite(0xfc, BT848_GPIO_DMA_CTL); + btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_PAL_BDGHI, BT848_IFORM); - bt848_bright(btv, 0x10); btwrite(0xd8, BT848_CONTRAST_LO); + bt848_bright(btv, 0x10); btwrite(0x60, BT848_E_VSCALE_HI); btwrite(0x60, BT848_O_VSCALE_HI); @@ -1719,19 +2390,27 @@ btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL); btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); + + btv->picture.colour=254<<7; + btv->picture.brightness=128<<8; + btv->picture.hue=128<<8; + btv->picture.contrast=0xd8<<7; + btwrite(0x00, BT848_E_SCLOOP); btwrite(0x00, BT848_O_SCLOOP); - btwrite(0xffffffUL,BT848_INT_STAT); -/* BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|BT848_INT_FDSR| - BT848_INT_FTRGT|BT848_INT_FBUS|*/ - btwrite(BT848_INT_ETBF| + /* clear interrupt status */ + btwrite(0xfffffUL, BT848_INT_STAT); + + /* set interrupt mask */ + btwrite(triton1| +/* BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR| + BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/ BT848_INT_SCERR| BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| BT848_INT_FMTCHG|BT848_INT_HLOCK, BT848_INT_MASK); -/* make_risctab(btv); */ make_vbitab(btv); bt848_set_risc_jmps(btv); @@ -1739,20 +2418,32 @@ * Now add the template and register the device unit. */ - memcpy(&btv->video_dev,&bttv_template,sizeof(bttv_template)); + memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template)); + memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template)); + memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template)); idcard(btv); - - btv->picture.brightness=0x90<<8; - btv->picture.contrast = 0x70 << 8; - btv->picture.colour = 0x70<<8; - btv->picture.hue = 0x8000; - - if(video_register_device(&btv->video_dev)<0) + + if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0) return -1; + if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0) + { + video_unregister_device(&btv->video_dev); + return -1; + } + if (radio) + { + if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) + { + video_unregister_device(&btv->vbi_dev); + video_unregister_device(&btv->video_dev); + return -1; + } + } + i2c_register_bus(&btv->i2c); + return 0; } - static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) { u32 stat,astat; @@ -1779,7 +2470,8 @@ if (astat&BT848_INT_FMTCHG) { IDEBUG(printk ("bttv: IRQ_FMTCHG\n")); -/* btv->win.norm&=(dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */ + /*btv->win.norm&= + (dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */ } if (astat&BT848_INT_VPRES) { @@ -1795,22 +2487,47 @@ bt848_dma(btv, 1); wake_up_interruptible(&btv->vbiq); wake_up_interruptible(&btv->capq); + } if (astat&BT848_INT_RISCI) { IDEBUG(printk ("bttv: IRQ_RISCI\n")); - /* printk ("bttv: IRQ_RISCI%d\n",stat>>28); */ + + /* captured VBI frame */ if (stat&(1<<28)) { btv->vbip=0; wake_up_interruptible(&btv->vbiq); } + + /* captured full frame */ if (stat&(2<<28)) { - bt848_set_risc_jmps(btv); + btv->grab++; wake_up_interruptible(&btv->capq); + if ((--btv->grabbing)) + { + btv->risc_jmp[5]=btv->gro; + btv->risc_jmp[11]=btv->gre; + bt848_set_geo(btv, btv->gwidth, + btv->gheight, + btv->gfmt); + } else { + bt848_set_risc_jmps(btv); + bt848_set_geo(btv, btv->win.width, + btv->win.height, + btv->win.color_fmt); + } break; } + if (stat&(8<<28)) + { + btv->risc_jmp[5]=btv->gro; + btv->risc_jmp[11]=btv->gre; + btv->risc_jmp[12]=BT848_RISC_JUMP; + bt848_set_geo(btv, btv->gwidth, btv->gheight, + btv->gfmt); + } } if (astat&BT848_INT_OCERR) { @@ -1842,7 +2559,7 @@ } if (astat&BT848_INT_HLOCK) { - if (dstat&BT848_DSTATUS_HLOC) + if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio)) audio(btv, AUDIO_ON); else audio(btv, AUDIO_OFF); @@ -1858,12 +2575,14 @@ if (count > 20) { btwrite(0, BT848_INT_MASK); - printk(KERN_ERR "bttv: IRQ lockup, cleared int mask\n"); + printk(KERN_ERR + "bttv: IRQ lockup, cleared int mask\n"); } } } + /* * Scan for a Bt848 card, request the irq and map the io memory */ @@ -1885,8 +2604,10 @@ } for (pci_index = 0; - !pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848, - pci_index, &bus, &devfn); + !pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849, + pci_index, &bus, &devfn) + ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848, + pci_index, &bus, &devfn); ++pci_index) { btv=&bttvs[bttv_num]; @@ -1899,8 +2620,13 @@ btv->vbi_even=NULL; btv->vbiq=NULL; btv->capq=NULL; + btv->capqo=NULL; + btv->capqe=NULL; + btv->vbip=VBIBUF_SIZE; + pcibios_read_config_word(btv->bus, btv->devfn, PCI_DEVICE_ID, + &btv->id); pcibios_read_config_byte(btv->bus, btv->devfn, PCI_INTERRUPT_LINE, &btv->irq); pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0, @@ -1921,7 +2647,8 @@ btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK; pcibios_read_config_byte(btv->bus, btv->devfn, PCI_CLASS_REVISION, &btv->revision); - printk(KERN_INFO "bttv: Brooktree Bt848 (rev %d) ",btv->revision); + printk(KERN_INFO "bttv: Brooktree Bt%d (rev %d) ", + btv->id, btv->revision); printk("bus: %d, devfn: %d, ", btv->bus, btv->devfn); printk("irq: %d, ",btv->irq); @@ -1959,8 +2686,8 @@ if (!latency) { latency=32; - pcibios_write_config_byte(btv->bus, btv->devfn, PCI_LATENCY_TIMER, - latency); + pcibios_write_config_byte(btv->bus, btv->devfn, + PCI_LATENCY_TIMER, latency); } DEBUG(printk(KERN_DEBUG "bttv: latency: %02x\n", latency)); bttv_num++; @@ -1970,6 +2697,7 @@ return bttv_num; } + static void release_bttv(void) { u8 command; @@ -1979,21 +2707,28 @@ for (i=0;ii2c)); + /* disable PCI bus-mastering */ pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command); command|=PCI_COMMAND_MASTER; pcibios_write_config_byte(btv->bus, btv->devfn, PCI_COMMAND, command); /* unmap and free memory */ + if (btv->grisc) + kfree((void *) btv->grisc); + if (btv->risc_odd) kfree((void *) btv->risc_odd); @@ -2007,15 +2742,20 @@ DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%08x.\n", btv->vbibuf)); if (btv->vbibuf) vfree((void *) btv->vbibuf); + + free_irq(btv->irq,btv); DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%08x.\n", btv->bt848_mem)); if (btv->bt848_mem) iounmap(btv->bt848_mem); + video_unregister_device(&btv->video_dev); + video_unregister_device(&btv->vbi_dev); + if (radio) + video_unregister_device(&btv->radio_dev); } } - #ifdef MODULE int init_module(void) @@ -2030,22 +2770,39 @@ if (find_bt848()<0) return -EIO; + /* initialize Bt848s */ for (i=0; i #include +#include "i2c.h" +#include "msp3400.h" #include "bt848.h" +#include + +#define MAX_CLIPRECS 100 +#define RISCMEM_LEN (32744*2) +#define MAX_FBUF 0x144000 + +struct riscprog +{ + unsigned int length; + u32 *busadr; + u32 *prog; +}; -typedef unsigned int dword; -struct riscprog { - uint length; - dword *busadr; - dword *prog; +/* clipping rectangle */ +struct cliprec +{ + int x, y, x2, y2; + struct cliprec *next; }; -/* values that can be set by user programs */ -struct bttv_window { - int x, y; - ushort width, height; - ushort bpp, bpl; - ushort swidth, sheight; - short cropx, cropy; - ushort cropwidth, cropheight; - int vidadr; - ushort freq; - int norm; - int interlace; - int color_fmt; +/* grab buffer */ +struct gbuffer +{ + struct gbuffer *next; + struct gbuffer *next_active; + void *adr; + int x, y; + int width, height; + unsigned int bpl; + unsigned int fmt; + int flags; +#define GBUF_ODD 1 +#define GBUF_EVEN 2 +#define GBUF_LFB 4 +#define GBUF_INT 8 + unsigned int length; + void *ro; + void *re; + u32 bro; + u32 bre; }; -/* private data that can only be read (or set indirectly) by user program */ -struct bttv { - struct video_device video_dev; - struct video_picture picture; /* Current picture params */ - struct video_audio audio_dev; /* Current audio params */ - u_char bus; /* PCI bus the Bt848 is on */ - u_char devfn; - u_char revision; - u_char irq; /* IRQ used by Bt848 card */ - uint bt848_adr; /* bus address of IO mem returned by PCI BIOS */ - u_char *bt848_mem; /* pointer to mapped IO memory */ - ulong busriscmem; - dword *riscmem; +#ifdef __KERNEL__ + +struct bttv_window +{ + int x, y; + ushort width, height; + ushort bpp, bpl; + ushort swidth, sheight; + short cropx, cropy; + ushort cropwidth, cropheight; + unsigned int vidadr; + ushort freq; + int norm; + int interlace; + int color_fmt; +}; + + +struct bttv +{ + struct video_device video_dev; + struct video_device radio_dev; + struct video_device vbi_dev; + struct video_picture picture; /* Current picture params */ + struct video_audio audio_dev; /* Current audio params */ + + struct i2c_bus i2c; + int have_msp3400; + int have_tuner; + + unsigned short id; + unsigned char bus; /* PCI bus the Bt848 is on */ + unsigned char devfn; + unsigned char revision; + unsigned char irq; /* IRQ used by Bt848 card */ + unsigned int bt848_adr; /* bus address of IO mem returned by PCI BIOS */ + unsigned char *bt848_mem; /* pointer to mapped IO memory */ + unsigned long busriscmem; + u32 *riscmem; - u_char *vbibuf; - struct bttv_window win; - int type; /* card type */ - int audio; /* audio mode */ - int user; - int tuner; - int tuneradr; - int dbx; - - dword *risc_jmp; - dword *vbi_odd; - dword *vbi_even; - dword bus_vbi_even; - dword bus_vbi_odd; - struct wait_queue *vbiq; - struct wait_queue *capq; - int vbip; - - dword *risc_odd; - dword *risc_even; - int cap; + unsigned char *vbibuf; + struct bttv_window win; + int type; /* card type */ + int audio; /* audio mode */ + int user; + int dbx; + int radio; + + u32 *risc_jmp; + u32 *vbi_odd; + u32 *vbi_even; + u32 bus_vbi_even; + u32 bus_vbi_odd; + struct wait_queue *vbiq; + struct wait_queue *capq; + struct wait_queue *capqo; + struct wait_queue *capqe; + int vbip; + + u32 *risc_odd; + u32 *risc_even; + int cap; + struct cliprec *cliprecs; + int ncr; /* number of clipping rectangles */ + + struct gbuffer *ogbuffers; + struct gbuffer *egbuffers; + u16 gwidth, gheight, gfmt; + u32 *grisc; + unsigned long gro; + unsigned long gre; + char *fbuffer; + int gmode; + int grabbing; + int lastgrab; + int grab; + int grabcount; }; +#endif + /*The following should be done in more portable way. It depends on define of _ALPHA_BTTV in the Makefile.*/ + #ifdef _ALPHA_BTTV #define btwrite(dat,adr) writel((dat),(char *) (btv->bt848_adr+(adr))) #define btread(adr) readl(btv->bt848_adr+(adr)) @@ -105,30 +171,10 @@ #define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) /* bttv ioctls */ -#define BTTV_WRITE_BTREG 0x00 -#define BTTV_READ_BTREG 0x01 -#define BTTV_SET_BTREG 0x02 -#define BTTV_SETRISC 0x03 -#define BTTV_SETWTW 0x04 -#define BTTV_GETWTW 0x05 -#define BTTV_DMA 0x06 -#define BTTV_CAP_OFF 0x07 -#define BTTV_CAP_ON 0x08 -#define BTTV_GETBTTV 0x09 -#define BTTV_SETFREQ 0x0a -#define BTTV_SETCHAN 0x0b -#define BTTV_INPUT 0x0c -#define BTTV_READEE 0x0d -#define BTTV_WRITEEE 0x0e -#define BTTV_BRIGHT 0x0f -#define BTTV_HUE 0x10 -#define BTTV_COLOR 0x11 -#define BTTV_CONTRAST 0x12 -#define BTTV_SET_FFREQ 0x13 -#define BTTV_MUTE 0x14 -#define BTTV_GRAB 0x20 -#define BTTV_TESTM 0x20 +#define BTTV_READEE _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]) +#define BTTV_WRITEE _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]) +#define BTTV_GRAB _IOR('v' , BASE_VIDIOCPRIVATE+2, struct gbuf) #define BTTV_UNKNOWN 0x00 @@ -137,12 +183,14 @@ #define BTTV_STB 0x03 #define BTTV_INTEL 0x04 #define BTTV_DIAMOND 0x05 +#define BTTV_AVERMEDIA 0x06 #define AUDIO_TUNER 0x00 -#define AUDIO_EXTERN 0x01 -#define AUDIO_INTERN 0x02 -#define AUDIO_OFF 0x03 -#define AUDIO_ON 0x04 +#define AUDIO_RADIO 0x01 +#define AUDIO_EXTERN 0x02 +#define AUDIO_INTERN 0x03 +#define AUDIO_OFF 0x04 +#define AUDIO_ON 0x05 #define AUDIO_MUTE 0x80 #define AUDIO_UNMUTE 0x81 diff -u --recursive --new-file v2.1.93/linux/drivers/char/bw-qcam.c linux/drivers/char/bw-qcam.c --- v2.1.93/linux/drivers/char/bw-qcam.c Mon Feb 23 18:12:04 1998 +++ linux/drivers/char/bw-qcam.c Wed Apr 8 17:24:48 1998 @@ -885,7 +885,7 @@ printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name); - if(video_register_device(&qcam->vdev)==-1) + if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1) { parport_unregister_device(qcam->pdev); kfree(qcam); diff -u --recursive --new-file v2.1.93/linux/drivers/char/c-qcam.c linux/drivers/char/c-qcam.c --- v2.1.93/linux/drivers/char/c-qcam.c Mon Feb 23 18:12:04 1998 +++ linux/drivers/char/c-qcam.c Wed Apr 8 17:24:48 1998 @@ -727,7 +727,7 @@ printk(KERN_INFO "Connectix Colour Quickcam on %s\n", qcam->pport->name); - if (video_register_device(&qcam->vdev)==-1) + if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1) { parport_unregister_device(qcam->pdev); kfree(qcam); diff -u --recursive --new-file v2.1.93/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.1.93/linux/drivers/char/console.c Wed Apr 1 20:11:48 1998 +++ linux/drivers/char/console.c Wed Apr 8 11:30:27 1998 @@ -204,7 +204,6 @@ int want_console = -1; int kmsg_redirect = 0; -#define CONFIG_SERIAL_ECHO #ifdef CONFIG_SERIAL_ECHO #include diff -u --recursive --new-file v2.1.93/linux/drivers/char/hfmodem/gentbl.c linux/drivers/char/hfmodem/gentbl.c --- v2.1.93/linux/drivers/char/hfmodem/gentbl.c Thu Mar 26 15:57:02 1998 +++ linux/drivers/char/hfmodem/gentbl.c Tue Apr 7 07:48:54 1998 @@ -62,7 +62,7 @@ printf("/*\n * This file is automatically generated by %s, DO NOT EDIT!\n*/\n\n", argv[0]); gensintbl(); - return(0); + exit(0); } /* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.1.93/linux/drivers/char/i2c.c linux/drivers/char/i2c.c --- v2.1.93/linux/drivers/char/i2c.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/i2c.c Wed Apr 8 17:24:48 1998 @@ -0,0 +1,430 @@ +/* + * Generic i2c interface for linux + * + * (c) 1998 Gerd Knorr + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c.h" + +#define REGPRINT(x) if (verbose) (x) +#define I2C_DEBUG(x) if (i2c_debug) (x) + +static int scan = 0; +static int verbose = 1; +static int i2c_debug = 0; + +MODULE_PARM(scan,"i"); +MODULE_PARM(verbose,"i"); +MODULE_PARM(i2c_debug,"i"); + +/* ----------------------------------------------------------------------- */ + +static struct i2c_bus *busses[I2C_BUS_MAX]; +static struct i2c_driver *drivers[I2C_DRIVER_MAX]; +static int bus_count = 0, driver_count = 0; + +int i2c_init(void) +{ + printk(KERN_INFO "i2c: initialized%s\n", + scan ? " (i2c bus scan enabled)" : ""); + /* anything to do here ? */ + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static void i2c_attach_device(struct i2c_bus *bus, struct i2c_driver *driver) +{ + unsigned long flags; + struct i2c_device *device; + int i,j,ack=1; + unsigned char addr; + + /* probe for device */ + LOCK_I2C_BUS(bus); + for (addr = driver->addr_l; addr <= driver->addr_h; addr += 2) + { + i2c_start(bus); + ack = i2c_sendbyte(bus,addr,0); + i2c_stop(bus); + if (!ack) + break; + } + UNLOCK_I2C_BUS(bus); + if (ack) + return; + + /* got answer */ + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (NULL == driver->devices[i]) + break; + if (I2C_DEVICE_MAX == i) + return; + + for (j = 0; j < I2C_DEVICE_MAX; j++) + if (NULL == bus->devices[j]) + break; + if (I2C_DEVICE_MAX == j) + return; + + if (NULL == (device = kmalloc(sizeof(struct i2c_device),GFP_KERNEL))) + return; + device->bus = bus; + device->driver = driver; + device->addr = addr; + + /* Attach */ + + if (driver->attach(device)!=0) + { + kfree(device); + return; + } + driver->devices[i] = device; + driver->devcount++; + bus->devices[j] = device; + bus->devcount++; + + if (bus->attach_inform) + bus->attach_inform(bus,driver->id); + REGPRINT(printk("i2c: device attached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,addr,bus->name,driver->name)); +} + +static void i2c_detach_device(struct i2c_device *device) +{ + int i; + + if (device->bus->detach_inform) + device->bus->detach_inform(device->bus,device->driver->id); + device->driver->detach(device); + + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (device == device->driver->devices[i]) + break; + if (I2C_DEVICE_MAX == i) + { + printk(KERN_WARNING "i2c: detach_device #1: device not found: %s\n", + device->name); + return; + } + device->driver->devices[i] = NULL; + device->driver->devcount--; + + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (device == device->bus->devices[i]) + break; + if (I2C_DEVICE_MAX == i) + { + printk(KERN_WARNING "i2c: detach_device #2: device not found: %s\n", + device->name); + return; + } + device->bus->devices[i] = NULL; + device->bus->devcount--; + + REGPRINT(printk("i2c: device detached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,device->addr,device->bus->name,device->driver->name)); + kfree(device); +} + +/* ----------------------------------------------------------------------- */ + +int i2c_register_bus(struct i2c_bus *bus) +{ + unsigned long flags; + int i,ack; + + memset(bus->devices,0,sizeof(bus->devices)); + bus->devcount = 0; + + for (i = 0; i < I2C_BUS_MAX; i++) + if (NULL == busses[i]) + break; + if (I2C_BUS_MAX == i) + return -ENOMEM; + + busses[i] = bus; + bus_count++; + REGPRINT(printk("i2c: bus registered: %s\n",bus->name)); + + MOD_INC_USE_COUNT; + + if (scan) + { + /* scan whole i2c bus */ + LOCK_I2C_BUS(bus); + for (i = 0; i < 256; i+=2) + { + i2c_start(bus); + ack = i2c_sendbyte(bus,i,0); + i2c_stop(bus); + if (!ack) + { + printk(KERN_INFO "i2c: scanning bus %s: found device at addr=0x%02x\n", + bus->name,i); + } + } + UNLOCK_I2C_BUS(bus); + } + + /* probe available drivers */ + for (i = 0; i < I2C_DRIVER_MAX; i++) + if (drivers[i]) + i2c_attach_device(bus,drivers[i]); + return 0; +} + +int i2c_unregister_bus(struct i2c_bus *bus) +{ + int i; + + /* detach devices */ + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (bus->devices[i]) + i2c_detach_device(bus->devices[i]); + + for (i = 0; i < I2C_BUS_MAX; i++) + if (bus == busses[i]) + break; + if (I2C_BUS_MAX == i) + { + printk(KERN_WARNING "i2c: unregister_bus #1: bus not found: %s\n", + bus->name); + return -ENODEV; + } + + MOD_DEC_USE_COUNT; + + busses[i] = NULL; + bus_count--; + REGPRINT(printk("i2c: bus unregistered: %s\n",bus->name)); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int i2c_register_driver(struct i2c_driver *driver) +{ + int i; + + memset(driver->devices,0,sizeof(driver->devices)); + driver->devcount = 0; + + for (i = 0; i < I2C_DRIVER_MAX; i++) + if (NULL == drivers[i]) + break; + if (I2C_DRIVER_MAX == i) + return -ENOMEM; + + drivers[i] = driver; + driver_count++; + + MOD_INC_USE_COUNT; + + REGPRINT(printk("i2c: driver registered: %s\n",driver->name)); + + /* Probe available busses */ + for (i = 0; i < I2C_BUS_MAX; i++) + if (busses[i]) + i2c_attach_device(busses[i],driver); + + return 0; +} + +int i2c_unregister_driver(struct i2c_driver *driver) +{ + int i; + + /* detach devices */ + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (driver->devices[i]) + i2c_detach_device(driver->devices[i]); + + for (i = 0; i < I2C_DRIVER_MAX; i++) + if (driver == drivers[i]) + break; + if (I2C_DRIVER_MAX == i) + { + printk(KERN_WARNING "i2c: unregister_driver: driver not found: %s\n", + driver->name); + return -ENODEV; + } + + MOD_DEC_USE_COUNT; + + drivers[i] = NULL; + driver_count--; + REGPRINT(printk("i2c: driver unregistered: %s\n",driver->name)); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int i2c_control_device(struct i2c_bus *bus, int id, + unsigned int cmd, void *arg) +{ + int i; + + for (i = 0; i < I2C_DEVICE_MAX; i++) + if (bus->devices[i] && bus->devices[i]->driver->id == id) + break; + if (i == I2C_DEVICE_MAX) + return -ENODEV; + if (NULL == bus->devices[i]->driver->command) + return -ENODEV; + return bus->devices[i]->driver->command(bus->devices[i],cmd,arg); +} + +/* ----------------------------------------------------------------------- */ + +#define I2C_SET(bus,ctrl,data) (bus->i2c_setlines(bus,ctrl,data)) +#define I2C_GET(bus) (bus->i2c_getdataline(bus)) + +void i2c_start(struct i2c_bus *bus) +{ + I2C_SET(bus,0,1); + I2C_SET(bus,1,1); + I2C_SET(bus,1,0); + I2C_SET(bus,0,0); + I2C_DEBUG(printk("%s: < ",bus->name)); +} + +void i2c_stop(struct i2c_bus *bus) +{ + I2C_SET(bus,0,0); + I2C_SET(bus,1,0); + I2C_SET(bus,1,1); + I2C_DEBUG(printk(">\n")); +} + +void i2c_one(struct i2c_bus *bus) +{ + I2C_SET(bus,0,1); + I2C_SET(bus,1,1); + I2C_SET(bus,0,1); +} + +void i2c_zero(struct i2c_bus *bus) +{ + I2C_SET(bus,0,0); + I2C_SET(bus,1,0); + I2C_SET(bus,0,0); +} + +int i2c_ack(struct i2c_bus *bus) +{ + int ack; + + I2C_SET(bus,0,1); + I2C_SET(bus,1,1); + ack = I2C_GET(bus); + I2C_SET(bus,0,1); + return ack; +} + +int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack) +{ + int i, ack; + + I2C_SET(bus,0,0); + for (i=7; i>=0; i--) + (data&(1<=0; i--) + { + I2C_SET(bus,1,1); + if (I2C_GET(bus)) + data |= (1<i2c_read) + return bus->i2c_read(bus, addr); + + i2c_start(bus); + i2c_sendbyte(bus,addr,0); + ret = i2c_readbyte(bus,1); + i2c_stop(bus); + return ret; +} + +int i2c_write(struct i2c_bus *bus, unsigned char addr, + unsigned char data1, unsigned char data2, int both) +{ + int ack; + + if (bus->i2c_write) + return bus->i2c_write(bus, addr, data1, data2, both); + + i2c_start(bus); + i2c_sendbyte(bus,addr,0); + ack = i2c_sendbyte(bus,data1,0); + if (both) + ack = i2c_sendbyte(bus,data2,0); + i2c_stop(bus); + return ack ? -1 : 0 ; +} + +/* ----------------------------------------------------------------------- */ + +#ifdef MODULE + +EXPORT_SYMBOL(i2c_register_bus); +EXPORT_SYMBOL(i2c_unregister_bus); +EXPORT_SYMBOL(i2c_register_driver); +EXPORT_SYMBOL(i2c_unregister_driver); +EXPORT_SYMBOL(i2c_control_device); +EXPORT_SYMBOL(i2c_start); +EXPORT_SYMBOL(i2c_stop); +EXPORT_SYMBOL(i2c_one); +EXPORT_SYMBOL(i2c_zero); +EXPORT_SYMBOL(i2c_ack); +EXPORT_SYMBOL(i2c_sendbyte); +EXPORT_SYMBOL(i2c_readbyte); +EXPORT_SYMBOL(i2c_read); +EXPORT_SYMBOL(i2c_write); + + +int init_module(void) +{ + return i2c_init(); +} + +void cleanup_module(void) +{ +} +#endif diff -u --recursive --new-file v2.1.93/linux/drivers/char/i2c.h linux/drivers/char/i2c.h --- v2.1.93/linux/drivers/char/i2c.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/i2c.h Wed Apr 8 17:24:48 1998 @@ -0,0 +1,166 @@ +#ifndef I2C_H +#define I2C_H + +/* + * linux i2c interface. Works a little bit like the scsi subsystem. + * There are: + * + * i2c the basic control module (like scsi_mod) + * bus driver a driver with a i2c bus (hostadapter driver) + * chip driver a driver for a chip connected + * to a i2c bus (cdrom/hd driver) + * + * A device will be attached to one bus and one chip driver. Every chip + * driver gets a unique ID. + * + * A chip driver can provide a ioctl-like callback for the + * communication with other parts of the kernel (not every i2c chip is + * useful without other devices, a TV card tuner for example). + * + * "i2c internal" parts of the structs: only the i2c module is allowed to + * write to them, for others they are read-only. + * + */ + +#define I2C_BUS_MAX 4 /* max # of bus drivers */ +#define I2C_DRIVER_MAX 8 /* max # of chip drivers */ +#define I2C_DEVICE_MAX 8 /* max # if devices per bus/driver */ + +struct i2c_bus; +struct i2c_driver; +struct i2c_device; + +#define I2C_DRIVERID_MSP3400 1 +#define I2C_DRIVERID_TUNER 2 +#define I2C_DRIVERID_VIDEOTEXT 3 + +#define I2C_BUSID_BT848 1 /* I2C bus on a BT848 */ + +/* + * struct for a driver for a i2c chip (tuner, soundprocessor, + * videotext, ... ). + * + * a driver will register within the i2c module. The i2c module will + * callback the driver (i2c_attach) for every device it finds on a i2c + * bus at the specified address. If the driver decides to "accept" + * the, device, it must return a struct i2c_device, and NULL + * otherwise. + * + * i2c_detach = i2c_attach ** -1 + * + * i2c_command will be used to pass commands to the driver in a + * ioctl-line manner. + * + */ + +struct i2c_driver +{ + char name[32]; /* some useful label */ + int id; /* device type ID */ + unsigned char addr_l, addr_h; /* address range of the chip */ + + int (*attach)(struct i2c_device *device); + int (*detach)(struct i2c_device *device); + int (*command)(struct i2c_device *device,unsigned int cmd, void *arg); + + /* i2c internal */ + struct i2c_device *devices[I2C_DEVICE_MAX]; + int devcount; +}; + + +/* + * this holds the informations about a i2c bus available in the system. + * + * a chip with a i2c bus interface (like bt848) registers the bus within + * the i2c module. This struct provides functions to access the i2c bus. + * + * One must hold the spinlock to access the i2c bus (XXX: is the irqsave + * required? Maybe better use a semaphore?). + * [-AC-] having a spinlock_irqsave is only needed if we have drivers wishing + * to bang their i2c bus from an interrupt. + * + * attach/detach_inform is a callback to inform the bus driver about + * attached chip drivers. + * + */ + +/* needed: unsigned long flags */ + +#define LOCK_I2C_BUS(bus) spin_lock_irqsave(&(bus->bus_lock),flags); +#define UNLOCK_I2C_BUS(bus) spin_unlock_irqrestore(&(bus->bus_lock),flags); + +struct i2c_bus +{ + char name[32]; /* some useful label */ + int id; + void *data; /* free for use by the bus driver */ + + spinlock_t bus_lock; + + /* attach/detach inform callbacks */ + void (*attach_inform)(struct i2c_bus *bus, int id); + void (*detach_inform)(struct i2c_bus *bus, int id); + + /* Software I2C */ + void (*i2c_setlines)(struct i2c_bus *bus, int ctrl, int data); + int (*i2c_getdataline)(struct i2c_bus *bus); + + /* Hardware I2C */ + int (*i2c_read)(struct i2c_bus *bus, unsigned char addr); + int (*i2c_write)(struct i2c_bus *bus, unsigned char addr, + unsigned char b1, unsigned char b2, int both); + + /* internal data for i2c module */ + struct i2c_device *devices[I2C_DEVICE_MAX]; + int devcount; +}; + + +/* + * This holds per-device data for a i2c device + */ + +struct i2c_device +{ + char name[32]; /* some useful label */ + void *data; /* free for use by the chip driver */ + unsigned char addr; /* chip addr */ + + /* i2c internal */ + struct i2c_bus *bus; + struct i2c_driver *driver; +}; + + +/* ------------------------------------------------------------------- */ +/* i2c module functions */ + +/* register/unregister a i2c bus */ +int i2c_register_bus(struct i2c_bus *bus); +int i2c_unregister_bus(struct i2c_bus *bus); + +/* register/unregister a chip driver */ +int i2c_register_driver(struct i2c_driver *driver); +int i2c_unregister_driver(struct i2c_driver *driver); + +/* send a command to a chip using the ioctl-like callback interface */ +int i2c_control_device(struct i2c_bus *bus, int id, + unsigned int cmd, void *arg); + +/* i2c bus access functions */ +void i2c_start(struct i2c_bus *bus); +void i2c_stop(struct i2c_bus *bus); +void i2c_one(struct i2c_bus *bus); +void i2c_zero(struct i2c_bus *bus); +int i2c_ack(struct i2c_bus *bus); + +int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack); +unsigned char i2c_readbyte(struct i2c_bus *bus,int last); + +/* i2c (maybe) hardware functions */ +int i2c_read(struct i2c_bus *bus, unsigned char addr); +int i2c_write(struct i2c_bus *bus, unsigned char addr, + unsigned char b1, unsigned char b2, int both); + +#endif /* I2C_H */ diff -u --recursive --new-file v2.1.93/linux/drivers/char/joystick.c linux/drivers/char/joystick.c --- v2.1.93/linux/drivers/char/joystick.c Tue Mar 10 10:03:31 1998 +++ linux/drivers/char/joystick.c Wed Apr 8 17:24:48 1998 @@ -1,7 +1,7 @@ /* - * $Id: joystick.c,v 1.2 1997/10/31 19:11:48 mj Exp $ + * $Id: joystick.c,v 1.6 1998/03/30 11:10:43 mj Exp $ * - * Copyright (C) 1997 Vojtech Pavlik + * Copyright (C) 1997, 1998 Vojtech Pavlik */ /* @@ -15,25 +15,20 @@ #include #include #include -#include #include #include #include #include #include - #include -#include -#include -#include #define PIT_HZ 1193180L /* PIT clock is 1.19318 MHz */ #define JS_MAXTIME PIT_HZ/250 /* timeout for read (4 ms) */ -#define JS_BUTTON_PERIOD HZ/50 /* button valid time (20 ms) */ -#define JS_AXIS_MIN_PERIOD HZ/25 /* axis min valid time (40 ms) */ -#define JS_AXIS_MAX_PERIOD HZ/25*2 /* axis max valid time (80 ms) */ +#define JS_TIMER_PERIOD HZ/50 /* button valid time (20 ms) */ +#define JS_BH_MIN_PERIOD HZ/25 /* axis min valid time (40 ms) */ +#define JS_BH_MAX_PERIOD HZ/25*2 /* axis max valid time (80 ms) */ #define JS_FIFO_SIZE 16 /* number of FIFO entries */ #define JS_BUFF_SIZE 32 /* output buffer size */ @@ -95,7 +90,7 @@ static struct js_fifo js_fifo[JS_FIFO_SIZE]; /* the fifo */ static unsigned char js_last_buttons = 0; /* last read button state */ -static unsigned long js_axis_time = 0; /* last read axis time */ +static unsigned long js_bh_time = 0; /* last read axis time */ static unsigned long js_mark_time = 0; static unsigned char js_axes_exist; /* all axes that exist */ @@ -132,12 +127,14 @@ * count_bits() counts set bits in a byte. */ -static int count_bits(unsigned char c) +static int count_bits(unsigned int c) { - int i, t = 0; - for (i = 0; i < 8; i++) - if (c & (1 << i)) t++; - return t; + int i = 0; + while (c) { + i += c & 1; + c >>= 1; + } + return i; } /* @@ -228,14 +225,59 @@ } } else - if ((jiffies > js_axis_time + JS_AXIS_MAX_PERIOD) && !js_mark_time) { + if ((jiffies > js_bh_time + JS_BH_MAX_PERIOD) && !js_mark_time) { js_mark_time = jiffies; mark_bh(JS_BH); } - js_timer.expires = jiffies + JS_BUTTON_PERIOD; + js_timer.expires = jiffies + JS_TIMER_PERIOD; add_timer(&js_timer); } + +/* + * Put an event in the buffer. This requires additional queue processing + * done by js_sync_buff, otherwise the buffer will be corrupted. + */ + +static void js_add_event(int i, __u32 time, __u8 type, __u8 number, __u16 value) +{ + int ahead = jsd[i].ahead++; + jsd[i].buff[ahead].time = time; + jsd[i].buff[ahead].type = type; + jsd[i].buff[ahead].number = number; + jsd[i].buff[ahead].value = value; + if (jsd[i].ahead == JS_BUFF_SIZE) jsd[i].ahead=0; +} + +/* + * This checks for all owerflows caused by recent additions to the buffer. + * It does anything only if some processes are reading the data too slowly. + */ + +static void js_sync_buff(void) +{ + int i; + + for (i = 0; i < JS_NUM; i++) + if (jsd[i].list) + if (jsd[i].bhead != jsd[i].ahead) { + if (ROT(jsd[i].bhead, jsd[i].tail, jsd[i].ahead) || (jsd[i].tail == jsd[i].bhead)) { + struct js_list *curl; + curl = jsd[i].list; + while (curl) { + if (ROT(jsd[i].bhead, curl->tail, jsd[i].ahead) || (curl->tail == jsd[i].bhead)) { + curl->tail = jsd[i].ahead; + curl->startup = jsd[i].exist; + } + curl = curl->next; + } + jsd[i].tail = jsd[i].ahead; + } + jsd[i].bhead = jsd[i].ahead; + wake_up_interruptible(&jsd[i].wait); + } +} + /* * js_do_bh() does the main processing and adds events to output buffers. */ @@ -246,7 +288,7 @@ int i, j, k; unsigned int t; - if (jiffies > js_axis_time + JS_AXIS_MIN_PERIOD) { + if (jiffies > js_bh_time + JS_BH_MIN_PERIOD) { unsigned int old_axis[4]; unsigned int t_low, t_high; @@ -348,18 +390,12 @@ k = 0; for (j = 0; j < 4; j++) if ((1 << j) & jsd[i].exist) { - if (!js_compare(js_axis[j].value, old_axis[j], js_axis[j].corr.prec)) { - jsd[i].buff[jsd[i].ahead].time = js_mark_time; - jsd[i].buff[jsd[i].ahead].type = JS_EVENT_AXIS; - jsd[i].buff[jsd[i].ahead].number = k; - jsd[i].buff[jsd[i].ahead].value = js_axis[j].value; - jsd[i].ahead++; - if (jsd[i].ahead == JS_BUFF_SIZE) jsd[i].ahead = 0; - } + if (!js_compare(js_axis[j].value, old_axis[j], js_axis[j].corr.prec)) + js_add_event(i, js_mark_time, JS_EVENT_AXIS, k, js_axis[j].value); k++; } } - js_axis_time = jiffies; + js_bh_time = jiffies; } js_mark_time = 0; @@ -373,14 +409,8 @@ k = 0; for (j = 4; j < 8; j++) if ((1 << j) & jsd[i].exist) { - if ((1 << j) & (js_buttons ^ js_fifo[t].event)) { - jsd[i].buff[jsd[i].ahead].time = js_fifo[t].time; - jsd[i].buff[jsd[i].ahead].type = JS_EVENT_BUTTON; - jsd[i].buff[jsd[i].ahead].number = k; - jsd[i].buff[jsd[i].ahead].value = (js_fifo[t].event >> j) & 1; - jsd[i].ahead++; - if (jsd[i].ahead == JS_BUFF_SIZE) jsd[i].ahead = 0; - } + if ((1 << j) & (js_buttons ^ js_fifo[t].event)) + js_add_event(i, js_fifo[t].time, JS_EVENT_BUTTON, k, (js_fifo[t].event >> j) & 1); k++; } } @@ -388,27 +418,10 @@ } /* - * Sync ahead with bhead and cut too long tails. + * Synchronize the buffer. */ - - for (i = 0; i < JS_NUM; i++) - if (jsd[i].list) - if (jsd[i].bhead != jsd[i].ahead) { - if (ROT(jsd[i].bhead, jsd[i].tail, jsd[i].ahead) || (jsd[i].tail == jsd[i].bhead)) { - struct js_list *curl; - curl = jsd[i].list; - while (curl) { - if (ROT(jsd[i].bhead, curl->tail, jsd[i].ahead) || (curl->tail == jsd[i].bhead)) { - curl->tail = jsd[i].ahead; - curl->startup = jsd[i].exist; - } - curl = curl->next; - } - jsd[i].tail = jsd[i].ahead; - } - jsd[i].bhead = jsd[i].ahead; - wake_up_interruptible(&jsd[i].wait); - } + + js_sync_buff(); } @@ -459,38 +472,46 @@ * Handle (non)blocking i/o. */ - if (count != sizeof(struct JS_DATA_TYPE)) { - if ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup) || (curl->startup && !js_axis_time)) { - add_wait_queue(&jsd[minor].wait, &wait); - current->state = TASK_INTERRUPTIBLE; - while ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup) || (curl->startup && !js_axis_time)) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - schedule(); - if (!jsd[minor].exist) { - retval = -ENODEV; - break; - } + if ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup && count != sizeof(struct JS_DATA_TYPE)) + || (curl->startup && !js_bh_time)) { + + add_wait_queue(&jsd[minor].wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup && count != sizeof(struct JS_DATA_TYPE)) + || (curl->startup && !js_bh_time)) { + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + if (!jsd[minor].exist) { + retval = -ENODEV; + break; } - current->state = TASK_RUNNING; - remove_wait_queue(&jsd[minor].wait, &wait); } + current->state = TASK_RUNNING; + remove_wait_queue(&jsd[minor].wait, &wait); + } - if (retval) return retval; + if (retval) return retval; /* * Do the i/o. */ + if (count != sizeof(struct JS_DATA_TYPE)) { if (curl->startup) { struct js_event tmpevent; +/* + * Initial button state. + */ t = 0; for (j = 0; j < 4 && (i < blocks) && !retval; j++) @@ -509,6 +530,10 @@ t++; } +/* + * Initial axis state. + */ + t = 0; for (j = 4; j < 8 && (i < blocks) && !retval; j++) if (jsd[minor].exist & (1 << j)) { @@ -527,6 +552,9 @@ } } +/* + * Buffer data. + */ while ((jsd[minor].ahead != (t = GOF(curl->tail))) && (i < blocks) && !retval) { if (copy_to_user(&buff[i], &jsd[minor].buff[t], sizeof(struct js_event))) @@ -562,6 +590,7 @@ buttons |= (!!(js_last_buttons & (1 << j))) << (i++); copy_to_user(&bufo->buttons, &buttons, sizeof(int)); + curl->startup = 0; curl->tail = GOB(jsd[minor].ahead); retval = sizeof(struct JS_DATA_TYPE); } @@ -637,7 +666,7 @@ sizeof(struct js_corr))) return -EFAULT; j++; } - js_axis_time = 0; + js_bh_time = 0; break; case JSIOCGCORR: j = 0; @@ -680,7 +709,7 @@ MOD_INC_USE_COUNT; if (!jsd[0].list && !jsd[1].list) { - js_timer.expires = jiffies + JS_BUTTON_PERIOD; + js_timer.expires = jiffies + JS_TIMER_PERIOD; add_timer(&js_timer); } @@ -793,8 +822,8 @@ } for (i = 0; i < JS_NUM; i++) { - if (jsd[i].exist) printk(KERN_INFO "js%d: %d-axis joystick at %#x\n", - i, count_bits(jsd[i].exist & JS_AXES), JS_PORT); + if (jsd[i].exist) printk(KERN_INFO "js%d: %d-axis %d-button joystick at %#x\n", + i, count_bits(jsd[i].exist & JS_AXES), count_bits(jsd[i].exist & JS_AXES), JS_PORT); jsd[i].ahead = jsd[i].bhead = 0; jsd[i].tail = JS_BUFF_SIZE - 1; jsd[i].list = NULL; diff -u --recursive --new-file v2.1.93/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.1.93/linux/drivers/char/lp.c Wed Apr 1 20:11:48 1998 +++ linux/drivers/char/lp.c Wed Apr 8 17:27:12 1998 @@ -14,6 +14,8 @@ * carsten@sol.wohnheim.uni-ulm.de * Support for parport by Philip Blundell * parport_sharing hacking by Andrea Arcangeli + * Fixed kernel_(to/from)_user memory copy to check for errors + * by Riccardo Facchetti */ /* This driver should, in theory, work with any parallel port that has an @@ -273,7 +275,9 @@ do { bytes_written = 0; copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE); - copy_from_user(lp->lp_buffer, buf, copy_size); + + if (copy_from_user(lp->lp_buffer, buf, copy_size)) + return -EFAULT; while (copy_size) { if (lp_char(lp->lp_buffer[bytes_written], minor)) { @@ -459,15 +463,19 @@ current->timeout=jiffies + LP_TIME(minor); schedule (); } + counter=0; + if (( i & 1) != 0) { Byte= (Byte | z<<4); - put_user(Byte, temp); + if (put_user(Byte, (char *)temp)) + return -EFAULT; temp++; } else Byte=z; } + lp_select_in_high(minor); - parport_release(lp_table[minor].dev); + lp_parport_release(minor); return temp-buf; } @@ -538,6 +546,7 @@ unsigned int cmd, unsigned long arg) { unsigned int minor = MINOR(inode->i_rdev); + int status; int retval = 0; #ifdef LP_DEBUG @@ -579,48 +588,33 @@ return -EINVAL; break; case LPGETIRQ: - retval = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(int)); - if (retval) - return retval; - copy_to_user((int *) arg, &LP_IRQ(minor), sizeof(int)); + if (copy_to_user((int *) arg, &LP_IRQ(minor), + sizeof(int))) + return -EFAULT; break; case LPGETSTATUS: - retval = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(int)); - if (retval) - return retval; - else { - int status; - lp_parport_claim (minor); - status = r_str(minor); - lp_parport_release (minor); - copy_to_user((int *) arg, &status, sizeof(int)); - } + lp_parport_claim(minor); + status = r_str(minor); + lp_parport_release(minor); + + if (copy_to_user((int *) arg, &status, sizeof(int))) + return -EFAULT; break; case LPRESET: lp_reset(minor); break; case LPGETSTATS: - retval = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct lp_stats)); - if (retval) - return retval; - else { - copy_to_user((int *) arg, &LP_STAT(minor), sizeof(struct lp_stats)); - if (suser()) - memset(&LP_STAT(minor), 0, sizeof(struct lp_stats)); - } + if (copy_to_user((int *) arg, &LP_STAT(minor), + sizeof(struct lp_stats))) + return -EFAULT; + if (suser()) + memset(&LP_STAT(minor), 0, + sizeof(struct lp_stats)); break; case LPGETFLAGS: - retval = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(int)); - if (retval) - return retval; - else { - int status = LP_F(minor); - copy_to_user((int *) arg, &status, sizeof(int)); - } + status = LP_F(minor); + if (copy_to_user((int *) arg, &status, sizeof(int))) + return -EFAULT; break; default: retval = -EINVAL; diff -u --recursive --new-file v2.1.93/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c --- v2.1.93/linux/drivers/char/msp3400.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/msp3400.c Wed Apr 8 17:24:48 1998 @@ -0,0 +1,923 @@ +/* + * programming the msp34* sound processor family + * + * (c) 1997,1998 Gerd Knorr + * + * what works and what doesn't: + * + * AM-Mono + * probably doesn't (untested) + * + * FM-Mono + * should work. The stereo modes are backward compatible to FM-mono, + * therefore FM-Mono should be allways available. + * + * FM-Stereo (B/G, used in germany) + * should work, with autodetect + * + * FM-Stereo (satellite) + * should work, no autodetect (i.e. default is mono, but you can + * switch to stereo -- untested) + * + * NICAM (B/G, used in UK, Scandinavia and Spain) + * should work, with autodetect. Support for NICAM was added by + * Pekka Pietikainen + * + * + * TODO: + * - better SAT support + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +/* #include */ + +/* kernel_thread */ +#define __KERNEL_SYSCALLS__ +#include + +#include "i2c.h" +#include + +#include "msp3400.h" + +int debug = 0; /* insmod parameter */ + +struct msp3400c +{ + struct i2c_bus *bus; + + int nicam; + int mode; + int norm; + int volume; + int stereo; + + /* thread */ + struct task_struct *thread; + struct semaphore *wait; + struct semaphore *notify; + int active,restart,rmmod; +}; + +#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ + +/* ---------------------------------------------------------------------- */ + +#define dprintk if (debug) printk + +MODULE_PARM(debug,"i"); + +/* ---------------------------------------------------------------------- */ + +#define I2C_MSP3400C 0x80 +#define I2C_MSP3400C_DEM 0x10 +#define I2C_MSP3400C_DFP 0x12 + +/* ----------------------------------------------------------------------- */ +/* functions for talking to the MSP3400C Sound processor */ + +static int msp3400c_reset(struct i2c_bus *bus) +{ + int ret = 0; + + udelay(2000); + i2c_start(bus); + i2c_sendbyte(bus, I2C_MSP3400C,2000); + i2c_sendbyte(bus, 0x00,0); + i2c_sendbyte(bus, 0x80,0); + i2c_sendbyte(bus, 0x00,0); + i2c_stop(bus); + udelay(2000); + i2c_start(bus); + if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) || + 0 != i2c_sendbyte(bus, 0x00,0) || + 0 != i2c_sendbyte(bus, 0x00,0) || + 0 != i2c_sendbyte(bus, 0x00,0)) + { + ret = -1; + printk(KERN_ERR "msp3400: chip reset failed, penguin on i2c bus?\n"); + } + i2c_stop(bus); + udelay(2000); + return ret; +} + +static int msp3400c_read(struct i2c_bus *bus, int dev, int addr) +{ + int ret=0; + short val = 0; + i2c_start(bus); + if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) || + 0 != i2c_sendbyte(bus, dev+1, 0) || + 0 != i2c_sendbyte(bus, addr >> 8, 0) || + 0 != i2c_sendbyte(bus, addr & 0xff, 0)) + { + ret = -1; + } + else + { + i2c_start(bus); + if (0 != i2c_sendbyte(bus, I2C_MSP3400C+1,2000)) + { + ret = -1; + } + else + { + val |= (int)i2c_readbyte(bus,0) << 8; + val |= (int)i2c_readbyte(bus,1); + } + } + i2c_stop(bus); + if (-1 == ret) + { + printk(KERN_WARNING "msp3400: I/O error, trying reset (read %s 0x%x)\n", + (dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr); + msp3400c_reset(bus); + } + return val; +} + +static int msp3400c_write(struct i2c_bus *bus, int dev, int addr, int val) +{ + int ret = 0; + + i2c_start(bus); + if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) || + 0 != i2c_sendbyte(bus, dev, 0) || + 0 != i2c_sendbyte(bus, addr >> 8, 0) || + 0 != i2c_sendbyte(bus, addr & 0xff, 0) || + 0 != i2c_sendbyte(bus, val >> 8, 0) || + 0 != i2c_sendbyte(bus, val & 0xff, 0)) + { + ret = -1; + } + i2c_stop(bus); + if (-1 == ret) + { + printk(KERN_ERR "msp3400: I/O error, trying reset (write %s 0x%x)\n", + (dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr); + msp3400c_reset(bus); + } + return ret; +} + +/* ------------------------------------------------------------------------ */ + +/* This macro is allowed for *constants* only, gcc must calculate it + at compile time. Remember -- no floats in kernel mode */ +#define MSP_CARRIER(freq) ((int)((float)(freq/18.432)*(1<<24))) + +#define MSP_MODE_AM_DETECT 0 +#define MSP_MODE_FM_RADIO 2 +#define MSP_MODE_FM_TERRA 3 +#define MSP_MODE_FM_SAT 4 +#define MSP_MODE_FM_NICAM1 5 +#define MSP_MODE_FM_NICAM2 6 + +static struct MSP_INIT_DATA_DEM +{ + int fir1[6]; + int fir2[6]; + int cdo1; + int cdo2; + int ad_cv; + int mode_reg; + int dfp_src; + int dfp_matrix; +} msp_init_data[] = { + /* AM (for carrier detect / msp3400) */ + { { 75, 19, 36, 35, 39, 40 }, { 75, 19, 36, 35, 39, 40 }, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0500, 0x0020, 0x3000}, + + /* AM (for carrier detect / msp3410) */ + { { -1, -1, -8, 2, 59, 126 }, { -1, -1, -8, 2, 59, 126 }, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0100, 0x0020, 0x3000}, + + /* FM Radio */ + { { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 }, + MSP_CARRIER(10.7), MSP_CARRIER(10.7), 0x00d0, 0x0480, 0x0020, 0x3002 }, + + /* Terrestial FM-mono */ + { { 3, 18, 27, 48, 66, 72 }, { 3, 18, 27, 48, 66, 72 }, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0480, 0x0030, 0x3000}, + + /* Sat FM-mono */ + { { 1, 9, 14, 24, 33, 37 }, { 3, 18, 27, 48, 66, 72 }, + MSP_CARRIER(6.5), MSP_CARRIER(6.5), 0x00c6, 0x0480, 0x0000, 0x3000}, + + /* NICAM B/G, D/K */ + { { -2, -8, -10, 10, 50, 86 }, { 3, 18, 27, 48, 66, 72 }, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0040, 0x0120, 0x3000}, + + /* NICAM I */ + { { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 }, + MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0040, 0x0120, 0x3000}, +}; + +struct CARRIER_DETECT +{ + int cdo; + char *name; +}; + +static struct CARRIER_DETECT carrier_detect_main[] = +{ + /* main carrier */ + { MSP_CARRIER(4.5), "4.5 NTSC" }, + { MSP_CARRIER(5.5), "5.5 PAL B/G" }, + { MSP_CARRIER(6.0), "6.0 PAL I" }, + { MSP_CARRIER(6.5), "6.5 PAL SAT / SECAM" } +}; + +static struct CARRIER_DETECT carrier_detect_55[] = { + /* PAL B/G */ + { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" }, + { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" } +}; + +static struct CARRIER_DETECT carrier_detect_65[] = { + /* PAL SAT / SECAM */ + { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" }, + { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" }, + { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" }, +}; + +#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT)) + +/* ------------------------------------------------------------------------ */ + +static void msp3400c_setcarrier(struct i2c_bus *bus, int cdo1, int cdo2) +{ + msp3400c_write(bus,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff); + msp3400c_write(bus,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12); + msp3400c_write(bus,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff); + msp3400c_write(bus,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12); +} + +static void msp3400c_setvolume(struct i2c_bus *bus, int vol) +{ + int val = (vol * 0x73 / 65535) << 8; + + dprintk("msp3400: setvolume: 0x%02x\n",val>>8); + msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */ + msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */ + /* scart - on/off only */ + msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0007, val ? 0x4000 : 0); +} + +static void msp3400c_setmode(struct msp3400c *msp, int type) +{ + int i; + + dprintk("msp3400: setmode: %d\n",type); + msp->mode = type; + msp->stereo = VIDEO_SOUND_MONO; + + msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */ + msp_init_data[type].ad_cv); + + for (i = 5; i >= 0; i--) /* fir 1 */ + msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0001, + msp_init_data[type].fir1[i]); + + msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */ + msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0040); + msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0000); + for (i = 5; i >= 0; i--) + msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, + msp_init_data[type].fir2[i]); + + msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */ + msp_init_data[type].mode_reg); + + msp3400c_setcarrier(msp->bus, msp_init_data[type].cdo1, + msp_init_data[type].cdo2); + + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, + msp_init_data[type].dfp_src); + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, + msp_init_data[type].dfp_src); + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a, + msp_init_data[type].dfp_src); + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, + msp_init_data[type].dfp_matrix); + + if (msp->nicam) + { + /* msp3410 needs some more initialization */ + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0010, 0x3000); + } +} + +static void msp3400c_setstereo(struct msp3400c *msp, int mode) +{ + int nicam=0; /* channel source: FM/AM or nicam */ + + /* switch demodulator */ + switch (msp->mode) + { + case MSP_MODE_FM_TERRA: + dprintk("msp3400: B/G setstereo: %d\n",mode); + msp->stereo = mode; + msp3400c_setcarrier(msp->bus,MSP_CARRIER(5.7421875),MSP_CARRIER(5.5)); + switch (mode) + { + case VIDEO_SOUND_STEREO: + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3001); + break; + case VIDEO_SOUND_MONO: + case VIDEO_SOUND_LANG1: + case VIDEO_SOUND_LANG2: + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3000); + break; + } + break; + case MSP_MODE_FM_SAT: + dprintk("msp3400: sat setstereo: %d\n",mode); + msp->stereo = mode; + switch (mode) + { + case VIDEO_SOUND_MONO: + msp3400c_setcarrier(msp->bus, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); + break; + case VIDEO_SOUND_STEREO: + msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); + break; + case VIDEO_SOUND_LANG1: + msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); + break; + case VIDEO_SOUND_LANG2: + msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); + break; + } + break; + case MSP_MODE_FM_NICAM1: + dprintk("msp3400: NICAM1 setstereo: %d\n",mode); + msp->stereo = mode; + msp3400c_setcarrier(msp->bus,MSP_CARRIER(5.85),MSP_CARRIER(5.5)); + nicam=0x0100; + break; + default: + /* can't do stereo - abort here */ + return; + } + + /* switch audio */ + switch (mode) + { + case VIDEO_SOUND_STEREO: + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, 0x0020|nicam); + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, 0x0020|nicam); + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a, 0x0020|nicam); + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0005, 0x4000); + break; + case VIDEO_SOUND_MONO: + case VIDEO_SOUND_LANG1: + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, 0x0000|nicam); + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, 0x0000|nicam); + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a, 0x0000|nicam); + break; + case VIDEO_SOUND_LANG2: + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, 0x0010|nicam); + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, 0x0010|nicam); + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a, 0x0010|nicam); + break; + } +} + +/* ----------------------------------------------------------------------- */ + +struct REGISTER_DUMP { + int addr; + char *name; +}; + +struct REGISTER_DUMP d1[] = +{ + { 0x007e, "autodetect" }, + { 0x0023, "C_AD_BITS " }, + { 0x0038, "ADD_BITS " }, + { 0x003e, "CIB_BITS " }, + { 0x0057, "ERROR_RATE" }, +}; + +/* + * A kernel thread for msp3400 control -- we don't want to block the + * in the ioctl while doing the sound carrier & stereo detect + */ + +int msp3400c_thread(void *data) +{ + unsigned long flags; + struct msp3400c *msp = data; + struct semaphore sem = MUTEX_LOCKED; + + struct CARRIER_DETECT *cd; + int count, max1,max2,val1,val2, val,this, check_stereo; + int i; + + /* lock_kernel(); */ + + exit_mm(current); + current->session = 1; + current->pgrp = 1; + sigfillset(¤t->blocked); + current->fs->umask = 0; + strcpy(current->comm,"msp3400"); + + msp->wait = &sem; + msp->thread = current; + + /* unlock_kernel(); */ + + dprintk("msp3400: thread: start\n"); + if(msp->notify != NULL) + up(msp->notify); + + for (;;) + { + if (msp->rmmod) + goto done; + dprintk("msp3400: thread: sleep\n"); + down_interruptible(&sem); + dprintk("msp3400: thread: wakeup\n"); + if (msp->rmmod) + goto done; +#if 0 + if (VIDEO_MODE_RADIO == msp->norm) + { + msp->active = 1; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + HZ/10; + schedule(); + if (signal_pending(current)) + goto done; + LOCK_I2C_BUS(msp->bus); + val1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b); + val2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c); + UNLOCK_I2C_BUS(msp->bus); + printk("msp3400: DC %d/%d\n",val1,val2); + msp->active = 0; + continue; + } +#endif + + if (VIDEO_MODE_RADIO == msp->norm) + continue; /* nothing to do */ + + msp->active = 1; +restart: + LOCK_I2C_BUS(msp->bus); + msp3400c_setvolume(msp->bus, 0); + msp3400c_setmode(msp, MSP_MODE_AM_DETECT); + val1 = val2 = max1 = max2 = check_stereo = 0; + + /* carrier detect pass #1 -- main carrier */ + cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main); + for (this = 0; this < count; this++) + { + msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo); + UNLOCK_I2C_BUS(msp->bus); + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + HZ/25; + schedule(); + if (signal_pending(current)) + goto done; + if (msp->restart) + { + msp->restart = 0; + goto restart; + } + + LOCK_I2C_BUS(msp->bus); + val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b); + if (val1 < val) + val1 = val, max1 = this; + dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name); + } + + /* carrier detect pass #2 -- second (stereo) carrier */ + switch (max1) + { + case 1: /* 5.5 */ + cd = carrier_detect_55; count = CARRIER_COUNT(carrier_detect_55); + break; + case 3: /* 6.5 */ + cd = carrier_detect_65; count = CARRIER_COUNT(carrier_detect_65); + break; + case 0: /* 4.5 */ + case 2: /* 6.0 */ + default: + cd = NULL; count = 0; + break; + } + for (this = 0; this < count; this++) + { + msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo); + UNLOCK_I2C_BUS(msp->bus); + + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + HZ/25; + schedule(); + if (signal_pending(current)) + goto done; + if (msp->restart) + { + msp->restart = 0; + goto restart; + } + + LOCK_I2C_BUS(msp->bus); + val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b); + if (val2 < val) + val2 = val, max2 = this; + dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name); + } + + /* programm the msp3400 according to the results */ + switch (max1) + { + case 0: /* 4.5 */ + case 1: /* 5.5 */ + msp3400c_setmode(msp, MSP_MODE_FM_TERRA); + msp3400c_setcarrier(msp->bus, carrier_detect_main[max1].cdo, + carrier_detect_main[max1].cdo); + if (max2 == 0) + { + /* B/G FM-stereo */ + msp3400c_setstereo(msp, VIDEO_SOUND_MONO); + check_stereo = 1; + } + if (max2 == 1 && msp->nicam) + { + /* B/G NICAM */ + msp3400c_setmode(msp, MSP_MODE_FM_NICAM1); + /* msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x21, 0x01); */ + msp3400c_setcarrier(msp->bus, MSP_CARRIER(5.85), + MSP_CARRIER(5.5)); + check_stereo = 1; + } + break; + case 2: /* 6.0 */ + case 3: /* 6.5 */ + default: + msp3400c_setmode(msp, MSP_MODE_FM_TERRA); + msp3400c_setcarrier(msp->bus, carrier_detect_main[max1].cdo, + carrier_detect_main[max1].cdo); + msp3400c_setstereo(msp, VIDEO_SOUND_STEREO); + break; + } + + /* unmute */ + msp3400c_setvolume(msp->bus, msp->volume); + + if (check_stereo) + { + /* stereo available -- check current mode */ + UNLOCK_I2C_BUS(msp->bus); + + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + HZ; + schedule(); + if (signal_pending(current)) + goto done; + if (msp->restart) + { + msp->restart = 0; + goto restart; + } + + LOCK_I2C_BUS(msp->bus); + switch (msp->mode) + { + case MSP_MODE_FM_TERRA: + val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x18); + dprintk("msp3400: stereo detect register: %d\n",val); + + if (val > 4096) + { + msp3400c_setstereo(msp, VIDEO_SOUND_STEREO); + } + else if (val < -4096) + { + msp3400c_setstereo(msp, VIDEO_SOUND_LANG1); + } + else + { + msp3400c_setstereo(msp, VIDEO_SOUND_MONO); + } + break; + case MSP_MODE_FM_NICAM1: + val = msp3400c_read(msp->bus, I2C_MSP3400C_DEM, 0x23); + switch ((val & 0x1e) >> 1) + { + case 0: + case 8: + msp3400c_setstereo(msp, VIDEO_SOUND_STEREO); + break; + default: + msp3400c_setstereo(msp, VIDEO_SOUND_MONO); + break; + } + + /* dump registers (for debugging) */ + if (debug) + { + for (i=0; ibus,I2C_MSP3400C_DEM, d1[i].addr); + printk(KERN_DEBUG "msp3400: %s = 0x%x\n", + d1[i].name,val); + } + } + break; + } + } + UNLOCK_I2C_BUS(msp->bus); + msp->active = 0; + } + +done: + dprintk("msp3400: thread: exit\n"); + msp->wait = NULL; + msp->active = 0; + msp->thread = NULL; + + if(msp->notify != NULL) + up(msp->notify); + return 0; +} + +int msp3410d_thread(void *data) +{ + unsigned long flags; + struct msp3400c *msp = data; + struct semaphore sem = MUTEX_LOCKED; + int i, val; + + /* lock_kernel(); */ + + exit_mm(current); + current->session = 1; + current->pgrp = 1; + sigfillset(¤t->blocked); + current->fs->umask = 0; + strcpy(current->comm,"msp3410 (nicam)"); + + msp->wait = &sem; + msp->thread = current; + + /* unlock_kernel(); */ + + dprintk("msp3410: thread: start\n"); + if(msp->notify != NULL) + up(msp->notify); + + for (;;) + { + if (msp->rmmod) + goto done; + dprintk("msp3410: thread: sleep\n"); + down_interruptible(&sem); + dprintk("msp3410: thread: wakeup\n"); + if (msp->rmmod) + goto done; + + if (VIDEO_MODE_RADIO == msp->norm) + continue; /* nothing to do */ + + msp->active = 1; + +restart: + LOCK_I2C_BUS(msp->bus); + /* mute */ + msp3400c_setvolume(msp->bus, 0); + /* quick & dirty hack: + get the audio proccessor into some useful state */ + msp3400c_setmode(msp, MSP_MODE_FM_NICAM1); + /* kick autodetect */ + msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x20, 0x01); + msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x21, 0x01); + UNLOCK_I2C_BUS(msp->bus); + + /* wait 1 sec */ + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + HZ; + schedule(); + if (signal_pending(current)) + goto done; + if (msp->restart) + { + msp->restart = 0; + goto restart; + } + + LOCK_I2C_BUS(msp->bus); + /* debug register dump */ + for (i = 0; i < sizeof(d1)/sizeof(struct REGISTER_DUMP); i++) + { + val = msp3400c_read(msp->bus,I2C_MSP3400C_DEM,d1[i].addr); + printk(KERN_DEBUG "msp3400: %s = 0x%x\n",d1[i].name,val); + } + /* unmute */ + msp3400c_setvolume(msp->bus, msp->volume); + UNLOCK_I2C_BUS(msp->bus); + + msp->active = 0; + } + +done: + dprintk("msp3410: thread: exit\n"); + msp->wait = NULL; + msp->active = 0; + msp->thread = NULL; + + if(msp->notify != NULL) + up(msp->notify); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int msp3400c_attach(struct i2c_device *device) +{ + unsigned long flags; + struct semaphore sem = MUTEX_LOCKED; + struct msp3400c *msp; + int rev1,rev2; + + /* + * MSP3400's are for now only assumed to live on busses + * connected to a BT848. Adjust as and when you get new + * funky cards using these components. + */ + + if(device->bus->id != I2C_BUSID_BT848) + return -EINVAL; + + device->data = msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL); + if (NULL == msp) + return -ENOMEM; + memset(msp,0,sizeof(struct msp3400c)); + msp->bus = device->bus; + msp->volume = 65535; + + LOCK_I2C_BUS(msp->bus); + if (-1 == msp3400c_reset(msp->bus)) + { + UNLOCK_I2C_BUS(msp->bus); + kfree(msp); + return -1; + } + + msp3400c_setmode(msp, MSP_MODE_FM_TERRA); + msp3400c_setvolume(msp->bus, msp->volume); + + rev1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1e); + rev2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1f); + +#if 0 + /* this will turn on a 1kHz beep - might be useful for debugging... */ + msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0014, 0x1040); +#endif + UNLOCK_I2C_BUS(msp->bus); + + sprintf(device->name,"MSP34%02d%c-%c%d", + (rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f); + msp->nicam = (((rev2>>8)&0xff) == 10) ? 1 : 0; + printk(KERN_INFO "msp3400: init: chip=%s%s\n", + device->name, msp->nicam ? ", can decode nicam" : ""); + + MOD_INC_USE_COUNT; + /* startup control thread */ + msp->notify = &sem; + kernel_thread(msp3400c_thread, (void *)msp, 0); + down(&sem); + msp->notify = NULL; + if (!msp->active) + up(msp->wait); + return 0; +} + +static int msp3400c_detach(struct i2c_device *device) +{ + unsigned long flags; + struct semaphore sem = MUTEX_LOCKED; + struct msp3400c *msp = (struct msp3400c*)device->data; + + /* shutdown control thread */ + msp->notify = &sem; + msp->rmmod = 1; + if (!msp->active) + up(msp->wait); + down(&sem); + msp->notify = NULL; + + LOCK_I2C_BUS(msp->bus); + msp3400c_reset(msp->bus); + UNLOCK_I2C_BUS(msp->bus); + + kfree(msp); + MOD_DEC_USE_COUNT; + return 0; +} + +static int msp3400c_command(struct i2c_device *device, + unsigned int cmd, void *arg) +{ + unsigned long flags; + struct msp3400c *msp = (struct msp3400c*)device->data; + int *iarg = (int*)arg; + + switch (cmd) + { + case MSP_SET_RADIO: + msp->norm = VIDEO_MODE_RADIO; + LOCK_I2C_BUS(msp->bus); + msp3400c_setmode(msp,MSP_MODE_FM_RADIO); + msp3400c_setcarrier(msp->bus, MSP_CARRIER(10.7),MSP_CARRIER(10.7)); + UNLOCK_I2C_BUS(msp->bus); + break; + case MSP_SET_TVNORM: + msp->norm = *iarg; + break; + case MSP_NEWCHANNEL: + if (!msp->active) + up(msp->wait); + else + msp->restart = 1; + break; + + case MSP_GET_VOLUME: + *iarg = msp->volume; + break; + case MSP_SET_VOLUME: + msp->volume = *iarg; + LOCK_I2C_BUS(msp->bus); + msp3400c_setvolume(msp->bus,msp->volume); + UNLOCK_I2C_BUS(msp->bus); + break; + + case MSP_GET_STEREO: + *iarg = msp->stereo; + break; + case MSP_SET_STEREO: + if (*iarg) + { + LOCK_I2C_BUS(msp->bus); + msp3400c_setstereo(msp,*iarg); + UNLOCK_I2C_BUS(msp->bus); + } + break; + + case MSP_GET_DC: + LOCK_I2C_BUS(msp->bus); + *iarg = (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b) + + (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c); + UNLOCK_I2C_BUS(msp->bus); + break; + + default: + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +struct i2c_driver i2c_driver_msp = +{ + "msp3400", /* name */ + I2C_DRIVERID_MSP3400, /* ID */ + I2C_MSP3400C, I2C_MSP3400C, /* addr range */ + + msp3400c_attach, + msp3400c_detach, + msp3400c_command +}; + +#ifdef MODULE +int init_module(void) +#else +int msp3400c_init(void) +#endif +{ + i2c_register_driver(&i2c_driver_msp); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_unregister_driver(&i2c_driver_msp); +} +#endif + diff -u --recursive --new-file v2.1.93/linux/drivers/char/msp3400.h linux/drivers/char/msp3400.h --- v2.1.93/linux/drivers/char/msp3400.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/msp3400.h Wed Apr 8 17:24:48 1998 @@ -0,0 +1,18 @@ +#ifndef MSP3400_H +#define MSP3400_H + +/* ---------------------------------------------------------------------- */ + +#define MSP_SET_TVNORM _IOW('m',1,int) /* TV mode + PAL/SECAM/NTSC */ +#define MSP_SET_RADIO _IO('m',2) /* Radio mode */ +#define MSP_NEWCHANNEL _IO('m',3) /* indicate new channel */ + +#define MSP_GET_VOLUME _IOR('m',4,int) +#define MSP_SET_VOLUME _IOW('m',5,int) + +#define MSP_GET_STEREO _IOR('m',6,int) +#define MSP_SET_STEREO _IOW('m',7,int) + +#define MSP_GET_DC _IOW('m',8,int) + +#endif /* MSP3400_H */ diff -u --recursive --new-file v2.1.93/linux/drivers/char/pms.c linux/drivers/char/pms.c --- v2.1.93/linux/drivers/char/pms.c Mon Feb 23 18:12:04 1998 +++ linux/drivers/char/pms.c Wed Apr 8 17:24:48 1998 @@ -1020,11 +1020,10 @@ */ #ifdef MODULE - -MODULE_PARM(io_port,"i"); -MODULE_PARM(mem_base,"i"); - int init_module(void) +#else +void init_pms_cards(void) +#endif { printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n"); @@ -1040,8 +1039,13 @@ pms_device.width=320; pms_swsense(75); pms_resolution(320,240); - return video_register_device((struct video_device *)&pms_device); + return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER); } + +#ifdef MODULE + +MODULE_PARM(io_port,"i"); +MODULE_PARM(mem_base,"i"); void cleanup_module(void) { diff -u --recursive --new-file v2.1.93/linux/drivers/char/pty.c linux/drivers/char/pty.c --- v2.1.93/linux/drivers/char/pty.c Mon Apr 6 17:40:59 1998 +++ linux/drivers/char/pty.c Tue Apr 7 07:52:04 1998 @@ -7,7 +7,6 @@ * -- C. Scott Ananian , 14-Jan-1998 */ -#include #include /* For EXPORT_SYMBOL */ #include diff -u --recursive --new-file v2.1.93/linux/drivers/char/tuner.c linux/drivers/char/tuner.c --- v2.1.93/linux/drivers/char/tuner.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/tuner.c Wed Apr 8 17:24:48 1998 @@ -0,0 +1,269 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c.h" +#include + +#include "tuner.h" + +int debug = 0; /* insmod parameter */ +int type = 0; /* tuner type */ + +#define dprintk if (debug) printk + +MODULE_PARM(debug,"i"); +MODULE_PARM(type,"i"); + +struct tuner +{ + struct i2c_bus *bus; /* where is our chip */ + int addr; + + int type; /* chip type */ + int freq; /* keep track of the current settings */ + int radio; +}; + +/* ---------------------------------------------------------------------- */ + +struct tunertype +{ + char *name; + unsigned char Vendor; + unsigned char Type; + + unsigned short thresh1; /* frequency Range for UHF,VHF-L, VHF_H */ + unsigned short thresh2; + unsigned char VHF_L; + unsigned char VHF_H; + unsigned char UHF; + unsigned char config; + unsigned char I2C; + unsigned short IFPCoff; +}; + +/* + * The floats in the tuner struct are computed at compile time + * by gcc and cast back to integers. Thus we don't violate the + * "no float in kernel" rule. + */ +static struct tunertype tuners[] = { + {"Temic PAL", TEMIC, PAL, + 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,623}, + {"Philips PAL_I", Philips, PAL_I, + 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc0,623}, + {"Philips NTSC", Philips, NTSC, + 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0,732}, + {"Philips SECAM", Philips, SECAM, + 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,0xc0,623}, + {"NoTuner", NoTuner, NOTUNER, + 0 ,0 ,0x00,0x00,0x00,0x00,0x00,000}, + {"Philips PAL", Philips, PAL, + 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0,623}, + {"Temic NTSC", TEMIC, NTSC, + 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,732}, + {"TEMIC PAL_I", TEMIC, PAL_I, + 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623}, +}; + +/* ---------------------------------------------------------------------- */ + +static int tuner_getstatus (struct tuner *t) +{ + return i2c_read(t->bus,t->addr+1); +} + +#define TUNER_POR 0x80 +#define TUNER_FL 0x40 +#define TUNER_AFC 0x07 + +static int tuner_islocked (struct tuner *t) +{ + return (tuner_getstatus (t) & TUNER_FL); +} + +static int tuner_afcstatus (struct tuner *t) +{ + return (tuner_getstatus (t) & TUNER_AFC) - 2; +} + + +static void set_tv_freq(struct tuner *t, int freq) +{ + unsigned long flags; + u8 config; + u16 div; + struct tunertype *tun=&tuners[t->type]; + + if (freq < tun->thresh1) + config = tun->VHF_L; + else if (freq < tun->thresh2) + config = tun->VHF_H; + else + config = tun->UHF; + + div=freq + (int)(16*38.9); + div&=0x7fff; + + LOCK_I2C_BUS(t->bus); + if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) { + printk("tuner: i2c i/o error #1\n"); + } else { + if (i2c_write(t->bus, t->addr, tun->config, config, 1)) + printk("tuner: i2c i/o error #2\n"); + } + UNLOCK_I2C_BUS(t->bus); +} + +static void set_radio_freq(struct tuner *t, int freq) +{ + unsigned long flags; + u8 config; + u16 div; + struct tunertype *tun=&tuners[type]; + + config = 0xa5; + div=freq + (int)(16*10.7); + div&=0x7fff; + + LOCK_I2C_BUS(t->bus); + if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) { + printk("tuner: i2c i/o error #1\n"); + } else { + if (i2c_write(t->bus, t->addr, tun->config, config, 1)) + printk("tuner: i2c i/o error #2\n"); + } + if (debug) { + UNLOCK_I2C_BUS(t->bus); + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + HZ/10; + schedule(); + LOCK_I2C_BUS(t->bus); + + if (tuner_islocked (t)) + printk ("tuner: PLL locked\n"); + else + printk ("tuner: PLL not locked\n"); + + printk ("tuner: AFC: %d\n", tuner_afcstatus (t)); + } + UNLOCK_I2C_BUS(t->bus); +} + +/* ---------------------------------------------------------------------- */ + +static int tuner_attach(struct i2c_device *device) +{ + struct tuner *t; + + /* + * For now we only try and attach these tuners to the BT848 + * bus. This same module will however work different species + * of card using these chips. Just change the constraints + * (i2c doesn't have a totally clash free 'address' space) + */ + + if(device->bus->id!=I2C_BUSID_BT848) + return -EINVAL; + + device->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL); + if (NULL == t) + return -ENOMEM; + memset(t,0,sizeof(struct tuner)); + strcpy(device->name,"tuner"); + t->bus = device->bus; + t->addr = device->addr; + t->type = type; + dprintk("tuner: type is %d (%s)\n",t->type,tuners[t->type].name); + + MOD_INC_USE_COUNT; + return 0; +} + +static int tuner_detach(struct i2c_device *device) +{ + struct tuner *t = (struct tuner*)device->data; + kfree(t); + MOD_DEC_USE_COUNT; + return 0; +} + +static int tuner_command(struct i2c_device *device, + unsigned int cmd, void *arg) +{ + struct tuner *t = (struct tuner*)device->data; + int *iarg = (int*)arg; + + switch (cmd) + { + case TUNER_SET_TYPE: + t->type = *iarg; + dprintk("tuner: type set to %d (%s)\n", + t->type,tuners[t->type].name); + break; + + case TUNER_SET_TVFREQ: + dprintk("tuner: tv freq set to %d.%02d\n", + (*iarg)/16,(*iarg)%16*100/16); + set_tv_freq(t,*iarg); + t->radio = 0; + t->freq = *iarg; + break; + + case TUNER_SET_RADIOFREQ: + dprintk("tuner: radio freq set to %d.%02d\n", + (*iarg)/16,(*iarg)%16*100/16); + set_radio_freq(t,*iarg); + t->radio = 1; + t->freq = *iarg; + break; + + default: + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +struct i2c_driver i2c_driver_tuner = +{ + "tuner", /* name */ + I2C_DRIVERID_TUNER, /* ID */ + 0xc0, 0xce, /* addr range */ + + tuner_attach, + tuner_detach, + tuner_command +}; + +#ifdef MODULE +int init_module(void) +#else +int msp3400c_init(void) +#endif +{ + i2c_register_driver(&i2c_driver_tuner); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_unregister_driver(&i2c_driver_tuner); +} +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -u --recursive --new-file v2.1.93/linux/drivers/char/tuner.h linux/drivers/char/tuner.h --- v2.1.93/linux/drivers/char/tuner.h Tue Jan 13 20:14:36 1998 +++ linux/drivers/char/tuner.h Wed Apr 8 17:24:48 1998 @@ -42,19 +42,8 @@ #define TEMIC 2 #define Sony 3 -struct tunertype { - char *name; - unchar Vendor; - unchar Type; - - ushort thresh1; /* frequency Range for UHF,VHF-L, VHF_H */ - ushort thresh2; - unchar VHF_L; - unchar VHF_H; - unchar UHF; - unchar config; - unchar I2C; - ushort IFPCoff; -}; -#endif +#define TUNER_SET_TYPE _IOW('t',1,int) /* set tuner type */ +#define TUNER_SET_TVFREQ _IOW('t',2,int) /* set tv freq */ +#define TUNER_SET_RADIOFREQ _IOW('t',3,int) /* set radio freq */ +#endif diff -u --recursive --new-file v2.1.93/linux/drivers/char/videodev.c linux/drivers/char/videodev.c --- v2.1.93/linux/drivers/char/videodev.c Fri Jan 23 18:10:31 1998 +++ linux/drivers/char/videodev.c Wed Apr 8 17:24:48 1998 @@ -39,6 +39,9 @@ #ifdef CONFIG_VIDEO_BT848 extern int init_bttv_cards(struct video_init *); #endif +#ifdef CONFIG_VIDEO_SAA5249 +extern int init_saa_5249(struct video_init *); +#endif #ifdef CONFIG_VIDEO_CQCAM extern int init_colour_qcams(struct video_init *); #endif @@ -50,6 +53,9 @@ #ifdef CONFIG_VIDEO_BT848 {"bttv", init_bttv_cards}, #endif +#ifdef CONFIG_VIDEO_SAA5249 + {"saa5249", init_saa_5249}, +#endif #ifdef CONFIG_VIDEO_CQCAM {"c-qcam", init_colour_qcams}, #endif @@ -57,7 +63,7 @@ {"bw-qcam", init_bw_qcams}, #endif #ifdef CONFIG_VIDEO_PMS - {"PMS", init_pms_cards}, /* not defined anywhere */ + {"PMS", init_pms_cards}, #endif {"end", NULL} }; @@ -74,6 +80,8 @@ return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK); } + + /* * Write for now does nothing. No reason it shouldnt do overlay setting * for some boards I guess.. @@ -162,18 +170,51 @@ /* * We need to do MMAP support */ + + +int video_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; + if(vfl->mmap) + return vfl->mmap(vfl, (char *)vma->vm_start, + (unsigned long)(vma->vm_end-vma->vm_start)); + return -EINVAL; +} /* * Video For Linux device drivers request registration here. */ -int video_register_device(struct video_device *vfd) +int video_register_device(struct video_device *vfd, int type) { int i=0; - int base=0; + int base; int err; + int end; + + switch(type) + { + case VFL_TYPE_GRABBER: + base=0; + end=64; + break; + case VFL_TYPE_VTX: + base=192; + end=224; + break; + case VFL_TYPE_VBI: + base=224; + end=240; + break; + case VFL_TYPE_RADIO: + base=64; + end=128; + break; + default: + return -1; + } - for(i=base;i #define __NO_VERSION__ #include "hisax.h" #include "isac.h" diff -u --recursive --new-file v2.1.93/linux/drivers/isdn/isdnloop/isdnloop.c linux/drivers/isdn/isdnloop/isdnloop.c --- v2.1.93/linux/drivers/isdn/isdnloop/isdnloop.c Wed Apr 1 20:11:51 1998 +++ linux/drivers/isdn/isdnloop/isdnloop.c Tue Apr 7 07:52:04 1998 @@ -38,6 +38,7 @@ * */ +#include #include "isdnloop.h" static char diff -u --recursive --new-file v2.1.93/linux/drivers/isdn/isdnloop/isdnloop.h linux/drivers/isdn/isdnloop/isdnloop.h --- v2.1.93/linux/drivers/isdn/isdnloop/isdnloop.h Wed Apr 1 20:11:51 1998 +++ linux/drivers/isdn/isdnloop/isdnloop.h Tue Apr 7 07:52:04 1998 @@ -53,7 +53,6 @@ #ifdef __KERNEL__ /* Kernel includes */ -#include #include #include #include diff -u --recursive --new-file v2.1.93/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c --- v2.1.93/linux/drivers/misc/parport_procfs.c Tue Feb 17 13:12:46 1998 +++ linux/drivers/misc/parport_procfs.c Wed Apr 8 17:27:12 1998 @@ -4,6 +4,7 @@ * Tim Waugh * Philip Blundell * Andrea Arcangeli + * Riccardo Facchetti * * based on work by Grant Guenther * and Philip Blundell @@ -11,6 +12,7 @@ #include #include +#include #include #include #include @@ -32,55 +34,78 @@ static int irq_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) { - int newirq, oldirq; + int retval = -EINVAL; + int newirq = PARPORT_IRQ_NONE; struct parport *pp = (struct parport *)data; - - if (count > 5 ) /* more than 4 digits + \n for a irq 0x?? 0?? ?? */ - return -EOVERFLOW; + struct pardevice *cad = pp->cad; + int oldirq = pp->irq; - if (buffer[0] < 32 || !strncmp(buffer, "none", 4)) { - newirq = PARPORT_IRQ_NONE; - } else { - if (buffer[0] == '0') { - if (buffer[1] == 'x') - newirq = simple_strtoul(&buffer[2], 0, 16); - else - newirq = simple_strtoul(&buffer[1], 0, 8); - } else { - newirq = simple_strtoul(buffer, 0, 10); - } - } +/* + * We can have these valid cases: + * "none" (count == 4 || count == 5) + * decimal number (count == 2 || count == 3) + * octal number (count == 3 || count == 4) + * hex number (count == 4 || count == 5) + * all other cases are -EINVAL + * + * Note: newirq is alredy set up to NONE. + * + * -RF + */ + if (count > 5 || count < 1) + goto out; - if (newirq >= NR_IRQS) - return -EOVERFLOW; + if (isdigit(buffer[0])) + newirq = simple_strtoul(buffer, NULL, 0); + else if (strncmp(buffer, "none", 4) != 0) { + if (buffer[0] < 32) + /* Things like '\n' are harmless */ + retval = count; - if (pp->irq != PARPORT_IRQ_NONE && !(pp->flags & PARPORT_FLAG_COMA)) { - if (pp->cad != NULL && pp->cad->irq_func != NULL) - free_irq(pp->irq, pp->cad->private); - else - free_irq(pp->irq, NULL); + goto out; } - oldirq = pp->irq; - pp->irq = newirq; + retval = count; + + if (oldirq == newirq) + goto out; - if (pp->irq != PARPORT_IRQ_NONE && !(pp->flags & PARPORT_FLAG_COMA)) { - struct pardevice *cad = pp->cad; + if (pp->flags & PARPORT_FLAG_COMA) + goto out_ok; - if (cad == NULL) - request_irq(pp->irq, parport_null_intr_func, - SA_INTERRUPT, pp->name, NULL); + if (newirq != PARPORT_IRQ_NONE) { + void (*handler)(int, void *, struct pt_regs *); + + if (cad && cad->irq_func) + handler = cad->irq_func; + else + handler = parport_null_intr_func; + + retval = request_irq(newirq, handler, + SA_INTERRUPT, + cad ? cad->name : pp->name, + cad ? cad->private : NULL); + if (retval) + goto out; + else retval = count; + } + + if (oldirq != PARPORT_IRQ_NONE) { + if (cad && cad->irq_func) + free_irq(oldirq, cad->private); else - request_irq(pp->irq, cad->irq_func ? cad->irq_func : - parport_null_intr_func, SA_INTERRUPT, - cad->name, cad->private); + free_irq(oldirq, NULL); } +out_ok: + pp->irq = newirq; + if (oldirq != PARPORT_IRQ_NONE && newirq == PARPORT_IRQ_NONE && - pp->cad != NULL && pp->cad->irq_func != NULL) - pp->cad->irq_func(pp->irq, pp->cad->private, NULL); + cad && cad->irq_func) + cad->irq_func(pp->irq, cad->private, NULL); - return count; +out: + return retval; } static int irq_read_proc(char *page, char **start, off_t off, @@ -167,6 +192,20 @@ *d = NULL; } +static void destroy_proc_tree(struct parport *pp) { + if (pp->pdir.entry) { + if (pp->pdir.irq) + destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq); + if (pp->pdir.devices) + destroy_proc_entry(pp->pdir.entry, &pp->pdir.devices); + if (pp->pdir.hardware) + destroy_proc_entry(pp->pdir.entry, &pp->pdir.hardware); + if (pp->pdir.probe) + destroy_proc_entry(pp->pdir.entry, &pp->pdir.probe); + destroy_proc_entry(base, &pp->pdir.entry); + } +} + static struct proc_dir_entry *new_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent, unsigned short ino) @@ -220,8 +259,6 @@ int parport_proc_register(struct parport *pp) { - static const char *proc_msg = KERN_ERR "%s: Trouble with /proc.\n"; - memset(&pp->pdir, 0, sizeof(struct parport_dir)); if (base == NULL) { @@ -233,63 +270,43 @@ sizeof(pp->pdir.name)); pp->pdir.entry = new_proc_entry(pp->pdir.name, S_IFDIR, base, 0); - if (pp->pdir.entry == NULL) { - printk(proc_msg, pp->name); - return 1; - } + if (pp->pdir.entry == NULL) + goto out_fail; pp->pdir.irq = new_proc_entry("irq", S_IFREG | S_IRUGO | S_IWUSR, pp->pdir.entry, 0); - if (pp->pdir.irq == NULL) { - printk(proc_msg, pp->name); - destroy_proc_entry(base, &pp->pdir.entry); - return 1; - } + if (pp->pdir.irq == NULL) + goto out_fail; + pp->pdir.irq->read_proc = irq_read_proc; pp->pdir.irq->write_proc = irq_write_proc; pp->pdir.irq->data = pp; pp->pdir.devices = new_proc_entry("devices", 0, pp->pdir.entry, 0); - if (pp->pdir.devices == NULL) { - printk(proc_msg, pp->name); - destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq); - destroy_proc_entry(base, &pp->pdir.entry); - return 1; - } + if (pp->pdir.devices == NULL) + goto out_fail; + pp->pdir.devices->read_proc = devices_read_proc; pp->pdir.devices->data = pp; pp->pdir.hardware = new_proc_entry("hardware", 0, pp->pdir.entry, 0); - if (pp->pdir.hardware == NULL) { - printk(proc_msg, pp->name); - destroy_proc_entry(pp->pdir.entry, &pp->pdir.devices); - destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq); - destroy_proc_entry(base, &pp->pdir.entry); - return 1; - } + if (pp->pdir.hardware == NULL) + goto out_fail; + pp->pdir.hardware->read_proc = hardware_read_proc; pp->pdir.hardware->data = pp; return 0; + +out_fail: + + printk(KERN_ERR "%s: failure registering /proc/ entry.\n", pp->name); + destroy_proc_tree(pp); + return 1; } int parport_proc_unregister(struct parport *pp) { - if (pp->pdir.entry) { - if (pp->pdir.irq) - destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq); - - if (pp->pdir.devices) - destroy_proc_entry(pp->pdir.entry, &pp->pdir.devices); - - if (pp->pdir.hardware) - destroy_proc_entry(pp->pdir.entry, &pp->pdir.hardware); - - if (pp->pdir.probe) - destroy_proc_entry(pp->pdir.entry, &pp->pdir.probe); - - destroy_proc_entry(base, &pp->pdir.entry); - } - + destroy_proc_tree(pp); return 0; } diff -u --recursive --new-file v2.1.93/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.1.93/linux/drivers/net/Config.in Tue Mar 17 22:18:14 1998 +++ linux/drivers/net/Config.in Tue Apr 7 08:05:05 1998 @@ -102,8 +102,9 @@ tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'TI ThunderLAN support (EXPERIMENTAL)' CONFIG_TLAN tristate 'Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 + tristate 'SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100 + tristate 'TI ThunderLAN support (EXPERIMENTAL)' CONFIG_TLAN bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET fi fi diff -u --recursive --new-file v2.1.93/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.1.93/linux/drivers/net/Makefile Thu Mar 26 15:57:03 1998 +++ linux/drivers/net/Makefile Tue Apr 7 08:05:05 1998 @@ -581,6 +581,14 @@ endif endif +ifeq ($(CONFIG_EPIC100),y) +L_OBJS += epic100.o +else + ifeq ($(CONFIG_EPIC100),m) + M_OBJS += epic100.o + endif +endif + # If anything built-in uses slhc, then build it into the kernel also. # If not, but a module uses it, build as a module. ifdef CONFIG_SLHC_BUILTIN diff -u --recursive --new-file v2.1.93/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.1.93/linux/drivers/net/Space.c Tue Mar 17 22:18:14 1998 +++ linux/drivers/net/Space.c Tue Apr 7 08:05:05 1998 @@ -94,6 +94,7 @@ extern int mace_probe(struct device *); extern int cs89x0_probe(struct device *dev); extern int ethertap_probe(struct device *dev); +extern int epic100_probe(struct device *dev); /* Detachable devices ("pocket adaptors") */ extern int atp_init(struct device *); @@ -286,6 +287,9 @@ #endif #ifdef CONFIG_ARM_AM79C961A && am79c961_probe(dev) +#endif +#ifdef CONFIG_EPIC100 + && epic100_probe(dev) #endif && 1 ) { return 1; /* -ENODEV or -EAGAIN would be more accurate. */ diff -u --recursive --new-file v2.1.93/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.1.93/linux/drivers/net/de4x5.c Mon Apr 6 17:41:00 1998 +++ linux/drivers/net/de4x5.c Tue Apr 7 07:52:04 1998 @@ -380,6 +380,7 @@ static const char *version = "de4x5.c:V0.536 1998/3/5 davies@maniac.ultranet.com\n"; +#include #include #include diff -u --recursive --new-file v2.1.93/linux/drivers/net/epic100.c linux/drivers/net/epic100.c --- v2.1.93/linux/drivers/net/epic100.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/epic100.c Tue Apr 7 08:05:05 1998 @@ -0,0 +1,1215 @@ +/* epic100.c: A SMC 83c170 EPIC/100 fast ethernet driver for Linux. */ +/* + NOTICE: THIS IS THE ALPHA TEST VERSION! + Written 1997 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + All other rights reserved. + + This driver is for the SMC EtherPower II 9432 PCI ethernet adapter based on + the SMC83c170. + + The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O + Center of Excellence in Space Data and Information Sciences + Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + + Support and updates available at + http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html +*/ + +static const char *version = +"epic100.c:v0.10 10/14/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html\n"; + +/* A few user-configurable values. */ + +/* Keep the ring sizes a power of two for efficiency. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ +#define TX_RING_SIZE 16 +#define RX_RING_SIZE 32 + +/* Set the copy breakpoint for the copy-only-tiny-frames scheme. + Setting to > 1518 effectively disables this feature. */ +static const int rx_copybreak = 200; + +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 10; + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT ((2000*HZ)/1000) + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ + +/* Bytes transferred to chip before transmission starts. */ +#define TX_FIFO_THRESH 128 /* Rounded down to 4 byte units. */ +#define RX_FIFO_THRESH 1 /* 0-3, 0==32, 64,96, or 3==128 bytes */ + +#include +#ifdef MODULE +#ifdef MODVERSIONS +#include +#endif +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include + +#include +#include +#include + +/* Kernel compatibility defines, common to David Hind's PCMCIA package. + This is only in the support-all-kernels source code. */ +#include /* Evil, but neccessary */ + +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10300 +#define RUN_AT(x) (x) /* What to put in timer->expires. */ +#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC) +#define virt_to_bus(addr) ((unsigned long)addr) +#define bus_to_virt(addr) ((void*)addr) + +#else /* 1.3.0 and later */ +#define RUN_AT(x) (jiffies + (x)) +#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2) +#endif + +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10338 +#ifdef MODULE +#if !defined(CONFIG_MODVERSIONS) && !defined(__NO_VERSION__) +char kernel_version[] = UTS_RELEASE; +#endif +#else +#undef MOD_INC_USE_COUNT +#define MOD_INC_USE_COUNT +#undef MOD_DEC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif +#endif /* 1.3.38 */ + +#if (LINUX_VERSION_CODE >= 0x10344) +#define NEW_MULTICAST +#include +#endif + +#ifdef SA_SHIRQ +#define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev) +#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance) +#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs) +#else +#define FREE_IRQ(irqnum, dev) free_irq(irqnum) +#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n) +#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs) +#endif + +#if (LINUX_VERSION_CODE < 0x20123) +#define test_and_set_bit(val, addr) set_bit(val, addr) +#else +#ifdef MODULE +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("SMC 82c170 EPIC series Ethernet driver"); +MODULE_PARM(debug, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(max_interrupt_work, "i"); +#endif +#endif + +/* The I/O extent. */ +#define EPIC_TOTAL_SIZE 0x100 + +#ifdef HAVE_DEVLIST +struct netdev_entry epic100_drv = +{"Epic100", epic100_pci_probe, EPIC_TOTAL_SIZE, NULL}; +#endif + +static int epic_debug = 1; + +/* + Theory of Operation + +I. Board Compatibility + +This device driver is designed for the SMC "EPCI/100", the SMC +single-chip ethernet controllers for PCI. This chip is used on +the SMC EtherPower II boards. + + +II. Board-specific settings + +PCI bus devices are configured by the system at boot time, so no jumpers +need to be set on the board. The system BIOS will assign the +PCI INTA signal to a (preferably otherwise unused) system IRQ line. +Note: Kernel versions earlier than 1.3.73 do not support shared PCI +interrupt lines. + +III. Driver operation + +IIIa. Ring buffers + +IVb. References + +http://www.smc.com/components/catalog/smc83c170.html +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.national.com/pf/DP/DP83840.html + +IVc. Errata + +*/ + +#ifndef PCI_VENDOR_ID_SMC +#define PCI_VENDOR_ID_SMC 0x10B8 +#endif +#ifndef PCI_DEVICE_ID_SMC_EPIC100 +#define PCI_DEVICE_ID_SMC_EPIC100 0x0005 +#endif + +/* The rest of these values should never change. */ +/* Offsets to registers, using the (ugh) SMC names. */ +enum epic_registers { + COMMAND=0, INTSTAT=4, INTMASK=8, GENCTL=0x0C, NVCTL=0x10, EECTL=0x14, + TEST1=0x1C, CRCCNT=0x20, ALICNT=0x24, MPCNT=0x28, /* Rx error counters. */ + MIICtrl=0x30, MIIData=0x34, MIICfg=0x38, + LAN0=64, /* MAC address. */ + MC0=80, /* Multicast filter table. */ + RxCtrl=96, TxCtrl=112, TxSTAT=0x74, + PRxCDAR=0x84, RxSTAT=0xA4, EarlyRx=0xB0, PTxCDAR=0xC4, TxThresh=0xDC, +}; + +/* Interrupt register bits, using my own meaningful names. */ +enum IntrStatus { + TxIdle=0x40000, RxIdle=0x20000, + CntFull=0x0200, TxUnderrun=0x0100, + TxEmpty=0x0080, TxDone=0x0020, RxError=0x0010, + RxOverflow=0x0008, RxFull=0x0004, RxHeader=0x0002, RxDone=0x0001, +}; + +/* The EPIC100 Rx and Tx buffer descriptors. */ + +struct epic_tx_desc { + s16 status; + u16 txlength; + u32 bufaddr; + u16 buflength; + u16 control; + u32 next; +}; + +struct epic_rx_desc { + s16 status; + u16 rxlength; + u32 bufaddr; + u32 buflength; + u32 next; +}; + +struct epic_private { + char devname[8]; /* Used only for kernel debugging. */ + const char *product_name; + struct device *next_module; + struct epic_rx_desc rx_ring[RX_RING_SIZE]; + struct epic_tx_desc tx_ring[TX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + int chip_id; + int revision; + struct enet_statistics stats; + struct timer_list timer; /* Media selection timer. */ + unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + unsigned char mc_filter[8]; + signed char phys[4]; /* MII device addresses. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + unsigned int media2:4; /* Secondary monitored media port. */ + unsigned int medialock:1; /* Don't sense media type. */ + unsigned int mediasense:1; /* Media sensing in progress. */ + int pad0, pad1; /* Used for 8-byte alignment */ +}; + +static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +#ifdef MODULE +/* Used to pass the full-duplex flag, etc. */ +static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +#endif + +static struct device *epic100_probe1(struct device *dev, int ioaddr, int irq, + int chip_id, int options, int card_idx); +static int epic_open(struct device *dev); +static int read_eeprom(int ioaddr, int location); +static int mii_read(int ioaddr, int phy_id, int location); +static void epic_timer(unsigned long data); +static void epic_tx_timeout(struct device *dev); +static void epic_init_ring(struct device *dev); +static int epic_start_xmit(struct sk_buff *skb, struct device *dev); +static int epic_rx(struct device *dev); +static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int epic_close(struct device *dev); +static struct enet_statistics *epic_get_stats(struct device *dev); +#ifdef NEW_MULTICAST +static void set_rx_mode(struct device *dev); +#else +static void set_rx_mode(struct device *dev, int num_addrs, void *addrs); +#endif + + + +#ifdef MODULE +/* A list of all installed EPIC devices, for removing the driver module. */ +static struct device *root_epic_dev = NULL; +#endif + +int epic100_probe(struct device *dev) +{ + int cards_found = 0; + static int pci_index = 0; /* Static, for multiple probe calls. */ + + /* Ideally we would detect all network cards in slot order. That would + be best done a central PCI probe dispatch, which wouldn't work + well with the current structure. So instead we detect just the + Epic cards in slot order. */ + + if (pcibios_present()) { + unsigned char pci_bus, pci_device_fn; + + for (;pci_index < 0xff; pci_index++) { + unsigned char pci_irq_line, pci_latency; + unsigned short pci_command, vendor, device; + unsigned int pci_ioaddr, chip_idx = 0; + + if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, +#ifdef REVERSE_PROBE_ORDER + 0xff - pci_index, +#else + pci_index, +#endif + &pci_bus, &pci_device_fn) + != PCIBIOS_SUCCESSFUL) + break; + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_VENDOR_ID, &vendor); + if (vendor != PCI_VENDOR_ID_SMC) + continue; + + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_DEVICE_ID, &device); + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq_line); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &pci_ioaddr); + /* Remove I/O space marker in bit 0. */ + pci_ioaddr &= ~3; + + if (device != PCI_DEVICE_ID_SMC_EPIC100) { + printk("Unknown SMC PCI ethernet chip type %4.4x detected:" + " not configured.\n", device); + continue; + } + if (epic_debug > 2) + printk("Found SMC PCI EPIC/100 at I/O %#x, IRQ %d.\n", + pci_ioaddr, pci_irq_line); + + if (check_region(pci_ioaddr, EPIC_TOTAL_SIZE)) + continue; + +#ifdef MODULE + dev = epic100_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx, + options[cards_found], cards_found); +#else + dev = epic100_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx, + dev ? dev->mem_start : 0, -1); +#endif + + if (dev) { + /* Get and check the bus-master and latency values. */ + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command); + if ( ! (pci_command & PCI_COMMAND_MASTER)) { + printk(" PCI Master Bit has not been set! Setting...\n"); + pci_command |= PCI_COMMAND_MASTER; + pcibios_write_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, pci_command); + } + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < 10) { + printk(" PCI latency timer (CFLT) is unreasonably low at %d." + " Setting to 255 clocks.\n", pci_latency); + pcibios_write_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, 255); + } else if (epic_debug > 1) + printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency); + dev = 0; + cards_found++; + } + } + } + +#if defined (MODULE) + return cards_found; +#else + return cards_found ? 0 : -ENODEV; +#endif +} + +static struct device *epic100_probe1(struct device *dev, int ioaddr, int irq, + int chip_id, int options, int card_idx) +{ + static int did_version = 0; /* Already printed version info. */ + struct epic_private *tp; + int i; + + if (epic_debug > 0 && did_version++ == 0) + printk(version); + + dev = init_etherdev(dev, 0); + + printk("%s: SMC EPIC/100 at %#3x, IRQ %d, ", dev->name, ioaddr, irq); + + /* Bring the chip out of low-power mode. */ + outl(0x0200, ioaddr + GENCTL); + /* Magic?! If we don't set this bit the MII interface won't work. */ + outl(0x0008, ioaddr + TEST1); + + /* This could also be read from the EEPROM. */ + for (i = 0; i < 3; i++) + ((u16 *)dev->dev_addr)[i] = inw(ioaddr + LAN0 + i*4); + + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x.\n", dev->dev_addr[i]); + + if (epic_debug > 1) { + printk("%s: EEPROM contents\n", dev->name); + for (i = 0; i < 64; i++) + printk(" %4.4x%s", read_eeprom(ioaddr, i), i % 16 == 15 ? "\n" : ""); + } + + /* We do a request_region() to register /proc/ioports info. */ + request_region(ioaddr, EPIC_TOTAL_SIZE, "SMC EPIC/100"); + + dev->base_addr = ioaddr; + dev->irq = irq; + + /* The data structures must be quadword aligned. */ + tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA); + memset(tp, 0, sizeof(*tp)); + dev->priv = tp; + +#ifdef MODULE + tp->next_module = root_epic_dev; + root_epic_dev = dev; +#endif + + tp->chip_id = chip_id; + + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, but + takes too much time. */ + { + int phy, phy_idx; + for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); + phy++) { + int mii_status = mii_read(ioaddr, phy, 0); + if (mii_status != 0xffff && mii_status != 0x0000) { + tp->phys[phy_idx++] = phy; + printk("%s: MII transceiver found at address %d.\n", + dev->name, phy); + } + } + if (phy_idx == 0) { + printk("%s: ***WARNING***: No MII transceiver found!\n", + dev->name); + /* Use the known PHY address of the EPII. */ + tp->phys[0] = 3; + } + } + + /* Leave the chip in low-power mode. */ + outl(0x0008, ioaddr + GENCTL); + + /* The lower four bits are the media type. */ + if (options > 0) { + tp->full_duplex = (options & 16) ? 1 : 0; + tp->default_port = options & 15; + if (tp->default_port) + tp->medialock = 1; + } + if (card_idx >= 0) { + if (full_duplex[card_idx] >= 0) + tp->full_duplex = full_duplex[card_idx]; + } + + /* The Epic-specific entries in the device structure. */ + dev->open = &epic_open; + dev->hard_start_xmit = &epic_start_xmit; + dev->stop = &epic_close; + dev->get_stats = &epic_get_stats; + dev->set_multicast_list = &set_rx_mode; + + return dev; +} + +/* Serial EEPROM section. */ + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ +#define EE_CS 0x02 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x08 /* EEPROM chip data in. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x09 +#define EE_DATA_READ 0x10 /* EEPROM chip data out. */ +#define EE_ENB (0x0001 | EE_CS) + +/* Delay between EEPROM clock transitions. + The 1.2 code is a "nasty" timing loop, but PC compatible machines are + *supposed* to delay an ISA-compatible period for the SLOW_DOWN_IO macro. */ +#ifdef _LINUX_DELAY_H +#define eeprom_delay(nanosec) udelay((nanosec + 999)/1000) +#else +#define eeprom_delay(nanosec) do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0) +#endif + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD (5 << 6) +#define EE_READ_CMD (6 << 6) +#define EE_ERASE_CMD (7 << 6) + +static int read_eeprom(int ioaddr, int location) +{ + int i; + int retval = 0; + int ee_addr = ioaddr + EECTL; + int read_cmd = location | EE_READ_CMD; + + outl(EE_ENB & ~EE_CS, ee_addr); + outl(EE_ENB, ee_addr); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + outl(EE_ENB | dataval, ee_addr); + eeprom_delay(100); + outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay(150); + outl(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */ + eeprom_delay(250); + } + outl(EE_ENB, ee_addr); + + for (i = 16; i > 0; i--) { + outl(EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay(100); + retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); + outl(EE_ENB, ee_addr); + eeprom_delay(100); + } + + /* Terminate the EEPROM access. */ + outl(EE_ENB & ~EE_CS, ee_addr); + return retval; +} + +#define MII_READOP 1 +#define MII_WRITEOP 2 +static int mii_read(int ioaddr, int phy_id, int location) +{ + int i; + + outl((phy_id << 9) | (location << 4) | MII_READOP, ioaddr + MIICtrl); + /* Typical operation takes < 50 ticks. */ + for (i = 4000; i > 0; i--) + if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) + break; + return inw(ioaddr + MIIData); +} + + +static int +epic_open(struct device *dev) +{ + struct epic_private *tp = (struct epic_private *)dev->priv; + int ioaddr = dev->base_addr; + int i; + int mii_reg5; + int full_duplex = 0; + + /* Soft reset the chip. */ + outl(0x0001, ioaddr + GENCTL); + +#ifdef SA_SHIRQ + if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, + "SMC EPIC/100", dev)) { + return -EAGAIN; + } +#else + if (irq2dev_map[dev->irq] != NULL + || (irq2dev_map[dev->irq] = dev) == NULL + || dev->irq == 0 + || request_irq(dev->irq, &epic_interrupt, 0, "SMC EPIC/100")) { + return -EAGAIN; + } +#endif + + MOD_INC_USE_COUNT; + + epic_init_ring(dev); + + /* This next line by Ken Yamaguchi.. ?? */ + outl(0x8, ioaddr + 0x1c); + + /* Pull the chip out of low-power mode, enable interrupts, and set for PCI read multiple. */ + outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); + + for (i = 0; i < 3; i++) + outl(((u16*)dev->dev_addr)[i], ioaddr + LAN0 + i*4); + + outl(TX_FIFO_THRESH, ioaddr + TxThresh); + full_duplex = tp->full_duplex; + + mii_reg5 = mii_read(ioaddr, tp->phys[0], 5); + if (mii_reg5 != 0xffff && (mii_reg5 & 0x0100)) { + full_duplex = 1; + if (epic_debug > 1) + printk("%s: Setting %s-duplex based on MII xcvr %d" + " register read of %4.4x.\n", dev->name, + full_duplex ? "full" : "half", tp->phys[0], + mii_read(ioaddr, tp->phys[0], 5)); + } + + outl(full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); + outl(virt_to_bus(tp->rx_ring), ioaddr + PRxCDAR); + outl(virt_to_bus(tp->tx_ring), ioaddr + PTxCDAR); + + /* Start the chip's Rx process. */ + set_rx_mode(dev); + outl(0x000A, ioaddr + COMMAND); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + /* Enable interrupts by setting the interrupt mask. */ + outl(CntFull | TxUnderrun | TxDone + | RxError | RxOverflow | RxFull | RxHeader | RxDone, + ioaddr + INTMASK); + + if (epic_debug > 1) + printk("%s: epic_open() ioaddr %4.4x IRQ %d status %4.4x %s-duplex.\n", + dev->name, ioaddr, dev->irq, inl(ioaddr + GENCTL), + full_duplex ? "full" : "half"); + + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer(&tp->timer); + tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ + tp->timer.data = (unsigned long)dev; + tp->timer.function = &epic_timer; /* timer handler */ + add_timer(&tp->timer); + + return 0; +} + +static void epic_timer(unsigned long data) +{ + struct device *dev = (struct device *)data; + struct epic_private *tp = (struct epic_private *)dev->priv; + int ioaddr = dev->base_addr; + int next_tick = 0; + + if (epic_debug > 3) { + printk("%s: Media selection tick, Tx status %8.8x.\n", + dev->name, inl(ioaddr + TxSTAT)); + printk("%s: Other registers are IntMask %4.4x IntStatus %4.4x RxStatus" + " %4.4x.\n", + dev->name, inl(ioaddr + INTMASK), inl(ioaddr + INTSTAT), + inl(ioaddr + RxSTAT)); + } + + if (next_tick) { + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); + } +} + +static void epic_tx_timeout(struct device *dev) +{ + struct epic_private *tp = (struct epic_private *)dev->priv; + int ioaddr = dev->base_addr; + + if (epic_debug > 0) { + printk("%s: Transmit timeout using MII device, Tx status %4.4x.\n", + dev->name, inw(ioaddr + TxSTAT)); + if (epic_debug > 1) { + printk("%s: Tx indices: dirty_tx %d, cur_tx %d.\n", + dev->name, tp->dirty_tx, tp->cur_tx); + } + } + /* Perhaps stop and restart the chip's Tx processes . */ + /* Trigger a transmit demand. */ + outl(0x0004, dev->base_addr + COMMAND); + + dev->trans_start = jiffies; + tp->stats.tx_errors++; + return; +} + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void +epic_init_ring(struct device *dev) +{ + struct epic_private *tp = (struct epic_private *)dev->priv; + int i; + + tp->tx_full = 0; + tp->cur_rx = tp->cur_tx = 0; + tp->dirty_rx = tp->dirty_tx = 0; + + for (i = 0; i < RX_RING_SIZE; i++) { + tp->rx_ring[i].status = 0x8000; /* Owned by Epic chip */ + tp->rx_ring[i].buflength = PKT_BUF_SZ; + { + /* Note the receive buffer must be longword aligned. + dev_alloc_skb() provides 16 byte alignment. But do *not* + use skb_reserve() to align the IP header! */ + struct sk_buff *skb; + skb = DEV_ALLOC_SKB(PKT_BUF_SZ); + tp->rx_skbuff[i] = skb; + if (skb == NULL) + break; /* Bad news! */ + skb->dev = dev; /* Mark as being used by this device. */ +#if LINUX_VERSION_CODE > 0x10300 + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + tp->rx_ring[i].bufaddr = virt_to_bus(skb->tail); +#else + tp->rx_ring[i].bufaddr = virt_to_bus(skb->data); +#endif + } + tp->rx_ring[i].next = virt_to_bus(&tp->rx_ring[i+1]); + } + /* Mark the last entry as wrapping the ring. */ + tp->rx_ring[i-1].next = virt_to_bus(&tp->rx_ring[0]); + + /* The Tx buffer descriptor is filled in as needed, but we + do need to clear the ownership bit. */ + for (i = 0; i < TX_RING_SIZE; i++) { + tp->tx_skbuff[i] = 0; + tp->tx_ring[i].status = 0x0000; + tp->tx_ring[i].next = virt_to_bus(&tp->tx_ring[i+1]); + } + tp->tx_ring[i-1].next = virt_to_bus(&tp->tx_ring[0]); +} + +static int +epic_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct epic_private *tp = (struct epic_private *)dev->priv; + int entry; + u32 flag; + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + if (jiffies - dev->trans_start < TX_TIMEOUT) + return 1; + epic_tx_timeout(dev); + return 1; + } + + /* Caution: the write order is important here, set the base address + with the "ownership" bits last. */ + + /* Calculate the next Tx descriptor entry. */ + entry = tp->cur_tx % TX_RING_SIZE; + + tp->tx_skbuff[entry] = skb; + tp->tx_ring[entry].txlength = (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN); + tp->tx_ring[entry].bufaddr = virt_to_bus(skb->data); + tp->tx_ring[entry].buflength = skb->len; + + if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ + flag = 0x10; /* No interrupt */ + dev->tbusy = 0; + } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { + flag = 0x14; /* Tx-done intr. */ + dev->tbusy = 0; + } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { + flag = 0x10; /* No Tx-done intr. */ + dev->tbusy = 0; + } else { + /* Leave room for two additional entries. */ + flag = 0x14; /* Tx-done intr. */ + tp->tx_full = 1; + } + + tp->tx_ring[entry].control = flag; + tp->tx_ring[entry].status = 0x8000; /* Pass ownership to the chip. */ + tp->cur_tx++; + /* Trigger an immediate transmit demand. */ + outl(0x0004, dev->base_addr + COMMAND); + + dev->trans_start = jiffies; + if (epic_debug > 4) + printk("%s: Queued Tx packet size %d to slot %d, " + "flag %2.2x Tx status %8.8x.\n", + dev->name, (int)skb->len, entry, flag, + inl(dev->base_addr + TxSTAT)); + + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void epic_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs) +{ +#ifdef SA_SHIRQ + struct device *dev = (struct device *)dev_instance; +#else + struct device *dev = (struct device *)(irq2dev_map[irq]); +#endif + struct epic_private *lp; + int status, ioaddr, boguscnt = max_interrupt_work; + + if (dev == NULL) { + printk ("epic_interrupt(): irq %d for unknown device.\n", irq); + return; + } + + ioaddr = dev->base_addr; + lp = (struct epic_private *)dev->priv; + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + + dev->interrupt = 1; + + do { + status = inl(ioaddr + INTSTAT); + /* Acknowledge all of the current interrupt sources ASAP. */ + outl(status & 0x00007fff, ioaddr + INTSTAT); + + if (epic_debug > 4) + printk("%s: interrupt interrupt=%#8.8x new intstat=%#8.8x.\n", + dev->name, status, inl(ioaddr + INTSTAT)); + + if ((status & (RxDone | TxEmpty | TxDone)) == 0) + break; + + if (status & RxDone) /* Rx interrupt */ + epic_rx(dev); + + if (status & (TxEmpty | TxDone)) { + int dirty_tx; + + for (dirty_tx = lp->dirty_tx; dirty_tx < lp->cur_tx; dirty_tx++) { + int entry = dirty_tx % TX_RING_SIZE; + int txstatus = lp->tx_ring[entry].status; + + if (txstatus < 0) + break; /* It still hasn't been Txed */ + + if ( ! (txstatus & 0x0001)) { + /* There was an major error, log it. */ +#ifndef final_version + if (epic_debug > 1) + printk("%s: Transmit error, Tx status %8.8x.\n", + dev->name, txstatus); +#endif + lp->stats.tx_errors++; + if (txstatus & 0x1050) lp->stats.tx_aborted_errors++; + if (txstatus & 0x0008) lp->stats.tx_carrier_errors++; + if (txstatus & 0x0040) lp->stats.tx_window_errors++; + if (txstatus & 0x0010) lp->stats.tx_fifo_errors++; +#ifdef ETHER_STATS + if (txstatus & 0x1000) lp->stats.collisions16++; +#endif + } else { +#ifdef ETHER_STATS + if ((txstatus & 0x0002) != 0) lp->stats.tx_deferred++; +#endif + lp->stats.collisions += (txstatus >> 8) & 15; + lp->stats.tx_packets++; + } + + /* Free the original skb. */ + dev_kfree_skb(lp->tx_skbuff[entry]); + lp->tx_skbuff[entry] = 0; + } + +#ifndef final_version + if (lp->cur_tx - dirty_tx > TX_RING_SIZE) { + printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, lp->cur_tx, lp->tx_full); + dirty_tx += TX_RING_SIZE; + } +#endif + + if (lp->tx_full && dev->tbusy + && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { + /* The ring is no longer full, clear tbusy. */ + lp->tx_full = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + + lp->dirty_tx = dirty_tx; + } + + /* Check uncommon events all at once. */ + if (status & (CntFull | TxUnderrun | RxOverflow)) { + /* Always update the error counts to avoid overhead later. */ + lp->stats.rx_missed_errors += inb(ioaddr + MPCNT); + lp->stats.rx_frame_errors += inb(ioaddr + ALICNT); + lp->stats.rx_crc_errors += inb(ioaddr + CRCCNT); + + if (status & TxUnderrun) { /* Tx FIFO underflow. */ + lp->stats.tx_fifo_errors++; + /* Restart the transmit process. */ + outl(0x0080, ioaddr + COMMAND); + } + if (status & RxOverflow) { /* Missed a Rx frame. */ + lp->stats.rx_errors++; + } + /* Clear all error sources. */ + outl(status & 0x7f18, ioaddr + INTSTAT); + } + if (--boguscnt < 0) { + printk("%s: Too much work at interrupt, IntrStatus=0x%8.8x.\n", + dev->name, status); + /* Clear all interrupt sources. */ + outl(0x0001ffff, ioaddr + INTSTAT); + break; + } + } while (1); + + if (epic_debug > 3) + printk("%s: exiting interrupt, intr_status=%#4.4x.\n", + dev->name, inl(ioaddr + INTSTAT)); + + /* Code that should never be run! Perhaps remove after testing.. */ + { + static int stopit = 10; + if (dev->start == 0 && --stopit < 0) { + printk("%s: Emergency stop, looping startup interrupt.\n", + dev->name); + FREE_IRQ(irq, dev); + } + } + + dev->interrupt = 0; + return; +} + +static int +epic_rx(struct device *dev) +{ + struct epic_private *lp = (struct epic_private *)dev->priv; + int entry = lp->cur_rx % RX_RING_SIZE; + + if (epic_debug > 4) + printk(" In epic_rx(), entry %d %8.8x.\n", entry, + lp->rx_ring[entry].status); + /* If we own the next entry, it's a new packet. Send it up. */ + while (lp->rx_ring[entry].status >= 0) { + int status = lp->rx_ring[entry].status; + + if (epic_debug > 4) + printk(" epic_rx() status was %8.8x.\n", status); + if (status & 0x2000) { + printk("%s: Oversized Ethernet frame spanned multiple buffers," + " status %4.4x!\n", dev->name, status); + lp->stats.rx_length_errors++; + } else if (status & 0x0006) { + /* Rx Frame errors are counted in hardware. */ + lp->stats.rx_errors++; + } else { + /* Malloc up new buffer, compatible with net-2e. */ + /* Omit the four octet CRC from the length. */ + short pkt_len = lp->rx_ring[entry].rxlength - 4; + struct sk_buff *skb; + int rx_in_place = 0; + + /* Check if the packet is long enough to just accept without + copying to a properly sized skbuff. */ + if (pkt_len > rx_copybreak) { + struct sk_buff *newskb; + char *temp; + + /* Pass up the skb already on the Rx ring. */ + skb = lp->rx_skbuff[entry]; + temp = skb_put(skb, pkt_len); + if (bus_to_virt(lp->rx_ring[entry].bufaddr) != temp) + printk("%s: Warning -- the skbuff addresses do not match" + " in epic_rx: %p vs. %p / %p.\n", dev->name, + bus_to_virt(lp->rx_ring[entry].bufaddr), + skb->head, temp); + /* Get a fresh skbuff to replace the filled one. */ + newskb = DEV_ALLOC_SKB(PKT_BUF_SZ); + if (newskb) { + rx_in_place = 1; + lp->rx_skbuff[entry] = newskb; + newskb->dev = dev; +#if LINUX_VERSION_CODE > 0x10300 + /* Align IP on 16 byte boundaries */ + skb_reserve(newskb, 2); + lp->rx_ring[entry].bufaddr = virt_to_bus(newskb->tail); +#else + lp->rx_ring[entry].bufaddr = virt_to_bus(newskb->data); +#endif + } else /* No memory, drop the packet. */ + skb = 0; + } else + skb = DEV_ALLOC_SKB(pkt_len + 2); + if (skb == NULL) { + int i; + printk("%s: Memory squeeze, deferring packet.\n", dev->name); + /* Check that at least two ring entries are free. + If not, free one and mark stats->rx_dropped++. */ + for (i = 0; i < RX_RING_SIZE; i++) + if (lp->rx_ring[(entry+i) % RX_RING_SIZE].status < 0) + break; + + if (i > RX_RING_SIZE -2) { + lp->stats.rx_dropped++; + lp->rx_ring[entry].status = 0x8000; + lp->cur_rx++; + } + break; + } + skb->dev = dev; + if (! rx_in_place) { + skb_reserve(skb, 2); /* 16 byte align the data fields */ + memcpy(skb_put(skb, pkt_len), + bus_to_virt(lp->rx_ring[entry].bufaddr), pkt_len); + } +#if LINUX_VERSION_CODE > 0x10300 + skb->protocol = eth_type_trans(skb, dev); +#else + skb->len = pkt_len; +#endif + netif_rx(skb); + lp->stats.rx_packets++; + } + + lp->rx_ring[entry].status = 0x8000; + entry = (++lp->cur_rx) % RX_RING_SIZE; + } + + return 0; +} + +static int +epic_close(struct device *dev) +{ + int ioaddr = dev->base_addr; + struct epic_private *tp = (struct epic_private *)dev->priv; + int i; + + dev->start = 0; + dev->tbusy = 1; + + if (epic_debug > 1) + printk("%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, inl(ioaddr + INTSTAT)); + + /* Disable interrupts by clearing the interrupt mask. */ + outl(0x00000000, ioaddr + INTMASK); + /* Stop the chip's Tx and Rx DMA processes. */ + outw(0x0061, ioaddr + COMMAND); + + /* Update the error counts. */ + tp->stats.rx_missed_errors += inb(ioaddr + MPCNT); + tp->stats.rx_frame_errors += inb(ioaddr + ALICNT); + tp->stats.rx_crc_errors += inb(ioaddr + CRCCNT); + + del_timer(&tp->timer); + +#ifdef SA_SHIRQ + free_irq(dev->irq, dev); +#else + free_irq(dev->irq); + irq2dev_map[dev->irq] = 0; +#endif + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = tp->rx_skbuff[i]; + tp->rx_skbuff[i] = 0; + tp->rx_ring[i].status = 0; /* Not owned by Epic chip. */ + tp->rx_ring[i].buflength = 0; + tp->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */ + if (skb) { +#if LINUX_VERSION_CODE < 0x20100 + skb->free = 1; +#endif + dev_kfree_skb(skb); + } + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (tp->tx_skbuff[i]) + dev_kfree_skb(tp->tx_skbuff[i]); + tp->tx_skbuff[i] = 0; + } + + + /* Green! Leave the chip in low-power mode. */ + outl(0x0008, ioaddr + GENCTL); + + MOD_DEC_USE_COUNT; + + return 0; +} + +static struct enet_statistics * +epic_get_stats(struct device *dev) +{ + struct epic_private *tp = (struct epic_private *)dev->priv; + int ioaddr = dev->base_addr; + + if (dev->start) { + /* Update the error counts. */ + tp->stats.rx_missed_errors += inb(ioaddr + MPCNT); + tp->stats.rx_frame_errors += inb(ioaddr + ALICNT); + tp->stats.rx_crc_errors += inb(ioaddr + CRCCNT); + } + + return &tp->stats; +} + +/* Set or clear the multicast filter for this adaptor. + Note that we only use exclusion around actually queueing the + new frame, not around filling tp->setup_frame. This is non-deterministic + when re-entered but still correct. */ + +/* The little-endian AUTODIN II ethernet CRC calculation. + N.B. Do not use for bulk data, use a table-based routine instead. + This is common code and should be moved to net/core/crc.c */ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline unsigned ether_crc_le(int length, unsigned char *data) +{ + unsigned int crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} + + +#ifdef NEW_MULTICAST +static void set_rx_mode(struct device *dev) +#else +static void set_rx_mode(struct device *dev, int num_addrs, void *addrs); +#endif +{ + int ioaddr = dev->base_addr; + struct epic_private *tp = (struct epic_private *)dev->priv; + unsigned char mc_filter[8]; /* Multicast hash filter */ + int i; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + outl(0x002C, ioaddr + RxCtrl); + /* Unconditionally log net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + memset(mc_filter, 0xff, sizeof(mc_filter)); + } else if ((dev->mc_count > 0) || (dev->flags & IFF_ALLMULTI)) { + /* There is apparently a chip bug, so the multicast filter + is never enabled. */ + /* Too many to filter perfectly -- accept all multicasts. */ + memset(mc_filter, 0xff, sizeof(mc_filter)); + outl(0x000C, ioaddr + RxCtrl); + } else if (dev->mc_count == 0) { + outl(0x0004, ioaddr + RxCtrl); + return; + } else { /* Never executed, for now. */ + struct dev_mc_list *mclist; + + memset(mc_filter, 0, sizeof(mc_filter)); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f, + mc_filter); + } + /* ToDo: perhaps we need to stop the Tx and Rx process here? */ + if (memcmp(mc_filter, tp->mc_filter, sizeof(mc_filter))) { + for (i = 0; i < 4; i++) + outw(((u16 *)mc_filter)[i], ioaddr + MC0 + i*4); + memcpy(tp->mc_filter, mc_filter, sizeof(mc_filter)); + } + return; +} + +#ifdef MODULE + +/* An additional parameter that may be passed in... */ +static int debug = -1; + +int +init_module(void) +{ + int cards_found; + + if (debug >= 0) + epic_debug = debug; + + root_epic_dev = NULL; + cards_found = epic100_probe(0); + + return cards_found ? 0 : -ENODEV; +} + +void +cleanup_module(void) +{ + struct device *next_dev; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_epic_dev) { + next_dev = ((struct epic_private *)root_epic_dev->priv)->next_module; + unregister_netdev(root_epic_dev); + release_region(root_epic_dev->base_addr, EPIC_TOTAL_SIZE); + kfree(root_epic_dev); + root_epic_dev = next_dev; + } +} + +#endif /* MODULE */ + +/* + * Local variables: + * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic100.c" + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -u --recursive --new-file v2.1.93/linux/drivers/net/hamradio/6pack.c linux/drivers/net/hamradio/6pack.c --- v2.1.93/linux/drivers/net/hamradio/6pack.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/6pack.c Wed Apr 8 17:31:27 1998 @@ -0,0 +1,1129 @@ +/* + * 6pack.c This module implements the 6pack protocol for kernel-based + * devices like TTY. It interfaces between a raw TTY and the + * kernel's AX.25 protocol layers. + * + * Version: @(#)6pack.c 0.3.0 04/07/98 + * + * Authors: Andreas Könsgen + * + * Quite a lot of stuff "stolen" by Jörg Reuter from slip.c, written by + * + * Laurence Culhane, + * Fred N. van Kempen, + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* +#include +#include +#include +#include +#include +*/ + +#include "6pack.h" + +typedef unsigned char byte; + + +typedef struct sixpack_ctrl { + char if_name[8]; /* "sp0\0" .. "sp99999\0" */ + struct sixpack ctrl; /* 6pack things */ + struct device dev; /* the device */ +} sixpack_ctrl_t; +static sixpack_ctrl_t **sixpack_ctrls = NULL; +int sixpack_maxdev = SIXP_NRUNIT; /* Can be overridden with insmod! */ + +static struct tty_ldisc sp_ldisc; + +static void sp_start_tx_timer(struct sixpack *); +static void sp_xmit_on_air(unsigned long); +static void resync_tnc(unsigned long); +void sixpack_decode(struct sixpack *, unsigned char[], int); +int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char); + +void decode_prio_command(byte, struct sixpack *); +void decode_std_command(byte, struct sixpack *); +void decode_data(byte, struct sixpack *); + +static int tnc_init(struct sixpack *); + +/* Find a free 6pack channel, and link in this `tty' line. */ +static inline struct sixpack * +sp_alloc(void) +{ + sixpack_ctrl_t *spp = NULL; + int i; + + if (sixpack_ctrls == NULL) return NULL; /* Master array missing ! */ + + for (i = 0; i < sixpack_maxdev; i++) + { + spp = sixpack_ctrls[i]; + + if (spp == NULL) + break; + + if (!test_and_set_bit(SIXPF_INUSE, &spp->ctrl.flags)) + break; + } + + /* Too many devices... */ + if (i >= sixpack_maxdev) + return NULL; + + /* If no channels are available, allocate one */ + if (!spp && + (sixpack_ctrls[i] = (sixpack_ctrl_t *)kmalloc(sizeof(sixpack_ctrl_t), + GFP_KERNEL)) != NULL) + { + spp = sixpack_ctrls[i]; + memset(spp, 0, sizeof(sixpack_ctrl_t)); + + /* Initialize channel control data */ + set_bit(SIXPF_INUSE, &spp->ctrl.flags); + spp->ctrl.tty = NULL; + sprintf(spp->if_name, "sp%d", i); + spp->dev.name = spp->if_name; + spp->dev.base_addr = i; + spp->dev.priv = (void*)&(spp->ctrl); + spp->dev.next = NULL; + spp->dev.init = sixpack_init; + } + + if (spp != NULL) + { + /* register device so that it can be ifconfig'ed */ + /* sixpack_init() will be called as a side-effect */ + /* SIDE-EFFECT WARNING: sixpack_init() CLEARS spp->ctrl ! */ + + if (register_netdev(&(spp->dev)) == 0) + { + set_bit(SIXPF_INUSE, &spp->ctrl.flags); + spp->ctrl.dev = &(spp->dev); + spp->dev.priv = (void*)&(spp->ctrl); + + return (&(spp->ctrl)); + } else { + clear_bit(SIXPF_INUSE,&(spp->ctrl.flags)); + printk(KERN_WARNING "sp_alloc() - register_netdev() failure.\n"); + } + } + + return NULL; +} + + +/* Free a 6pack channel. */ +static inline void +sp_free(struct sixpack *sp) +{ + /* Free all 6pack frame buffers. */ + if (sp->rbuff) + kfree(sp->rbuff); + sp->rbuff = NULL; + if (sp->xbuff) { + kfree(sp->xbuff); + } + sp->xbuff = NULL; + + if (!test_and_clear_bit(SIXPF_INUSE, &sp->flags)) + { + printk(KERN_WARNING "%s: sp_free for already free unit.\n", sp->dev->name); + } +} + + +/* Set the "sending" flag. */ +static inline void +sp_lock(struct sixpack *sp) +{ + if (test_and_set_bit(0, (void *) &sp->dev->tbusy)) + printk(KERN_WARNING "%s: trying to lock already locked device!\n", sp->dev->name); +} + + +/* Clear the "sending" flag. */ +static inline void +sp_unlock(struct sixpack *sp) +{ + if (!test_and_clear_bit(0, (void *)&sp->dev->tbusy)) + printk(KERN_WARNING "%s: trying to unlock already unlocked device!\n", sp->dev->name); +} + + +/* Send one completely decapsulated IP datagram to the IP layer. */ + +/* This is the routine that sends the received data to the kernel AX.25. + 'cmd' is the KISS command. For AX.25 data, it is zero. */ + +static void +sp_bump(struct sixpack *sp, char cmd) +{ + struct sk_buff *skb; + int count; + unsigned char *ptr; + + count = sp->rcount+1; + + sp->rx_bytes+=count; + + skb = dev_alloc_skb(count); + if (skb == NULL) + { + printk(KERN_DEBUG "%s: memory squeeze, dropping packet.\n", sp->dev->name); + sp->rx_dropped++; + return; + } + + skb->dev = sp->dev; + ptr = skb_put(skb, count); + *ptr++ = cmd; /* KISS command */ + + memcpy(ptr, (sp->cooked_buf)+1, count); + skb->mac.raw=skb->data; + skb->protocol=htons(ETH_P_AX25); + netif_rx(skb); + sp->rx_packets++; +} + + +/* ----------------------------------------------------------------------- */ + +/* Encapsulate one AX.25 frame and stuff into a TTY queue. */ +static void +sp_encaps(struct sixpack *sp, unsigned char *icp, int len) +{ + unsigned char *p; + int actual, count; + + if (len > sp->mtu) /* sp->mtu = AX25_MTU = max. PACLEN = 256 */ + { + len = sp->mtu; + printk(KERN_DEBUG "%s: truncating oversized transmit packet!\n", sp->dev->name); + sp->tx_dropped++; + sp_unlock(sp); + return; + } + + p = icp; + + if (p[0] > 5) + { + printk(KERN_DEBUG "%s: invalid KISS command -- dropped\n", sp->dev->name); + sp_unlock(sp); + return; + } + + if ((p[0] != 0) && (len > 2)) + { + printk(KERN_DEBUG "%s: KISS control packet too long -- dropped\n", sp->dev->name); + sp_unlock(sp); + return; + } + + if ((p[0] == 0) && (len < 15)) + { + printk(KERN_DEBUG "%s: bad AX.25 packet to transmit -- dropped\n", sp->dev->name); + sp_unlock(sp); + sp->tx_dropped++; + return; + } + + count = encode_sixpack(p, (unsigned char *) sp->xbuff, len, sp->tx_delay); + sp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + + switch(p[0]) + { + case 1: sp->tx_delay = p[1]; return; + case 2: sp->persistance = p[1]; return; + case 3: sp->slottime = p[1]; return; + case 4: /* ignored */ return; + case 5: sp->duplex = p[1]; return; + } + + if (p[0] == 0) { + /* in case of fullduplex or DAMA operation, we don't take care + about the state of the DCD or of any timers, as the determination + of the correct time to send is the job of the AX.25 layer. We send + immediately after data has arrived. */ + if (sp->duplex == 1){ + sp->led_state = 0x70; + sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1); + sp->tx_enable = 1; + actual = sp->tty->driver.write(sp->tty, 0, sp->xbuff, count); + sp->xleft = count - actual; + sp->xhead = sp->xbuff + actual; + sp->led_state = 0x60; + sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1); + } + else { + sp->xleft = count; + sp->xhead = sp->xbuff; + sp->status2 = count; + if (sp->duplex == 0) + sp_start_tx_timer(sp); + } + } +} + +/* + * Called by the TTY driver when there's room for more data. If we have + * more packets to send, we send them here. + */ +static void sixpack_write_wakeup(struct tty_struct *tty) +{ + int actual; + struct sixpack *sp = (struct sixpack *) tty->disc_data; + + /* First make sure we're connected. */ + if (!sp || sp->magic != SIXPACK_MAGIC || !sp->dev->start) { + return; + } + if (sp->xleft <= 0) { + /* Now serial buffer is almost free & we can start + * transmission of another packet */ + sp->tx_packets++; + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + sp_unlock(sp); + sp->tx_enable = 0; + mark_bh(NET_BH); + return; + } + + if (sp->tx_enable == 1) { + actual = tty->driver.write(tty, 0, sp->xhead, sp->xleft); + sp->xleft -= actual; + sp->xhead += actual; + } +} + +/* ----------------------------------------------------------------------- */ + +/* Encapsulate an IP datagram and kick it into a TTY queue. */ + +static int +sp_xmit(struct sk_buff *skb, struct device *dev) +{ + struct sixpack *sp = (struct sixpack*)(dev->priv); + + if (!dev->start) + { + printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name); + return 1; + } + + if (dev->tbusy) + return 1; + + /* We were not busy, so we are now... :-) */ + if (skb != NULL) { + sp_lock(sp); + sp->tx_bytes+=skb->len; /*---2.1.x---*/ + sp_encaps(sp, skb->data, skb->len); + dev_kfree_skb(skb); + } + return 0; +} +/* #endif */ + + +/* perform the persistence/slottime algorithm for CSMA access. If the persistence + check was successful, write the data to the serial driver. Note that in case + of DAMA operation, the data is not sent here. */ + +static +void sp_xmit_on_air(unsigned long channel) +{ + struct sixpack *sp = (struct sixpack *) channel; + int actual; + static unsigned char random; + + random = random * 17 + 41; + + if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistance)) { + sp->led_state = 0x70; + sp->tty->driver.write(sp->tty, 0, &(sp->led_state),1); + sp->tx_enable = 1; + actual = sp->tty->driver.write(sp->tty, 0, sp->xbuff, sp->status2); + sp->xleft -= actual; + sp->xhead += actual; + sp->led_state = 0x60; + sp->tty->driver.write(sp->tty, 0, &(sp->led_state),1); + sp->status2 = 0; + } else + sp_start_tx_timer(sp); +} /* sp_xmit */ + +/* #if defined(CONFIG_6PACK) || defined(CONFIG_6PACK_MODULE) */ + +/* Return the frame type ID */ +static int sp_header(struct sk_buff *skb, struct device *dev, unsigned short type, + void *daddr, void *saddr, unsigned len) +{ +#ifdef CONFIG_INET + if (type != htons(ETH_P_AX25)) + return ax25_encapsulate(skb, dev, type, daddr, saddr, len); +#endif + return 0; +} + + +static int sp_rebuild_header(struct sk_buff *skb) +{ +#ifdef CONFIG_INET + return ax25_rebuild_header(skb); +#else + return 0; +#endif +} + +/* #endif */ /* CONFIG_{AX25,AX25_MODULE} */ + +/* Open the low-level part of the 6pack channel. */ +static int +sp_open(struct device *dev) +{ + struct sixpack *sp = (struct sixpack*)(dev->priv); + unsigned long len; + + if (sp->tty == NULL) + return -ENODEV; + + /* + * Allocate the 6pack frame buffers: + * + * rbuff Receive buffer. + * xbuff Transmit buffer. + * cbuff Temporary compression buffer. + */ + + /* !!! length of the buffers. MTU is IP MTU, not PACLEN! + */ + + len = dev->mtu * 2; + + sp->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); + if (sp->rbuff == NULL) + return -ENOMEM; + + sp->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); + if (sp->xbuff == NULL) + { + kfree(sp->rbuff); + return -ENOMEM; + } + + sp->mtu = AX25_MTU + 73; + sp->buffsize = len; + sp->rcount = 0; + sp->rx_count = 0; + sp->rx_count_cooked = 0; + sp->xleft = 0; + + sp->flags &= (1 << SIXPF_INUSE); /* Clear ESCAPE & ERROR flags */ + + sp->duplex = 0; + sp->tx_delay = SIXP_TXDELAY; + sp->persistance = SIXP_PERSIST; + sp->slottime = SIXP_SLOTTIME; + sp->led_state = 0x60; + sp->status = 1; + sp->status1 = 1; + sp->status2 = 0; + sp->tnc_ok = 0; + sp->tx_enable = 0; + + dev->tbusy = 0; + dev->start = 1; + + init_timer(&sp->tx_t); + init_timer(&sp->resync_t); + return 0; +} + + +/* Close the low-level part of the 6pack channel. */ +static int +sp_close(struct device *dev) +{ + struct sixpack *sp = (struct sixpack*)(dev->priv); + + if (sp->tty == NULL) { + return -EBUSY; + } + sp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + dev->tbusy = 1; + dev->start = 0; + + return 0; +} + +static int +sixpack_receive_room(struct tty_struct *tty) +{ + return 65536; /* We can handle an infinite amount of data. :-) */ +} + +/* !!! receive state machine */ + +/* + * Handle the 'receiver data ready' interrupt. + * This function is called by the 'tty_io' module in the kernel when + * a block of 6pack data has been received, which can now be decapsulated + * and sent on to some IP layer for further processing. + */ +static void +sixpack_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +{ + unsigned char buf[512]; + unsigned long flags; + int count1; + + struct sixpack *sp = (struct sixpack *) tty->disc_data; + + if (!sp || sp->magic != SIXPACK_MAGIC || !sp->dev->start || !count) + return; + + save_flags(flags); + cli(); + memcpy(buf, cp, countflags)) { + sp->rx_errors++; + } + continue; + } + } + sixpack_decode(sp, buf, count1); +} + +/* + * Open the high-level part of the 6pack channel. + * This function is called by the TTY module when the + * 6pack line discipline is called for. Because we are + * sure the tty line exists, we only have to link it to + * a free 6pcack channel... + */ +static int +sixpack_open(struct tty_struct *tty) +{ + struct sixpack *sp = (struct sixpack *) tty->disc_data; + int err; + + /* First make sure we're not already connected. */ + + if (sp && sp->magic == SIXPACK_MAGIC) + return -EEXIST; + + /* OK. Find a free 6pack channel to use. */ + if ((sp = sp_alloc()) == NULL) + return -ENFILE; + sp->tty = tty; + tty->disc_data = sp; + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + + /* Restore default settings */ + sp->dev->type = ARPHRD_AX25; + + /* Perform the low-level 6pack initialization. */ + if ((err = sp_open(sp->dev))) + return err; + + MOD_INC_USE_COUNT; + + /* Done. We have linked the TTY line to a channel. */ + + tnc_init(sp); + + return sp->dev->base_addr; +} + + +/* + * Close down a 6pack channel. + * This means flushing out any pending queues, and then restoring the + * TTY line discipline to what it was before it got hooked to 6pack + * (which usually is TTY again). + */ +static void +sixpack_close(struct tty_struct *tty) +{ + struct sixpack *sp = (struct sixpack *) tty->disc_data; + + /* First make sure we're connected. */ + if (!sp || sp->magic != SIXPACK_MAGIC) + return; + + rtnl_lock(); + if (sp->dev->flags & IFF_UP) + (void) dev_close(sp->dev); + + del_timer(&(sp->tx_t)); + del_timer(&(sp->resync_t)); + + tty->disc_data = 0; + sp->tty = NULL; + /* VSV = very important to remove timers */ + + sp_free(sp); + unregister_netdev(sp->dev); + rtnl_unlock(); + MOD_DEC_USE_COUNT; +} + + +static struct net_device_stats * +sp_get_stats(struct device *dev) +{ + static struct net_device_stats stats; + struct sixpack *sp = (struct sixpack*)(dev->priv); + + memset(&stats, 0, sizeof(struct net_device_stats)); + + stats.rx_packets = sp->rx_packets; + stats.tx_packets = sp->tx_packets; + stats.rx_bytes = sp->rx_bytes; + stats.tx_bytes = sp->tx_bytes; + stats.rx_dropped = sp->rx_dropped; + stats.tx_dropped = sp->tx_dropped; + stats.tx_errors = sp->tx_errors; + stats.rx_errors = sp->rx_errors; + stats.rx_over_errors = sp->rx_over_errors; + return (&stats); +} + + +int +sp_set_mac_address(struct device *dev, void *addr) +{ + int err; + + err = verify_area(VERIFY_READ, addr, AX25_ADDR_LEN); + if (err) { + return err; + } + + copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN); /* addr is an AX.25 shifted ASCII mac address */ + + return 0; +} + +static int +sp_set_dev_mac_address(struct device *dev, void *addr) +{ + struct sockaddr *sa=addr; + memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN); + return 0; +} + + +/* Perform I/O control on an active 6pack channel. */ +static int +sixpack_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) +{ + struct sixpack *sp = (struct sixpack *) tty->disc_data; + int err; + unsigned int tmp; + + /* First make sure we're connected. */ + if (!sp || sp->magic != SIXPACK_MAGIC) { + return -EINVAL; + } + + switch(cmd) { + case SIOCGIFNAME: + err = verify_area(VERIFY_WRITE, arg, strlen(sp->dev->name) + 1); + if (err) { + return err; + } + copy_to_user(arg, sp->dev->name, strlen(sp->dev->name) + 1); + return 0; + + case SIOCGIFENCAP: + err = verify_area(VERIFY_WRITE, arg, sizeof(int)); + if (err) { + return err; + } + put_user(0, (int *)arg); + return 0; + + case SIOCSIFENCAP: + err = verify_area(VERIFY_READ, arg, sizeof(int)); + if (err) { + return err; + } + get_user(tmp,(int *)arg); + + sp->mode = tmp; + sp->dev->addr_len = AX25_ADDR_LEN; /* sizeof an AX.25 addr */ + sp->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3; + sp->dev->type = ARPHRD_AX25; + + return 0; + + case SIOCSIFHWADDR: + return sp_set_mac_address(sp->dev, arg); + + /* Allow stty to read, but not set, the serial port */ + case TCGETS: + case TCGETA: + return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg); + + default: + return -ENOIOCTLCMD; + } +} + +static int sp_open_dev(struct device *dev) +{ + struct sixpack *sp = (struct sixpack*)(dev->priv); + if(sp->tty==NULL) + return -ENODEV; + return 0; +} + +/* Initialize 6pack control device -- register 6pack line discipline */ + +#ifdef MODULE +static int sixpack_init_ctrl_dev(void) +#else /* !MODULE */ +__initfunc sixpack_init_ctrl_dev(struct device *dummy) +#endif /* !MODULE */ +{ + int status; + + if (sixpack_maxdev < 4) sixpack_maxdev = 4; /* Sanity */ + + printk(KERN_INFO "6pack: %s (dynamic channels, max=%d)\n", + SIXPACK_VERSION, sixpack_maxdev); + + sixpack_ctrls = (sixpack_ctrl_t **) kmalloc(sizeof(void*)*sixpack_maxdev, GFP_KERNEL); + if (sixpack_ctrls == NULL) + { + printk(KERN_WARNING "6pack: Can't allocate sixpack_ctrls[] array! Uaargh! (-> No 6pack available)\n"); + return -ENOMEM; + } + + /* Clear the pointer array, we allocate devices when we need them */ + memset(sixpack_ctrls, 0, sizeof(void*)*sixpack_maxdev); /* Pointers */ + + + /* Fill in our line protocol discipline, and register it */ + memset(&sp_ldisc, 0, sizeof(sp_ldisc)); + sp_ldisc.magic = TTY_LDISC_MAGIC; + sp_ldisc.name = "6pack"; + sp_ldisc.flags = 0; + sp_ldisc.open = sixpack_open; + sp_ldisc.close = sixpack_close; + sp_ldisc.read = NULL; + sp_ldisc.write = NULL; + sp_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, + unsigned int, unsigned long)) sixpack_ioctl; + sp_ldisc.poll = NULL; + sp_ldisc.receive_buf = sixpack_receive_buf; + sp_ldisc.receive_room = sixpack_receive_room; + sp_ldisc.write_wakeup = sixpack_write_wakeup; + if ((status = tty_register_ldisc(N_6PACK, &sp_ldisc)) != 0) { + printk(KERN_WARNING "6pack: can't register line discipline (err = %d)\n", status); + } + +#ifdef MODULE + return status; +#else + /* Return "not found", so that dev_init() will unlink + * the placeholder device entry for us. + */ + return ENODEV; +#endif +} + +/* Initialize the 6pack driver. Called by DDI. */ +int +sixpack_init(struct device *dev) +{ + struct sixpack *sp = (struct sixpack*)(dev->priv); + + static char ax25_bcast[AX25_ADDR_LEN] = + {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; + static char ax25_test[AX25_ADDR_LEN] = + {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; + + if (sp == NULL) /* Allocation failed ?? */ + return -ENODEV; + + /* Set up the "6pack Control Block". (And clear statistics) */ + + memset(sp, 0, sizeof (struct sixpack)); + sp->magic = SIXPACK_MAGIC; + sp->dev = dev; + + /* Finish setting up the DEVICE info. */ + dev->mtu = SIXP_MTU; + dev->hard_start_xmit = sp_xmit; + dev->open = sp_open_dev; + dev->stop = sp_close; + dev->hard_header = sp_header; + dev->get_stats = sp_get_stats; + dev->set_mac_address = sp_set_dev_mac_address; + dev->hard_header_len = AX25_MAX_HEADER_LEN; + dev->addr_len = AX25_ADDR_LEN; + dev->type = ARPHRD_AX25; + dev->tx_queue_len = 10; + dev->rebuild_header = sp_rebuild_header; + + memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); /* Only activated in AX.25 mode */ + memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); /* "" "" "" "" */ + + dev_init_buffers(dev); + + /* New-style flags. */ + dev->flags = 0; + + return 0; +} + +#ifdef MODULE + +int +init_module(void) +{ + return sixpack_init_ctrl_dev(); +} + +void +cleanup_module(void) +{ + int i; + + if (sixpack_ctrls != NULL) + { + for (i = 0; i < sixpack_maxdev; i++) + { + if (sixpack_ctrls[i]) + { + /* + * VSV = if dev->start==0, then device + * unregistered while close proc. + */ + if (sixpack_ctrls[i]->dev.start) + unregister_netdev(&(sixpack_ctrls[i]->dev)); + + kfree(sixpack_ctrls[i]); + sixpack_ctrls[i] = NULL; + } + } + kfree(sixpack_ctrls); + sixpack_ctrls = NULL; + } + if ((i = tty_register_ldisc(N_6PACK, NULL))) + { + printk(KERN_WARNING "6pack: can't unregister line discipline (err = %d)\n", i); + } +} +#endif /* MODULE */ + +/* ----> 6pack timer interrupt handler and friends. <---- */ +static void +sp_start_tx_timer(struct sixpack *sp) +{ + int when = sp->slottime; + + del_timer(&(sp->tx_t)); + sp->tx_t.data = (unsigned long) sp; + sp->tx_t.function = sp_xmit_on_air; + sp->tx_t.expires = jiffies + ((when+1)*HZ)/100; + add_timer(&(sp->tx_t)); +} + + +/* encode an AX.25 packet into 6pack */ + +int encode_sixpack(byte *tx_buf, byte *tx_buf_raw, int length, byte tx_delay) +{ + int count = 0; + byte checksum = 0, buf[400]; + int raw_count = 0; + + tx_buf_raw[raw_count++] = SIXP_PRIO_CMD_MASK | SIXP_TX_MASK; + tx_buf_raw[raw_count++] = SIXP_SEOF; + + buf[0] = tx_delay; + for(count = 1; count < length; count++) + buf[count] = tx_buf[count]; + + for(count = 0; count < length; count++) + checksum += buf[count]; + buf[length] = (byte)0xff - checksum; + + for(count = 0; count <= length; count++) { + if((count % 3) == 0) { + tx_buf_raw[raw_count++] = (buf[count] & 0x3f); + tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x30); + } + else if((count % 3) == 1) { + tx_buf_raw[raw_count++] |= (buf[count] & 0x0f); + tx_buf_raw[raw_count] = + ((buf[count] >> 2) & 0x3c); + } else { + tx_buf_raw[raw_count++] |= (buf[count] & 0x03); + tx_buf_raw[raw_count++] = + (buf[count] >> 2); + } /* else */ + } /* for */ + if ((length % 3) != 2) + raw_count++; + tx_buf_raw[raw_count++] = SIXP_SEOF; + return(raw_count); +} + + +/* decode a 6pack packet */ + +void +sixpack_decode(struct sixpack *sp, unsigned char pre_rbuff[], int count) +{ + byte inbyte; + int count1; + + for (count1 = 0; count1 < count; count1++) { + inbyte = pre_rbuff[count1]; + if (inbyte == SIXP_FOUND_TNC) { + printk(KERN_INFO "6pack: TNC found.\n"); + sp->tnc_ok = 1; + del_timer(&(sp->resync_t)); + } + if((inbyte & SIXP_PRIO_CMD_MASK) != 0) + decode_prio_command(inbyte, sp); + else if((inbyte & SIXP_STD_CMD_MASK) != 0) + decode_std_command(inbyte, sp); + else { + if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK) + decode_data(inbyte, sp); + } /* else */ + } /* for */ +} + +static int +tnc_init(struct sixpack *sp) +{ + static byte inbyte; + + inbyte = 0xe8; + sp->tty->driver.write(sp->tty, 0, &inbyte, 1); + + del_timer(&(sp->resync_t)); + sp->resync_t.data = (unsigned long) sp; + sp->resync_t.function = resync_tnc; + sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT; + add_timer(&(sp->resync_t)); + + return 0; +} + + +/* identify and execute a 6pack priority command byte */ + +void decode_prio_command(byte cmd, struct sixpack *sp) +{ + byte channel; + int actual; + + channel = cmd & SIXP_CHN_MASK; + if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */ + + /* RX and DCD flags can only be set in the same prio command, + if the DCD flag has been set without the RX flag in the previous + prio command. If DCD has not been set before, something in the + transmission has gone wrong. In this case, RX and DCD are + cleared in order to prevent the decode_data routine from + reading further data that might be corrupt. */ + + if (((sp->status & SIXP_DCD_MASK) == 0) && + ((cmd & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)) { + if (sp->status != 1) + printk(KERN_DEBUG "6pack: protocol violation\n"); + else + sp->status = 0; + cmd &= !SIXP_RX_DCD_MASK; + } + sp->status = cmd & SIXP_PRIO_DATA_MASK; + } /* if */ + else { /* output watchdog char if idle */ + if ((sp->status2 != 0) && (sp->duplex == 1)) { + sp->led_state = 0x70; + sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1); + sp->tx_enable = 1; + actual = sp->tty->driver.write(sp->tty, 0, sp->xbuff, sp->status2); + sp->xleft -= actual; + sp->xhead += actual; + sp->led_state = 0x60; + sp->status2 = 0; + + } /* if */ + } /* else */ + + /* needed to trigger the TNC watchdog */ + sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1); + + /* if the state byte has been received, the TNC is present, + so the resync timer can be reset. */ + + if (sp->tnc_ok == 1) { + del_timer(&(sp->resync_t)); + sp->resync_t.data = (unsigned long) sp; + sp->resync_t.function = resync_tnc; + sp->resync_t.expires = jiffies + SIXP_INIT_RESYNC_TIMEOUT; + add_timer(&(sp->resync_t)); + } + + sp->status1 = cmd & SIXP_PRIO_DATA_MASK; +} + +/* try to resync the TNC. Called by the resync timer defined in + decode_prio_command */ + +static void +resync_tnc(unsigned long channel) +{ + static char resync_cmd = 0xe8; + struct sixpack *sp = (struct sixpack *) channel; + + printk(KERN_INFO "6pack: resyncing TNC\n"); + + /* clear any data that might have been received */ + + sp->rx_count = 0; + sp->rx_count_cooked = 0; + + /* reset state machine */ + + sp->status = 1; + sp->status1 = 1; + sp->status2 = 0; + sp->tnc_ok = 0; + + /* resync the TNC */ + + sp->led_state = 0x60; + sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1); + sp->tty->driver.write(sp->tty, 0, &resync_cmd, 1); + + + /* Start resync timer again -- the TNC might be still absent */ + + del_timer(&(sp->resync_t)); + sp->resync_t.data = (unsigned long) sp; + sp->resync_t.function = resync_tnc; + sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT; + add_timer(&(sp->resync_t)); +} + + + +/* identify and execute a standard 6pack command byte */ + +void decode_std_command(byte cmd, struct sixpack *sp) +{ + byte checksum = 0, rest = 0, channel; + short i; + + channel = cmd & SIXP_CHN_MASK; + switch(cmd & SIXP_CMD_MASK) { /* normal command */ + case SIXP_SEOF: + if ((sp->rx_count == 0) && (sp->rx_count_cooked == 0)) { + if ((sp->status & SIXP_RX_DCD_MASK) == + SIXP_RX_DCD_MASK) { + sp->led_state = 0x68; + sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1); + } /* if */ + } else { + sp->led_state = 0x60; + /* fill trailing bytes with zeroes */ + sp->tty->driver.write(sp->tty, 0, &(sp->led_state), 1); + rest = sp->rx_count; + if (rest != 0) + for(i=rest; i<=3; i++) + decode_data(0, sp); + if (rest == 2) + sp->rx_count_cooked -= 2; + else if (rest == 3) + sp->rx_count_cooked -= 1; + for (i=0; irx_count_cooked; i++) + checksum+=sp->cooked_buf[i]; + if (checksum != SIXP_CHKSUM) { + printk(KERN_DEBUG "6pack: bad checksum %2.2x\n", checksum); + } else { + sp->rcount = sp->rx_count_cooked-2; + sp_bump(sp, 0); + } /* else */ + sp->rx_count_cooked = 0; + } /* else */ + break; + case SIXP_TX_URUN: printk(KERN_DEBUG "6pack: TX underrun\n"); + break; + case SIXP_RX_ORUN: printk(KERN_DEBUG "6pack: RX overrun\n"); + break; + case SIXP_RX_BUF_OVL: + printk(KERN_DEBUG "6pack: RX buffer overflow\n"); + } /* switch */ +} /* function */ + +/* decode 4 sixpack-encoded bytes into 3 data bytes */ + +void decode_data(byte inbyte, struct sixpack *sp) +{ + + unsigned char *buf; + + if (sp->rx_count != 3) + sp->raw_buf[sp->rx_count++] = inbyte; + else { + buf = sp->raw_buf; + sp->cooked_buf[sp->rx_count_cooked++] = + buf[0] | ((buf[1] << 2) & 0xc0); + sp->cooked_buf[sp->rx_count_cooked++] = + (buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0); + sp->cooked_buf[sp->rx_count_cooked++] = + (buf[2] & 0x03) | (inbyte << 2); + sp->rx_count = 0; + } +} diff -u --recursive --new-file v2.1.93/linux/drivers/net/hamradio/6pack.h linux/drivers/net/hamradio/6pack.h --- v2.1.93/linux/drivers/net/hamradio/6pack.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamradio/6pack.h Wed Apr 8 17:31:27 1998 @@ -0,0 +1,135 @@ +/* + * 6pack.h Define the 6pack device driver interface and constants. + * + * NOTE: THIS FILE WILL BE MOVED TO THE LINUX INCLUDE DIRECTORY + * AS SOON AS POSSIBLE! + * + * Version: @(#)6pack.h 0.3.0 04/07/98 + * + * Fixes: + * + * Author: Andreas Könsgen + * + * This file is derived from slip.h, written by + * Fred N. van Kempen, + */ + +#ifndef _LINUX_6PACK_H +#define _LINUX_6PACK_H + +#define SIXPACK_VERSION "Revision: 0.3.0" + +#ifdef __KERNEL__ + +/* sixpack priority commands */ +#define SIXP_SEOF 0x40 /* start and end of a 6pack frame */ +#define SIXP_TX_URUN 0x48 /* transmit overrun */ +#define SIXP_RX_ORUN 0x50 /* receive overrun */ +#define SIXP_RX_BUF_OVL 0x58 /* receive buffer overflow */ + +#define SIXP_CHKSUM 0xFF /* valid checksum of a 6pack frame */ + +/* masks to get certain bits out of the status bytes sent by the TNC */ + +#define SIXP_CMD_MASK 0xC0 +#define SIXP_CHN_MASK 0x07 +#define SIXP_PRIO_CMD_MASK 0x80 +#define SIXP_STD_CMD_MASK 0x40 +#define SIXP_PRIO_DATA_MASK 0x38 +#define SIXP_TX_MASK 0x20 +#define SIXP_RX_MASK 0x10 +#define SIXP_RX_DCD_MASK 0x18 +#define SIXP_LEDS_ON 0x78 +#define SIXP_LEDS_OFF 0x60 +#define SIXP_CON 0x08 +#define SIXP_STA 0x10 + +#define SIXP_FOUND_TNC 0xe9 +#define SIXP_CON_ON 0x68 +#define SIXP_DCD_MASK 0x08 +#define SIXP_DAMA_OFF 0 + +/* default level 2 parameters */ +#define SIXP_TXDELAY 25 /* in 10 ms */ +#define SIXP_PERSIST 50 /* in 256ths */ +#define SIXP_SLOTTIME 10 /* in 10 ms */ +#define SIXP_INIT_RESYNC_TIMEOUT 150 /* in 10 ms */ +#define SIXP_RESYNC_TIMEOUT 500 /* in 10 ms */ + +/* 6pack configuration. */ +#define SIXP_NRUNIT 256 /* MAX number of 6pack channels */ +#define SIXP_MTU 256 /* Default MTU */ + +enum sixpack_flags { + SIXPF_INUSE, /* Channel in use */ + SIXPF_ERROR, /* Parity, etc. error */ +}; + +struct sixpack { + int magic; + + /* Various fields. */ + struct tty_struct *tty; /* ptr to TTY structure */ + struct device *dev; /* easy for intr handling */ + + /* These are pointers to the malloc()ed frame buffers. */ + unsigned char *rbuff; /* receiver buffer */ + int rcount; /* received chars counter */ + unsigned char *xbuff; /* transmitter buffer */ + unsigned char *xhead; /* pointer to next byte to XMIT */ + int xleft; /* bytes left in XMIT queue */ + + unsigned char raw_buf[4]; + unsigned char cooked_buf[400]; + + unsigned int rx_count; + unsigned int rx_count_cooked; + + /* 6pack interface statistics. */ + unsigned long rx_packets; /* inbound frames counter */ + unsigned long tx_packets; /* outbound frames counter */ + unsigned long rx_bytes; /* inbound bytes counter */ + unsigned long tx_bytes; /* outboud bytes counter */ + unsigned long rx_errors; /* Parity, etc. errors */ + unsigned long tx_errors; /* Planned stuff */ + unsigned long rx_dropped; /* No memory for skb */ + unsigned long tx_dropped; /* When MTU change */ + unsigned long rx_over_errors; /* Frame bigger then 6pack buf. */ + + /* Detailed 6pack statistics. */ + + int mtu; /* Our mtu (to spot changes!) */ + int buffsize; /* Max buffers sizes */ + + unsigned char flags; /* Flag values/ mode etc */ + unsigned char mode; /* 6pack mode */ + +/* 6pack stuff */ + + unsigned char tx_delay; + unsigned char persistance; + unsigned char slottime; + unsigned char duplex; + unsigned char led_state; + unsigned char status; + unsigned char status1; + unsigned char status2; + unsigned char tx_enable; + unsigned char tnc_ok; + +/* unsigned char retval; */ + + struct timer_list tx_t; + struct timer_list resync_t; +}; /* struct sixpack */ + + +/* should later be moved to include/net/ax25.h */ +#define AX25_6PACK_HEADER_LEN 0 +#define SIXPACK_MAGIC 0x5304 + +extern int sixpack_init(struct device *dev); + +#endif + +#endif /* _LINUX_6PACK.H */ diff -u --recursive --new-file v2.1.93/linux/drivers/net/hamradio/Config.in linux/drivers/net/hamradio/Config.in --- v2.1.93/linux/drivers/net/hamradio/Config.in Wed Feb 4 11:36:00 1998 +++ linux/drivers/net/hamradio/Config.in Wed Apr 8 17:31:27 1998 @@ -1,7 +1,7 @@ comment 'AX.25 network device drivers' dep_tristate 'Serial port KISS driver' CONFIG_MKISS $CONFIG_AX25 -# dep_tristate 'Serial port 6PACK driver' CONFIG_6PACK $CONFIG_AX25 +dep_tristate 'Serial port 6PACK driver' CONFIG_6PACK $CONFIG_AX25 dep_tristate 'BPQ Ethernet driver' CONFIG_BPQETHER $CONFIG_AX25 dep_tristate 'High-speed (DMA) SCC driver for AX.25' CONFIG_DMASCC $CONFIG_AX25 diff -u --recursive --new-file v2.1.93/linux/drivers/net/hamradio/Makefile linux/drivers/net/hamradio/Makefile --- v2.1.93/linux/drivers/net/hamradio/Makefile Sun Jan 4 10:40:16 1998 +++ linux/drivers/net/hamradio/Makefile Wed Apr 8 17:31:27 1998 @@ -45,6 +45,14 @@ endif endif +ifeq ($(CONFIG_6PACK),y) +L_OBJS += 6pack.o +else + ifeq ($(CONFIG_6PACK),m) + M_OBJS += 6pack.o + endif +endif + ifeq ($(CONFIG_PI),y) L_OBJS += pi2.o else diff -u --recursive --new-file v2.1.93/linux/drivers/net/hamradio/soundmodem/gentbl.c linux/drivers/net/hamradio/soundmodem/gentbl.c --- v2.1.93/linux/drivers/net/hamradio/soundmodem/gentbl.c Thu Mar 26 15:57:03 1998 +++ linux/drivers/net/hamradio/soundmodem/gentbl.c Tue Apr 7 07:48:54 1998 @@ -681,7 +681,7 @@ gentbl_costab(f, 6); gentbl_afsk2400(f, 7372800); fclose(f); - return(0); + exit(0); } diff -u --recursive --new-file v2.1.93/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c --- v2.1.93/linux/drivers/net/sdla_fr.c Thu Mar 26 15:57:03 1998 +++ linux/drivers/net/sdla_fr.c Tue Apr 7 07:52:04 1998 @@ -83,7 +83,6 @@ * Jan 02, 1997 Gene Kozin Initial version. *****************************************************************************/ -#include /* OS configuration options */ #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ #include /* return codes */ diff -u --recursive --new-file v2.1.93/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c --- v2.1.93/linux/drivers/net/sdla_ppp.c Thu Mar 26 15:57:03 1998 +++ linux/drivers/net/sdla_ppp.c Tue Apr 7 07:52:04 1998 @@ -56,7 +56,6 @@ * Jan 06, 1997 Gene Kozin Initial version. *****************************************************************************/ -#include /* OS configuration options */ #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ #include /* return codes */ diff -u --recursive --new-file v2.1.93/linux/drivers/net/sdla_x25.c linux/drivers/net/sdla_x25.c --- v2.1.93/linux/drivers/net/sdla_x25.c Thu Mar 26 15:57:03 1998 +++ linux/drivers/net/sdla_x25.c Tue Apr 7 07:52:04 1998 @@ -42,7 +42,6 @@ #error This code MUST be compiled as a kernel module! #endif -#include /* OS configuration options */ #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ #include /* return codes */ diff -u --recursive --new-file v2.1.93/linux/drivers/scsi/mvme16x.c linux/drivers/scsi/mvme16x.c --- v2.1.93/linux/drivers/scsi/mvme16x.c Thu Mar 26 15:57:03 1998 +++ linux/drivers/scsi/mvme16x.c Tue Apr 7 07:52:04 1998 @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.1.93/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.1.93/linux/drivers/sound/Config.in Tue Mar 17 22:18:14 1998 +++ linux/drivers/sound/Config.in Wed Apr 8 17:24:48 1998 @@ -6,8 +6,6 @@ dep_tristate '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB $CONFIG_SOUND if [ "$CONFIG_SB" = "y" ]; then - bool 'Is the card a Soundman Games ?' CONFIG_SM_GAMES - bool 'Are you using the IBM Mwave "emulation" of SB ?' CONFIG_SB_MWAVE hex 'I/O base for SB Check from manual of the card' CONFIG_SB_BASE 220 int 'Sound Blaster IRQ Check from manual of the card' CONFIG_SB_IRQ 7 int 'Sound Blaster DMA 0, 1 or 3' CONFIG_SB_DMA 1 @@ -43,7 +41,7 @@ int 'MPU401 IRQ Check from manual of the card' CONFIG_MPU_IRQ 9 fi -dep_tristate 'PSS (ECHO-ADI2111) support' CONFIG_PSS $CONFIG_SOUND +dep_tristate 'PSS (AD1848, ADSP-2115, ESC614) support' CONFIG_PSS $CONFIG_SOUND if [ "$CONFIG_PSS" = "y" ]; then hex 'PSS I/O base 220 or 240' CONFIG_PSS_BASE 220 hex 'PSS audio I/O base 530, 604, E80 or F40' CONFIG_PSS_MSS_BASE 530 @@ -56,6 +54,9 @@ string ' Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE fi fi +if [ "$CONFIG_PSS" = "m" ] || [ "$CONFIG_PSS" = "y" ]; then + bool ' Enable PSS mixer (Beethoven ADSP-16 and other compatibile)' CONFIG_PSS_MIXER +fi dep_tristate 'Microsoft Sound System support' CONFIG_MSS $CONFIG_SOUND if [ "$CONFIG_MSS" = "y" ]; then @@ -92,6 +93,7 @@ fi dep_tristate 'Support for OPTi MAD16 and/or Mozart based cards' CONFIG_MAD16 $CONFIG_SOUND +dep_tristate 'Support MIDI in older MAD16 based cards (requires SB)' CONFIG_MAD16_OLDCARD $CONFIG_MAD16 if [ "$CONFIG_MAD16" = "y" ]; then hex 'MAD16 audio I/O base 530, 604, E80 or F40' CONFIG_MAD16_BASE 530 int 'MAD16 audio IRQ 7, 9, 10 or 11' CONFIG_MAD16_IRQ 11 @@ -213,3 +215,6 @@ fi fi +if [ "$CONFIG_ARM" = "y" ]; then + bool 'VIDC 16-bit sound' CONFIG_VIDC_SOUND +fi diff -u --recursive --new-file v2.1.93/linux/drivers/sound/Defines linux/drivers/sound/Defines --- v2.1.93/linux/drivers/sound/Defines Mon Feb 23 18:12:08 1998 +++ linux/drivers/sound/Defines Wed Apr 8 17:24:48 1998 @@ -231,6 +231,12 @@ endif endif +ifdef CONFIG_VIDC_SOUND +ifneq ($(CONFIG_SEQUENCER),Y) +CONFIG_SEQUENCER=y +endif +endif + ifdef CONFIG_PAS ifneq ($(CONFIG_AUDIO),Y) CONFIG_AUDIO=y @@ -304,6 +310,12 @@ endif ifdef CONFIG_SOFTOSS +ifneq ($(CONFIG_AUDIO),Y) +CONFIG_AUDIO=y +endif +endif + +ifdef CONFIG_VIDC_SOUND ifneq ($(CONFIG_AUDIO),Y) CONFIG_AUDIO=y endif diff -u --recursive --new-file v2.1.93/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.1.93/linux/drivers/sound/Makefile Tue Mar 17 22:18:14 1998 +++ linux/drivers/sound/Makefile Wed Apr 8 17:24:48 1998 @@ -117,6 +117,22 @@ endif endif +ifeq ($(CONFIG_MPU401),y) +LX_OBJS += mpu401.o +else + ifeq ($(CONFIG_MPU401),m) + MX_OBJS += mpu401.o + else + ifeq ($(CONFIG_MPU_EMU),y) + LX_OBJS += mpu401.o + else + ifeq ($(CONFIG_MPU_EMU),m) + MX_OBJS += mpu401.o + endif + endif + endif +endif + ifeq ($(CONFIG_UART401),y) LX_OBJS += uart401.o else @@ -143,31 +159,9 @@ ifeq ($(CONFIG_SSCAPE),y) L_OBJS += sscape.o -LX_OBJS += ad1848.o -CONFIG_MPU401 = y else ifeq ($(CONFIG_SSCAPE),m) M_OBJS += sscape.o - MX_OBJS += ad1848.o - ifneq ($(CONFIG_MPU401),y) - CONFIG_MPU401 = m - endif - endif -endif - -ifeq ($(CONFIG_MPU401),y) -LX_OBJS += mpu401.o -else - ifeq ($(CONFIG_MPU401),m) - MX_OBJS += mpu401.o - else - ifeq ($(CONFIG_MPU_EMU),y) - LX_OBJS += mpu401.o - else - ifeq ($(CONFIG_MPU_EMU),m) - MX_OBJS += mpu401.o - endif - endif endif endif @@ -230,27 +224,31 @@ endif endif +ifeq ($(CONFIG_VIDC_SOUND),y) + L_OBJS += vidc.o vidc_audio.o vidc_mixer.o vidc_synth.o vidc_fill.o +endif + include $(TOPDIR)/Rules.make softoss2.o: softoss.o softoss_rs.o - ld -r -o softoss2.o softoss.o softoss_rs.o + $(LD) -r -o softoss2.o softoss.o softoss_rs.o pas2.o: pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o - ld -r -o pas2.o pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o + $(LD) -r -o pas2.o pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o sb.o: sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o - ld -r -o sb.o sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o + $(LD) -r -o sb.o sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o lowlevel/lowlevel.o: cd lowlevel; make -sound.o: soundcard.o dev_table.o audio.o dmabuf.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o - ld -r -o sound.o soundcard.o dev_table.o audio.o dmabuf.o \ +sound.o: soundcard.o dev_table.o audio.o dmabuf.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o sound_syms.o + $(LD) -r -o sound.o soundcard.o dev_table.o audio.o dmabuf.o \ sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o \ - midi_synth.o midibuf.o sound_firmware.o + midi_synth.o midibuf.o sound_firmware.o sound_syms.o gus.o: gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o - ld -r -o gus.o gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o + $(LD) -r -o gus.o gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o # Firmware files that need translation # diff -u --recursive --new-file v2.1.93/linux/drivers/sound/README.C931 linux/drivers/sound/README.C931 --- v2.1.93/linux/drivers/sound/README.C931 Sun Dec 21 17:41:24 1997 +++ linux/drivers/sound/README.C931 Wed Dec 31 16:00:00 1969 @@ -1,62 +0,0 @@ -Support for the OPTI 82C931 chip --------------------------------- - -The opti 82C931 is supported in it's non PnP mode. -You do not need to set jumpers etc... The sound driver -will check the card status and if it is required it will -force the card into a mode that it can be programmed. - -To compile support for the OPTI 82C931 card you can use -the regular Linux config menus (ie, "make xconfig"). - -Sound card support should be enabled as a module (chose m). -Enable (m) for these items: - 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support (CONFIG_SB) - Generic OPL2/OPL3 FM synthesizer support (CONFIG_ADLIB) - Microsoft Sound System support (CONFIG_MSS) - Support for OPTi MAD16 and/or Mozart based cards (CONFIG_MAD16) - FM synthesizer (YM3812/OPL-3) support (CONFIG_YM3812) - -The configuration menu may ask for addresses, irq lines or dma -channels. If the card is used as a module the module loading -options will override these values. - -Go on and compile your kernel and modules, install the modules. - -I use this configuration as part of /etc/conf.modules: - -options sb mad16=1 -options mad16 irq=10 dma=1 io=0x530 joystick=1 cdtype=0 -options opl3 io=0x388 - -After installing everything and booting to a kernel that -matches the modules you can load the sound driver: - -modprobe mad16 -modprobe opl3 - -As a result these modules are loaded: -Module Size Used by -opl3 10416 0 (unused) -mad16 6472 0 -sb 23544 0 [mad16] -uart401 5796 0 [mad16 sb] -ad1848 16532 1 [mad16] -sound 82052 0 [opl3 mad16 sb uart401 ad1848] - -Known problems: -1. The uart401 cannot be used. This is probably a problem which - was introduced when the sound driver was modularized. - Do not try to load uart401 with options (io=xxx, irq=yyy) because - it will try to initialize itself and fail. - -2. Cannot use the sound driver in Duplex mode. Until it is fixed - use only one DMA channel (0, 1 or 3) for mad16. - -3. Configuration of the cdrom adaptor on the sound card is not - tested and probably does not work. - -4. General problem with the modularized sound driver: If you - load part of the sound driver while a sound program is - running, stopping the program may result with a situation - where the "Used by" count becomes negative. diff -u --recursive --new-file v2.1.93/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.1.93/linux/drivers/sound/ad1848.c Tue Mar 17 22:18:14 1998 +++ linux/drivers/sound/ad1848.c Wed Apr 8 17:24:48 1998 @@ -12,16 +12,16 @@ * * CS4232 is a PnP audio chip which contains a CS4231A (and SB, MPU). * CS4232A is an improved version of CS4232. - */ - -/* + * + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. - */ -/* + * + * * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) * general sleep/wakeup clean up. * Alan Cox : reformatted. Fixed SMP bugs. Moved to kernel alloc/free @@ -84,7 +84,6 @@ int irq_ok; mixer_ents *mix_devices; int mixer_output_port; - int c930_password_port; } ad1848_info; typedef struct ad1848_port_info @@ -561,6 +560,12 @@ val = devc->mixer_output_port; return put_user(val, (int *)arg); } + if (cmd == SOUND_MIXER_PRIVATE2) + { + if (get_user(val, (int *)arg)) + return -EFAULT; + return(ad1848_control(AD1848_MIXER_REROUTE, val)); + } if (((cmd >> 8) & 0xff) == 'M') { if (_SIOC_DIR(cmd) & _SIOC_WRITE) @@ -1409,7 +1414,6 @@ devc->chip_name = devc->name = "AD1848"; devc->model = MD_1848; /* AD1848 or CS4248 */ devc->levels = NULL; - devc->c930_password_port = 0; devc->debug_flag = 0; /* @@ -1789,11 +1793,15 @@ if (request_irq(devc->irq, adintr, 0, devc->name, (void *)my_dev) < 0) { printk(KERN_WARNING "ad1848: Unable to allocate IRQ\n"); + /* Don't free it either then.. */ + devc->irq = 0; } if (devc->model != MD_1848 && devc->model != MD_C930) { +#ifndef __SMP__ int x; unsigned char tmp = ad_read(devc, 16); +#endif devc->timer_ticks = 0; @@ -1843,16 +1851,15 @@ { audio_devs[my_dev]->mixer_dev = e; } - MOD_INC_USE_COUNT; return my_dev; } -void ad1848_control(int cmd, int arg) +int ad1848_control(int cmd, int arg) { ad1848_info *devc; if (nr_ad1848_devs < 1) - return; + return -ENODEV; devc = &adev_info[nr_ad1848_devs - 1]; @@ -1860,7 +1867,7 @@ { case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */ if (devc->model != MD_1845) - return; + return -EINVAL; ad_enter_MCE(devc); ad_write(devc, 29, (ad_read(devc, 29) & 0x1f) | (arg << 5)); ad_leave_MCE(devc); @@ -1871,32 +1878,37 @@ int o = (arg >> 8) & 0xff; int n = arg & 0xff; + if (o < 0 || o >= SOUND_MIXER_NRDEVICES) + return -EINVAL; + + if (!(devc->supported_devices & (1 << o)) && + !(devc->supported_rec_devices & (1 << o))) + return -EINVAL; + if (n == SOUND_MIXER_NONE) { /* Just hide this control */ ad1848_mixer_set(devc, o, 0); /* Shut up it */ devc->supported_devices &= ~(1 << o); devc->supported_rec_devices &= ~(1 << o); - return; + break; } - /* Make the mixer control identified by o to appear as n */ - if (o < 0 || o > SOUND_MIXER_NRDEVICES) - return; - if (n < 0 || n > SOUND_MIXER_NRDEVICES) - return; - if (!(devc->supported_devices & (1 << o))) - return; /* Not supported */ + /* Make the mixer control identified by o to appear as n */ + if (n < 0 || n >= SOUND_MIXER_NRDEVICES) + return -EINVAL; devc->mixer_reroute[n] = o; /* Rename the control */ - devc->supported_devices &= ~(1 << o); - devc->supported_devices |= (1 << n); + if (devc->supported_devices & (1 << o)) + devc->supported_devices |= (1 << n); if (devc->supported_rec_devices & (1 << o)) devc->supported_rec_devices |= (1 << n); + + devc->supported_devices &= ~(1 << o); devc->supported_rec_devices &= ~(1 << o); } break; } - return; + return 0; } void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int share_dma) @@ -1932,7 +1944,6 @@ } else printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base); - MOD_DEC_USE_COUNT; } void adintr(int irq, void *dev_id, struct pt_regs *dummy) @@ -1965,37 +1976,22 @@ save_flags(flags); cli(); - alt_stat = 0; - - if (devc->c930_password_port) - outb((0xe4), devc->c930_password_port); /* Password */ + /* 0xe0e is C930 address port + * 0xe0f is C930 data port + */ outb(11, 0xe0e); c930_stat = inb(0xe0f); + outb((~c930_stat), 0xe0f); - if (c930_stat & 0x04) - alt_stat |= 0x10; /* Playback intr */ - if (c930_stat & 0x08) - alt_stat |= 0x20; /* Playback intr */ restore_flags(flags); - } else if (devc->model != MD_1848) - alt_stat = ad_read(devc, 24); - - /* Acknowledge the intr before proceeding */ - if (devc->model == MD_C930) - { /* 82C930 has interrupt status register in MAD16 register MC11 */ - unsigned long flags; - - save_flags(flags); - cli(); - if (devc->c930_password_port) - outb((0xe4), devc->c930_password_port); /* Password */ - outb((11), 0xe0e); - outb((~c930_stat), 0xe0f); - restore_flags(flags); + alt_stat = (c930_stat << 2) & 0x30; } else if (devc->model != MD_1848) + { + alt_stat = ad_read(devc, 24); ad_write(devc, 24, ad_read(devc, 24) & ~alt_stat); /* Selective ack */ + } if (devc->open_mode & OPEN_READ && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20) { @@ -2550,11 +2546,10 @@ struct address_info hw_config; - int init_module(void) { printk(KERN_INFO "ad1848/cs4248 codec driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - if(io!=-1) + if(io != -1) { if(irq == -1 || dma == -1) { @@ -2581,12 +2576,5 @@ if(loaded) unload_ms_sound(&hw_config); } - -#else - -void export_ad1848_syms(void) -{ -} - #endif #endif diff -u --recursive --new-file v2.1.93/linux/drivers/sound/ad1848_mixer.h linux/drivers/sound/ad1848_mixer.h --- v2.1.93/linux/drivers/sound/ad1848_mixer.h Tue Sep 30 08:46:44 1997 +++ linux/drivers/sound/ad1848_mixer.h Wed Apr 8 17:24:48 1998 @@ -1,6 +1,6 @@ /* * sound/ad1848_mixer.h - * + * * Definitions for the mixer of AD1848 and compatible codecs. */ @@ -77,7 +77,7 @@ */ #define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r, mute_bit) \ - {{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r, mute_bit}} + {{reg_l, pola_l, pos_l, len_l, mute_bit}, {reg_r, pola_r, pos_r, len_r, mute_bit}} static mixer_ents ad1848_mix_devices[32] = { MIX_ENT(SOUND_MIXER_VOLUME, 27, 1, 0, 4, 29, 1, 0, 4, 8), @@ -88,13 +88,13 @@ MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0, 8), MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5, 7), MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1, 8), -MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5, 7), MIX_ENT(SOUND_MIXER_IMIX, 13, 1, 2, 6, 0, 0, 0, 0, 8), MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4, 8), MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), -MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5, 7), MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5, 7), MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5, 7) }; @@ -108,13 +108,13 @@ MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0, 8), MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5, 7), MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1, 8), -MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5, 7), MIX_ENT(SOUND_MIXER_IMIX, 16, 1, 0, 5, 17, 1, 0, 5, 8), MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4, 8), MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), -MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5, 7), MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5, 7), MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5, 7) }; @@ -125,21 +125,21 @@ * MIC is level of mic monitoring direct to output. Same for CD, LINE, etc. */ static mixer_ents c930_mix_devices[32] = { -MIX_ENT(SOUND_MIXER_VOLUME, 22, 1, 0, 5, 23, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_VOLUME, 22, 1, 1, 5, 23, 1, 1, 5, 7), MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), -MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5, 7), -MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6, 7), -MIX_ENT(SOUND_MIXER_SPEAKER, 22, 1, 0, 5, 23, 1, 0, 5, 8), +MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 1, 4, 5, 1, 1, 4, 7), +MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 5, 7, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_SPEAKER, 22, 1, 1, 5, 23, 1, 1, 5, 7), MIX_ENT(SOUND_MIXER_LINE, 18, 1, 1, 4, 19, 1, 1, 4, 7), -MIX_ENT(SOUND_MIXER_MIC, 20, 1, 0, 4, 21, 1, 0, 4, 8), -MIX_ENT(SOUND_MIXER_CD, 2, 1, 1, 4, 3, 1, 1, 4, 7), -MIX_ENT(SOUND_MIXER_IMIX, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_MIC, 20, 1, 1, 4, 21, 1, 1, 4, 7), +MIX_ENT(SOUND_MIXER_CD, 2, 1, 1, 4, 3, 1, 1, 4, 7), +MIX_ENT(SOUND_MIXER_IMIX, 0, 0, 0, 0, 0, 0, 0, 0, 8), MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4, 8), MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), -MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 1, 4, 3, 1, 1, 4, 7), +MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 1, 4, 3, 1, 1, 4, 7), MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 1, 4, 5, 1, 1, 4, 7), MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 1, 4, 19, 1, 1, 4, 7) }; diff -u --recursive --new-file v2.1.93/linux/drivers/sound/adlib_card.c linux/drivers/sound/adlib_card.c --- v2.1.93/linux/drivers/sound/adlib_card.c Tue Jan 20 16:44:57 1998 +++ linux/drivers/sound/adlib_card.c Wed Apr 8 17:24:48 1998 @@ -2,19 +2,17 @@ * sound/adlib_card.c * * Detection routine for the AdLib card. - */ - -/* + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. */ -#include -#include +#include +#include #include "sound_config.h" #include "soundmodule.h" @@ -28,7 +26,8 @@ int probe_adlib(struct address_info *hw_config) { - if (check_region(hw_config->io_base, 4)) { + if (check_region(hw_config->io_base, 4)) + { DDB(printk("opl3.c: I/O port %x already in use\n", hw_config->io_base)); return 0; } @@ -46,12 +45,14 @@ int io = -1; MODULE_PARM(io, "i"); +EXPORT_NO_SYMBOLS; + struct address_info cfg; int init_module(void) { if (io == -1) { - printk("adlib: must specify I/O address.\n"); + printk(KERN_ERR "adlib: must specify I/O address.\n"); return -EINVAL; } cfg.io_base = io; diff -u --recursive --new-file v2.1.93/linux/drivers/sound/audio.c linux/drivers/sound/audio.c --- v2.1.93/linux/drivers/sound/audio.c Tue Mar 17 22:18:14 1998 +++ linux/drivers/sound/audio.c Wed Apr 8 17:24:48 1998 @@ -21,6 +21,7 @@ #include #include +#include #include "sound_config.h" @@ -164,8 +165,6 @@ DMAbuf_release(dev, mode); } -#if defined(NO_INLINE_ASM) || !defined(i386) - static void translate_bytes(const unsigned char *table, unsigned char *buff, int n) { unsigned long i; @@ -177,24 +176,6 @@ buff[i] = table[buff[i]]; } -#else -extern inline void -translate_bytes(const void *table, void *buff, int n) -{ - if (n > 0) - { - __asm__("cld\n" - "1:\tlodsb\n\t" - "xlatb\n\t" - "stosb\n\t" - "loop 1b\n\t": - : "b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff) - : "bx", "cx", "di", "si", "ax"); - } -} - -#endif - int audio_write(int dev, struct file *file, const char *buf, int count) { int c, p, l, buf_size; @@ -827,8 +808,10 @@ DMAbuf_launch_output(dev, dmap_out); } audio_devs[dev]->enable_bits = bits; +#if 0 if (changed && audio_devs[dev]->d->trigger) audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go); +#endif restore_flags(flags); /* Falls through... */ diff -u --recursive --new-file v2.1.93/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c --- v2.1.93/linux/drivers/sound/cs4232.c Tue Mar 17 22:18:14 1998 +++ linux/drivers/sound/cs4232.c Wed Apr 8 17:24:48 1998 @@ -301,6 +301,8 @@ MODULE_PARM(dma,"i"); MODULE_PARM(dma2,"i"); +EXPORT_NO_SYMBOLS; + struct address_info cfg; /* diff -u --recursive --new-file v2.1.93/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c --- v2.1.93/linux/drivers/sound/dev_table.c Tue Mar 17 22:18:14 1998 +++ linux/drivers/sound/dev_table.c Wed Apr 8 17:24:48 1998 @@ -18,7 +18,6 @@ #define _DEV_TABLE_C_ #include "sound_config.h" -int sb_be_quiet = 0; int softoss_dev = 0; int sound_started = 0; int sndtable_get_cardcount(void); @@ -148,6 +147,9 @@ } } + for (i=0;iraw_buf_phys = virt_to_bus(start_addr); for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++) - set_bit(PG_reserved, &mem_map[i].flags); + set_bit(PG_reserved, &mem_map[i].flags);; return 0; } @@ -115,6 +115,8 @@ if (dmap->raw_buf == NULL) return; + if (dmap->mapping_flags & DMA_MAP_MAPPED) + return; /* Don't free mmapped buffer. Will use it next time */ for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1); start_addr = (unsigned long) dmap->raw_buf; @@ -125,8 +127,6 @@ free_pages((unsigned long) dmap->raw_buf, sz); dmap->raw_buf = NULL; - /* Remember the buffer is deleted so we dont Oops later */ - dmap->fragment_size = 0; } @@ -206,7 +206,6 @@ dmap->dma_mode = DMODE_NONE; dmap->flags &= ~DMA_BUSY; disable_dma(dmap->dma); - sound_free_dmap(dmap); } @@ -1210,6 +1209,20 @@ unsigned int DMAbuf_poll(struct file * file, int dev, poll_table *wait) { return poll_input(file, dev, wait) | poll_output(file, dev, wait); +} + +void DMAbuf_deinit(int dev) +{ + struct audio_operations *adev = audio_devs[dev]; + /* This routine is called when driver is being unloaded */ + if (!adev) + return; +#ifdef RUNTIME_DMA_ALLOC + sound_free_dmap(adev->dmap_out); + + if (adev->flags & DMA_DUPLEX) + sound_free_dmap(adev->dmap_in); +#endif } #endif diff -u --recursive --new-file v2.1.93/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c --- v2.1.93/linux/drivers/sound/dmasound.c Mon Dec 1 09:45:01 1997 +++ linux/drivers/sound/dmasound.c Wed Apr 8 17:24:48 1998 @@ -3,76 +3,76 @@ /* - OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k +OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k - (c) 1995 by Michael Schlueter & Michael Marte +(c) 1995 by Michael Schlueter & Michael Marte - Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS - interface and the u-law to signed byte conversion. +Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS +interface and the u-law to signed byte conversion. - Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue, - /dev/mixer, /dev/sndstat and complemented the VFS interface. He would like - to thank: - Michael Schlueter for initial ideas and documentation on the MFP and - the DMA sound hardware. - Therapy? for their CD 'Troublegum' which really made me rock. - - /dev/sndstat is based on code by Hannu Savolainen, the author of the - VoxWare family of drivers. - - This file is subject to the terms and conditions of the GNU General Public - License. See the file COPYING in the main directory of this archive - for more details. - - History: - 1995/8/25 first release - - 1995/9/02 ++roman: fixed atari_stram_alloc() call, the timer programming - and several race conditions - - 1995/9/14 ++roman: After some discussion with Michael Schlueter, revised - the interrupt disabling - Slightly speeded up U8->S8 translation by using long - operations where possible - Added 4:3 interpolation for /dev/audio - - 1995/9/20 ++TeSche: Fixed a bug in sq_write and changed /dev/audio - converting to play at 12517Hz instead of 6258Hz. - - 1995/9/23 ++TeSche: Changed sq_interrupt() and sq_play() to pre-program - the DMA for another frame while there's still one - running. This allows the IRQ response to be - arbitrarily delayed and playing will still continue. - - 1995/10/14 ++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for - Falcon audio (the Falcon doesn't raise an IRQ at the - end of a frame, but at the beginning instead!). uses - 'if (codec_dma)' in lots of places to simply switch - between Falcon and TT code. - - 1995/11/06 ++TeSche: started introducing a hardware abstraction scheme - (may perhaps also serve for Amigas?), can now play - samples at almost all frequencies by means of a more - generalized expand routine, takes a good deal of care - to cut data only at sample sizes, buffer size is now - a kernel runtime option, implemented fsync() & several - minor improvements - ++Guenther: useful hints and bug fixes, cross-checked it for - Falcons - - 1996/3/9 ++geert: support added for Amiga, A-law, 16-bit little endian. - Unification to drivers/sound/dmasound.c. - - 1996/4/6 ++Martin Mitchell: updated to 1.3 kernel. - - 1996/6/13 ++topi: fixed things that were broken (mainly the amiga - 14-bit routines), /dev/sndstat shows now the real - hardware frequency, the lowpass filter is disabled - by default now. +Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue, +/dev/mixer, /dev/sndstat and complemented the VFS interface. He would like +to thank: +Michael Schlueter for initial ideas and documentation on the MFP and +the DMA sound hardware. +Therapy? for their CD 'Troublegum' which really made me rock. + +/dev/sndstat is based on code by Hannu Savolainen, the author of the +VoxWare family of drivers. + +This file is subject to the terms and conditions of the GNU General Public +License. See the file COPYING in the main directory of this archive +for more details. + +History: +1995/8/25 first release + +1995/9/02 ++roman: fixed atari_stram_alloc() call, the timer programming + and several race conditions + +1995/9/14 ++roman: After some discussion with Michael Schlueter, revised + the interrupt disabling + Slightly speeded up U8->S8 translation by using long + operations where possible + Added 4:3 interpolation for /dev/audio + +1995/9/20 ++TeSche: Fixed a bug in sq_write and changed /dev/audio + converting to play at 12517Hz instead of 6258Hz. + +1995/9/23 ++TeSche: Changed sq_interrupt() and sq_play() to pre-program + the DMA for another frame while there's still one + running. This allows the IRQ response to be + arbitrarily delayed and playing will still continue. + +1995/10/14 ++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for + Falcon audio (the Falcon doesn't raise an IRQ at the + end of a frame, but at the beginning instead!). uses + 'if (codec_dma)' in lots of places to simply switch + between Falcon and TT code. + +1995/11/06 ++TeSche: started introducing a hardware abstraction scheme + (may perhaps also serve for Amigas?), can now play + samples at almost all frequencies by means of a more + generalized expand routine, takes a good deal of care + to cut data only at sample sizes, buffer size is now + a kernel runtime option, implemented fsync() & several + minor improvements + ++Guenther: useful hints and bug fixes, cross-checked it for + Falcons + +1996/3/9 ++geert: support added for Amiga, A-law, 16-bit little endian. + Unification to drivers/sound/dmasound.c. + +1996/4/6 ++Martin Mitchell: updated to 1.3 kernel. + +1996/6/13 ++topi: fixed things that were broken (mainly the amiga + 14-bit routines), /dev/sndstat shows now the real + hardware frequency, the lowpass filter is disabled + by default now. - 1996/9/25 ++geert: modularization +1996/9/25 ++geert: modularization - */ +*/ #include @@ -94,55 +94,54 @@ #ifdef CONFIG_ATARI #include #include -#endif /* CONFIG_ATARI */ +#include +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA #include #include -#endif /* CONFIG_AMIGA */ +#endif /* CONFIG_AMIGA */ #include "dmasound.h" #include #ifdef MODULE -static int chrdev_registered = 0; -static int irq_installed = 0; - -#endif /* MODULE */ -static char **sound_buffers = NULL; +static int chrdev_registered = 0; +static int irq_installed = 0; +#endif /* MODULE */ +static char **sound_buffers = NULL; #ifdef CONFIG_ATARI -extern void atari_microwire_cmd(int cmd); - -#endif /* CONFIG_ATARI */ +extern void atari_microwire_cmd(int cmd); +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA /* - * The minimum period for audio depends on htotal (for OCS/ECS/AGA) - * (Imported from arch/m68k/amiga/amisound.c) + * The minimum period for audio depends on htotal (for OCS/ECS/AGA) + * (Imported from arch/m68k/amiga/amisound.c) */ extern volatile u_short amiga_audio_min_period; /* - * amiga_mksound() should be able to restore the period after beeping - * (Imported from arch/m68k/amiga/amisound.c) + * amiga_mksound() should be able to restore the period after beeping + * (Imported from arch/m68k/amiga/amisound.c) */ -extern u_short amiga_audio_period; +extern u_short amiga_audio_period; /* - * Audio DMA masks + * Audio DMA masks */ #define AMI_AUDIO_OFF (DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3) #define AMI_AUDIO_8 (DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1) #define AMI_AUDIO_14 (AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3) -#endif /* CONFIG_AMIGA */ +#endif /* CONFIG_AMIGA */ /*** Some declarations *******************************************************/ @@ -157,7 +156,7 @@ #define MIN_BUFSIZE 4 #define MAX_BUFSIZE 128 /* Limit for Amiga */ -static int catchRadius = 0, numBufs = 4, bufSize = 32; +static int catchRadius = 0, numBufs = 4, bufSize = 32; #define arraysize(x) (sizeof(x)/sizeof(*(x))) @@ -177,78 +176,76 @@ /* 8 bit mu-law */ -static char ulaw2dma8[] = -{ - -126, -122, -118, -114, -110, -106, -102, -98, - -94, -90, -86, -82, -78, -74, -70, -66, - -63, -61, -59, -57, -55, -53, -51, -49, - -47, -45, -43, -41, -39, -37, -35, -33, - -31, -30, -29, -28, -27, -26, -25, -24, - -23, -22, -21, -20, -19, -18, -17, -16, - -16, -15, -15, -14, -14, -13, -13, -12, - -12, -11, -11, -10, -10, -9, -9, -8, - -8, -8, -7, -7, -7, -7, -6, -6, - -6, -6, -5, -5, -5, -5, -4, -4, - -4, -4, -4, -4, -3, -3, -3, -3, - -3, -3, -3, -3, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 0, - 125, 121, 117, 113, 109, 105, 101, 97, - 93, 89, 85, 81, 77, 73, 69, 65, - 62, 60, 58, 56, 54, 52, 50, 48, - 46, 44, 42, 40, 38, 36, 34, 32, - 30, 29, 28, 27, 26, 25, 24, 23, - 22, 21, 20, 19, 18, 17, 16, 15, - 15, 14, 14, 13, 13, 12, 12, 11, - 11, 10, 10, 9, 9, 8, 8, 7, - 7, 7, 6, 6, 6, 6, 5, 5, - 5, 5, 4, 4, 4, 4, 3, 3, - 3, 3, 3, 3, 2, 2, 2, 2, - 2, 2, 2, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 +static char ulaw2dma8[] = { + -126, -122, -118, -114, -110, -106, -102, -98, + -94, -90, -86, -82, -78, -74, -70, -66, + -63, -61, -59, -57, -55, -53, -51, -49, + -47, -45, -43, -41, -39, -37, -35, -33, + -31, -30, -29, -28, -27, -26, -25, -24, + -23, -22, -21, -20, -19, -18, -17, -16, + -16, -15, -15, -14, -14, -13, -13, -12, + -12, -11, -11, -10, -10, -9, -9, -8, + -8, -8, -7, -7, -7, -7, -6, -6, + -6, -6, -5, -5, -5, -5, -4, -4, + -4, -4, -4, -4, -3, -3, -3, -3, + -3, -3, -3, -3, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 0, + 125, 121, 117, 113, 109, 105, 101, 97, + 93, 89, 85, 81, 77, 73, 69, 65, + 62, 60, 58, 56, 54, 52, 50, 48, + 46, 44, 42, 40, 38, 36, 34, 32, + 30, 29, 28, 27, 26, 25, 24, 23, + 22, 21, 20, 19, 18, 17, 16, 15, + 15, 14, 14, 13, 13, 12, 12, 11, + 11, 10, 10, 9, 9, 8, 8, 7, + 7, 7, 6, 6, 6, 6, 5, 5, + 5, 5, 4, 4, 4, 4, 3, 3, + 3, 3, 3, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; /* 8 bit A-law */ -static char alaw2dma8[] = -{ - -22, -21, -24, -23, -18, -17, -20, -19, - -30, -29, -32, -31, -26, -25, -28, -27, - -11, -11, -12, -12, -9, -9, -10, -10, - -15, -15, -16, -16, -13, -13, -14, -14, - -86, -82, -94, -90, -70, -66, -78, -74, - -118, -114, -126, -122, -102, -98, -110, -106, - -43, -41, -47, -45, -35, -33, -39, -37, - -59, -57, -63, -61, -51, -49, -55, -53, - -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -6, -6, -6, -6, -5, -5, -5, -5, - -8, -8, -8, -8, -7, -7, -7, -7, - -3, -3, -3, -3, -3, -3, -3, -3, - -4, -4, -4, -4, -4, -4, -4, -4, - 21, 20, 23, 22, 17, 16, 19, 18, - 29, 28, 31, 30, 25, 24, 27, 26, - 10, 10, 11, 11, 8, 8, 9, 9, - 14, 14, 15, 15, 12, 12, 13, 13, - 86, 82, 94, 90, 70, 66, 78, 74, - 118, 114, 126, 122, 102, 98, 110, 106, - 43, 41, 47, 45, 35, 33, 39, 37, - 59, 57, 63, 61, 51, 49, 55, 53, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 5, 5, 5, 5, 4, 4, 4, 4, - 7, 7, 7, 7, 6, 6, 6, 6, - 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3 +static char alaw2dma8[] = { + -22, -21, -24, -23, -18, -17, -20, -19, + -30, -29, -32, -31, -26, -25, -28, -27, + -11, -11, -12, -12, -9, -9, -10, -10, + -15, -15, -16, -16, -13, -13, -14, -14, + -86, -82, -94, -90, -70, -66, -78, -74, + -118, -114, -126, -122, -102, -98, -110, -106, + -43, -41, -47, -45, -35, -33, -39, -37, + -59, -57, -63, -61, -51, -49, -55, -53, + -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -6, -6, -6, -6, -5, -5, -5, -5, + -8, -8, -8, -8, -7, -7, -7, -7, + -3, -3, -3, -3, -3, -3, -3, -3, + -4, -4, -4, -4, -4, -4, -4, -4, + 21, 20, 23, 22, 17, 16, 19, 18, + 29, 28, 31, 30, 25, 24, 27, 26, + 10, 10, 11, 11, 8, 8, 9, 9, + 14, 14, 15, 15, 12, 12, 13, 13, + 86, 82, 94, 90, 70, 66, 78, 74, + 118, 114, 126, 122, 102, 98, 110, 106, + 43, 41, 47, 45, 35, 33, 39, 37, + 59, 57, 63, 61, 51, 49, 55, 53, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 4, 4, 4, 4, + 7, 7, 7, 7, 6, 6, 6, 6, + 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3 }; @@ -256,403 +253,381 @@ /* 16 bit mu-law */ -static char ulaw2dma16[] = -{ - -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, - -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, - -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, - -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, - -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, - -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, - -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, - -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, - -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, - -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, - -876, -844, -812, -780, -748, -716, -684, -652, - -620, -588, -556, -524, -492, -460, -428, -396, - -372, -356, -340, -324, -308, -292, -276, -260, - -244, -228, -212, -196, -180, -164, -148, -132, - -120, -112, -104, -96, -88, -80, -72, -64, - -56, -48, -40, -32, -24, -16, -8, 0, - 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, - 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, - 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, - 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, - 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, - 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, - 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, - 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, - 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, - 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, - 876, 844, 812, 780, 748, 716, 684, 652, - 620, 588, 556, 524, 492, 460, 428, 396, - 372, 356, 340, 324, 308, 292, 276, 260, - 244, 228, 212, 196, 180, 164, 148, 132, - 120, 112, 104, 96, 88, 80, 72, 64, - 56, 48, 40, 32, 24, 16, 8, 0, +static char ulaw2dma16[] = { + -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, + -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, + -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, + -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0, }; /* 16 bit A-law */ -static char alaw2dma16[] = -{ - -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, - -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, - -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, - -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, - -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, - -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, - -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, - -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, - -344, -328, -376, -360, -280, -264, -312, -296, - -472, -456, -504, -488, -408, -392, -440, -424, - -88, -72, -120, -104, -24, -8, -56, -40, - -216, -200, -248, -232, -152, -136, -184, -168, - -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, - -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, - -688, -656, -752, -720, -560, -528, -624, -592, - -944, -912, -1008, -976, -816, -784, -880, -848, - 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, - 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, - 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, - 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, - 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, - 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, - 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, - 344, 328, 376, 360, 280, 264, 312, 296, - 472, 456, 504, 488, 408, 392, 440, 424, - 88, 72, 120, 104, 24, 8, 56, 40, - 216, 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, - 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, - 688, 656, 752, 720, 560, 528, 624, 592, - 944, 912, 1008, 976, 816, 784, 880, 848, +static char alaw2dma16[] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, + -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, + -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848, }; - -#endif /* HAS_16BIT_TABLES */ +#endif /* HAS_16BIT_TABLES */ #ifdef HAS_14BIT_TABLES /* 14 bit mu-law (LSB) */ -static char alaw2dma14l[] = -{ - 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 49, 17, 49, 17, 49, 17, 49, 17, - 49, 17, 49, 17, 49, 17, 49, 17, - 41, 57, 9, 25, 41, 57, 9, 25, - 41, 57, 9, 25, 41, 57, 9, 25, - 37, 45, 53, 61, 5, 13, 21, 29, - 37, 45, 53, 61, 5, 13, 21, 29, - 35, 39, 43, 47, 51, 55, 59, 63, - 3, 7, 11, 15, 19, 23, 27, 31, - 34, 36, 38, 40, 42, 44, 46, 48, - 50, 52, 54, 56, 58, 60, 62, 0, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 15, 47, 15, 47, 15, 47, 15, 47, - 15, 47, 15, 47, 15, 47, 15, 47, - 23, 7, 55, 39, 23, 7, 55, 39, - 23, 7, 55, 39, 23, 7, 55, 39, - 27, 19, 11, 3, 59, 51, 43, 35, - 27, 19, 11, 3, 59, 51, 43, 35, - 29, 25, 21, 17, 13, 9, 5, 1, - 61, 57, 53, 49, 45, 41, 37, 33, - 30, 28, 26, 24, 22, 20, 18, 16, - 14, 12, 10, 8, 6, 4, 2, 0 +static char alaw2dma14l[] = { + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 49, 17, 49, 17, 49, 17, 49, 17, + 49, 17, 49, 17, 49, 17, 49, 17, + 41, 57, 9, 25, 41, 57, 9, 25, + 41, 57, 9, 25, 41, 57, 9, 25, + 37, 45, 53, 61, 5, 13, 21, 29, + 37, 45, 53, 61, 5, 13, 21, 29, + 35, 39, 43, 47, 51, 55, 59, 63, + 3, 7, 11, 15, 19, 23, 27, 31, + 34, 36, 38, 40, 42, 44, 46, 48, + 50, 52, 54, 56, 58, 60, 62, 0, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 15, 47, 15, 47, 15, 47, 15, 47, + 15, 47, 15, 47, 15, 47, 15, 47, + 23, 7, 55, 39, 23, 7, 55, 39, + 23, 7, 55, 39, 23, 7, 55, 39, + 27, 19, 11, 3, 59, 51, 43, 35, + 27, 19, 11, 3, 59, 51, 43, 35, + 29, 25, 21, 17, 13, 9, 5, 1, + 61, 57, 53, 49, 45, 41, 37, 33, + 30, 28, 26, 24, 22, 20, 18, 16, + 14, 12, 10, 8, 6, 4, 2, 0 }; /* 14 bit A-law (LSB) */ -static char alaw2dma14l[] = -{ - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 16, 48, 16, 48, 16, 48, 16, 48, - 16, 48, 16, 48, 16, 48, 16, 48, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 42, 46, 34, 38, 58, 62, 50, 54, - 10, 14, 2, 6, 26, 30, 18, 22, - 42, 46, 34, 38, 58, 62, 50, 54, - 10, 14, 2, 6, 26, 30, 18, 22, - 40, 56, 8, 24, 40, 56, 8, 24, - 40, 56, 8, 24, 40, 56, 8, 24, - 20, 28, 4, 12, 52, 60, 36, 44, - 20, 28, 4, 12, 52, 60, 36, 44, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 48, 16, 48, 16, 48, 16, 48, 16, - 48, 16, 48, 16, 48, 16, 48, 16, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 22, 18, 30, 26, 6, 2, 14, 10, - 54, 50, 62, 58, 38, 34, 46, 42, - 22, 18, 30, 26, 6, 2, 14, 10, - 54, 50, 62, 58, 38, 34, 46, 42, - 24, 8, 56, 40, 24, 8, 56, 40, - 24, 8, 56, 40, 24, 8, 56, 40, - 44, 36, 60, 52, 12, 4, 28, 20, - 44, 36, 60, 52, 12, 4, 28, 20 +static char alaw2dma14l[] = { + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 16, 48, 16, 48, 16, 48, 16, 48, + 16, 48, 16, 48, 16, 48, 16, 48, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 42, 46, 34, 38, 58, 62, 50, 54, + 10, 14, 2, 6, 26, 30, 18, 22, + 42, 46, 34, 38, 58, 62, 50, 54, + 10, 14, 2, 6, 26, 30, 18, 22, + 40, 56, 8, 24, 40, 56, 8, 24, + 40, 56, 8, 24, 40, 56, 8, 24, + 20, 28, 4, 12, 52, 60, 36, 44, + 20, 28, 4, 12, 52, 60, 36, 44, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 48, 16, 48, 16, 48, 16, 48, 16, + 48, 16, 48, 16, 48, 16, 48, 16, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 22, 18, 30, 26, 6, 2, 14, 10, + 54, 50, 62, 58, 38, 34, 46, 42, + 22, 18, 30, 26, 6, 2, 14, 10, + 54, 50, 62, 58, 38, 34, 46, 42, + 24, 8, 56, 40, 24, 8, 56, 40, + 24, 8, 56, 40, 24, 8, 56, 40, + 44, 36, 60, 52, 12, 4, 28, 20, + 44, 36, 60, 52, 12, 4, 28, 20 }; - -#endif /* HAS_14BIT_TABLES */ +#endif /* HAS_14BIT_TABLES */ /*** Translations ************************************************************/ #ifdef CONFIG_ATARI -static long ata_ct_law(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_s8(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_u8(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_s16be(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_u16be(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_s16le(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ct_u16le(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_law(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_s8(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_u8(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_s16be(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_u16be(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_s16le(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ata_ctx_u16le(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); - -#endif /* CONFIG_ATARI */ +static long ata_ct_law(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_s8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_u8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_law(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA -static long ami_ct_law(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_s8(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_u8(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_s16be(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_u16be(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_s16le(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); -static long ami_ct_u16le(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft); - -#endif /* CONFIG_AMIGA */ +static long ami_ct_law(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_s8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_u8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +#endif /* CONFIG_AMIGA */ /*** Machine definitions *****************************************************/ -typedef struct - { - int type; - void *(*dma_alloc) (unsigned int, int); - void (*dma_free) (void *, unsigned int); - int (*irqinit) (void); +typedef struct { + int type; + void *(*dma_alloc)(unsigned int, int); + void (*dma_free)(void *, unsigned int); + int (*irqinit)(void); #ifdef MODULE - void (*irqcleanup) (void); -#endif /* MODULE */ - void (*init) (void); - void (*silence) (void); - int (*setFormat) (int); - int (*setVolume) (int); - int (*setBass) (int); - int (*setTreble) (int); - void (*play) (void); - } -MACHINE; + void (*irqcleanup)(void); +#endif /* MODULE */ + void (*init)(void); + void (*silence)(void); + int (*setFormat)(int); + int (*setVolume)(int); + int (*setBass)(int); + int (*setTreble)(int); + int (*setGain)(int); + void (*play)(void); +} MACHINE; /*** Low level stuff *********************************************************/ -typedef struct - { - int format; /* AFMT_* */ - int stereo; /* 0 = mono, 1 = stereo */ - int size; /* 8/16 bit */ - int speed; /* speed */ - } -SETTINGS; - -typedef struct - { - long (*ct_ulaw) (const u_char *, unsigned long, u_char *, long *, long); - long (*ct_alaw) (const u_char *, unsigned long, u_char *, long *, long); - long (*ct_s8) (const u_char *, unsigned long, u_char *, long *, long); - long (*ct_u8) (const u_char *, unsigned long, u_char *, long *, long); - long (*ct_s16be) (const u_char *, unsigned long, u_char *, long *, long); - long (*ct_u16be) (const u_char *, unsigned long, u_char *, long *, long); - long (*ct_s16le) (const u_char *, unsigned long, u_char *, long *, long); - long (*ct_u16le) (const u_char *, unsigned long, u_char *, long *, long); - } -TRANS; - -struct sound_settings - { - MACHINE mach; /* machine dependent things */ - SETTINGS hard; /* hardware settings */ - SETTINGS soft; /* software settings */ - SETTINGS dsp; /* /dev/dsp default settings */ - TRANS *trans; /* supported translations */ - int volume_left; /* volume (range is machine dependent) */ - int volume_right; - int bass; /* tone (range is machine dependent) */ - int treble; - int minDev; /* minor device number currently open */ +typedef struct { + int format; /* AFMT_* */ + int stereo; /* 0 = mono, 1 = stereo */ + int size; /* 8/16 bit*/ + int speed; /* speed */ +} SETTINGS; + +typedef struct { + long (*ct_ulaw)(const u_char *, unsigned long, u_char *, long *, long); + long (*ct_alaw)(const u_char *, unsigned long, u_char *, long *, long); + long (*ct_s8)(const u_char *, unsigned long, u_char *, long *, long); + long (*ct_u8)(const u_char *, unsigned long, u_char *, long *, long); + long (*ct_s16be)(const u_char *, unsigned long, u_char *, long *, long); + long (*ct_u16be)(const u_char *, unsigned long, u_char *, long *, long); + long (*ct_s16le)(const u_char *, unsigned long, u_char *, long *, long); + long (*ct_u16le)(const u_char *, unsigned long, u_char *, long *, long); +} TRANS; + +struct sound_settings { + MACHINE mach; /* machine dependent things */ + SETTINGS hard; /* hardware settings */ + SETTINGS soft; /* software settings */ + SETTINGS dsp; /* /dev/dsp default settings */ + TRANS *trans; /* supported translations */ + int volume_left; /* volume (range is machine dependent) */ + int volume_right; + int bass; /* tone (range is machine dependent) */ + int treble; + int gain; + int minDev; /* minor device number currently open */ #ifdef CONFIG_ATARI - int bal; /* balance factor for expanding (not volume!) */ - u_long data; /* data for expanding */ -#endif /* CONFIG_ATARI */ - }; + int bal; /* balance factor for expanding (not volume!) */ + u_long data; /* data for expanding */ +#endif /* CONFIG_ATARI */ +}; static struct sound_settings sound; #ifdef CONFIG_ATARI -static void *AtaAlloc(unsigned int size, int flags); -static void AtaFree(void *, unsigned int size); -static int AtaIrqInit(void); - +static void *AtaAlloc(unsigned int size, int flags); +static void AtaFree(void *, unsigned int size); +static int AtaIrqInit(void); #ifdef MODULE -static void AtaIrqCleanUp(void); - -#endif /* MODULE */ -static int AtaSetBass(int bass); -static int AtaSetTreble(int treble); -static void TTSilence(void); -static void TTInit(void); -static int TTSetFormat(int format); -static int TTSetVolume(int volume); -static void FalconSilence(void); -static void FalconInit(void); -static int FalconSetFormat(int format); -static int FalconSetVolume(int volume); -static void ata_sq_play_next_frame(int index); -static void AtaPlay(void); -static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); - -#endif /* CONFIG_ATARI */ +static void AtaIrqCleanUp(void); +#endif /* MODULE */ +static int AtaSetBass(int bass); +static int AtaSetTreble(int treble); +static void TTSilence(void); +static void TTInit(void); +static int TTSetFormat(int format); +static int TTSetVolume(int volume); +static int TTSetGain(int gain); +static void FalconSilence(void); +static void FalconInit(void); +static int FalconSetFormat(int format); +static int FalconSetVolume(int volume); +static void ata_sq_play_next_frame(int index); +static void AtaPlay(void); +static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA -static void *AmiAlloc(unsigned int size, int flags); -static void AmiFree(void *, unsigned int); -static int AmiIrqInit(void); - +static void *AmiAlloc(unsigned int size, int flags); +static void AmiFree(void *, unsigned int); +static int AmiIrqInit(void); #ifdef MODULE -static void AmiIrqCleanUp(void); - -#endif /* MODULE */ -static void AmiSilence(void); -static void AmiInit(void); -static int AmiSetFormat(int format); -static int AmiSetVolume(int volume); -static int AmiSetTreble(int treble); -static void ami_sq_play_next_frame(int index); -static void AmiPlay(void); -static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); - -#endif /* CONFIG_AMIGA */ +static void AmiIrqCleanUp(void); +#endif /* MODULE */ +static void AmiSilence(void); +static void AmiInit(void); +static int AmiSetFormat(int format); +static int AmiSetVolume(int volume); +static int AmiSetTreble(int treble); +static void ami_sq_play_next_frame(int index); +static void AmiPlay(void); +static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); +#endif /* CONFIG_AMIGA */ /*** Mid level stuff *********************************************************/ -static void sound_silence(void); -static void sound_init(void); -static int sound_set_format(int format); -static int sound_set_speed(int speed); -static int sound_set_stereo(int stereo); -static int sound_set_volume(int volume); - +static void sound_silence(void); +static void sound_init(void); +static int sound_set_format(int format); +static int sound_set_speed(int speed); +static int sound_set_stereo(int stereo); +static int sound_set_volume(int volume); #ifdef CONFIG_ATARI -static int sound_set_bass(int bass); - -#endif /* CONFIG_ATARI */ -static int sound_set_treble(int treble); -static long sound_copy_translate(const u_char * userPtr, - unsigned long userCount, - u_char frame[], long *frameUsed, - long frameLeft); +static int sound_set_bass(int bass); +#endif /* CONFIG_ATARI */ +static int sound_set_treble(int treble); +static long sound_copy_translate(const u_char *userPtr, + unsigned long userCount, + u_char frame[], long *frameUsed, + long frameLeft); /* * /dev/mixer abstraction */ -struct sound_mixer - { - int busy; - }; +struct sound_mixer { + int busy; +}; static struct sound_mixer mixer; -static void mixer_init(void); -static int mixer_open(int open_mode); -static int mixer_release(void); -static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg); +static void mixer_init(void); +static int mixer_open(int open_mode); +static int mixer_release(void); +static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg); /* * Sound queue stuff, the heart of the driver */ -struct sound_queue - { - int max_count, block_size; - char **buffers; - - /* it shouldn't be necessary to declare any of these volatile */ - int front, rear, count; - int rear_size; - /* - * The use of the playing field depends on the hardware - * - * Atari: The number of frames that are loaded/playing - * - * Amiga: Bit 0 is set: a frame is loaded - * Bit 1 is set: a frame is playing - */ - int playing; - struct wait_queue *write_queue, *open_queue, *sync_queue; - int open_mode; - int busy, syncing; +struct sound_queue { + int max_count, block_size; + char **buffers; + + /* it shouldn't be necessary to declare any of these volatile */ + int front, rear, count; + int rear_size; + /* + * The use of the playing field depends on the hardware + * + * Atari: The number of frames that are loaded/playing + * + * Amiga: Bit 0 is set: a frame is loaded + * Bit 1 is set: a frame is playing + */ + int playing; + struct wait_queue *write_queue, *open_queue, *sync_queue; + int open_mode; + int busy, syncing; #ifdef CONFIG_ATARI - int ignore_int; /* ++TeSche: used for Falcon */ -#endif /* CONFIG_ATARI */ + int ignore_int; /* ++TeSche: used for Falcon */ +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - int block_size_half, block_size_quarter; -#endif /* CONFIG_AMIGA */ - }; + int block_size_half, block_size_quarter; +#endif /* CONFIG_AMIGA */ +}; static struct sound_queue sq; @@ -666,72 +641,69 @@ interruptible_sleep_on(&queue); #define WAKE_UP(queue) (wake_up_interruptible(&queue)) -static void sq_init(int numBufs, int bufSize, char **buffers); -static void sq_play(void); -static long sq_write(const char *src, unsigned long uLeft); -static int sq_open(int open_mode); -static void sq_reset(void); -static int sq_sync(void); -static int sq_release(void); +static void sq_init(int numBufs, int bufSize, char **buffers); +static void sq_play(void); +static long sq_write(const char *src, unsigned long uLeft); +static int sq_open(int open_mode); +static void sq_reset(void); +static int sq_sync(void); +static int sq_release(void); /* * /dev/sndstat */ -struct sound_state - { - int busy; - char buf[512]; - int len, ptr; - }; +struct sound_state { + int busy; + char buf[512]; + int len, ptr; +}; static struct sound_state state; -static void state_init(void); -static int state_open(int open_mode); -static int state_release(void); -static long state_read(char *dest, unsigned long count); +static void state_init(void); +static int state_open(int open_mode); +static int state_release(void); +static long state_read(char *dest, unsigned long count); /*** High level stuff ********************************************************/ -static int sound_open(struct inode *inode, struct file *file); -static int sound_fsync(struct inode *inode, struct file *filp); -static void sound_release(struct inode *inode, struct file *file); -static long long sound_lseek(struct inode *inode, struct file *file, - long long offset, int orig); -static long sound_read(struct inode *inode, struct file *file, char *buf, - unsigned long count); -static long sound_write(struct inode *inode, struct file *file, - const char *buf, unsigned long count); -static inline int -ioctl_return(int *addr, int value) -{ - if (value < 0) - return (value); - - return put_user(value, addr); -} -static int unknown_minor_dev(char *fname, int dev); -static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg); +static int sound_open(struct inode *inode, struct file *file); +static int sound_fsync(struct file *filp, struct dentry *dentry); +static int sound_release(struct inode *inode, struct file *file); +static long long sound_lseek(struct file *file, long long offset, int orig); +static ssize_t sound_read(struct file *file, char *buf, size_t count, + loff_t *ppos); +static ssize_t sound_write(struct file *file, const char *buf, size_t count, + loff_t *ppos); +static inline int ioctl_return(int *addr, int value) +{ + if (value < 0) + return(value); + + return put_user(value, addr); +} +static int unknown_minor_dev(char *fname, int dev); +static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg); /*** Config & Setup **********************************************************/ -void soundcard_init(void); -void dmasound_setup(char *str, int *ints); -void sound_setup(char *str, int *ints); /* ++Martin: stub for now */ +void soundcard_init(void); +void dmasound_setup(char *str, int *ints); +void sound_setup(char *str, int *ints); /* ++Martin: stub for now */ /*** Translations ************************************************************/ /* ++TeSche: radically changed for new expanding purposes... - + * * These two routines now deal with copying/expanding/translating the samples * from user space into our buffer at the right frequency. They take care about * how much data there's actually to read, how much buffer space there is and @@ -755,1014 +727,849 @@ */ #ifdef CONFIG_ATARI -static long -ata_ct_law(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; - long count, used; - u_char *p = &frame[*frameUsed]; - - count = min(userCount, frameLeft); - if (sound.soft.stereo) - count &= ~1; - used = count; - while (count > 0) - { - u_char data; - - get_user(data, userPtr++); - *p++ = table[data]; - count--; - } - *frameUsed += used; - return (used); -} - - -static long -ata_ct_s8(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long ata_ct_law(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - void *p = &frame[*frameUsed]; + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + long count, used; + u_char *p = &frame[*frameUsed]; - count = min(userCount, frameLeft); - if (sound.soft.stereo) - count &= ~1; - used = count; - copy_from_user(p, userPtr, count); - *frameUsed += used; - return (used); + count = min(userCount, frameLeft); + if (sound.soft.stereo) + count &= ~1; + used = count; + while (count > 0) { + u_char data; + get_user(data, userPtr++); + *p++ = table[data]; + count--; + } + *frameUsed += used; + return(used); } -static long -ata_ct_u8(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long ata_ct_s8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - - if (!sound.soft.stereo) - { - u_char *p = &frame[*frameUsed]; - - count = min(userCount, frameLeft); - used = count; - while (count > 0) - { - u_char data; + long count, used; + void *p = &frame[*frameUsed]; - get_user(data, userPtr++); - *p++ = data ^ 0x80; - count--; - } - } else - { - u_short *p = (u_short *) & frame[*frameUsed]; - - count = min(userCount, frameLeft) >> 1; - used = count * 2; - while (count > 0) - { - u_short data; - - get_user(data, ((u_short *) userPtr)++); - *p++ = data ^ 0x8080; - count--; - } - } - *frameUsed += used; - return (used); + count = min(userCount, frameLeft); + if (sound.soft.stereo) + count &= ~1; + used = count; + copy_from_user(p, userPtr, count); + *frameUsed += used; + return(used); } -static long -ata_ct_s16be(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long ata_ct_u8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - u_long data; + long count, used; - if (!sound.soft.stereo) - { - u_short *p = (u_short *) & frame[*frameUsed]; + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + count = min(userCount, frameLeft); + used = count; + while (count > 0) { + u_char data; + get_user(data, userPtr++); + *p++ = data ^ 0x80; + count--; + } + } else { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + u_short data; + get_user(data, ((u_short *)userPtr)++); + *p++ = data ^ 0x8080; + count--; + } + } + *frameUsed += used; + return(used); +} - count = min(userCount, frameLeft) >> 1; - used = count * 2; - while (count > 0) - { - get_user(data, ((u_short *) userPtr)++); - *p++ = data; - *p++ = data; - count--; - } - *frameUsed += used * 2; - } else - { - void *p = (u_short *) & frame[*frameUsed]; - count = min(userCount, frameLeft) & ~3; - used = count; - copy_from_user(p, userPtr, count); - *frameUsed += used; - } - return (used); +static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used*2; + } else { + void *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft) & ~3; + used = count; + copy_from_user(p, userPtr, count); + *frameUsed += used; + } + return(used); } -static long -ata_ct_u16be(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - u_long data; - - if (!sound.soft.stereo) - { - u_short *p = (u_short *) & frame[*frameUsed]; - - count = min(userCount, frameLeft) >> 1; - used = count * 2; - while (count > 0) - { - get_user(data, ((u_short *) userPtr)++); - data ^= 0x8000; - *p++ = data; - *p++ = data; - count--; - } - *frameUsed += used * 2; - } else - { - u_long *p = (u_long *) & frame[*frameUsed]; - - count = min(userCount, frameLeft) >> 2; - used = count * 4; - while (count > 0) - { - get_user(data, ((u_int *) userPtr)++); - *p++ = data ^ 0x80008000; - count--; - } - *frameUsed += used; - } - return (used); + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data ^= 0x8000; + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used*2; + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>2; + used = count*4; + while (count > 0) { + get_user(data, ((u_int *)userPtr)++); + *p++ = data ^ 0x80008000; + count--; + } + *frameUsed += used; + } + return(used); } -static long -ata_ct_s16le(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - u_long data; - - count = frameLeft; - if (!sound.soft.stereo) - { - u_short *p = (u_short *) & frame[*frameUsed]; - - count = min(userCount, frameLeft) >> 1; - used = count * 2; - while (count > 0) - { - get_user(data, ((u_short *) userPtr)++); - data = le2be16(data); - *p++ = data; - *p++ = data; - count--; - } - *frameUsed += used * 2; - } else - { - u_long *p = (u_long *) & frame[*frameUsed]; - - count = min(userCount, frameLeft) >> 2; - used = count * 4; - while (count > 0) - { - get_user(data, ((u_int *) userPtr)++); - data = le2be16dbl(data); - *p++ = data; - count--; - } - *frameUsed += used; - } - return (used); + long count, used; + u_long data; + + count = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data); + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used*2; + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>2; + used = count*4; + while (count > 0) { + get_user(data, ((u_int *)userPtr)++); + data = le2be16dbl(data); + *p++ = data; + count--; + } + *frameUsed += used; + } + return(used); } -static long -ata_ct_u16le(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - u_long data; - - count = frameLeft; - if (!sound.soft.stereo) - { - u_short *p = (u_short *) & frame[*frameUsed]; - - count = min(userCount, frameLeft) >> 1; - used = count * 2; - while (count > 0) - { - get_user(data, ((u_short *) userPtr)++); - data = le2be16(data) ^ 0x8000; - *p++ = data; - *p++ = data; - } - *frameUsed += used * 2; - } else - { - u_long *p = (u_long *) & frame[*frameUsed]; - - count = min(userCount, frameLeft) >> 2; - used = count; - while (count > 0) - { - get_user(data, ((u_int *) userPtr)++); - data = le2be16dbl(data) ^ 0x80008000; - *p++ = data; - count--; - } - *frameUsed += used; - } - return (used); + long count, used; + u_long data; + + count = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + *p++ = data; + *p++ = data; + } + *frameUsed += used*2; + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>2; + used = count; + while (count > 0) { + get_user(data, ((u_int *)userPtr)++); + data = le2be16dbl(data) ^ 0x80008000; + *p++ = data; + count--; + } + *frameUsed += used; + } + return(used); } -static long -ata_ctx_law(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long ata_ctx_law(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; - - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) - { - u_char *p = &frame[*frameUsed]; - - while (frameLeft) - { - u_char c; - - if (bal < 0) - { - if (!userCount) - break; - get_user(c, userPtr++); - data = table[c]; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - } else - { - u_short *p = (u_short *) & frame[*frameUsed]; - - while (frameLeft >= 2) - { - u_char c; - - if (bal < 0) - { - if (userCount < 2) - break; - get_user(c, userPtr++); - data = table[c] << 8; - get_user(c, userPtr++); - data |= table[c]; - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 2; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf - frameLeft; - return (used); + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + while (frameLeft) { + u_char c; + if (bal < 0) { + if (!userCount) + break; + get_user(c, userPtr++); + data = table[c]; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 2) { + u_char c; + if (bal < 0) { + if (userCount < 2) + break; + get_user(c, userPtr++); + data = table[c] << 8; + get_user(c, userPtr++); + data |= table[c]; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); } -static long -ata_ctx_s8(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) - { - u_char *p = &frame[*frameUsed]; - - while (frameLeft) - { - if (bal < 0) - { - if (!userCount) - break; - get_user(data, userPtr++); - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - } else - { - u_short *p = (u_short *) & frame[*frameUsed]; - - while (frameLeft >= 2) - { - if (bal < 0) - { - if (userCount < 2) - break; - get_user(data, ((u_short *) userPtr)++); - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 2; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf - frameLeft; - return (used); +static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + while (frameLeft) { + if (bal < 0) { + if (!userCount) + break; + get_user(data, userPtr++); + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 2) { + if (bal < 0) { + if (userCount < 2) + break; + get_user(data, ((u_short *)userPtr)++); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); } -static long -ata_ctx_u8(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) - { - u_char *p = &frame[*frameUsed]; - - while (frameLeft) - { - if (bal < 0) - { - if (!userCount) - break; - get_user(data, userPtr++); - data ^= 0x80; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - } else - { - u_short *p = (u_short *) & frame[*frameUsed]; - - while (frameLeft >= 2) - { - if (bal < 0) - { - if (userCount < 2) - break; - get_user(data, ((u_short *) userPtr)++); - data ^= 0x8080; - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 2; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf - frameLeft; - return (used); +static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + while (frameLeft) { + if (bal < 0) { + if (!userCount) + break; + get_user(data, userPtr++); + data ^= 0x80; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 2) { + if (bal < 0) { + if (userCount < 2) + break; + get_user(data, ((u_short *)userPtr)++); + data ^= 0x8080; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); } -static long -ata_ctx_s16be(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) - { - u_short *p = (u_short *) & frame[*frameUsed]; - - while (frameLeft >= 4) - { - if (bal < 0) - { - if (userCount < 2) - break; - get_user(data, ((u_short *) userPtr)++); - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } else - { - u_long *p = (u_long *) & frame[*frameUsed]; - - while (frameLeft >= 4) - { - if (bal < 0) - { - if (userCount < 4) - break; - get_user(data, ((u_int *) userPtr)++); - userCount -= 4; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf - frameLeft; - return (used); +static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 2) + break; + get_user(data, ((u_short *)userPtr)++); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 4) + break; + get_user(data, ((u_int *)userPtr)++); + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); } -static long -ata_ctx_u16be(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) - { - u_short *p = (u_short *) & frame[*frameUsed]; - - while (frameLeft >= 4) - { - if (bal < 0) - { - if (userCount < 2) - break; - get_user(data, ((u_short *) userPtr)++); - data ^= 0x8000; - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } else - { - u_long *p = (u_long *) & frame[*frameUsed]; - - while (frameLeft >= 4) - { - if (bal < 0) - { - if (userCount < 4) - break; - get_user(data, ((u_int *) userPtr)++); - data ^= 0x80008000; - userCount -= 4; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf - frameLeft; - return (used); +static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 2) + break; + get_user(data, ((u_short *)userPtr)++); + data ^= 0x8000; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 4) + break; + get_user(data, ((u_int *)userPtr)++); + data ^= 0x80008000; + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); } -static long -ata_ctx_s16le(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) - { - u_short *p = (u_short *) & frame[*frameUsed]; - - while (frameLeft >= 4) - { - if (bal < 0) - { - if (userCount < 2) - break; - get_user(data, ((u_short *) userPtr)++); - data = le2be16(data); - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } else - { - u_long *p = (u_long *) & frame[*frameUsed]; - - while (frameLeft >= 4) - { - if (bal < 0) - { - if (userCount < 4) - break; - get_user(data, ((u_int *) userPtr)++); - data = le2be16dbl(data); - userCount -= 4; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf - frameLeft; - return (used); +static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 2) + break; + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 4) + break; + get_user(data, ((u_int *)userPtr)++); + data = le2be16dbl(data); + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); } -static long -ata_ctx_u16le(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - /* this should help gcc to stuff everything into registers */ - u_long data = sound.data; - long bal = sound.bal; - long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; - long used, usedf; - - used = userCount; - usedf = frameLeft; - if (!sound.soft.stereo) - { - u_short *p = (u_short *) & frame[*frameUsed]; - - while (frameLeft >= 4) - { - if (bal < 0) - { - if (userCount < 2) - break; - get_user(data, ((u_short *) userPtr)++); - data = le2be16(data) ^ 0x8000; - userCount -= 2; - bal += hSpeed; - } - *p++ = data; - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } else - { - u_long *p = (u_long *) & frame[*frameUsed]; - - while (frameLeft >= 4) - { - if (bal < 0) - { - if (userCount < 4) - break; - get_user(data, ((u_int *) userPtr)++); - data = le2be16dbl(data) ^ 0x80008000; - userCount -= 4; - bal += hSpeed; - } - *p++ = data; - frameLeft -= 4; - bal -= sSpeed; - } - } - sound.bal = bal; - sound.data = data; - used -= userCount; - *frameUsed += usedf - frameLeft; - return (used); +static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 2) + break; + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 4) + break; + get_user(data, ((u_int *)userPtr)++); + data = le2be16dbl(data) ^ 0x80008000; + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); } -#endif /* CONFIG_ATARI */ +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA -static long -ami_ct_law(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; - long count, used; - - if (!sound.soft.stereo) - { - u_char *p = &frame[*frameUsed]; - - count = min(userCount, frameLeft) & ~1; - used = count; - while (count > 0) - { - u_char data; - - get_user(data, userPtr++); - *p++ = table[data]; - count--; - } - } else - { - u_char *left = &frame[*frameUsed >> 1]; - u_char *right = left + sq.block_size_half; - - count = min(userCount, frameLeft) >> 1 & ~1; - used = count * 2; - while (count > 0) - { - u_char data; - - get_user(data, userPtr++); - *left++ = table[data]; - get_user(data, userPtr++); - *right++ = table[data]; - count--; - } - } - *frameUsed += used; - return (used); -} - - -static long -ami_ct_s8(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long ami_ct_law(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - - if (!sound.soft.stereo) - { - void *p = &frame[*frameUsed]; + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + long count, used; - count = min(userCount, frameLeft) & ~1; - used = count; - copy_from_user(p, userPtr, count); - } else - { - u_char *left = &frame[*frameUsed >> 1]; - u_char *right = left + sq.block_size_half; - - count = min(userCount, frameLeft) >> 1 & ~1; - used = count * 2; - while (count > 0) - { - get_user(*left++, userPtr++); - get_user(*right++, userPtr++); - count--; - } - } - *frameUsed += used; - return (used); + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + count = min(userCount, frameLeft) & ~1; + used = count; + while (count > 0) { + u_char data; + get_user(data, userPtr++); + *p++ = table[data]; + count--; + } + } else { + u_char *left = &frame[*frameUsed>>1]; + u_char *right = left+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + u_char data; + get_user(data, userPtr++); + *left++ = table[data]; + get_user(data, userPtr++); + *right++ = table[data]; + count--; + } + } + *frameUsed += used; + return(used); } -static long -ami_ct_u8(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long ami_ct_s8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - - if (!sound.soft.stereo) - { - char *p = &frame[*frameUsed]; - - count = min(userCount, frameLeft) & ~1; - used = count; - while (count > 0) - { - u_char data; + long count, used; - get_user(data, userPtr++); - *p++ = data ^ 0x80; - count--; - } - } else - { - u_char *left = &frame[*frameUsed >> 1]; - u_char *right = left + sq.block_size_half; - - count = min(userCount, frameLeft) >> 1 & ~1; - used = count * 2; - while (count > 0) - { - u_char data; - - get_user(data, userPtr++); - *left++ = data ^ 0x80; - get_user(data, userPtr++); - *right++ = data ^ 0x80; - count--; - } - } - *frameUsed += used; - return (used); + if (!sound.soft.stereo) { + void *p = &frame[*frameUsed]; + count = min(userCount, frameLeft) & ~1; + used = count; + copy_from_user(p, userPtr, count); + } else { + u_char *left = &frame[*frameUsed>>1]; + u_char *right = left+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + get_user(*left++, userPtr++); + get_user(*right++, userPtr++); + count--; + } + } + *frameUsed += used; + return(used); } -static long -ami_ct_s16be(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) +static long ami_ct_u8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) { - long count, used; - u_long data; - - if (!sound.soft.stereo) - { - u_char *high = &frame[*frameUsed >> 1]; - u_char *low = high + sq.block_size_half; + long count, used; - count = min(userCount, frameLeft) >> 1 & ~1; - used = count * 2; - while (count > 0) - { - get_user(data, ((u_short *) userPtr)++); - *high++ = data >> 8; - *low++ = (data >> 2) & 0x3f; - count--; - } - } else - { - u_char *lefth = &frame[*frameUsed >> 2]; - u_char *leftl = lefth + sq.block_size_quarter; - u_char *righth = lefth + sq.block_size_half; - u_char *rightl = righth + sq.block_size_quarter; - - count = min(userCount, frameLeft) >> 2 & ~1; - used = count * 4; - while (count > 0) - { - get_user(data, ((u_short *) userPtr)++); - *lefth++ = data >> 8; - *leftl++ = (data >> 2) & 0x3f; - get_user(data, ((u_short *) userPtr)++); - *righth++ = data >> 8; - *rightl++ = (data >> 2) & 0x3f; - count--; - } - } - *frameUsed += used; - return (used); + if (!sound.soft.stereo) { + char *p = &frame[*frameUsed]; + count = min(userCount, frameLeft) & ~1; + used = count; + while (count > 0) { + u_char data; + get_user(data, userPtr++); + *p++ = data ^ 0x80; + count--; + } + } else { + u_char *left = &frame[*frameUsed>>1]; + u_char *right = left+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + u_char data; + get_user(data, userPtr++); + *left++ = data ^ 0x80; + get_user(data, userPtr++); + *right++ = data ^ 0x80; + count--; + } + } + *frameUsed += used; + return(used); } -static long -ami_ct_u16be(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - long count, used; - u_long data; - - if (!sound.soft.stereo) - { - u_char *high = &frame[*frameUsed >> 1]; - u_char *low = high + sq.block_size_half; - - count = min(userCount, frameLeft) >> 1 & ~1; - used = count * 2; - while (count > 0) - { - get_user(data, ((u_short *) userPtr)++); - data ^= 0x8000; - *high++ = data >> 8; - *low++ = (data >> 2) & 0x3f; - count--; - } - } else - { - u_char *lefth = &frame[*frameUsed >> 2]; - u_char *leftl = lefth + sq.block_size_quarter; - u_char *righth = lefth + sq.block_size_half; - u_char *rightl = righth + sq.block_size_quarter; - - count = min(userCount, frameLeft) >> 2 & ~1; - used = count * 4; - while (count > 0) - { - get_user(data, ((u_short *) userPtr)++); - data ^= 0x8000; - *lefth++ = data >> 8; - *leftl++ = (data >> 2) & 0x3f; - get_user(data, ((u_short *) userPtr)++); - data ^= 0x8000; - *righth++ = data >> 8; - *rightl++ = (data >> 2) & 0x3f; - count--; - } - } - *frameUsed += used; - return (used); +static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_char *high = &frame[*frameUsed>>1]; + u_char *low = high+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + *high++ = data>>8; + *low++ = (data>>2) & 0x3f; + count--; + } + } else { + u_char *lefth = &frame[*frameUsed>>2]; + u_char *leftl = lefth+sq.block_size_quarter; + u_char *righth = lefth+sq.block_size_half; + u_char *rightl = righth+sq.block_size_quarter; + count = min(userCount, frameLeft)>>2 & ~1; + used = count*4; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + *lefth++ = data>>8; + *leftl++ = (data>>2) & 0x3f; + get_user(data, ((u_short *)userPtr)++); + *righth++ = data>>8; + *rightl++ = (data>>2) & 0x3f; + count--; + } + } + *frameUsed += used; + return(used); } -static long -ami_ct_s16le(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - long count, used; - u_long data; - - if (!sound.soft.stereo) - { - u_char *high = &frame[*frameUsed >> 1]; - u_char *low = high + sq.block_size_half; - - count = min(userCount, frameLeft) >> 1 & ~1; - used = count * 2; - while (count > 0) - { - get_user(data, ((u_short *) userPtr)++); - data = le2be16(data); - *high++ = data >> 8; - *low++ = (data >> 2) & 0x3f; - count--; - } - } else - { - u_char *lefth = &frame[*frameUsed >> 2]; - u_char *leftl = lefth + sq.block_size_quarter; - u_char *righth = lefth + sq.block_size_half; - u_char *rightl = righth + sq.block_size_quarter; - - count = min(userCount, frameLeft) >> 2 & ~1; - used = count * 4; - while (count > 0) - { - get_user(data, ((u_short *) userPtr)++); - data = le2be16(data); - *lefth++ = data >> 8; - *leftl++ = (data >> 2) & 0x3f; - get_user(data, ((u_short *) userPtr)++); - data = le2be16(data); - *righth++ = data >> 8; - *rightl++ = (data >> 2) & 0x3f; - count--; - } - } - *frameUsed += used; - return (used); +static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_char *high = &frame[*frameUsed>>1]; + u_char *low = high+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data ^= 0x8000; + *high++ = data>>8; + *low++ = (data>>2) & 0x3f; + count--; + } + } else { + u_char *lefth = &frame[*frameUsed>>2]; + u_char *leftl = lefth+sq.block_size_quarter; + u_char *righth = lefth+sq.block_size_half; + u_char *rightl = righth+sq.block_size_quarter; + count = min(userCount, frameLeft)>>2 & ~1; + used = count*4; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data ^= 0x8000; + *lefth++ = data>>8; + *leftl++ = (data>>2) & 0x3f; + get_user(data, ((u_short *)userPtr)++); + data ^= 0x8000; + *righth++ = data>>8; + *rightl++ = (data>>2) & 0x3f; + count--; + } + } + *frameUsed += used; + return(used); } -static long -ami_ct_u16le(const u_char * userPtr, unsigned long userCount, - u_char frame[], long *frameUsed, long frameLeft) -{ - long count, used; - u_long data; +static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_char *high = &frame[*frameUsed>>1]; + u_char *low = high+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data); + *high++ = data>>8; + *low++ = (data>>2) & 0x3f; + count--; + } + } else { + u_char *lefth = &frame[*frameUsed>>2]; + u_char *leftl = lefth+sq.block_size_quarter; + u_char *righth = lefth+sq.block_size_half; + u_char *rightl = righth+sq.block_size_quarter; + count = min(userCount, frameLeft)>>2 & ~1; + used = count*4; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data); + *lefth++ = data>>8; + *leftl++ = (data>>2) & 0x3f; + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data); + *righth++ = data>>8; + *rightl++ = (data>>2) & 0x3f; + count--; + } + } + *frameUsed += used; + return(used); +} - if (!sound.soft.stereo) - { - u_char *high = &frame[*frameUsed >> 1]; - u_char *low = high + sq.block_size_half; - count = min(userCount, frameLeft) >> 1 & ~1; - used = count * 2; - while (count > 0) - { - get_user(data, ((u_short *) userPtr)++); - data = le2be16(data) ^ 0x8000; - *high++ = data >> 8; - *low++ = (data >> 2) & 0x3f; - count--; - } - } else - { - u_char *lefth = &frame[*frameUsed >> 2]; - u_char *leftl = lefth + sq.block_size_quarter; - u_char *righth = lefth + sq.block_size_half; - u_char *rightl = righth + sq.block_size_quarter; - - count = min(userCount, frameLeft) >> 2 & ~1; - used = count * 4; - while (count > 0) - { - get_user(data, ((u_short *) userPtr)++); - data = le2be16(data) ^ 0x8000; - *lefth++ = data >> 8; - *leftl++ = (data >> 2) & 0x3f; - get_user(data, ((u_short *) userPtr)++); - data = le2be16(data) ^ 0x8000; - *righth++ = data >> 8; - *rightl++ = (data >> 2) & 0x3f; - count--; - } - } - *frameUsed += used; - return (used); +static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_char *high = &frame[*frameUsed>>1]; + u_char *low = high+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + *high++ = data>>8; + *low++ = (data>>2) & 0x3f; + count--; + } + } else { + u_char *lefth = &frame[*frameUsed>>2]; + u_char *leftl = lefth+sq.block_size_quarter; + u_char *righth = lefth+sq.block_size_half; + u_char *rightl = righth+sq.block_size_quarter; + count = min(userCount, frameLeft)>>2 & ~1; + used = count*4; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + *lefth++ = data>>8; + *leftl++ = (data>>2) & 0x3f; + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + *righth++ = data>>8; + *rightl++ = (data>>2) & 0x3f; + count--; + } + } + *frameUsed += used; + return(used); } -#endif /* CONFIG_AMIGA */ +#endif /* CONFIG_AMIGA */ #ifdef CONFIG_ATARI -static TRANS transTTNormal = -{ - ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL +static TRANS transTTNormal = { + ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL }; -static TRANS transTTExpanding = -{ - ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL +static TRANS transTTExpanding = { + ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL }; -static TRANS transFalconNormal = -{ -ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, ata_ct_s16be, ata_ct_u16be, - ata_ct_s16le, ata_ct_u16le +static TRANS transFalconNormal = { + ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, ata_ct_s16be, ata_ct_u16be, + ata_ct_s16le, ata_ct_u16le }; -static TRANS transFalconExpanding = -{ - ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, ata_ctx_s16be, - ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le +static TRANS transFalconExpanding = { + ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, ata_ctx_s16be, + ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le }; - -#endif /* CONFIG_ATARI */ +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA -static TRANS transAmiga = -{ -ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8, ami_ct_s16be, ami_ct_u16be, - ami_ct_s16le, ami_ct_u16le +static TRANS transAmiga = { + ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8, ami_ct_s16be, ami_ct_u16be, + ami_ct_s16le, ami_ct_u16le }; - -#endif /* CONFIG_AMIGA */ +#endif /* CONFIG_AMIGA */ /*** Low level stuff *********************************************************/ @@ -1774,68 +1581,44 @@ * Atari (TT/Falcon) */ -static void * -AtaAlloc(unsigned int size, int flags) +static void *AtaAlloc(unsigned int size, int flags) { - int order; - unsigned int a_size; + return( atari_stram_alloc( size, NULL, "dmasound" )); +} + +static void AtaFree(void *obj, unsigned int size) +{ + atari_stram_free( obj ); +} - order = 0; - a_size = PAGE_SIZE; - while (a_size < size) - { - order++; - a_size <<= 1; - } - return (void *) __get_dma_pages(flags, order); -} - -static void -AtaFree(void *obj, unsigned int size) -{ - int order; - unsigned int a_size; - - order = 0; - a_size = PAGE_SIZE; - while (a_size < size) - { - order++; - a_size <<= 1; - } - free_pages((unsigned long) obj, order); -} - -static int -AtaIrqInit(void) -{ - /* Set up timer A. Timer A - will receive a signal upon end of playing from the sound - hardware. Furthermore Timer A is able to count events - and will cause an interrupt after a programmed number - of events. So all we need to keep the music playing is - to provide the sound hardware with new data upon - an interrupt from timer A. */ - mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */ - mfp.tim_dt_a = 1; /* Cause interrupt after first event. */ - mfp.tim_ct_a = 8; /* Turn on event counting. */ - /* Register interrupt handler. */ - request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW, - "DMA sound", ata_sq_interrupt); - mfp.int_en_a |= 0x20; /* Turn interrupt on. */ - mfp.int_mk_a |= 0x20; - return (1); +static int AtaIrqInit(void) +{ + /* Set up timer A. Timer A + will receive a signal upon end of playing from the sound + hardware. Furthermore Timer A is able to count events + and will cause an interrupt after a programmed number + of events. So all we need to keep the music playing is + to provide the sound hardware with new data upon + an interrupt from timer A. */ + mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */ + mfp.tim_dt_a = 1; /* Cause interrupt after first event. */ + mfp.tim_ct_a = 8; /* Turn on event counting. */ + /* Register interrupt handler. */ + request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW, + "DMA sound", ata_sq_interrupt); + mfp.int_en_a |= 0x20; /* Turn interrupt on. */ + mfp.int_mk_a |= 0x20; + return(1); } #ifdef MODULE -static void -AtaIrqCleanUp(void) +static void AtaIrqCleanUp(void) { - mfp.tim_ct_a = 0; /* stop timer */ - mfp.int_en_a &= ~0x20; /* turn interrupt off */ - free_irq(IRQ_MFP_TIMA, ata_sq_interrupt); + mfp.tim_ct_a = 0; /* stop timer */ + mfp.int_en_a &= ~0x20; /* turn interrupt off */ + free_irq(IRQ_MFP_TIMA, ata_sq_interrupt); } -#endif /* MODULE */ +#endif /* MODULE */ #define TONE_VOXWARE_TO_DB(v) \ @@ -1843,21 +1626,19 @@ #define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50) -static int -AtaSetBass(int bass) +static int AtaSetBass(int bass) { - sound.bass = TONE_VOXWARE_TO_DB(bass); - atari_microwire_cmd(MW_LM1992_BASS(sound.bass)); - return (TONE_DB_TO_VOXWARE(sound.bass)); + sound.bass = TONE_VOXWARE_TO_DB(bass); + atari_microwire_cmd(MW_LM1992_BASS(sound.bass)); + return(TONE_DB_TO_VOXWARE(sound.bass)); } -static int -AtaSetTreble(int treble) +static int AtaSetTreble(int treble) { - sound.treble = TONE_VOXWARE_TO_DB(treble); - atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble)); - return (TONE_DB_TO_VOXWARE(sound.treble)); + sound.treble = TONE_VOXWARE_TO_DB(treble); + atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble)); + return(TONE_DB_TO_VOXWARE(sound.treble)); } @@ -1867,100 +1648,88 @@ */ -static void -TTSilence(void) +static void TTSilence(void) { - tt_dmasnd.ctrl = DMASND_CTRL_OFF; - atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */ + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */ } -static void -TTInit(void) +static void TTInit(void) { - int mode, i, idx; - const int freq[4] = - {50066, 25033, 12517, 6258}; - - /* search a frequency that fits into the allowed error range */ - - idx = -1; - for (i = 0; i < arraysize(freq); i++) - /* this isn't as much useful for a TT than for a Falcon, but - * then it doesn't hurt very much to implement it for a TT too. - */ - if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) - idx = i; - if (idx > -1) - { - sound.soft.speed = freq[idx]; - sound.trans = &transTTNormal; - } else - sound.trans = &transTTExpanding; + int mode, i, idx; + const int freq[4] = {50066, 25033, 12517, 6258}; - TTSilence(); - sound.hard = sound.soft; + /* search a frequency that fits into the allowed error range */ - if (sound.hard.speed > 50066) - { - /* we would need to squeeze the sound, but we won't do that */ - sound.hard.speed = 50066; - mode = DMASND_MODE_50KHZ; - sound.trans = &transTTNormal; - } else if (sound.hard.speed > 25033) - { - sound.hard.speed = 50066; - mode = DMASND_MODE_50KHZ; - } else if (sound.hard.speed > 12517) - { - sound.hard.speed = 25033; - mode = DMASND_MODE_25KHZ; - } else if (sound.hard.speed > 6258) - { - sound.hard.speed = 12517; - mode = DMASND_MODE_12KHZ; - } else - { - sound.hard.speed = 6258; - mode = DMASND_MODE_6KHZ; - } - - tt_dmasnd.mode = (sound.hard.stereo ? - DMASND_MODE_STEREO : DMASND_MODE_MONO) | - DMASND_MODE_8BIT | mode; - - sound.bal = -sound.soft.speed; + idx = -1; + for (i = 0; i < arraysize(freq); i++) + /* this isn't as much useful for a TT than for a Falcon, but + * then it doesn't hurt very much to implement it for a TT too. + */ + if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) + idx = i; + if (idx > -1) { + sound.soft.speed = freq[idx]; + sound.trans = &transTTNormal; + } else + sound.trans = &transTTExpanding; + + TTSilence(); + sound.hard = sound.soft; + + if (sound.hard.speed > 50066) { + /* we would need to squeeze the sound, but we won't do that */ + sound.hard.speed = 50066; + mode = DMASND_MODE_50KHZ; + sound.trans = &transTTNormal; + } else if (sound.hard.speed > 25033) { + sound.hard.speed = 50066; + mode = DMASND_MODE_50KHZ; + } else if (sound.hard.speed > 12517) { + sound.hard.speed = 25033; + mode = DMASND_MODE_25KHZ; + } else if (sound.hard.speed > 6258) { + sound.hard.speed = 12517; + mode = DMASND_MODE_12KHZ; + } else { + sound.hard.speed = 6258; + mode = DMASND_MODE_6KHZ; + } + + tt_dmasnd.mode = (sound.hard.stereo ? + DMASND_MODE_STEREO : DMASND_MODE_MONO) | + DMASND_MODE_8BIT | mode; + + sound.bal = -sound.soft.speed; } -static int -TTSetFormat(int format) -{ - /* TT sound DMA supports only 8bit modes */ - - switch (format) - { - case AFMT_QUERY: - return (sound.soft.format); - case AFMT_MU_LAW: - case AFMT_A_LAW: - case AFMT_S8: - case AFMT_U8: - break; - default: - format = AFMT_S8; - } - - sound.soft.format = format; - sound.soft.size = 8; - if (sound.minDev == SND_DEV_DSP) - { - sound.dsp.format = format; - sound.dsp.size = 8; - } - TTInit(); +static int TTSetFormat(int format) +{ + /* TT sound DMA supports only 8bit modes */ + + switch (format) { + case AFMT_QUERY: + return(sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_S8: + case AFMT_U8: + break; + default: + format = AFMT_S8; + } + + sound.soft.format = format; + sound.soft.size = 8; + if (sound.minDev == SND_DEV_DSP) { + sound.dsp.format = format; + sound.dsp.size = 8; + } + TTInit(); - return (format); + return(format); } @@ -1969,15 +1738,26 @@ #define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2) -static int -TTSetVolume(int volume) +static int TTSetVolume(int volume) +{ + sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff); + atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left)); + sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8); + atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right)); + return(VOLUME_DB_TO_VOXWARE(sound.volume_left) | + (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)); +} + + +#define GAIN_VOXWARE_TO_DB(v) \ + (((v) < 0) ? -80 : ((v) > 100) ? 0 : ((v) * 4) / 5 - 80) +#define GAIN_DB_TO_VOXWARE(v) ((((v) + 80) * 5 + 1) / 4) + +static int TTSetGain(int gain) { - sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff); - atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left)); - sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8); - atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right)); - return (VOLUME_DB_TO_VOXWARE(sound.volume_left) | - (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)); + sound.gain = GAIN_VOXWARE_TO_DB(gain); + atari_microwire_cmd(MW_LM1992_VOLUME(sound.gain)); + return GAIN_DB_TO_VOXWARE(sound.gain); } @@ -1987,151 +1767,135 @@ */ -static void -FalconSilence(void) +static void FalconSilence(void) { - /* stop playback, set sample rate 50kHz for PSG sound */ - tt_dmasnd.ctrl = DMASND_CTRL_OFF; - tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT; - tt_dmasnd.int_div = 0; /* STE compatible divider */ - tt_dmasnd.int_ctrl = 0x0; - tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */ - tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */ - tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */ - tt_dmasnd.adc_src = 3; /* ADC Input = PSG */ + /* stop playback, set sample rate 50kHz for PSG sound */ + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT; + tt_dmasnd.int_div = 0; /* STE compatible divider */ + tt_dmasnd.int_ctrl = 0x0; + tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */ + tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */ + tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */ + tt_dmasnd.adc_src = 3; /* ADC Input = PSG */ } -static void -FalconInit(void) -{ - int divider, i, idx; - const int freq[8] = - {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195}; - - /* search a frequency that fits into the allowed error range */ - - idx = -1; - for (i = 0; i < arraysize(freq); i++) - /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would - * be playable without expanding, but that now a kernel runtime - * option - */ - if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) - idx = i; - if (idx > -1) - { - sound.soft.speed = freq[idx]; - sound.trans = &transFalconNormal; - } else - sound.trans = &transFalconExpanding; - - FalconSilence(); - sound.hard = sound.soft; +static void FalconInit(void) +{ + int divider, i, idx; + const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195}; - if (sound.hard.size == 16) - { - /* the Falcon can play 16bit samples only in stereo */ - sound.hard.stereo = 1; - } - if (sound.hard.speed > 49170) - { - /* we would need to squeeze the sound, but we won't do that */ - sound.hard.speed = 49170; - divider = 1; - sound.trans = &transFalconNormal; - } else if (sound.hard.speed > 32780) - { - sound.hard.speed = 49170; - divider = 1; - } else if (sound.hard.speed > 24585) - { - sound.hard.speed = 32780; - divider = 2; - } else if (sound.hard.speed > 19668) - { - sound.hard.speed = 24585; - divider = 3; - } else if (sound.hard.speed > 16390) - { - sound.hard.speed = 19668; - divider = 4; - } else if (sound.hard.speed > 12292) - { - sound.hard.speed = 16390; - divider = 5; - } else if (sound.hard.speed > 9834) - { - sound.hard.speed = 12292; - divider = 7; - } else if (sound.hard.speed > 8195) - { - sound.hard.speed = 9834; - divider = 9; - } else - { - sound.hard.speed = 8195; - divider = 11; - } - tt_dmasnd.int_div = divider; - - /* Setup Falcon sound DMA for playback */ - tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */ - tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */ - tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */ - tt_dmasnd.cbar_dst = 0x0000; - tt_dmasnd.rec_track_select = 0; - tt_dmasnd.dac_src = 2; /* connect matrix to DAC */ - tt_dmasnd.adc_src = 0; /* ADC Input = Mic */ - - tt_dmasnd.mode = (sound.hard.stereo ? - DMASND_MODE_STEREO : DMASND_MODE_MONO) | - ((sound.hard.size == 8) ? - DMASND_MODE_8BIT : DMASND_MODE_16BIT) | - DMASND_MODE_6KHZ; - - sound.bal = -sound.soft.speed; -} + /* search a frequency that fits into the allowed error range */ + idx = -1; + for (i = 0; i < arraysize(freq); i++) + /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would + * be playable without expanding, but that now a kernel runtime + * option + */ + if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) + idx = i; + if (idx > -1) { + sound.soft.speed = freq[idx]; + sound.trans = &transFalconNormal; + } else + sound.trans = &transFalconExpanding; + + FalconSilence(); + sound.hard = sound.soft; + + if (sound.hard.size == 16) { + /* the Falcon can play 16bit samples only in stereo */ + sound.hard.stereo = 1; + } + + if (sound.hard.speed > 49170) { + /* we would need to squeeze the sound, but we won't do that */ + sound.hard.speed = 49170; + divider = 1; + sound.trans = &transFalconNormal; + } else if (sound.hard.speed > 32780) { + sound.hard.speed = 49170; + divider = 1; + } else if (sound.hard.speed > 24585) { + sound.hard.speed = 32780; + divider = 2; + } else if (sound.hard.speed > 19668) { + sound.hard.speed = 24585; + divider = 3; + } else if (sound.hard.speed > 16390) { + sound.hard.speed = 19668; + divider = 4; + } else if (sound.hard.speed > 12292) { + sound.hard.speed = 16390; + divider = 5; + } else if (sound.hard.speed > 9834) { + sound.hard.speed = 12292; + divider = 7; + } else if (sound.hard.speed > 8195) { + sound.hard.speed = 9834; + divider = 9; + } else { + sound.hard.speed = 8195; + divider = 11; + } + tt_dmasnd.int_div = divider; + + /* Setup Falcon sound DMA for playback */ + tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */ + tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */ + tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */ + tt_dmasnd.cbar_dst = 0x0000; + tt_dmasnd.rec_track_select = 0; + tt_dmasnd.dac_src = 2; /* connect matrix to DAC */ + tt_dmasnd.adc_src = 0; /* ADC Input = Mic */ + + tt_dmasnd.mode = (sound.hard.stereo ? + DMASND_MODE_STEREO : DMASND_MODE_MONO) | + ((sound.hard.size == 8) ? + DMASND_MODE_8BIT : DMASND_MODE_16BIT) | + DMASND_MODE_6KHZ; + + sound.bal = -sound.soft.speed; +} + + +static int FalconSetFormat(int format) +{ + int size; + /* Falcon sound DMA supports 8bit and 16bit modes */ + + switch (format) { + case AFMT_QUERY: + return(sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + size = 8; + break; + case AFMT_S16_BE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_U16_LE: + size = 16; + break; + default: /* :-) */ + size = 8; + format = AFMT_S8; + } + + sound.soft.format = format; + sound.soft.size = size; + if (sound.minDev == SND_DEV_DSP) { + sound.dsp.format = format; + sound.dsp.size = sound.soft.size; + } -static int -FalconSetFormat(int format) -{ - int size; - - /* Falcon sound DMA supports 8bit and 16bit modes */ - - switch (format) - { - case AFMT_QUERY: - return (sound.soft.format); - case AFMT_MU_LAW: - case AFMT_A_LAW: - case AFMT_U8: - case AFMT_S8: - size = 8; - break; - case AFMT_S16_BE: - case AFMT_U16_BE: - case AFMT_S16_LE: - case AFMT_U16_LE: - size = 16; - break; - default: /* :-) */ - size = 8; - format = AFMT_S8; - } - - sound.soft.format = format; - sound.soft.size = size; - if (sound.minDev == SND_DEV_DSP) - { - sound.dsp.format = format; - sound.dsp.size = sound.soft.size; - } - FalconInit(); + FalconInit(); - return (format); + return(format); } @@ -2143,181 +1907,168 @@ #define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3) -static int -FalconSetVolume(int volume) +static int FalconSetVolume(int volume) { - sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff); - sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8); - tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4; - return (VOLUME_ATT_TO_VOXWARE(sound.volume_left) | - VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8); + sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff); + sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8); + tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4; + return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) | + VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8); } -static void -ata_sq_play_next_frame(int index) +static void ata_sq_play_next_frame(int index) { - char *start, *end; + char *start, *end; - /* used by AtaPlay() if all doubts whether there really is something - * to be played are already wiped out. - */ - start = sq_block_address(sq.front); - end = start + ((sq.count == index) ? sq.rear_size : sq.block_size); - /* end might not be a legal virtual address. */ - DMASNDSetEnd(VTOP(end - 1) + 1); - DMASNDSetBase(VTOP(start)); + /* used by AtaPlay() if all doubts whether there really is something + * to be played are already wiped out. + */ + start = sq_block_address(sq.front); + end = start+((sq.count == index) ? sq.rear_size : sq.block_size); + /* end might not be a legal virtual address. */ + DMASNDSetEnd(VTOP(end - 1) + 1); + DMASNDSetBase(VTOP(start)); /* Since only an even number of samples per frame can - be played, we might lose one byte here. (TO DO) */ - sq.front = (sq.front + 1) % sq.max_count; - sq.playing++; - tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT; + be played, we might lose one byte here. (TO DO) */ + sq.front = (sq.front+1) % sq.max_count; + sq.playing++; + tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT; } -static void -AtaPlay(void) -{ - /* ++TeSche: Note that sq.playing is no longer just a flag but holds - * the number of frames the DMA is currently programmed for instead, - * may be 0, 1 (currently being played) or 2 (pre-programmed). - * - * Changes done to sq.count and sq.playing are a bit more subtle again - * so now I must admit I also prefer disabling the irq here rather - * than considering all possible situations. But the point is that - * disabling the irq doesn't have any bad influence on this version of - * the driver as we benefit from having pre-programmed the DMA - * wherever possible: There's no need to reload the DMA at the exact - * time of an interrupt but only at some time while the pre-programmed - * frame is playing! - */ - atari_disable_irq(IRQ_MFP_TIMA); +static void AtaPlay(void) +{ + /* ++TeSche: Note that sq.playing is no longer just a flag but holds + * the number of frames the DMA is currently programmed for instead, + * may be 0, 1 (currently being played) or 2 (pre-programmed). + * + * Changes done to sq.count and sq.playing are a bit more subtle again + * so now I must admit I also prefer disabling the irq here rather + * than considering all possible situations. But the point is that + * disabling the irq doesn't have any bad influence on this version of + * the driver as we benefit from having pre-programmed the DMA + * wherever possible: There's no need to reload the DMA at the exact + * time of an interrupt but only at some time while the pre-programmed + * frame is playing! + */ + atari_disable_irq(IRQ_MFP_TIMA); - if (sq.playing == 2 || /* DMA is 'full' */ - sq.count <= 0) - { /* nothing to do */ - atari_enable_irq(IRQ_MFP_TIMA); - return; - } - if (sq.playing == 0) - { - /* looks like there's nothing 'in' the DMA yet, so try - * to put two frames into it (at least one is available). - */ - if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) - { - /* hmmm, the only existing frame is not - * yet filled and we're not syncing? - */ - atari_enable_irq(IRQ_MFP_TIMA); - return; - } - ata_sq_play_next_frame(1); - if (sq.count == 1) - { - /* no more frames */ - atari_enable_irq(IRQ_MFP_TIMA); - return; - } - if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) - { - /* hmmm, there were two frames, but the second - * one is not yet filled and we're not syncing? - */ - atari_enable_irq(IRQ_MFP_TIMA); - return; - } - ata_sq_play_next_frame(2); - } else - { - /* there's already a frame being played so we may only stuff - * one new into the DMA, but even if this may be the last - * frame existing the previous one is still on sq.count. - */ - if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) - { - /* hmmm, the only existing frame is not - * yet filled and we're not syncing? - */ - atari_enable_irq(IRQ_MFP_TIMA); - return; - } - ata_sq_play_next_frame(2); - } + if (sq.playing == 2 || /* DMA is 'full' */ + sq.count <= 0) { /* nothing to do */ atari_enable_irq(IRQ_MFP_TIMA); + return; + } + + if (sq.playing == 0) { + /* looks like there's nothing 'in' the DMA yet, so try + * to put two frames into it (at least one is available). + */ + if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(1); + if (sq.count == 1) { + /* no more frames */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) { + /* hmmm, there were two frames, but the second + * one is not yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(2); + } else { + /* there's already a frame being played so we may only stuff + * one new into the DMA, but even if this may be the last + * frame existing the previous one is still on sq.count. + */ + if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(2); + } + atari_enable_irq(IRQ_MFP_TIMA); } -static void -ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) +static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) { #if 0 - /* ++TeSche: if you should want to test this... */ - static int cnt = 0; - - if (sq.playing == 2) - if (++cnt == 10) - { - /* simulate losing an interrupt */ - cnt = 0; - return; - } + /* ++TeSche: if you should want to test this... */ + static int cnt = 0; + if (sq.playing == 2) + if (++cnt == 10) { + /* simulate losing an interrupt */ + cnt = 0; + return; + } #endif - if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) - { - /* ++TeSche: Falcon only: ignore first irq because it comes - * immediately after starting a frame. after that, irqs come - * (almost) like on the TT. - */ - sq.ignore_int = 0; - return; - } - if (!sq.playing) - { - /* playing was interrupted and sq_reset() has already cleared - * the sq variables, so better don't do anything here. - */ - WAKE_UP(sq.sync_queue); - return; - } - /* Probably ;) one frame is finished. Well, in fact it may be that a - * pre-programmed one is also finished because there has been a long - * delay in interrupt delivery and we've completely lost one, but - * there's no way to detect such a situation. In such a case the last - * frame will be played more than once and the situation will recover - * as soon as the irq gets through. + if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) { + /* ++TeSche: Falcon only: ignore first irq because it comes + * immediately after starting a frame. after that, irqs come + * (almost) like on the TT. */ - sq.count--; - sq.playing--; + sq.ignore_int = 0; + return; + } - if (!sq.playing) - { - tt_dmasnd.ctrl = DMASND_CTRL_OFF; - sq.ignore_int = 1; - } - WAKE_UP(sq.write_queue); + if (!sq.playing) { + /* playing was interrupted and sq_reset() has already cleared + * the sq variables, so better don't do anything here. + */ + WAKE_UP(sq.sync_queue); + return; + } + + /* Probably ;) one frame is finished. Well, in fact it may be that a + * pre-programmed one is also finished because there has been a long + * delay in interrupt delivery and we've completely lost one, but + * there's no way to detect such a situation. In such a case the last + * frame will be played more than once and the situation will recover + * as soon as the irq gets through. + */ + sq.count--; + sq.playing--; + + if (!sq.playing) { + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + sq.ignore_int = 1; + } + + WAKE_UP(sq.write_queue); /* At least one block of the queue is free now - so wake up a writing process blocked because - of a full queue. */ + so wake up a writing process blocked because + of a full queue. */ - if ((sq.playing != 1) || (sq.count != 1)) - /* We must be a bit carefully here: sq.count indicates the - * number of buffers used and not the number of frames to - * be played. If sq.count==1 and sq.playing==1 that means - * the only remaining frame was already programmed earlier - * (and is currently running) so we mustn't call AtaPlay() - * here, otherwise we'll play one frame too much. - */ - AtaPlay(); + if ((sq.playing != 1) || (sq.count != 1)) + /* We must be a bit carefully here: sq.count indicates the + * number of buffers used and not the number of frames to + * be played. If sq.count==1 and sq.playing==1 that means + * the only remaining frame was already programmed earlier + * (and is currently running) so we mustn't call AtaPlay() + * here, otherwise we'll play one frame too much. + */ + AtaPlay(); - if (!sq.playing) - WAKE_UP(sq.sync_queue); + if (!sq.playing) WAKE_UP(sq.sync_queue); /* We are not playing after AtaPlay(), so there - is nothing to play any more. Wake up a process - waiting for audio output to drain. */ + is nothing to play any more. Wake up a process + waiting for audio output to drain. */ } -#endif /* CONFIG_ATARI */ +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA @@ -2327,120 +2078,109 @@ */ -static void * -AmiAlloc(unsigned int size, int flags) +static void *AmiAlloc(unsigned int size, int flags) { - return (amiga_chip_alloc((long) size)); + return(amiga_chip_alloc((long)size)); } -static void -AmiFree(void *obj, unsigned int size) +static void AmiFree(void *obj, unsigned int size) { - amiga_chip_free(obj); + amiga_chip_free (obj); } -static int -AmiIrqInit(void) +static int AmiIrqInit(void) { - /* turn off DMA for audio channels */ - custom.dmacon = AMI_AUDIO_OFF; + /* turn off DMA for audio channels */ + custom.dmacon = AMI_AUDIO_OFF; - /* Register interrupt handler. */ - if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0, - "DMA sound", ami_sq_interrupt)) - return (0); - return (1); + /* Register interrupt handler. */ + if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0, + "DMA sound", ami_sq_interrupt)) + return(0); + return(1); } #ifdef MODULE -static void -AmiIrqCleanUp(void) +static void AmiIrqCleanUp(void) { - /* turn off DMA for audio channels */ - custom.dmacon = AMI_AUDIO_OFF; - /* release the interrupt */ - free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt); + /* turn off DMA for audio channels */ + custom.dmacon = AMI_AUDIO_OFF; + /* release the interrupt */ + free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt); } -#endif /* MODULE */ +#endif /* MODULE */ -static void -AmiSilence(void) +static void AmiSilence(void) { - /* turn off DMA for audio channels */ - custom.dmacon = AMI_AUDIO_OFF; + /* turn off DMA for audio channels */ + custom.dmacon = AMI_AUDIO_OFF; } -static void -AmiInit(void) +static void AmiInit(void) { - int period, i; + int period, i; + + AmiSilence(); + + if (sound.soft.speed) + period = amiga_colorclock/sound.soft.speed-1; + else + period = amiga_audio_min_period; + sound.hard = sound.soft; + sound.trans = &transAmiga; - AmiSilence(); + if (period < amiga_audio_min_period) { + /* we would need to squeeze the sound, but we won't do that */ + period = amiga_audio_min_period; + } else if (period > 65535) { + period = 65535; + } + sound.hard.speed = amiga_colorclock/(period+1); - if (sound.soft.speed) - period = amiga_colorclock / sound.soft.speed - 1; - else - period = amiga_audio_min_period; - sound.hard = sound.soft; - sound.trans = &transAmiga; - - if (period < amiga_audio_min_period) - { - /* we would need to squeeze the sound, but we won't do that */ - period = amiga_audio_min_period; - } else if (period > 65535) - { - period = 65535; - } - sound.hard.speed = amiga_colorclock / (period + 1); - - for (i = 0; i < 4; i++) - custom.aud[i].audper = period; - amiga_audio_period = period; - - AmiSetTreble(50); /* recommended for newer amiga models */ -} - - -static int -AmiSetFormat(int format) -{ - int size; - - /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */ - - switch (format) - { - case AFMT_QUERY: - return (sound.soft.format); - case AFMT_MU_LAW: - case AFMT_A_LAW: - case AFMT_U8: - case AFMT_S8: - size = 8; - break; - case AFMT_S16_BE: - case AFMT_U16_BE: - case AFMT_S16_LE: - case AFMT_U16_LE: - size = 16; - break; - default: /* :-) */ - size = 8; - format = AFMT_S8; - } - - sound.soft.format = format; - sound.soft.size = size; - if (sound.minDev == SND_DEV_DSP) - { - sound.dsp.format = format; - sound.dsp.size = sound.soft.size; - } - AmiInit(); + for (i = 0; i < 4; i++) + custom.aud[i].audper = period; + amiga_audio_period = period; - return (format); + AmiSetTreble(50); /* recommended for newer amiga models */ +} + + +static int AmiSetFormat(int format) +{ + int size; + + /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */ + + switch (format) { + case AFMT_QUERY: + return(sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + size = 8; + break; + case AFMT_S16_BE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_U16_LE: + size = 16; + break; + default: /* :-) */ + size = 8; + format = AFMT_S8; + } + + sound.soft.format = format; + sound.soft.size = size; + if (sound.minDev == SND_DEV_DSP) { + sound.dsp.format = format; + sound.dsp.size = sound.soft.size; + } + AmiInit(); + + return(format); } @@ -2448,26 +2188,24 @@ (((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100) #define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64) -static int -AmiSetVolume(int volume) +static int AmiSetVolume(int volume) { - sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff); - custom.aud[0].audvol = sound.volume_left; - sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8); - custom.aud[1].audvol = sound.volume_right; - return (VOLUME_AMI_TO_VOXWARE(sound.volume_left) | - (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); -} - -static int -AmiSetTreble(int treble) -{ - sound.treble = treble; - if (treble < 50) - ciaa.pra &= ~0x02; - else - ciaa.pra |= 0x02; - return (treble); + sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff); + custom.aud[0].audvol = sound.volume_left; + sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8); + custom.aud[1].audvol = sound.volume_right; + return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) | + (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); +} + +static int AmiSetTreble(int treble) +{ + sound.treble = treble; + if (treble < 50) + ciaa.pra &= ~0x02; + else + ciaa.pra |= 0x02; + return(treble); } @@ -2476,302 +2214,286 @@ #define AMI_PLAY_MASK 3 -static void -ami_sq_play_next_frame(int index) +static void ami_sq_play_next_frame(int index) { - u_char *start, *ch0, *ch1, *ch2, *ch3; - u_long size; - - /* used by AmiPlay() if all doubts whether there really is something - * to be played are already wiped out. - */ - start = sq_block_address(sq.front); - size = (sq.count == index ? sq.rear_size : sq.block_size) >> 1; + u_char *start, *ch0, *ch1, *ch2, *ch3; + u_long size; - if (sound.hard.stereo) - { - ch0 = start; - ch1 = start + sq.block_size_half; - size >>= 1; - } else - { - ch0 = start; - ch1 = start; - } - if (sound.hard.size == 8) - { - custom.aud[0].audlc = (u_short *) ZTWO_PADDR(ch0); - custom.aud[0].audlen = size; - custom.aud[1].audlc = (u_short *) ZTWO_PADDR(ch1); - custom.aud[1].audlen = size; - custom.dmacon = AMI_AUDIO_8; - } else - { - size >>= 1; - custom.aud[0].audlc = (u_short *) ZTWO_PADDR(ch0); - custom.aud[0].audlen = size; - custom.aud[1].audlc = (u_short *) ZTWO_PADDR(ch1); - custom.aud[1].audlen = size; - if (sound.volume_left == 64 && sound.volume_right == 64) - { - /* We can play pseudo 14-bit only with the maximum volume */ - ch3 = ch0 + sq.block_size_quarter; - ch2 = ch1 + sq.block_size_quarter; - custom.aud[2].audvol = 1; /* we are being affected by the beeps */ - custom.aud[3].audvol = 1; /* restoring volume here helps a bit */ - custom.aud[2].audlc = (u_short *) ZTWO_PADDR(ch2); - custom.aud[2].audlen = size; - custom.aud[3].audlc = (u_short *) ZTWO_PADDR(ch3); - custom.aud[3].audlen = size; - custom.dmacon = AMI_AUDIO_14; - } else - custom.dmacon = AMI_AUDIO_8; - } - sq.front = (sq.front + 1) % sq.max_count; - sq.playing |= AMI_PLAY_LOADED; + /* used by AmiPlay() if all doubts whether there really is something + * to be played are already wiped out. + */ + start = sq_block_address(sq.front); + size = (sq.count == index ? sq.rear_size : sq.block_size)>>1; + + if (sound.hard.stereo) { + ch0 = start; + ch1 = start+sq.block_size_half; + size >>= 1; + } else { + ch0 = start; + ch1 = start; + } + if (sound.hard.size == 8) { + custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0); + custom.aud[0].audlen = size; + custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1); + custom.aud[1].audlen = size; + custom.dmacon = AMI_AUDIO_8; + } else { + size >>= 1; + custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0); + custom.aud[0].audlen = size; + custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1); + custom.aud[1].audlen = size; + if (sound.volume_left == 64 && sound.volume_right == 64) { + /* We can play pseudo 14-bit only with the maximum volume */ + ch3 = ch0+sq.block_size_quarter; + ch2 = ch1+sq.block_size_quarter; + custom.aud[2].audvol = 1; /* we are being affected by the beeps */ + custom.aud[3].audvol = 1; /* restoring volume here helps a bit */ + custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2); + custom.aud[2].audlen = size; + custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3); + custom.aud[3].audlen = size; + custom.dmacon = AMI_AUDIO_14; + } else + custom.dmacon = AMI_AUDIO_8; + } + sq.front = (sq.front+1) % sq.max_count; + sq.playing |= AMI_PLAY_LOADED; } -static void -AmiPlay(void) -{ - int minframes = 1; - - custom.intena = IF_AUD0; - - if (sq.playing & AMI_PLAY_LOADED) - { - /* There's already a frame loaded */ - custom.intena = IF_SETCLR | IF_AUD0; - return; - } - if (sq.playing & AMI_PLAY_PLAYING) - /* Increase threshold: frame 1 is already being played */ - minframes = 2; - - if (sq.count < minframes) - { - /* Nothing to do */ - custom.intena = IF_SETCLR | IF_AUD0; - return; - } - if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) - { - /* hmmm, the only existing frame is not - * yet filled and we're not syncing? - */ - custom.intena = IF_SETCLR | IF_AUD0; - return; - } - ami_sq_play_next_frame(minframes); +static void AmiPlay(void) +{ + int minframes = 1; + custom.intena = IF_AUD0; + + if (sq.playing & AMI_PLAY_LOADED) { + /* There's already a frame loaded */ custom.intena = IF_SETCLR | IF_AUD0; + return; + } + + if (sq.playing & AMI_PLAY_PLAYING) + /* Increase threshold: frame 1 is already being played */ + minframes = 2; + + if (sq.count < minframes) { + /* Nothing to do */ + custom.intena = IF_SETCLR | IF_AUD0; + return; + } + + if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + custom.intena = IF_SETCLR | IF_AUD0; + return; + } + + ami_sq_play_next_frame(minframes); + + custom.intena = IF_SETCLR | IF_AUD0; } -static void -ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) +static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) { - int minframes = 1; + int minframes = 1; + + if (!sq.playing) { + /* Playing was interrupted and sq_reset() has already cleared + * the sq variables, so better don't do anything here. + */ + WAKE_UP(sq.sync_queue); + return; + } + + if (sq.playing & AMI_PLAY_PLAYING) { + /* We've just finished a frame */ + sq.count--; + WAKE_UP(sq.write_queue); + } + + if (sq.playing & AMI_PLAY_LOADED) + /* Increase threshold: frame 1 is already being played */ + minframes = 2; + + /* Shift the flags */ + sq.playing = (sq.playing<<1) & AMI_PLAY_MASK; - if (!sq.playing) - { - /* Playing was interrupted and sq_reset() has already cleared - * the sq variables, so better don't do anything here. - */ - WAKE_UP(sq.sync_queue); - return; - } - if (sq.playing & AMI_PLAY_PLAYING) - { - /* We've just finished a frame */ - sq.count--; - WAKE_UP(sq.write_queue); - } - if (sq.playing & AMI_PLAY_LOADED) - /* Increase threshold: frame 1 is already being played */ - minframes = 2; - - /* Shift the flags */ - sq.playing = (sq.playing << 1) & AMI_PLAY_MASK; - - if (!sq.playing) - /* No frame is playing, disable audio DMA */ - custom.dmacon = AMI_AUDIO_OFF; - - if (sq.count >= minframes) - /* Try to play the next frame */ - AmiPlay(); - - if (!sq.playing) - /* Nothing to play anymore. - Wake up a process waiting for audio output to drain. */ - WAKE_UP(sq.sync_queue); + if (!sq.playing) + /* No frame is playing, disable audio DMA */ + custom.dmacon = AMI_AUDIO_OFF; + + if (sq.count >= minframes) + /* Try to play the next frame */ + AmiPlay(); + + if (!sq.playing) + /* Nothing to play anymore. + Wake up a process waiting for audio output to drain. */ + WAKE_UP(sq.sync_queue); } -#endif /* CONFIG_AMIGA */ +#endif /* CONFIG_AMIGA */ /*** Machine definitions *****************************************************/ #ifdef CONFIG_ATARI -static MACHINE machTT = -{ - DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit, +static MACHINE machTT = { + DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit, #ifdef MODULE - AtaIrqCleanUp, -#endif /* MODULE */ - TTInit, TTSilence, TTSetFormat, TTSetVolume, AtaSetBass, AtaSetTreble, - AtaPlay + AtaIrqCleanUp, +#endif /* MODULE */ + TTInit, TTSilence, TTSetFormat, TTSetVolume, AtaSetBass, AtaSetTreble, + TTSetGain, + AtaPlay }; -static MACHINE machFalcon = -{ - DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit, +static MACHINE machFalcon = { + DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit, #ifdef MODULE - AtaIrqCleanUp, -#endif /* MODULE */ - FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume, AtaSetBass, - AtaSetTreble, AtaPlay + AtaIrqCleanUp, +#endif /* MODULE */ + FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume, AtaSetBass, + AtaSetTreble, NULL, AtaPlay }; - -#endif /* CONFIG_ATARI */ +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA -static MACHINE machAmiga = -{ - DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit, +static MACHINE machAmiga = { + DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit, #ifdef MODULE - AmiIrqCleanUp, -#endif /* MODULE */ - AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble, - AmiPlay + AmiIrqCleanUp, +#endif /* MODULE */ + AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble, + NULL, + AmiPlay }; - -#endif /* CONFIG_AMIGA */ +#endif /* CONFIG_AMIGA */ /*** Mid level stuff *********************************************************/ -static void -sound_silence(void) +static void sound_silence(void) { - /* update hardware settings one more */ - (*sound.mach.init) (); + /* update hardware settings one more */ + (*sound.mach.init)(); - (*sound.mach.silence) (); + (*sound.mach.silence)(); } -static void -sound_init(void) +static void sound_init(void) { - (*sound.mach.init) (); + (*sound.mach.init)(); } -static int -sound_set_format(int format) +static int sound_set_format(int format) { - return (*sound.mach.setFormat) (format); + return(*sound.mach.setFormat)(format); } -static int -sound_set_speed(int speed) +static int sound_set_speed(int speed) { - if (speed < 0) - return (sound.soft.speed); + if (speed < 0) + return(sound.soft.speed); - sound.soft.speed = speed; - (*sound.mach.init) (); - if (sound.minDev == SND_DEV_DSP) - sound.dsp.speed = sound.soft.speed; + sound.soft.speed = speed; + (*sound.mach.init)(); + if (sound.minDev == SND_DEV_DSP) + sound.dsp.speed = sound.soft.speed; - return (sound.soft.speed); + return(sound.soft.speed); } -static int -sound_set_stereo(int stereo) +static int sound_set_stereo(int stereo) { - if (stereo < 0) - return (sound.soft.stereo); + if (stereo < 0) + return(sound.soft.stereo); - stereo = !!stereo; /* should be 0 or 1 now */ + stereo = !!stereo; /* should be 0 or 1 now */ - sound.soft.stereo = stereo; - if (sound.minDev == SND_DEV_DSP) - sound.dsp.stereo = stereo; - (*sound.mach.init) (); + sound.soft.stereo = stereo; + if (sound.minDev == SND_DEV_DSP) + sound.dsp.stereo = stereo; + (*sound.mach.init)(); - return (stereo); + return(stereo); } -static int -sound_set_volume(int volume) +static int sound_set_volume(int volume) { - return (*sound.mach.setVolume) (volume); + return(*sound.mach.setVolume)(volume); } #ifdef CONFIG_ATARI -static int -sound_set_bass(int bass) +static int sound_set_bass(int bass) { - return (sound.mach.setBass ? (*sound.mach.setBass) (bass) : 50); + return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50); } -#endif /* CONFIG_ATARI */ - -static int -sound_set_treble(int treble) -{ - return (sound.mach.setTreble ? (*sound.mach.setTreble) (treble) : 50); +static int sound_set_gain(int gain) +{ + return sound.mach.setGain ? sound.mach.setGain(gain) : 100; +} +#endif /* CONFIG_ATARI */ + + +static int sound_set_treble(int treble) +{ + return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50); } -static long -sound_copy_translate(const u_char * userPtr, - unsigned long userCount, - u_char frame[], long *frameUsed, - long frameLeft) -{ - long (*ct_func) (const u_char *, unsigned long, u_char *, long *, long) = NULL; - - switch (sound.soft.format) - { - case AFMT_MU_LAW: - ct_func = sound.trans->ct_ulaw; - break; - case AFMT_A_LAW: - ct_func = sound.trans->ct_alaw; - break; - case AFMT_S8: - ct_func = sound.trans->ct_s8; - break; - case AFMT_U8: - ct_func = sound.trans->ct_u8; - break; - case AFMT_S16_BE: - ct_func = sound.trans->ct_s16be; - break; - case AFMT_U16_BE: - ct_func = sound.trans->ct_u16be; - break; - case AFMT_S16_LE: - ct_func = sound.trans->ct_s16le; - break; - case AFMT_U16_LE: - ct_func = sound.trans->ct_u16le; - break; - } - if (ct_func) - return (ct_func(userPtr, userCount, frame, frameUsed, frameLeft)); - else - return (0); +static long sound_copy_translate(const u_char *userPtr, + unsigned long userCount, + u_char frame[], long *frameUsed, + long frameLeft) +{ + long (*ct_func)(const u_char *, unsigned long, u_char *, long *, long) = NULL; + + switch (sound.soft.format) { + case AFMT_MU_LAW: + ct_func = sound.trans->ct_ulaw; + break; + case AFMT_A_LAW: + ct_func = sound.trans->ct_alaw; + break; + case AFMT_S8: + ct_func = sound.trans->ct_s8; + break; + case AFMT_U8: + ct_func = sound.trans->ct_u8; + break; + case AFMT_S16_BE: + ct_func = sound.trans->ct_s16be; + break; + case AFMT_U16_BE: + ct_func = sound.trans->ct_u16be; + break; + case AFMT_S16_LE: + ct_func = sound.trans->ct_s16le; + break; + case AFMT_U16_LE: + ct_func = sound.trans->ct_u16le; + break; + } + if (ct_func) + return(ct_func(userPtr, userCount, frame, frameUsed, frameLeft)); + else + return(0); } @@ -2785,215 +2507,203 @@ #define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3) -static void -mixer_init(void) +static void mixer_init(void) { - mixer.busy = 0; - sound.treble = 0; - sound.bass = 0; - switch (sound.mach.type) - { + mixer.busy = 0; + sound.treble = 0; + sound.bass = 0; + switch (sound.mach.type) { #ifdef CONFIG_ATARI - case DMASND_TT: - atari_microwire_cmd(MW_LM1992_VOLUME(0)); - sound.volume_left = 0; - atari_microwire_cmd(MW_LM1992_BALLEFT(0)); - sound.volume_right = 0; - atari_microwire_cmd(MW_LM1992_BALRIGHT(0)); - atari_microwire_cmd(MW_LM1992_TREBLE(0)); - atari_microwire_cmd(MW_LM1992_BASS(0)); - break; - case DMASND_FALCON: - sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8; - sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4; - break; -#endif /* CONFIG_ATARI */ + case DMASND_TT: + atari_microwire_cmd(MW_LM1992_VOLUME(0)); + sound.volume_left = 0; + atari_microwire_cmd(MW_LM1992_BALLEFT(0)); + sound.volume_right = 0; + atari_microwire_cmd(MW_LM1992_BALRIGHT(0)); + atari_microwire_cmd(MW_LM1992_TREBLE(0)); + atari_microwire_cmd(MW_LM1992_BASS(0)); + break; + case DMASND_FALCON: + sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8; + sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4; + break; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case DMASND_AMIGA: - sound.volume_left = 64; - sound.volume_right = 64; - custom.aud[0].audvol = sound.volume_left; - custom.aud[3].audvol = 1; /* For pseudo 14bit */ - custom.aud[1].audvol = sound.volume_right; - custom.aud[2].audvol = 1; /* For pseudo 14bit */ - sound.treble = 50; - break; -#endif /* CONFIG_AMIGA */ - } + case DMASND_AMIGA: + sound.volume_left = 64; + sound.volume_right = 64; + custom.aud[0].audvol = sound.volume_left; + custom.aud[3].audvol = 1; /* For pseudo 14bit */ + custom.aud[1].audvol = sound.volume_right; + custom.aud[2].audvol = 1; /* For pseudo 14bit */ + sound.treble = 50; + break; +#endif /* CONFIG_AMIGA */ + } } -static int -mixer_open(int open_mode) +static int mixer_open(int open_mode) { - if (mixer.busy) - return (-EBUSY); - mixer.busy = 1; - return (0); + if (mixer.busy) + return(-EBUSY); + mixer.busy = 1; + return(0); } -static int -mixer_release(void) +static int mixer_release(void) { - mixer.busy = 0; - return (0); + mixer.busy = 0; + return(0); } -static int -mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg) +static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg) { - int data; - - switch (sound.mach.type) - { + int data; + switch (sound.mach.type) { #ifdef CONFIG_ATARI - case DMASND_FALCON: - switch (cmd) - { - case SOUND_MIXER_READ_DEVMASK: - return (IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); - case SOUND_MIXER_READ_RECMASK: - return (IOCTL_OUT(arg, SOUND_MASK_MIC)); - case SOUND_MIXER_READ_STEREODEVS: - return (IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC)); - case SOUND_MIXER_READ_CAPS: - return (IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT)); - case SOUND_MIXER_READ_VOLUME: - return (IOCTL_OUT(arg, - VOLUME_ATT_TO_VOXWARE(sound.volume_left) | - VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8)); - case SOUND_MIXER_WRITE_MIC: - IOCTL_IN(arg, data); - tt_dmasnd.input_gain = - RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 | - RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff); - /* fall thru, return set value */ - case SOUND_MIXER_READ_MIC: - return (IOCTL_OUT(arg, - RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) | - RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8)); - case SOUND_MIXER_READ_SPEAKER: - { - int porta; - - cli(); - sound_ym.rd_data_reg_sel = 14; - porta = sound_ym.rd_data_reg_sel; - sti(); - return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); - } - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - return (IOCTL_OUT(arg, sound_set_volume(data))); - case SOUND_MIXER_WRITE_SPEAKER: - { - int porta; - - IOCTL_IN(arg, data); - cli(); - sound_ym.rd_data_reg_sel = 14; - porta = (sound_ym.rd_data_reg_sel & ~0x40) | - (data < 50 ? 0x40 : 0); - sound_ym.wd_data = porta; - sti(); - return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); - } - } - break; - - case DMASND_TT: - switch (cmd) - { - case SOUND_MIXER_READ_DEVMASK: - return (IOCTL_OUT(arg, - SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS | - ((atari_mch_cookie >> 16) == ATARI_MCH_TT ? - SOUND_MASK_SPEAKER : 0))); - case SOUND_MIXER_READ_RECMASK: - return (IOCTL_OUT(arg, 0)); - case SOUND_MIXER_READ_STEREODEVS: - return (IOCTL_OUT(arg, SOUND_MASK_VOLUME)); - case SOUND_MIXER_READ_VOLUME: - return (IOCTL_OUT(arg, - VOLUME_DB_TO_VOXWARE(sound.volume_left) | - (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8))); - case SOUND_MIXER_READ_BASS: - return (IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass))); - case SOUND_MIXER_READ_TREBLE: - return (IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble))); - case SOUND_MIXER_READ_SPEAKER: - { - int porta; - - if ((atari_mch_cookie >> 16) == ATARI_MCH_TT) - { - cli(); - sound_ym.rd_data_reg_sel = 14; - porta = sound_ym.rd_data_reg_sel; - sti(); - return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); - } else - return (-EINVAL); - } - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - return (IOCTL_OUT(arg, sound_set_volume(data))); - case SOUND_MIXER_WRITE_BASS: - IOCTL_IN(arg, data); - return (IOCTL_OUT(arg, sound_set_bass(data))); - case SOUND_MIXER_WRITE_TREBLE: - IOCTL_IN(arg, data); - return (IOCTL_OUT(arg, sound_set_treble(data))); - case SOUND_MIXER_WRITE_SPEAKER: - if ((atari_mch_cookie >> 16) == ATARI_MCH_TT) - { - int porta; - - IOCTL_IN(arg, data); - cli(); - sound_ym.rd_data_reg_sel = 14; - porta = (sound_ym.rd_data_reg_sel & ~0x40) | - (data < 50 ? 0x40 : 0); - sound_ym.wd_data = porta; - sti(); - return (IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); - } else - return (-EINVAL); - } - break; -#endif /* CONFIG_ATARI */ + case DMASND_FALCON: + switch (cmd) { + case SOUND_MIXER_READ_DEVMASK: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); + case SOUND_MIXER_READ_RECMASK: + return(IOCTL_OUT(arg, SOUND_MASK_MIC)); + case SOUND_MIXER_READ_STEREODEVS: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC)); + case SOUND_MIXER_READ_CAPS: + return(IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT)); + case SOUND_MIXER_READ_VOLUME: + return(IOCTL_OUT(arg, + VOLUME_ATT_TO_VOXWARE(sound.volume_left) | + VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8)); + case SOUND_MIXER_WRITE_MIC: + IOCTL_IN(arg, data); + tt_dmasnd.input_gain = + RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 | + RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff); + /* fall thru, return set value */ + case SOUND_MIXER_READ_MIC: + return(IOCTL_OUT(arg, + RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) | + RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8)); + case SOUND_MIXER_READ_SPEAKER: + { + int porta; + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = sound_ym.rd_data_reg_sel; + sti(); + return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_volume(data))); + case SOUND_MIXER_WRITE_SPEAKER: + { + int porta; + IOCTL_IN(arg, data); + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = (sound_ym.rd_data_reg_sel & ~0x40) | + (data < 50 ? 0x40 : 0); + sound_ym.wd_data = porta; + sti(); + return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } + } + break; + + case DMASND_TT: + switch (cmd) { + case SOUND_MIXER_READ_DEVMASK: + return(IOCTL_OUT(arg, + SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS | + (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0))); + case SOUND_MIXER_READ_RECMASK: + return(IOCTL_OUT(arg, 0)); + case SOUND_MIXER_READ_STEREODEVS: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME)); + case SOUND_MIXER_READ_VOLUME: + return(IOCTL_OUT(arg, + VOLUME_DB_TO_VOXWARE(sound.volume_left) | + (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8))); + case SOUND_MIXER_READ_BASS: + return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass))); + case SOUND_MIXER_READ_TREBLE: + return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble))); + case SOUND_MIXER_READ_OGAIN: + return(IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(sound.gain))); + case SOUND_MIXER_READ_SPEAKER: + { + int porta; + if (MACH_IS_TT) { + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = sound_ym.rd_data_reg_sel; + sti(); + return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } else + return(-EINVAL); + } + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_volume(data))); + case SOUND_MIXER_WRITE_BASS: + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_bass(data))); + case SOUND_MIXER_WRITE_TREBLE: + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_treble(data))); + case SOUND_MIXER_WRITE_OGAIN: + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_gain(data))); + case SOUND_MIXER_WRITE_SPEAKER: + if (MACH_IS_TT) { + int porta; + IOCTL_IN(arg, data); + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = (sound_ym.rd_data_reg_sel & ~0x40) | + (data < 50 ? 0x40 : 0); + sound_ym.wd_data = porta; + sti(); + return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } else + return(-EINVAL); + } + break; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case DMASND_AMIGA: - switch (cmd) - { - case SOUND_MIXER_READ_DEVMASK: - return (IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE)); - case SOUND_MIXER_READ_RECMASK: - return (IOCTL_OUT(arg, 0)); - case SOUND_MIXER_READ_STEREODEVS: - return (IOCTL_OUT(arg, SOUND_MASK_VOLUME)); - case SOUND_MIXER_READ_VOLUME: - return (IOCTL_OUT(arg, - VOLUME_AMI_TO_VOXWARE(sound.volume_left) | - VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - return (IOCTL_OUT(arg, sound_set_volume(data))); - case SOUND_MIXER_READ_TREBLE: - return (IOCTL_OUT(arg, sound.treble)); - case SOUND_MIXER_WRITE_TREBLE: - IOCTL_IN(arg, data); - return (IOCTL_OUT(arg, sound_set_treble(data))); - } - break; -#endif /* CONFIG_AMIGA */ - } + case DMASND_AMIGA: + switch (cmd) { + case SOUND_MIXER_READ_DEVMASK: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE)); + case SOUND_MIXER_READ_RECMASK: + return(IOCTL_OUT(arg, 0)); + case SOUND_MIXER_READ_STEREODEVS: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME)); + case SOUND_MIXER_READ_VOLUME: + return(IOCTL_OUT(arg, + VOLUME_AMI_TO_VOXWARE(sound.volume_left) | + VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_volume(data))); + case SOUND_MIXER_READ_TREBLE: + return(IOCTL_OUT(arg, sound.treble)); + case SOUND_MIXER_WRITE_TREBLE: + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_treble(data))); + } + break; +#endif /* CONFIG_AMIGA */ + } - return (-EINVAL); + return(-EINVAL); } @@ -3003,216 +2713,198 @@ */ -static void -sq_init(int numBufs, int bufSize, char **buffers) +static void sq_init(int numBufs, int bufSize, char **buffers) { - sq.max_count = numBufs; - sq.block_size = bufSize; - sq.buffers = buffers; - - sq.front = sq.count = 0; - sq.rear = -1; - sq.write_queue = sq.open_queue = sq.sync_queue = 0; - sq.busy = 0; - sq.syncing = 0; + sq.max_count = numBufs; + sq.block_size = bufSize; + sq.buffers = buffers; + + sq.front = sq.count = 0; + sq.rear = -1; + sq.write_queue = sq.open_queue = sq.sync_queue = 0; + sq.busy = 0; + sq.syncing = 0; - sq.playing = 0; + sq.playing = 0; #ifdef CONFIG_ATARI - sq.ignore_int = 0; -#endif /* CONFIG_ATARI */ + sq.ignore_int = 0; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - sq.block_size_half = sq.block_size >> 1; - sq.block_size_quarter = sq.block_size_half >> 1; -#endif /* CONFIG_AMIGA */ + sq.block_size_half = sq.block_size>>1; + sq.block_size_quarter = sq.block_size_half>>1; +#endif /* CONFIG_AMIGA */ + + sound_silence(); + + /* whatever you like as startup mode for /dev/dsp, + * (/dev/audio hasn't got a startup mode). note that + * once changed a new open() will *not* restore these! + */ + sound.dsp.format = AFMT_S8; + sound.dsp.stereo = 0; + sound.dsp.size = 8; - sound_silence(); - - /* whatever you like as startup mode for /dev/dsp, - * (/dev/audio hasn't got a startup mode). note that - * once changed a new open() will *not* restore these! - */ - sound.dsp.format = AFMT_S8; - sound.dsp.stereo = 0; - sound.dsp.size = 8; - - /* set minimum rate possible without expanding */ - switch (sound.mach.type) - { + /* set minimum rate possible without expanding */ + switch (sound.mach.type) { #ifdef CONFIG_ATARI - case DMASND_TT: - sound.dsp.speed = 6258; - break; - case DMASND_FALCON: - sound.dsp.speed = 8195; - break; -#endif /* CONFIG_ATARI */ + case DMASND_TT: + sound.dsp.speed = 6258; + break; + case DMASND_FALCON: + sound.dsp.speed = 8195; + break; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case DMASND_AMIGA: - sound.dsp.speed = 8000; - break; -#endif /* CONFIG_AMIGA */ - } + case DMASND_AMIGA: + sound.dsp.speed = 8000; + break; +#endif /* CONFIG_AMIGA */ + } - /* before the first open to /dev/dsp this wouldn't be set */ - sound.soft = sound.dsp; - sound.hard = sound.dsp; + /* before the first open to /dev/dsp this wouldn't be set */ + sound.soft = sound.dsp; + sound.hard = sound.dsp; } -static void -sq_play(void) +static void sq_play(void) { - (*sound.mach.play) (); + (*sound.mach.play)(); } /* ++TeSche: radically changed this one too */ -static long -sq_write(const char *src, unsigned long uLeft) +static long sq_write(const char *src, unsigned long uLeft) { - long uWritten = 0; - u_char *dest; - long uUsed, bUsed, bLeft; - - /* ++TeSche: Is something like this necessary? - * Hey, that's an honest question! Or does any other part of the - * filesystem already checks this situation? I really don't know. - */ - if (uLeft == 0) - return (0); + long uWritten = 0; + u_char *dest; + long uUsed, bUsed, bLeft; + + /* ++TeSche: Is something like this necessary? + * Hey, that's an honest question! Or does any other part of the + * filesystem already checks this situation? I really don't know. + */ + if (uLeft == 0) + return(0); + + /* The interrupt doesn't start to play the last, incomplete frame. + * Thus we can append to it without disabling the interrupts! (Note + * also that sq.rear isn't affected by the interrupt.) + */ + + if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) { + dest = sq_block_address(sq.rear); + bUsed = sq.rear_size; + uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); + src += uUsed; + uWritten += uUsed; + uLeft -= uUsed; + sq.rear_size = bUsed; + } + + do { + while (sq.count == sq.max_count) { + sq_play(); + if (NON_BLOCKING(sq.open_mode)) + return(uWritten > 0 ? uWritten : -EAGAIN); + SLEEP(sq.write_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) + return(uWritten > 0 ? uWritten : -EINTR); + } - /* The interrupt doesn't start to play the last, incomplete frame. - * Thus we can append to it without disabling the interrupts! (Note - * also that sq.rear isn't affected by the interrupt.) + /* Here, we can avoid disabling the interrupt by first + * copying and translating the data, and then updating + * the sq variables. Until this is done, the interrupt + * won't see the new frame and we can work on it + * undisturbed. */ - if (sq.count > 0 && (bLeft = sq.block_size - sq.rear_size) > 0) - { - dest = sq_block_address(sq.rear); - bUsed = sq.rear_size; - uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); - src += uUsed; - uWritten += uUsed; - uLeft -= uUsed; - sq.rear_size = bUsed; - } - do - { - while (sq.count == sq.max_count) - { - sq_play(); - if (NON_BLOCKING(sq.open_mode)) - return (uWritten > 0 ? uWritten : -EAGAIN); - SLEEP(sq.write_queue, ONE_SECOND); - if (SIGNAL_RECEIVED) - return (uWritten > 0 ? uWritten : -EINTR); - } - - /* Here, we can avoid disabling the interrupt by first - * copying and translating the data, and then updating - * the sq variables. Until this is done, the interrupt - * won't see the new frame and we can work on it - * undisturbed. - */ - - dest = sq_block_address((sq.rear + 1) % sq.max_count); - bUsed = 0; - bLeft = sq.block_size; - uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); - src += uUsed; - uWritten += uUsed; - uLeft -= uUsed; - if (bUsed) - { - sq.rear = (sq.rear + 1) % sq.max_count; - sq.rear_size = bUsed; - sq.count++; - } - } - while (bUsed); /* uUsed may have been 0 */ + dest = sq_block_address((sq.rear+1) % sq.max_count); + bUsed = 0; + bLeft = sq.block_size; + uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); + src += uUsed; + uWritten += uUsed; + uLeft -= uUsed; + if (bUsed) { + sq.rear = (sq.rear+1) % sq.max_count; + sq.rear_size = bUsed; + sq.count++; + } + } while (bUsed); /* uUsed may have been 0 */ - sq_play(); + sq_play(); - return (uWritten); + return(uWritten); } -static int -sq_open(int open_mode) +static int sq_open(int open_mode) { - if (sq.busy) - { - if (NON_BLOCKING(open_mode)) - return (-EBUSY); - while (sq.busy) - { - SLEEP(sq.open_queue, ONE_SECOND); - if (SIGNAL_RECEIVED) - return (-EINTR); - } - } - sq.open_mode = open_mode; - sq.busy = 1; + if (sq.busy) { + if (NON_BLOCKING(open_mode)) + return(-EBUSY); + while (sq.busy) { + SLEEP(sq.open_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) + return(-EINTR); + } + } + sq.open_mode = open_mode; + sq.busy = 1; #ifdef CONFIG_ATARI - sq.ignore_int = 1; -#endif /* CONFIG_ATARI */ - return (0); + sq.ignore_int = 1; +#endif /* CONFIG_ATARI */ + return(0); } -static void -sq_reset(void) +static void sq_reset(void) { - sound_silence(); - sq.playing = 0; - sq.count = 0; - sq.front = (sq.rear + 1) % sq.max_count; + sound_silence(); + sq.playing = 0; + sq.count = 0; + sq.front = (sq.rear+1) % sq.max_count; } -static int -sq_sync(void) +static int sq_sync(void) { - int rc = 0; + int rc = 0; - sq.syncing = 1; - sq_play(); /* there may be an incomplete frame waiting */ + sq.syncing = 1; + sq_play(); /* there may be an incomplete frame waiting */ - while (sq.playing) - { - SLEEP(sq.sync_queue, ONE_SECOND); - if (SIGNAL_RECEIVED) - { - /* While waiting for audio output to drain, an interrupt occurred. - Stop audio output immediately and clear the queue. */ - sq_reset(); - rc = -EINTR; - break; - } - } + while (sq.playing) { + SLEEP(sq.sync_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) { + /* While waiting for audio output to drain, an interrupt occurred. + Stop audio output immediately and clear the queue. */ + sq_reset(); + rc = -EINTR; + break; + } + } - sq.syncing = 0; - return (rc); + sq.syncing = 0; + return(rc); } -static int -sq_release(void) +static int sq_release(void) { - int rc = 0; - - if (sq.busy) - { - rc = sq_sync(); - sq.busy = 0; - WAKE_UP(sq.open_queue); - /* Wake up a process waiting for the queue being released. - Note: There may be several processes waiting for a call to open() - returning. */ - } - return (rc); + int rc = 0; + if (sq.busy) { + rc = sq_sync(); + sq.busy = 0; + WAKE_UP(sq.open_queue); + /* Wake up a process waiting for the queue being released. + Note: There may be several processes waiting for a call to open() + returning. */ + } + return(rc); } @@ -3222,136 +2914,128 @@ */ -static void -state_init(void) +static void state_init(void) { - state.busy = 0; + state.busy = 0; } /* state.buf should not overflow! */ -static int -state_open(int open_mode) +static int state_open(int open_mode) { - char *buffer = state.buf, *mach = ""; - int len = 0; + char *buffer = state.buf, *mach = ""; + int len = 0; - if (state.busy) - return (-EBUSY); + if (state.busy) + return(-EBUSY); - state.ptr = 0; - state.busy = 1; + state.ptr = 0; + state.busy = 1; - switch (sound.mach.type) - { + switch (sound.mach.type) { #ifdef CONFIG_ATARI - case DMASND_TT: - case DMASND_FALCON: - mach = "Atari "; - break; -#endif /* CONFIG_ATARI */ + case DMASND_TT: + case DMASND_FALCON: + mach = "Atari "; + break; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case DMASND_AMIGA: - mach = "Amiga "; - break; -#endif /* CONFIG_AMIGA */ - } - len += sprintf(buffer + len, "%sDMA sound driver:\n", mach); - - len += sprintf(buffer + len, "\tsound.format = 0x%x", sound.soft.format); - switch (sound.soft.format) - { - case AFMT_MU_LAW: - len += sprintf(buffer + len, " (mu-law)"); - break; - case AFMT_A_LAW: - len += sprintf(buffer + len, " (A-law)"); - break; - case AFMT_U8: - len += sprintf(buffer + len, " (unsigned 8 bit)"); - break; - case AFMT_S8: - len += sprintf(buffer + len, " (signed 8 bit)"); - break; - case AFMT_S16_BE: - len += sprintf(buffer + len, " (signed 16 bit big)"); - break; - case AFMT_U16_BE: - len += sprintf(buffer + len, " (unsigned 16 bit big)"); - break; - case AFMT_S16_LE: - len += sprintf(buffer + len, " (signed 16 bit little)"); - break; - case AFMT_U16_LE: - len += sprintf(buffer + len, " (unsigned 16 bit little)"); - break; - } - len += sprintf(buffer + len, "\n"); - len += sprintf(buffer + len, "\tsound.speed = %dHz (phys. %dHz)\n", - sound.soft.speed, sound.hard.speed); - len += sprintf(buffer + len, "\tsound.stereo = 0x%x (%s)\n", - sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono"); - switch (sound.mach.type) - { + case DMASND_AMIGA: + mach = "Amiga "; + break; +#endif /* CONFIG_AMIGA */ + } + len += sprintf(buffer+len, "%sDMA sound driver:\n", mach); + + len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format); + switch (sound.soft.format) { + case AFMT_MU_LAW: + len += sprintf(buffer+len, " (mu-law)"); + break; + case AFMT_A_LAW: + len += sprintf(buffer+len, " (A-law)"); + break; + case AFMT_U8: + len += sprintf(buffer+len, " (unsigned 8 bit)"); + break; + case AFMT_S8: + len += sprintf(buffer+len, " (signed 8 bit)"); + break; + case AFMT_S16_BE: + len += sprintf(buffer+len, " (signed 16 bit big)"); + break; + case AFMT_U16_BE: + len += sprintf(buffer+len, " (unsigned 16 bit big)"); + break; + case AFMT_S16_LE: + len += sprintf(buffer+len, " (signed 16 bit little)"); + break; + case AFMT_U16_LE: + len += sprintf(buffer+len, " (unsigned 16 bit little)"); + break; + } + len += sprintf(buffer+len, "\n"); + len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n", + sound.soft.speed, sound.hard.speed); + len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n", + sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono"); + switch (sound.mach.type) { #ifdef CONFIG_ATARI - case DMASND_TT: - len += sprintf(buffer + len, "\tsound.volume_left = %ddB [-40...0]\n", - sound.volume_left); - len += sprintf(buffer + len, "\tsound.volume_right = %ddB [-40...0]\n", - sound.volume_right); - len += sprintf(buffer + len, "\tsound.bass = %ddB [-12...+12]\n", - sound.bass); - len += sprintf(buffer + len, "\tsound.treble = %ddB [-12...+12]\n", - sound.treble); - break; - case DMASND_FALCON: - len += sprintf(buffer + len, "\tsound.volume_left = %ddB [-22.5...0]\n", - sound.volume_left); - len += sprintf(buffer + len, "\tsound.volume_right = %ddB [-22.5...0]\n", - sound.volume_right); - break; -#endif /* CONFIG_ATARI */ + case DMASND_TT: + len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n", + sound.volume_left); + len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n", + sound.volume_right); + len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n", + sound.bass); + len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n", + sound.treble); + break; + case DMASND_FALCON: + len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n", + sound.volume_left); + len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n", + sound.volume_right); + break; +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case DMASND_AMIGA: - len += sprintf(buffer + len, "\tsound.volume_left = %d [0...64]\n", - sound.volume_left); - len += sprintf(buffer + len, "\tsound.volume_right = %d [0...64]\n", - sound.volume_right); - break; -#endif /* CONFIG_AMIGA */ - } - len += sprintf(buffer + len, "\tsq.block_size = %d sq.max_count = %d\n", - sq.block_size, sq.max_count); - len += sprintf(buffer + len, "\tsq.count = %d sq.rear_size = %d\n", sq.count, - sq.rear_size); - len += sprintf(buffer + len, "\tsq.playing = %d sq.syncing = %d\n", - sq.playing, sq.syncing); - state.len = len; - return (0); + case DMASND_AMIGA: + len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n", + sound.volume_left); + len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n", + sound.volume_right); + break; +#endif /* CONFIG_AMIGA */ + } + len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d\n", + sq.block_size, sq.max_count); + len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count, + sq.rear_size); + len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n", + sq.playing, sq.syncing); + state.len = len; + return(0); } -static int -state_release(void) -{ - state.busy = 0; - return (0); +static int state_release(void) +{ + state.busy = 0; + return(0); } -static long -state_read(char *dest, unsigned long count) -{ - int n = state.len - state.ptr; - - if (n > count) - n = count; - if (n <= 0) - return (0); - copy_to_user(dest, &state.buf[state.ptr], n); - state.ptr += n; - return (n); +static long state_read(char *dest, unsigned long count) +{ + int n = state.len-state.ptr; + if (n > count) + n = count; + if (n <= 0) + return(0); + copy_to_user(dest, &state.buf[state.ptr], n); + state.ptr += n; + return(n); } @@ -3359,241 +3043,232 @@ /*** High level stuff ********************************************************/ -static int -sound_open(struct inode *inode, struct file *file) +static int sound_open(struct inode *inode, struct file *file) { - int dev = MINOR(inode->i_rdev) & 0x0f; - int rc = 0; + int dev = MINOR(inode->i_rdev) & 0x0f; + int rc = 0; - switch (dev) - { - case SND_DEV_STATUS: - rc = state_open(file->f_flags); - break; - case SND_DEV_CTL: - rc = mixer_open(file->f_flags); - break; - case SND_DEV_DSP: - case SND_DEV_AUDIO: - rc = sq_open(file->f_flags); - if (rc == 0) - { - sound.minDev = dev; - sound.soft = sound.dsp; - sound.hard = sound.dsp; - sound_init(); - if (dev == SND_DEV_AUDIO) - { - sound_set_speed(8000); - sound_set_stereo(0); - sound_set_format(AFMT_MU_LAW); - } - } - break; - default: - rc = -ENXIO; - } + switch (dev) { + case SND_DEV_STATUS: + rc = state_open(file->f_flags); + break; + case SND_DEV_CTL: + rc = mixer_open(file->f_flags); + break; + case SND_DEV_DSP: + case SND_DEV_AUDIO: + rc = sq_open(file->f_flags); + if (rc == 0) { + sound.minDev = dev; + sound.soft = sound.dsp; + sound.hard = sound.dsp; + sound_init(); + if (dev == SND_DEV_AUDIO) { + sound_set_speed(8000); + sound_set_stereo(0); + sound_set_format(AFMT_MU_LAW); + } + } + break; + default: + rc = -ENXIO; + } #ifdef MODULE - if (rc >= 0) - MOD_INC_USE_COUNT; + if (rc >= 0) + MOD_INC_USE_COUNT; #endif - return (rc); + return(rc); } -static int -sound_fsync(struct inode *inode, struct file *filp) +static int sound_fsync(struct file *filp, struct dentry *dentry) { - int dev = MINOR(inode->i_rdev) & 0x0f; + int dev = MINOR(dentry->d_inode->i_rdev) & 0x0f; - switch (dev) - { - case SND_DEV_STATUS: - case SND_DEV_CTL: - return (0); - case SND_DEV_DSP: - case SND_DEV_AUDIO: - return (sq_sync()); - default: - return (unknown_minor_dev("sound_fsync", dev)); - } + switch (dev) { + case SND_DEV_STATUS: + case SND_DEV_CTL: + return(0); + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return(sq_sync()); + default: + return(unknown_minor_dev("sound_fsync", dev)); + } } -static void -sound_release(struct inode *inode, struct file *file) -{ - int dev = MINOR(inode->i_rdev); - - switch (dev & 0x0f) - { - case SND_DEV_STATUS: - state_release(); - break; - case SND_DEV_CTL: - mixer_release(); - break; - case SND_DEV_DSP: - case SND_DEV_AUDIO: - sq_release(); - sound.soft = sound.dsp; - sound.hard = sound.dsp; - sound_silence(); - break; - default: - unknown_minor_dev("sound_release", dev); - return; - } +static int sound_release(struct inode *inode, struct file *file) +{ + int dev = MINOR(inode->i_rdev); + + switch (dev & 0x0f) { + case SND_DEV_STATUS: + state_release(); + break; + case SND_DEV_CTL: + mixer_release(); + break; + case SND_DEV_DSP: + case SND_DEV_AUDIO: + sq_release(); + sound.soft = sound.dsp; + sound.hard = sound.dsp; + sound_silence(); + break; + default: + return unknown_minor_dev("sound_release", dev); + } #ifdef MODULE - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; #endif + return 0; } -static long long -sound_lseek(struct inode *inode, struct file *file, - long long offset, int orig) +static long long sound_lseek(struct file *file, long long offset, int orig) { - return -ESPIPE; + return -ESPIPE; } -static ssize_t sound_read(struct file *file, char *buf, szie_t count, loff_t *ppos) +static ssize_t sound_read(struct file *file, char *buf, size_t count, + loff_t *ppos) { - int dev = MINOR(file->f_dentry->d_inode->i_rdev); + struct inode *inode = file->f_dentry->d_inode; + int dev = MINOR(inode->i_rdev); - switch (dev & 0x0f) - { - case SND_DEV_STATUS: - return (state_read(buf, count)); - case SND_DEV_CTL: - case SND_DEV_DSP: - case SND_DEV_AUDIO: - return (-EPERM); - default: - return (unknown_minor_dev("sound_read", dev)); - } + switch (dev & 0x0f) { + case SND_DEV_STATUS: + return(state_read(buf, count)); + case SND_DEV_CTL: + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return(-EPERM); + default: + return(unknown_minor_dev("sound_read", dev)); + } } -static ssize_t sound_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +static ssize_t sound_write(struct file *file, const char *buf, size_t count, + loff_t *ppos) { - int dev = MINOR(file->f_dentry->d_inode->i_rdev); + struct inode *inode = file->f_dentry->d_inode; + int dev = MINOR(inode->i_rdev); - switch (dev & 0x0f) - { - case SND_DEV_STATUS: - case SND_DEV_CTL: - return (-EPERM); - case SND_DEV_DSP: - case SND_DEV_AUDIO: - return (sq_write(buf, count)); - default: - return (unknown_minor_dev("sound_write", dev)); - } + switch (dev & 0x0f) { + case SND_DEV_STATUS: + case SND_DEV_CTL: + return(-EPERM); + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return(sq_write(buf, count)); + default: + return(unknown_minor_dev("sound_write", dev)); + } } static int unknown_minor_dev(char *fname, int dev) { - /* printk("%s: Unknown minor device %d\n", fname, dev); */ - return (-ENXIO); + /* printk("%s: Unknown minor device %d\n", fname, dev); */ + return(-ENXIO); } -static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) +static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg) { - int dev = MINOR(inode->i_rdev); - u_long fmt; - int data; - - switch (dev & 0x0f) - { - case SND_DEV_STATUS: - return (-EPERM); - case SND_DEV_CTL: - return (mixer_ioctl(inode, file, cmd, arg)); - case SND_DEV_AUDIO: - case SND_DEV_DSP: - switch (cmd) - { - case SNDCTL_DSP_RESET: - sq_reset(); - return (0); - case SNDCTL_DSP_POST: - case SNDCTL_DSP_SYNC: - return (sound_fsync(inode, file)); - - /* ++TeSche: before changing any of these it's probably wise to - * wait until sound playing has settled down - */ - case SNDCTL_DSP_SPEED: - sound_fsync(inode, file); - IOCTL_IN(arg, data); - return (IOCTL_OUT(arg, sound_set_speed(data))); - case SNDCTL_DSP_STEREO: - sound_fsync(inode, file); - IOCTL_IN(arg, data); - return (IOCTL_OUT(arg, sound_set_stereo(data))); - case SOUND_PCM_WRITE_CHANNELS: - sound_fsync(inode, file); - IOCTL_IN(arg, data); - return (IOCTL_OUT(arg, sound_set_stereo(data - 1) + 1)); - case SNDCTL_DSP_SETFMT: - sound_fsync(inode, file); - IOCTL_IN(arg, data); - return (IOCTL_OUT(arg, sound_set_format(data))); - case SNDCTL_DSP_GETFMTS: - fmt = 0; - if (sound.trans) - { - if (sound.trans->ct_ulaw) - fmt |= AFMT_MU_LAW; - if (sound.trans->ct_alaw) - fmt |= AFMT_A_LAW; - if (sound.trans->ct_s8) - fmt |= AFMT_S8; - if (sound.trans->ct_u8) - fmt |= AFMT_U8; - if (sound.trans->ct_s16be) - fmt |= AFMT_S16_BE; - if (sound.trans->ct_u16be) - fmt |= AFMT_U16_BE; - if (sound.trans->ct_s16le) - fmt |= AFMT_S16_LE; - if (sound.trans->ct_u16le) - fmt |= AFMT_U16_LE; - } - return (IOCTL_OUT(arg, fmt)); - case SNDCTL_DSP_GETBLKSIZE: - return (IOCTL_OUT(arg, 10240)); - case SNDCTL_DSP_SUBDIVIDE: - case SNDCTL_DSP_SETFRAGMENT: - break; - default: - return (mixer_ioctl(inode, file, cmd, arg)); - } - break; + int dev = MINOR(inode->i_rdev); + u_long fmt; + int data; + + switch (dev & 0x0f) { + case SND_DEV_STATUS: + return(-EPERM); + case SND_DEV_CTL: + return(mixer_ioctl(inode, file, cmd, arg)); + case SND_DEV_AUDIO: + case SND_DEV_DSP: + switch (cmd) { + case SNDCTL_DSP_RESET: + sq_reset(); + return(0); + case SNDCTL_DSP_POST: + case SNDCTL_DSP_SYNC: + return(sound_fsync(file, file->f_dentry)); + + /* ++TeSche: before changing any of these it's probably wise to + * wait until sound playing has settled down + */ + case SNDCTL_DSP_SPEED: + sound_fsync(file, file->f_dentry); + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_speed(data))); + case SNDCTL_DSP_STEREO: + sound_fsync(file, file->f_dentry); + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_stereo(data))); + case SOUND_PCM_WRITE_CHANNELS: + sound_fsync(file, file->f_dentry); + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_stereo(data-1)+1)); + case SNDCTL_DSP_SETFMT: + sound_fsync(file, file->f_dentry); + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_format(data))); + case SNDCTL_DSP_GETFMTS: + fmt = 0; + if (sound.trans) { + if (sound.trans->ct_ulaw) + fmt |= AFMT_MU_LAW; + if (sound.trans->ct_alaw) + fmt |= AFMT_A_LAW; + if (sound.trans->ct_s8) + fmt |= AFMT_S8; + if (sound.trans->ct_u8) + fmt |= AFMT_U8; + if (sound.trans->ct_s16be) + fmt |= AFMT_S16_BE; + if (sound.trans->ct_u16be) + fmt |= AFMT_U16_BE; + if (sound.trans->ct_s16le) + fmt |= AFMT_S16_LE; + if (sound.trans->ct_u16le) + fmt |= AFMT_U16_LE; + } + return(IOCTL_OUT(arg, fmt)); + case SNDCTL_DSP_GETBLKSIZE: + return(IOCTL_OUT(arg, 10240)); + case SNDCTL_DSP_SUBDIVIDE: + case SNDCTL_DSP_SETFRAGMENT: + break; default: - return (unknown_minor_dev("sound_ioctl", dev)); - } - return (-EINVAL); + return(mixer_ioctl(inode, file, cmd, arg)); + } + break; + + default: + return(unknown_minor_dev("sound_ioctl", dev)); + } + return(-EINVAL); } static struct file_operations sound_fops = { - sound_lseek, - sound_read, - sound_write, - NULL, - NULL, /* select */ - sound_ioctl, - NULL, - sound_open, - sound_release, - sound_fsync + sound_lseek, + sound_read, + sound_write, + NULL, + NULL, /* select */ + sound_ioctl, + NULL, + sound_open, + sound_release, + sound_fsync }; @@ -3601,186 +3276,171 @@ /*** Config & Setup **********************************************************/ -void -soundcard_init(void) +void soundcard_init(void) { - int has_sound = 0; - int i; + int has_sound = 0; + int i; - switch (m68k_machtype) - { + switch (m68k_machtype) { #ifdef CONFIG_ATARI - case MACH_ATARI: - if (ATARIHW_PRESENT(PCM_8BIT)) - { - if (ATARIHW_PRESENT(CODEC)) - sound.mach = machFalcon; - else if (ATARIHW_PRESENT(MICROWIRE)) - sound.mach = machTT; - else - break; - if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0) - has_sound = 1; - else - printk(KERN_ERR "DMA sound driver: Timer A interrupt already in use\n"); - } - break; + case MACH_ATARI: + if (ATARIHW_PRESENT(PCM_8BIT)) { + if (ATARIHW_PRESENT(CODEC)) + sound.mach = machFalcon; + else if (ATARIHW_PRESENT(MICROWIRE)) + sound.mach = machTT; + else + break; + if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0) + has_sound = 1; + else + printk("DMA sound driver: Timer A interrupt already in use\n"); + } + break; -#endif /* CONFIG_ATARI */ +#endif /* CONFIG_ATARI */ #ifdef CONFIG_AMIGA - case MACH_AMIGA: - if (AMIGAHW_PRESENT(AMI_AUDIO)) - { - sound.mach = machAmiga; - has_sound = 1; - } - break; -#endif /* CONFIG_AMIGA */ - } - if (!has_sound) - return; - - /* Set up sound queue, /dev/audio and /dev/dsp. */ - sound_buffers = kmalloc(numBufs * sizeof(char *), GFP_KERNEL); + case MACH_AMIGA: + if (AMIGAHW_PRESENT(AMI_AUDIO)) { + sound.mach = machAmiga; + has_sound = 1; + } + break; +#endif /* CONFIG_AMIGA */ + } + if (!has_sound) + return; - if (!sound_buffers) - { + /* Set up sound queue, /dev/audio and /dev/dsp. */ + sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL); + if (!sound_buffers) { out_of_memory: - printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n"); - return; - } - for (i = 0; i < numBufs; i++) - { - sound_buffers[i] = sound.mach.dma_alloc(bufSize << 10, GFP_KERNEL); - if (!sound_buffers[i]) - { - while (i--) - sound.mach.dma_free(sound_buffers[i], bufSize << 10); - kfree(sound_buffers); - sound_buffers = 0; - goto out_of_memory; - } - } + printk("DMA sound driver: Not enough buffer memory, driver disabled!\n"); + return; + } + for (i = 0; i < numBufs; i++) { + sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL); + if (!sound_buffers[i]) { + while (i--) + sound.mach.dma_free (sound_buffers[i], bufSize << 10); + kfree (sound_buffers); + sound_buffers = 0; + goto out_of_memory; + } + } #ifndef MODULE - /* Register driver with the VFS. */ - register_chrdev(SOUND_MAJOR, "sound", &sound_fops); + /* Register driver with the VFS. */ + register_chrdev(SOUND_MAJOR, "sound", &sound_fops); #endif - sq_init(numBufs, bufSize << 10, sound_buffers); + sq_init(numBufs, bufSize << 10, sound_buffers); - /* Set up /dev/sndstat. */ - state_init(); + /* Set up /dev/sndstat. */ + state_init(); - /* Set up /dev/mixer. */ - mixer_init(); + /* Set up /dev/mixer. */ + mixer_init(); - if (!sound.mach.irqinit()) - { - printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n"); - return; - } + if (!sound.mach.irqinit()) { + printk("DMA sound driver: Interrupt initialization failed\n"); + return; + } #ifdef MODULE - irq_installed = 1; + irq_installed = 1; #endif - printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n", numBufs, - bufSize); + printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs, + bufSize); - return; + return; } void sound_setup(char *str, int *ints) { - /* ++Martin: stub, could possibly be merged with soundcard.c et al later */ + /* ++Martin: stub, could possibly be merged with soundcard.c et al later */ } #define MAXARGS 8 /* Should be sufficient for now */ -void -dmasound_setup(char *str, int *ints) +void dmasound_setup(char *str, int *ints) { - /* check the bootstrap parameter for "dmasound=" */ + /* check the bootstrap parameter for "dmasound=" */ - switch (ints[0]) - { - case 3: - if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS)) - printk(KERN_WARNING "dmasound_setup: illegal catch radius, using default = %d\n", catchRadius); - else - catchRadius = ints[3]; - /* fall through */ - case 2: - if (ints[1] < MIN_BUFFERS) - printk(KERN_WARNING "dmasound_setup: illegal number of buffers, using default = %d\n", numBufs); - else - numBufs = ints[1]; - if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE) - printk(KERN_WARNING "dmasound_setup: illegal buffer size, using default = %d\n", bufSize); - else - bufSize = ints[2]; - break; - case 0: - break; - default: - printk(KERN_WARNING "dmasound_setup: illegal number of arguments\n"); - } + switch (ints[0]) { + case 3: + if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS)) + printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius); + else + catchRadius = ints[3]; + /* fall through */ + case 2: + if (ints[1] < MIN_BUFFERS) + printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs); + else + numBufs = ints[1]; + if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE) + printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize); + else + bufSize = ints[2]; + break; + case 0: + break; + default: + printk("dmasound_setup: illegal number of arguments\n"); + } } #ifdef MODULE -static int dmasound[MAXARGS] = { - 0 -}; +static int dmasound[MAXARGS] = { 0 }; int init_module(void) { - int err, i = 0; - int ints[MAXARGS + 1]; + int err, i = 0; + int ints[MAXARGS+1]; - while (i < MAXARGS && dmasound[i]) - ints[i + 1] = dmasound[i++]; - ints[0] = i; - - if (i) - dmasound_setup("dmasound=", ints); - - err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops); - if (err) - { - printk(KERN_ERR "dmasound: driver already loaded/included in kernel\n"); - return err; - } - chrdev_registered = 1; - soundcard_init(); + while (i < MAXARGS && dmasound[i]) + ints[i + 1] = dmasound[i++]; + ints[0] = i; + + if (i) + dmasound_setup("dmasound=", ints); + + err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops); + if (err) { + printk("dmasound: driver already loaded/included in kernel\n"); + return err; + } + chrdev_registered = 1; + soundcard_init(); - return 0; + return 0; } void cleanup_module(void) { - int i; + int i; - if (MOD_IN_USE) - return; + if (MOD_IN_USE) + return; - if (chrdev_registered) - unregister_chrdev(SOUND_MAJOR, "sound"); + if (chrdev_registered) + unregister_chrdev(SOUND_MAJOR, "sound"); - if (irq_installed) - { - sound_silence(); - sound.mach.irqcleanup(); - } - if (sound_buffers) - { - for (i = 0; i < numBufs; i++) - sound.mach.dma_free(sound_buffers[i], bufSize << 10); - kfree(sound_buffers); - } + if (irq_installed) { + sound_silence(); + sound.mach.irqcleanup(); + } + + if (sound_buffers) { + for (i = 0; i < numBufs; i++) + sound.mach.dma_free(sound_buffers[i], bufSize << 10); + kfree(sound_buffers); + } } -#endif /* MODULE */ +#endif /* MODULE */ diff -u --recursive --new-file v2.1.93/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v2.1.93/linux/drivers/sound/gus_card.c Tue Mar 17 22:18:14 1998 +++ linux/drivers/sound/gus_card.c Wed Apr 8 17:24:48 1998 @@ -30,7 +30,8 @@ void attach_gus_card(struct address_info *hw_config) { - snd_set_irq_handler(hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp, hw_config); + if(request_irq(hw_config->irq, gusintr, 0, "Gravis Ultrasound", hw_config)<0) + printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq); gus_wave_init(hw_config); @@ -38,10 +39,10 @@ request_region(hw_config->io_base + 0x100, 12, "GUS"); /* 0x10c-> is MAX */ if (sound_alloc_dma(hw_config->dma, "GUS")) - printk("gus_card.c: Can't allocate DMA channel\n"); + printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma); if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) if (sound_alloc_dma(hw_config->dma2, "GUS(2)")) - printk("gus_card.c: Can't allocate DMA channel 2\n"); + printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma2); #if defined(CONFIG_MIDI) gus_midi_init(hw_config); #endif @@ -101,7 +102,7 @@ release_region(hw_config->io_base, 16); release_region(hw_config->io_base + 0x100, 12); /* 0x10c-> is MAX */ - snd_release_irq(hw_config->irq, hw_config); + free_irq(hw_config->irq, hw_config); sound_free_dma(hw_config->dma); diff -u --recursive --new-file v2.1.93/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v2.1.93/linux/drivers/sound/gus_wave.c Mon Feb 23 18:12:09 1998 +++ linux/drivers/sound/gus_wave.c Wed Apr 8 17:24:48 1998 @@ -859,26 +859,26 @@ int bank_sizes[4]; int i, j, bits = -1, nbanks = 0; -/* - * This routine determines what kind of RAM is installed in each of the four - * SIMM banks and configures the DRAM address decode logic accordingly. - */ + /* + * This routine determines what kind of RAM is installed in each of the four + * SIMM banks and configures the DRAM address decode logic accordingly. + */ -/* - * Place the chip into enhanced mode - */ + /* + * Place the chip into enhanced mode + */ gus_write8(0x19, gus_read8(0x19) | 0x01); gus_write8(0x53, gus_look8(0x53) & ~0x02); /* Select DRAM I/O access */ -/* - * Set memory configuration to 4 DRAM banks of 4M in each (16M total). - */ + /* + * Set memory configuration to 4 DRAM banks of 4M in each (16M total). + */ gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | 0x000c); -/* - * Perform the DRAM size detection for each bank individually. - */ + /* + * Perform the DRAM size detection for each bank individually. + */ for (bank = 0; bank < 4; bank++) { int size = 0; diff -u --recursive --new-file v2.1.93/linux/drivers/sound/local.h.master linux/drivers/sound/local.h.master --- v2.1.93/linux/drivers/sound/local.h.master Tue Mar 10 10:03:33 1998 +++ linux/drivers/sound/local.h.master Wed Apr 8 17:24:48 1998 @@ -42,7 +42,7 @@ defined(CONFIG_MSS_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) || \ defined(CONFIG_CS4232_MODULE) || defined(CONFIG_OPL3SA1_MODULE) || \ - defined(CONFIG_SOFTOSS_MODULE) + defined(CONFIG_SOFTOSS_MODULE) || defined(CONFIG_VIDC_SOUND) # define CONFIG_AUDIO #endif diff -u --recursive --new-file v2.1.93/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c --- v2.1.93/linux/drivers/sound/mad16.c Sun Dec 21 17:41:24 1997 +++ linux/drivers/sound/mad16.c Wed Apr 8 17:24:48 1998 @@ -56,6 +56,10 @@ * CD-ROM DMA (Mitsumi or IDE): 0x00=DMA5, 0x01=DMA6, 0x02=DMA7 or 0x03=disabled * * For use with sbpcd, address 0x340, set MAD16_CDSEL to 0x03 or 0x23. + * + * Changes + * + * Alan Cox Clean up, added module selections. */ #include "sound_config.h" @@ -118,48 +122,47 @@ #define DDB(x) #endif -static unsigned char -mad_read(int port) +static unsigned char mad_read(int port) { - unsigned long flags; - unsigned char tmp; + unsigned long flags; + unsigned char tmp; save_flags(flags); cli(); switch (board_type) /* Output password */ - { - case C928: - case MOZART: - outb((0xE2), PASSWD_REG); - break; - - case C929: - outb((0xE3), PASSWD_REG); - break; - - case C930: - /* outb(( 0xE4), PASSWD_REG); */ - break; - - case C924: - outb((0xE5), PASSWD_REG); - break; - } + { + case C928: + case MOZART: + outb((0xE2), PASSWD_REG); + break; + + case C929: + outb((0xE3), PASSWD_REG); + break; + + case C930: + /* outb(( 0xE4), PASSWD_REG); */ + break; + + case C924: + outb((0xE5), PASSWD_REG); + break; + } if (board_type == C930) - { - outb((port - MC0_PORT), 0xe0e); /* Write to index reg */ - tmp = inb(0xe0f); /* Read from data reg */ - } else + { + outb((port - MC0_PORT), 0xe0e); /* Write to index reg */ + tmp = inb(0xe0f); /* Read from data reg */ + } + else tmp = inb(port); restore_flags(flags); return tmp; } -static void -mad_write(int port, int value) +static void mad_write(int port, int value) { unsigned long flags; @@ -167,65 +170,65 @@ cli(); switch (board_type) /* Output password */ - { - case C928: - case MOZART: - outb((0xE2), PASSWD_REG); - break; - - case C929: - outb((0xE3), PASSWD_REG); - break; - - case C930: - /* outb(( 0xE4), PASSWD_REG); */ - break; - - case C924: - outb((0xE5), PASSWD_REG); - break; - } + { + case C928: + case MOZART: + outb((0xE2), PASSWD_REG); + break; + + case C929: + outb((0xE3), PASSWD_REG); + break; + + case C930: + /* outb(( 0xE4), PASSWD_REG); */ + break; + + case C924: + outb((0xE5), PASSWD_REG); + break; + } if (board_type == C930) - { - outb((port - MC0_PORT), 0xe0e); /* Write to index reg */ - outb(((unsigned char) (value & 0xff)), 0xe0f); - } else + { + outb((port - MC0_PORT), 0xe0e); /* Write to index reg */ + outb(((unsigned char) (value & 0xff)), 0xe0f); + } + else outb(((unsigned char) (value & 0xff)), port); restore_flags(flags); } -static int -detect_c930(void) +static int detect_c930(void) { unsigned char tmp = mad_read(MC1_PORT); if ((tmp & 0x06) != 0x06) - { - DDB(printk("Wrong C930 signature (%x)\n", tmp)); - /* return 0; */ - } + { + DDB(printk("Wrong C930 signature (%x)\n", tmp)); + /* return 0; */ + } mad_write(MC1_PORT, 0); if (mad_read(MC1_PORT) != 0x06) - { - DDB(printk("Wrong C930 signature2 (%x)\n", tmp)); - /* return 0; */ - } + { + DDB(printk("Wrong C930 signature2 (%x)\n", tmp)); + /* return 0; */ + } mad_write(MC1_PORT, tmp); /* Restore bits */ mad_write(MC7_PORT, 0); if ((tmp = mad_read(MC7_PORT)) != 0) - { - DDB(printk("MC7 not writable (%x)\n", tmp)); - return 0; - } + { + DDB(printk("MC7 not writable (%x)\n", tmp)); + return 0; + } mad_write(MC7_PORT, 0xcb); if ((tmp = mad_read(MC7_PORT)) != 0xcb) - { - DDB(printk("MC7 not writable2 (%x)\n", tmp)); - return 0; - } + { + DDB(printk("MC7 not writable2 (%x)\n", tmp)); + return 0; + } tmp = mad_read(MC0_PORT+18); if (tmp == 0xff) @@ -262,113 +265,109 @@ * the PnP bios will not recognize the chip on the next * warm boot and may assignd different resources to other * PnP/PCI cards. - */ + */ mad_write(MC0_PORT+17, 0x04); return 1; } -static int -detect_mad16(void) +static int detect_mad16(void) { - unsigned char tmp, tmp2; - int i; + unsigned char tmp, tmp2; + int i; + + /* + * Check that reading a register doesn't return bus float (0xff) + * when the card is accessed using password. This may fail in case + * the card is in low power mode. Normally at least the power saving mode + * bit should be 0. + */ -/* - * Check that reading a register doesn't return bus float (0xff) - * when the card is accessed using password. This may fail in case - * the card is in low power mode. Normally at least the power saving mode - * bit should be 0. - */ if ((tmp = mad_read(MC1_PORT)) == 0xff) - { - DDB(printk("MC1_PORT returned 0xff\n")); - return 0; - } + { + DDB(printk("MC1_PORT returned 0xff\n")); + return 0; + } for (i = 0xf8d; i <= 0xf98; i++) DDB(printk("Port %0x (init value) = %0x\n", i, mad_read(i))); if (board_type == C930) return detect_c930(); -/* - * Now check that the gate is closed on first I/O after writing - * the password. (This is how a MAD16 compatible card works). - */ + + /* + * Now check that the gate is closed on first I/O after writing + * the password. (This is how a MAD16 compatible card works). + */ if ((tmp2 = inb(MC1_PORT)) == tmp) /* It didn't close */ - { - DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2)); - return 0; - } + { + DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2)); + return 0; + } mad_write(MC1_PORT, tmp ^ 0x80); /* Toggle a bit */ if ((tmp2 = mad_read(MC1_PORT)) != (tmp ^ 0x80)) /* Compare the bit */ - { - mad_write(MC1_PORT, tmp); /* Restore */ - DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2)); - return 0; - } + { + mad_write(MC1_PORT, tmp); /* Restore */ + DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2)); + return 0; + } mad_write(MC1_PORT, tmp); /* Restore */ return 1; /* Bingo */ - } -static int -wss_init(struct address_info *hw_config) +static int wss_init(struct address_info *hw_config) { - int ad_flags = 0; + int ad_flags = 0; -/* - * Verify the WSS parameters - */ + /* + * Verify the WSS parameters + */ if (check_region(hw_config->io_base, 8)) - { - printk("MSS: I/O port conflict\n"); - return 0; - } + { + printk(KERN_ERR "MSS: I/O port conflict\n"); + return 0; + } if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp)) return 0; /* - * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTrix Pro for example) - * return 0x00. + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (AudioTrix Pro for example) + * return 0x00. */ if ((inb(hw_config->io_base + 3) & 0x3f) != 0x04 && (inb(hw_config->io_base + 3) & 0x3f) != 0x00) - { - DDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb(hw_config->io_base + 3))); - return 0; - } + { + DDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb(hw_config->io_base + 3))); + return 0; + } if (hw_config->irq > 11) - { - printk("MSS: Bad IRQ %d\n", hw_config->irq); - return 0; - } + { + printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq); + return 0; + } if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) - { - printk("MSS: Bad DMA %d\n", hw_config->dma); - return 0; - } + { + printk(KERN_ERR "MSS: Bad DMA %d\n", hw_config->dma); + return 0; + } /* - * Check that DMA0 is not in use with a 8 bit board. + * Check that DMA0 is not in use with a 8 bit board. */ if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) - { - printk("MSS: Can't use DMA0 with a 8 bit card/slot\n"); - return 0; - } + { + printk("MSS: Can't use DMA0 with a 8 bit card/slot\n"); + return 0; + } if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80) - { - printk("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); - } + printk(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); return 1; } -static int -init_c930(struct address_info *hw_config) +static int init_c930(struct address_info *hw_config) { - unsigned char cfg = 0; + unsigned char cfg = 0; #ifdef MAD16_CONF cfg |= (0x0f & MAD16_CONF); @@ -384,24 +383,23 @@ } switch (hw_config->io_base) - { - case 0x530: - cfg |= 0x00; - break; - case 0xe80: - cfg |= 0x10; - break; - case 0xf40: - cfg |= 0x20; - break; - case 0x604: - cfg |= 0x30; - break; - - default: - printk("MAD16: Invalid codec port %x\n", hw_config->io_base); - return 0; - } + { + case 0x530: + cfg |= 0x00; + break; + case 0xe80: + cfg |= 0x10; + break; + case 0xf40: + cfg |= 0x20; + break; + case 0x604: + cfg |= 0x30; + break; + default: + printk(KERN_ERR "MAD16: Invalid codec port %x\n", hw_config->io_base); + return 0; + } mad_write(MC1_PORT, cfg); /* MC2 is CD configuration. Don't touch it. */ @@ -423,94 +421,98 @@ return wss_init(hw_config); } -static int -chip_detect(void) +static int chip_detect(void) { - int i; + int i; -/* - * Then try to detect with the old password - */ + /* + * Then try to detect with the old password + */ board_type = C924; DDB(printk("Detect using password = 0xE5\n")); if (!detect_mad16()) /* No luck. Try different model */ - { - board_type = C928; - - DDB(printk("Detect using password = 0xE2\n")); - - if (!detect_mad16()) - { - board_type = C929; - - DDB(printk("Detect using password = 0xE3\n")); - - if (!detect_mad16()) - { - if (inb(PASSWD_REG) != 0xff) - return 0; - -/* - * First relocate MC# registers to 0xe0e/0xe0f, disable password - */ - - outb((0xE4), PASSWD_REG); - outb((0x80), PASSWD_REG); - - board_type = C930; + { + board_type = C928; - DDB(printk("Detect using password = 0xE4\n")); + DDB(printk("Detect using password = 0xE2\n")); - for (i = 0xf8d; i <= 0xf93; i++) - DDB(printk("port %03x = %02x\n", i, mad_read(i))); - - if (!detect_mad16()) - return 0; - - DDB(printk("mad16.c: 82C930 detected\n")); - } else - { - DDB(printk("mad16.c: 82C929 detected\n")); - } - } else - { - unsigned char model; - - if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) - { - DDB(printk("mad16.c: Mozart detected\n")); - board_type = MOZART; - } else - { - DDB(printk("mad16.c: 82C928 detected???\n")); - board_type = C928; - } - } - } + if (!detect_mad16()) + { + board_type = C929; + + DDB(printk("Detect using password = 0xE3\n")); + + if (!detect_mad16()) + { + if (inb(PASSWD_REG) != 0xff) + return 0; + + /* + * First relocate MC# registers to 0xe0e/0xe0f, disable password + */ + + outb((0xE4), PASSWD_REG); + outb((0x80), PASSWD_REG); + + board_type = C930; + + DDB(printk("Detect using password = 0xE4\n")); + + for (i = 0xf8d; i <= 0xf93; i++) + DDB(printk("port %03x = %02x\n", i, mad_read(i))); + + if (!detect_mad16()) + return 0; + + DDB(printk("mad16.c: 82C930 detected\n")); + } + else + { + DDB(printk("mad16.c: 82C929 detected\n")); + } + } + else + { + unsigned char model; + + if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) + { + DDB(printk("mad16.c: Mozart detected\n")); + board_type = MOZART; + } + else + { + DDB(printk("mad16.c: 82C928 detected???\n")); + board_type = C928; + } + } + } return 1; } -int -probe_mad16(struct address_info *hw_config) +int probe_mad16(struct address_info *hw_config) { - int i; - static int valid_ports[] = - {0x530, 0xe80, 0xf40, 0x604}; - unsigned char tmp; - unsigned char cs4231_mode = 0; + int i; + static int valid_ports[] = + { + 0x530, 0xe80, 0xf40, 0x604 + }; + unsigned char tmp; + unsigned char cs4231_mode = 0; - int ad_flags = 0; + int ad_flags = 0; if (already_initialized) return 0; mad16_osp = hw_config->osp; -/* - * Check that all ports return 0xff (bus float) when no password - * is written to the password register. - */ + + /* + * Check that all ports return 0xff (bus float) when no password + * is written to the password register. + */ DDB(printk("--- Detecting MAD16 / Mozart ---\n")); if (!chip_detect()) @@ -530,25 +532,25 @@ tmp = (mad_read(MC1_PORT) & 0x0f) | 0x80; /* Enable WSS, Disable SB */ for (i = 0; i < 5; i++) - { - if (i > 3) /* Not a valid port */ - { - printk("MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base); - return 0; - } - if (valid_ports[i] == hw_config->io_base) - { - tmp |= i << 4; /* WSS port select bits */ - break; - } - } + { + if (i > 3) /* Not a valid port */ + { + printk(KERN_ERR "MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base); + return 0; + } + if (valid_ports[i] == hw_config->io_base) + { + tmp |= i << 4; /* WSS port select bits */ + break; + } + } -/* - * Set optional CD-ROM and joystick settings. - */ + /* + * Set optional CD-ROM and joystick settings. + */ -#ifdef MAD16_CONF tmp &= ~0x0f; +#if defined(MAD16_CONF) tmp |= ((MAD16_CONF) & 0x0f); /* CD-ROM and joystick bits */ #endif mad_write(MC1_PORT, tmp); @@ -567,11 +569,11 @@ mad_write(MC3_PORT, 0xf0); /* Disable SB */ if (board_type == C924) /* Specific C924 init values */ - { - mad_write(MC4_PORT, 0xA0); - mad_write(MC5_PORT, 0x05); - mad_write(MC6_PORT, 0x03); - } + { + mad_write(MC4_PORT, 0xA0); + mad_write(MC5_PORT, 0x05); + mad_write(MC6_PORT, 0x03); + } if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp)) return 0; @@ -579,15 +581,16 @@ cs4231_mode = 0x02; /* CS4248/CS4231 sync delay switch */ if (board_type == C929) - { - mad_write(MC4_PORT, 0xa2); - mad_write(MC5_PORT, 0xA5 | cs4231_mode); - mad_write(MC6_PORT, 0x03); /* Disable MPU401 */ - } else - { - mad_write(MC4_PORT, 0x02); - mad_write(MC5_PORT, 0x30 | cs4231_mode); - } + { + mad_write(MC4_PORT, 0xa2); + mad_write(MC5_PORT, 0xA5 | cs4231_mode); + mad_write(MC6_PORT, 0x03); /* Disable MPU401 */ + } + else + { + mad_write(MC4_PORT, 0x02); + mad_write(MC5_PORT, 0x30 | cs4231_mode); + } for (i = 0xf8d; i <= 0xf93; i++) DDB(printk("port %03x after init = %02x\n", i, mad_read(i))); @@ -597,24 +600,21 @@ return 1; } -void -attach_mad16(struct address_info *hw_config) +void attach_mad16(struct address_info *hw_config) { - static char interrupt_bits[12] = - { + static char interrupt_bits[12] = { -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 }; - char bits; + char bits; - static char dma_bits[4] = - { + static char dma_bits[4] = { 1, 2, 0, 3 }; - int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; - int ad_flags = 0, dma = hw_config->dma, dma2 = hw_config->dma2; - unsigned char dma2_bit = 0; + int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; + int ad_flags = 0, dma = hw_config->dma, dma2 = hw_config->dma2; + unsigned char dma2_bit = 0; already_initialized = 1; @@ -622,8 +622,9 @@ return; /* - * Set the IRQ and DMA addresses. + * Set the IRQ and DMA addresses. */ + if (board_type == C930) interrupt_bits[5] = 0x28; /* Also IRQ5 is possible on C930 */ @@ -633,35 +634,35 @@ outb((bits | 0x40), config_port); if ((inb(version_port) & 0x40) == 0) - printk("[IRQ Conflict?]"); + printk(KERN_ERR "[IRQ Conflict?]\n"); -/* - * Handle the capture DMA channel - */ + /* + * Handle the capture DMA channel + */ if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma) - { - if (!((dma == 0 && dma2 == 1) || + { + if (!((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) || (dma == 3 && dma2 == 0))) - { /* Unsupported combination. Try to swap channels */ - int tmp = dma; + { /* Unsupported combination. Try to swap channels */ + int tmp = dma; - dma = dma2; - dma2 = tmp; - } - if ((dma == 0 && dma2 == 1) || - (dma == 1 && dma2 == 0) || - (dma == 3 && dma2 == 0)) - { - dma2_bit = 0x04; /* Enable capture DMA */ - } else - { - printk("MAD16: Invalid capture DMA\n"); - dma2 = dma; - } - } else - dma2 = dma; + dma = dma2; + dma2 = tmp; + } + if ((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0)) + { + dma2_bit = 0x04; /* Enable capture DMA */ + } + else + { + printk("MAD16: Invalid capture DMA\n"); + dma2 = dma; + } + } + else dma2 = dma; outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ @@ -673,24 +674,23 @@ request_region(hw_config->io_base, 4, "MAD16 WSS config"); } -void -attach_mad16_mpu(struct address_info *hw_config) +void attach_mad16_mpu(struct address_info *hw_config) { if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ - { -#if defined(CONFIG_MIDI) + { +#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD) - if (mad_read(MC1_PORT) & 0x20) - hw_config->io_base = 0x240; - else - hw_config->io_base = 0x220; + if (mad_read(MC1_PORT) & 0x20) + hw_config->io_base = 0x240; + else + hw_config->io_base = 0x220; - hw_config->name = "Mad16/Mozart"; - sb_dsp_init(hw_config); + hw_config->name = "Mad16/Mozart"; + sb_dsp_init(hw_config); #endif - return; - } + return; + } #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) if (!already_initialized) return; @@ -701,68 +701,67 @@ #endif } -int -probe_mad16_mpu(struct address_info *hw_config) +int probe_mad16_mpu(struct address_info *hw_config) { #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - static int mpu_attached = 0; - static int valid_ports[] = - {0x330, 0x320, 0x310, 0x300}; - static short valid_irqs[] = - {9, 10, 5, 7}; - unsigned char tmp; - - int i; /* A variable with secret power */ + static int mpu_attached = 0; + static int valid_ports[] = { + 0x330, 0x320, 0x310, 0x300 + }; + + static short valid_irqs[] = {9, 10, 5, 7}; + unsigned char tmp; + int i; /* A variable with secret power */ if (!already_initialized) /* The MSS port must be initialized first */ return 0; - if (mpu_attached) /* Don't let them call this twice */ + if (mpu_attached) /* Don't let them call this twice */ return 0; mpu_attached = 1; if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ - { + { -#if defined(CONFIG_MIDI) - unsigned char tmp; +#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD) + unsigned char tmp; - tmp = mad_read(MC3_PORT); + tmp = mad_read(MC3_PORT); - /* - * MAD16 SB base is defined by the WSS base. It cannot be changed - * alone. - * Ignore configured I/O base. Use the active setting. - */ - - if (mad_read(MC1_PORT) & 0x20) - hw_config->io_base = 0x240; - else - hw_config->io_base = 0x220; - - switch (hw_config->irq) - { - case 5: - tmp = (tmp & 0x3f) | 0x80; - break; - case 7: - tmp = (tmp & 0x3f); - break; - case 11: - tmp = (tmp & 0x3f) | 0x40; - break; - default: - printk("mad16/Mozart: Invalid MIDI IRQ\n"); - return 0; - } - - mad_write(MC3_PORT, tmp | 0x04); - hw_config->driver_use_1 = SB_MIDI_ONLY; - return sb_dsp_detect(hw_config); + /* + * MAD16 SB base is defined by the WSS base. It cannot be changed + * alone. + * Ignore configured I/O base. Use the active setting. + */ + + if (mad_read(MC1_PORT) & 0x20) + hw_config->io_base = 0x240; + else + hw_config->io_base = 0x220; + + switch (hw_config->irq) + { + case 5: + tmp = (tmp & 0x3f) | 0x80; + break; + case 7: + tmp = (tmp & 0x3f); + break; + case 11: + tmp = (tmp & 0x3f) | 0x40; + break; + default: + printk(KERN_ERR "mad16/Mozart: Invalid MIDI IRQ\n"); + return 0; + } + + mad_write(MC3_PORT, tmp | 0x04); + hw_config->driver_use_1 = SB_MIDI_ONLY; + return sb_dsp_detect(hw_config); #else - return 0; + return 0; #endif - } + } tmp = mad_read(MC6_PORT) & 0x83; tmp |= 0x80; /* MPU-401 enable */ @@ -771,36 +770,36 @@ */ for (i = 0; i < 5; i++) - { - if (i > 3) /* Out of array bounds */ - { - printk("MAD16 / Mozart: Invalid MIDI port 0x%x\n", hw_config->io_base); - return 0; - } - if (valid_ports[i] == hw_config->io_base) - { - tmp |= i << 5; - break; - } - } + { + if (i > 3) /* Out of array bounds */ + { + printk(KERN_ERR "MAD16 / Mozart: Invalid MIDI port 0x%x\n", hw_config->io_base); + return 0; + } + if (valid_ports[i] == hw_config->io_base) + { + tmp |= i << 5; + break; + } + } /* * Set the MPU IRQ bits */ for (i = 0; i < 5; i++) - { - if (i > 3) /* Out of array bounds */ - { - printk("MAD16 / Mozart: Invalid MIDI IRQ %d\n", hw_config->irq); - return 0; - } - if (valid_irqs[i] == hw_config->irq) - { - tmp |= i << 3; - break; - } - } + { + if (i > 3) /* Out of array bounds */ + { + printk(KERN_ERR "MAD16 / Mozart: Invalid MIDI IRQ %d\n", hw_config->irq); + return 0; + } + if (valid_irqs[i] == hw_config->irq) + { + tmp |= i << 3; + break; + } + } mad_write(MC6_PORT, tmp); /* Write MPU401 config */ return probe_uart401(hw_config); @@ -809,13 +808,12 @@ #endif } -void -unload_mad16(struct address_info *hw_config) +void unload_mad16(struct address_info *hw_config) { ad1848_unload(hw_config->io_base + 4, - hw_config->irq, - hw_config->dma, - hw_config->dma2, 0); + hw_config->irq, + hw_config->dma, + hw_config->dma2, 0); release_region(hw_config->io_base, 4); sound_unload_audiodev(hw_config->slots[0]); @@ -824,12 +822,12 @@ void unload_mad16_mpu(struct address_info *hw_config) { -#if defined(CONFIG_MIDI) +#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD) if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ - { - sb_dsp_unload(hw_config); - return; - } + { + sb_dsp_unload(hw_config); + return; + } #endif #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) @@ -839,6 +837,8 @@ #ifdef MODULE +int mpu_io = 0; +int mpu_irq = 0; int io = -1; int dma = -1; int dma16 = -1; /* Set this for modules that need it */ @@ -851,6 +851,8 @@ int opl4 = 0; int joystick = 0; +MODULE_PARM(mpu_io, "i"); +MODULE_PARM(mpu_irq, "i"); MODULE_PARM(io,"i"); MODULE_PARM(dma,"i"); MODULE_PARM(dma16,"i"); @@ -862,17 +864,18 @@ MODULE_PARM(opl4,"i"); MODULE_PARM(joystick,"i"); +EXPORT_NO_SYMBOLS; -static int found_mpu; +static int found_mpu; -static int dma_map[2][8] = +static int dma_map[2][8] = { {0x03, -1, -1, -1, -1, 0x00, 0x01, 0x02}, {0x03, -1, 0x01, 0x00, -1, -1, -1, -1} }; -static int irq_map[16] = +static int irq_map[16] = { 0x00, -1, -1, 0x0A, -1, 0x04, -1, 0x08, @@ -881,80 +884,83 @@ }; struct address_info config; +struct address_info config_mpu; -int -init_module(void) +int init_module(void) { - int dmatype = 0; + int dmatype = 0; - printk("MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + printk(KERN_INFO "MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); if (io == -1 || dma == -1 || irq == -1) - { - printk("I/O, DMA and irq are mandatory\n"); - return -EINVAL; - } - printk("CDROM "); + { + printk(KERN_ERR "I/O, DMA and irq are mandatory\n"); + return -EINVAL; + } + printk(KERN_INFO "CDROM "); switch (cdtype) - { - case 0x00: - printk("Disabled"); - cdirq = 0; - break; - case 0x02: - printk("Sony CDU31A"); - dmatype = 2; - break; - case 0x04: - printk("Mitsumi"); - dmatype = 1; - break; - case 0x06: - printk("Panasonic Lasermate"); - dmatype = 2; - break; - case 0x08: - printk("Secondary IDE"); - dmatype = 1; - break; - case 0x0A: - printk("Primary IDE"); - dmatype = 1; - break; - default: - printk("\nInvalid CDROM type\n"); - return -EINVAL; - } + { + case 0x00: + printk("Disabled"); + cdirq = 0; + break; + case 0x02: + printk("Sony CDU31A"); + dmatype = 2; + break; + case 0x04: + printk("Mitsumi"); + dmatype = 1; + break; + case 0x06: + printk("Panasonic Lasermate"); + dmatype = 2; + break; + case 0x08: + printk("Secondary IDE"); + dmatype = 1; + break; + case 0x0A: + printk("Primary IDE"); + dmatype = 1; + break; + default: + printk("\n"); + printk(KERN_ERR "Invalid CDROM type\n"); + return -EINVAL; + } if (dmatype) - { - if (cddma > 7 || cddma < 0 || dma_map[dmatype][cddma] == -1) - { - printk("\nInvalid CDROM DMA\n"); - return -EINVAL; - } - if (cddma) - printk(", DMA %d", cddma); - else - printk(", no DMA"); - } + { + if (cddma > 7 || cddma < 0 || dma_map[dmatype][cddma] == -1) + { + printk("\n"); + printk(KERN_ERR "Invalid CDROM DMA\n"); + return -EINVAL; + } + if (cddma) + printk(", DMA %d", cddma); + else + printk(", no DMA"); + } if (cdtype && !cdirq) printk(", no IRQ"); else if (cdirq < 0 || cdirq > 15 || irq_map[cdirq] == -1) - { + { printk(", invalid IRQ (disabling)"); cdirq = 0; - } else - printk(", IRQ %d", cdirq); + } + else printk(", IRQ %d", cdirq); - printk(".\nJoystick port "); + printk(".\n"); + printk(KERN_INFO "Joystick port "); if (joystick == 1) printk("enabled.\n"); else - { - joystick = 0; - printk("disabled.\n"); - } + { + joystick = 0; + printk("disabled.\n"); + } /* * Build the config words @@ -967,26 +973,26 @@ mad16_cdsel |= dma_map[dmatype][cddma]; if (cdtype < 0x08) - { - switch (cdport) - { - case 0x340: - mad16_cdsel |= 0x00; - break; - case 0x330: - mad16_cdsel |= 0x40; - break; - case 0x360: - mad16_cdsel |= 0x80; - break; - case 0x320: - mad16_cdsel |= 0xC0; - break; - default: - printk("Unknown CDROM I/O base %d\n", cdport); - return -EINVAL; - } - } + { + switch (cdport) + { + case 0x340: + mad16_cdsel |= 0x00; + break; + case 0x330: + mad16_cdsel |= 0x40; + break; + case 0x360: + mad16_cdsel |= 0x80; + break; + case 0x320: + mad16_cdsel |= 0xC0; + break; + default: + printk(KERN_ERR "Unknown CDROM I/O base %d\n", cdport); + return -EINVAL; + } + } mad16_cdsel |= irq_map[cdirq]; config.io_base = io; @@ -996,19 +1002,21 @@ if (!probe_mad16(&config)) return -ENODEV; - found_mpu = probe_mad16_mpu(&config); + + config_mpu.io_base = mpu_io; + config_mpu.irq = mpu_irq; + found_mpu = probe_mad16_mpu(&config_mpu); attach_mad16(&config); if (found_mpu) - attach_mad16_mpu(&config); + attach_mad16_mpu(&config_mpu); SOUND_LOCK; return 0; } -void -cleanup_module(void) +void cleanup_module(void) { if (found_mpu) unload_mad16_mpu(&config); diff -u --recursive --new-file v2.1.93/linux/drivers/sound/maui.c linux/drivers/sound/maui.c --- v2.1.93/linux/drivers/sound/maui.c Tue Mar 17 22:18:15 1998 +++ linux/drivers/sound/maui.c Wed Apr 8 17:24:48 1998 @@ -20,6 +20,7 @@ #include #include +#include #define USE_SEQ_MACROS #define USE_SIMPLE_MACROS @@ -452,6 +453,11 @@ #ifdef MODULE +MODULE_PARM(io,"i"); +MODULE_PARM(irq,"i"); + +EXPORT_NO_SYMBOLS; + int io = -1; int irq = -1; @@ -489,7 +495,7 @@ void cleanup_module(void) { if (fw_load && maui_os) - kfree(maui_os); + vfree(maui_os); unload_maui(&cfg); SOUND_LOCK_END; } diff -u --recursive --new-file v2.1.93/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c --- v2.1.93/linux/drivers/sound/midibuf.c Tue Mar 17 22:18:15 1998 +++ linux/drivers/sound/midibuf.c Wed Apr 8 17:24:48 1998 @@ -15,6 +15,7 @@ */ #include #include +#include #define MIDIBUF_C diff -u --recursive --new-file v2.1.93/linux/drivers/sound/opl3sa.c linux/drivers/sound/opl3sa.c --- v2.1.93/linux/drivers/sound/opl3sa.c Sat Nov 29 10:33:21 1997 +++ linux/drivers/sound/opl3sa.c Wed Apr 8 17:24:48 1998 @@ -3,14 +3,21 @@ * * Low level driver for Yamaha YMF701B aka OPL3-SA chip * - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. + * + * Changes: + * Alan Cox Modularisation + * + * FIXME: + * Check for install of mpu etc is wrong, should check result of the mss stuff */ + #include #undef SB_OK @@ -18,22 +25,21 @@ #include "sound_config.h" #ifdef SB_OK #include "sb.h" -static int sb_initialized = 0; +static int sb_initialized = 0; #endif #ifdef CONFIG_OPL3SA1 -static int kilroy_was_here = 0; /* Don't detect twice */ -static int mpu_initialized = 0; +static int kilroy_was_here = 0; /* Don't detect twice */ +static int mpu_initialized = 0; -static int *opl3sa_osp = NULL; +static int *opl3sa_osp = NULL; -static unsigned char -opl3sa_read(int addr) +static unsigned char opl3sa_read(int addr) { - unsigned long flags; - unsigned char tmp; + unsigned long flags; + unsigned char tmp; save_flags(flags); cli(); @@ -45,10 +51,9 @@ return tmp; } -static void -opl3sa_write(int addr, int data) +static void opl3sa_write(int addr, int data) { - unsigned long flags; + unsigned long flags; save_flags(flags); cli(); @@ -58,31 +63,32 @@ restore_flags(flags); } -static int -opl3sa_detect(void) +static int opl3sa_detect(void) { - int tmp; + int tmp; if (((tmp = opl3sa_read(0x01)) & 0xc4) != 0x04) - { - DDB(printk("OPL3-SA detect error 1 (%x)\n", opl3sa_read(0x01))); - /* return 0; */ - } -/* - * Check that the password feature has any effect - */ + { + DDB(printk("OPL3-SA detect error 1 (%x)\n", opl3sa_read(0x01))); + /* return 0; */ + } + + /* + * Check that the password feature has any effect + */ + if (inb(0xf87) == tmp) - { - DDB(printk("OPL3-SA detect failed 2 (%x/%x)\n", tmp, inb(0xf87))); - return 0; - } + { + DDB(printk("OPL3-SA detect failed 2 (%x/%x)\n", tmp, inb(0xf87))); + return 0; + } tmp = (opl3sa_read(0x04) & 0xe0) >> 5; if (tmp != 0 && tmp != 1) - { - DDB(printk("OPL3-SA detect failed 3 (%d)\n", tmp)); - return 0; - } + { + DDB(printk("OPL3-SA detect failed 3 (%d)\n", tmp)); + return 0; + } DDB(printk("OPL3-SA mode %x detected\n", tmp)); opl3sa_write(0x01, 0x00); /* Disable MSS */ @@ -97,49 +103,50 @@ * OPL3-SA */ -int -probe_opl3sa_wss(struct address_info *hw_config) +int probe_opl3sa_wss(struct address_info *hw_config) { - int ret; - unsigned char tmp = 0x24; /* WSS enable */ + int ret; + unsigned char tmp = 0x24; /* WSS enable */ if (check_region(0xf86, 2)) /* Control port is busy */ return 0; /* - * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (OPL3-SA for example) - * return 0x00. + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (OPL3-SA for example) + * return 0x00. */ + if (check_region(hw_config->io_base, 8)) - { - printk("OPL3-SA: MSS I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } + { + printk(KERN_ERR "OPL3-SA: MSS I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } opl3sa_osp = hw_config->osp; if (!opl3sa_detect()) - { - printk("OSS: OPL3-SA chip not found\n"); - return 0; - } + { + printk(KERN_ERR "OSS: OPL3-SA chip not found\n"); + return 0; + } + switch (hw_config->io_base) - { - case 0x530: - tmp |= 0x00; - break; - case 0xe80: - tmp |= 0x08; - break; - case 0xf40: - tmp |= 0x10; - break; - case 0x604: - tmp |= 0x18; - break; - default: - printk("OSS: Unsupported OPL3-SA/WSS base %x\n", hw_config->io_base); + { + case 0x530: + tmp |= 0x00; + break; + case 0xe80: + tmp |= 0x08; + break; + case 0xf40: + tmp |= 0x10; + break; + case 0x604: + tmp |= 0x18; + break; + default: + printk(KERN_ERR "OSS: Unsupported OPL3-SA/WSS base %x\n", hw_config->io_base); return 0; - } + } opl3sa_write(0x01, tmp); /* WSS setup register */ kilroy_was_here = 1; @@ -151,23 +158,21 @@ return ret; } -void -attach_opl3sa_wss(struct address_info *hw_config) +void attach_opl3sa_wss(struct address_info *hw_config) { - int nm = num_mixers; + int nm = num_mixers; attach_ms_sound(hw_config); if (num_mixers > nm) /* A mixer was installed */ - { - AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD); - AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH); - AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE); - } + { + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD); + AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH); + AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE); + } } -void -attach_opl3sa_mpu(struct address_info *hw_config) +void attach_opl3sa_mpu(struct address_info *hw_config) { #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) hw_config->name = "OPL3-SA (MPU401)"; @@ -175,55 +180,54 @@ #endif } -int -probe_opl3sa_mpu(struct address_info *hw_config) +int probe_opl3sa_mpu(struct address_info *hw_config) { #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - unsigned char conf; - static char irq_bits[] = - {-1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4}; + unsigned char conf; + static char irq_bits[] = { + -1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4 + }; if (!kilroy_was_here) - { - return 0; /* OPL3-SA has not been detected earlier */ - } + return 0; /* OPL3-SA has not been detected earlier */ + if (mpu_initialized) - { - DDB(printk("OPL3-SA: MPU mode already initialized\n")); - return 0; - } + { + DDB(printk("OPL3-SA: MPU mode already initialized\n")); + return 0; + } if (check_region(hw_config->io_base, 4)) - { - printk("OPL3-SA: MPU I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } + { + printk(KERN_ERR "OPL3-SA: MPU I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } if (hw_config->irq > 10) - { - printk("OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } + { + printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); + return 0; + } if (irq_bits[hw_config->irq] == -1) - { - printk("OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } + { + printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); + return 0; + } switch (hw_config->io_base) - { - case 0x330: - conf = 0x00; - break; - case 0x332: - conf = 0x20; - break; - case 0x334: - conf = 0x40; - break; - case 0x300: - conf = 0x60; - break; - default: - return 0; /* Invalid port */ - } + { + case 0x330: + conf = 0x00; + break; + case 0x332: + conf = 0x20; + break; + case 0x334: + conf = 0x40; + break; + case 0x300: + conf = 0x60; + break; + default: + return 0; /* Invalid port */ + } conf |= 0x83; /* MPU & OPL3 (synth) & game port enable */ conf |= irq_bits[hw_config->irq] << 2; @@ -238,10 +242,9 @@ #endif } -void -unload_opl3sa_wss(struct address_info *hw_config) +void unload_opl3sa_wss(struct address_info *hw_config) { - int dma2 = hw_config->dma2; + int dma2 = hw_config->dma2; if (dma2 == -1) dma2 = hw_config->dma; @@ -256,16 +259,15 @@ 0); } -void -unload_opl3sa_mpu(struct address_info *hw_config) +void unload_opl3sa_mpu(struct address_info *hw_config) { #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unload_uart401(hw_config); #endif } + #ifdef SB_OK -void -unload_opl3sa_sb(struct address_info *hw_config) +void unload_opl3sa_sb(struct address_info *hw_config) { #ifdef CONFIG_SBDSP sb_dsp_unload(hw_config); @@ -273,5 +275,60 @@ } #endif +#ifdef MODULE +int io = -1; +int irq = -1; +int dma = -1; +int dma2 = -1; + +int mpu_io = -1; +int mpu_irq = -1; + +MODULE_PARM(io,"i"); +MODULE_PARM(irq,"i"); +MODULE_PARM(dma,"i"); +MODULE_PARM(dma2,"i"); +MODULE_PARM(mpu_io,"i"); +MODULE_PARM(mpu_irq,"i"); + +struct address_info cfg; +struct address_info mpu_cfg; + +int init_module(void) +{ + if (io == -1 || irq == -1 || dma == -1) + { + printk(KERN_ERR "opl3sa: dma, irq and io must be set.\n"); + return -EINVAL; + } + cfg.io_base = io; + cfg.irq = irq; + cfg.dma = dma; + cfg.dma2 = dma2; + + mpu_cfg.io_base = mpu_io; + mpu_cfg.irq = mpu_irq; + + if (probe_opl3sa_wss(&cfg) == 0) + return -ENODEV; + + found_mpu=probe_opl3_mpu(&mpu_cfg); + + attach_opl3sa_wss(&cfg); + if(found_mpu) + attach_opl3sa_mpu(&mpu_cfg); + SOUND_LOCK; + return 0; +} + +void cleanup_module(void) +{ + if(found_mpu) + unload_opl3sa_mpu(&mpu_cfg); + unload_opl3sa(&cfg); + SOUND_LOCK_END; +} + +#endif #endif diff -u --recursive --new-file v2.1.93/linux/drivers/sound/os.h linux/drivers/sound/os.h --- v2.1.93/linux/drivers/sound/os.h Mon Feb 23 18:12:09 1998 +++ linux/drivers/sound/os.h Wed Apr 8 17:24:48 1998 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -32,7 +33,6 @@ #include #include #include -#include #endif #include @@ -52,7 +52,6 @@ #define USE_AUTOINIT_DMA extern caddr_t sound_mem_blocks[1024]; -extern int sound_mem_sizes[1024]; extern int sound_nblocks; #undef PSEUDO_DMA_AUTOINIT diff -u --recursive --new-file v2.1.93/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c --- v2.1.93/linux/drivers/sound/pas2_card.c Thu Mar 26 15:57:04 1998 +++ linux/drivers/sound/pas2_card.c Wed Apr 8 17:24:48 1998 @@ -164,7 +164,7 @@ } else { - if (request_irq(pas_irq, pasintr, 0, "PAS16", NULL) < 0) + if (request_irq(pas_irq, pasintr, 0, "PAS16",NULL) < 0) ok = 0; } } diff -u --recursive --new-file v2.1.93/linux/drivers/sound/pss.c linux/drivers/sound/pss.c --- v2.1.93/linux/drivers/sound/pss.c Tue Mar 17 22:18:15 1998 +++ linux/drivers/sound/pss.c Wed Apr 8 17:24:48 1998 @@ -2,18 +2,29 @@ * sound/pss.c * * The low level driver for the Personal Sound System (ECHO ESC614). - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. - */ -/* + * + * * Thomas Sailer ioctl code reworked (vmalloc/vfree removed) * Alan Cox modularisation, clean up. + * + * 98-02-21: Vladimir Michl + * Added mixer device for Beethoven ADSP-16 (master volume, + * bass, treble, synth), only for speakers. + * Fixed bug in pss_write (exchange parameters) + * Fixed config port of SB + * Requested two regions for PSS (PSS mixer, PSS config) + * Modified pss_download_boot + * To probe_pss_mss added test for initialize AD1848 */ + + #include #include @@ -39,7 +50,7 @@ */ #define CONF_PSS 0x10 #define CONF_WSS 0x12 -#define CONF_SB 0x13 +#define CONF_SB 0x14 #define CONF_CDROM 0x16 #define CONF_MIDI 0x18 @@ -53,6 +64,20 @@ #define PSS_WRITE_EMPTY 0x8000 #define PSS_READ_FULL 0x4000 +/* + * WSS registers + */ +#define WSS_INDEX 4 +#define WSS_DATA 5 + +/* + * WSS status bits + */ +#define WSS_INITIALIZING 0x80 +#define WSS_AUTOCALIBRATION 0x20 + +#define NO_WSS_MIXER -1 + #include "coproc.h" #ifdef CONFIG_PSS_HAVE_BOOT @@ -62,23 +87,32 @@ static int pss_synthLen = 0; #endif -typedef struct pss_confdata -{ - int base; - int irq; - int dma; - int *osp; -} - -pss_confdata; +unsigned char pss_mixer = 1; +typedef struct pss_mixerdata { + unsigned int volume_l; + unsigned int volume_r; + unsigned int bass; + unsigned int treble; + unsigned int synth; +} pss_mixerdata; + +typedef struct pss_confdata { + int base; + int irq; + int dma; + int *osp; + pss_mixerdata mixer; + int ad_mixer_dev; +} pss_confdata; + static pss_confdata pss_data; static pss_confdata *devc = &pss_data; static int pss_initialized = 0; static int nonstandard_microcode = 0; -static void pss_write(int data) +static void pss_write(pss_confdata *devc, int data) { int i, limit; @@ -92,14 +126,14 @@ */ for (i = 0; i < 5000000 && jiffies < limit; i++) - { - if (inw(devc->base + PSS_STATUS) & PSS_WRITE_EMPTY) - { - outw(devc->base + PSS_DATA, data); - return; - } - } - printk(KERN_ERR "PSS: DSP Command (%04x) Timeout.\n", data); + { + if (inw(REG(PSS_STATUS)) & PSS_WRITE_EMPTY) + { + outw(data, REG(PSS_DATA)); + return; + } + } + printk(KERN_WARNING "PSS: DSP Command (%04x) Timeout.\n", data); } int probe_pss(struct address_info *hw_config) @@ -116,7 +150,7 @@ if (devc->base != 0x230 && devc->base != 0x250) /* Some cards use these */ return 0; - if (check_region(devc->base, 16)) { + if (check_region(devc->base, 0x19 /*16*/)) { printk(KERN_ERR "PSS: I/O port conflict\n"); return 0; } @@ -249,7 +283,7 @@ pss_reset_dsp(devc); } count = 1; - while (1) + while ((flags&CPF_LAST) || count= size) + { + /* If not data in block send 0xffff */ + outw (0xffff, REG (PSS_DATA)); + } + else + { + /*_____ Send the next byte */ + outw (*block++, REG (PSS_DATA)); + }; count++; } @@ -309,6 +353,237 @@ return 1; } +/* Mixer */ +static void set_master_volume(pss_confdata *devc, int left, int right) +{ + static unsigned char log_scale[101] = { + 0xdb, 0xe0, 0xe3, 0xe5, 0xe7, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xed, 0xee, + 0xef, 0xef, 0xf0, 0xf0, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, + 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, + 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, + 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, + 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xfe, 0xfe, 0xff, 0xff, 0xff + }; + pss_write(devc, 0x0010); + pss_write(devc, log_scale[left] | 0x0000); + pss_write(devc, 0x0010); + pss_write(devc, log_scale[right] | 0x0100); +} + +static void set_synth_volume(pss_confdata *devc, int volume) +{ + /* Should use: + int vol = (int)(0x8000/100.0 * (float)volume); + + Fixme: integerise the above cleanly + */ + int vol = (0x8000/(100L*volume)); + pss_write(devc, 0x0080); + pss_write(devc, vol); + pss_write(devc, 0x0081); + pss_write(devc, vol); +} + +static void set_bass(pss_confdata *devc, int level) +{ + /* Should use + int vol = (int)((0xfd - 0xf0)/100.0 * (float)level) + 0xf0; + + Fixme: integerise cleanly + */ + int vol = (int)((0xfd - 0xf0)/100L * level) + 0xf0; + pss_write(devc, 0x0010); + pss_write(devc, vol | 0x0200); +}; + +static void set_treble(pss_confdata *devc, int level) +{ + /* Should use + int vol = (int)((0xfd - 0xf0)/100.0 * (float)level) + 0xf0; + + Fixme: integerise properly + */ + + int vol = ((0xfd - 0xf0)/100L * level) + 0xf0; + pss_write(devc, 0x0010); + pss_write(devc, vol | 0x0300); +}; + +static void pss_mixer_reset(pss_confdata *devc) +{ + set_master_volume(devc, 23, 23); + set_bass(devc, 50); + set_treble(devc, 50); + set_synth_volume(devc, 30); + pss_write (devc, 0x0010); + pss_write (devc, 0x0800 | 0xce); /* Stereo */ + + if(pss_mixer) + { + devc->mixer.volume_l = devc->mixer.volume_r = 23; + devc->mixer.bass = 50; + devc->mixer.treble = 50; + devc->mixer.synth = 30; + } +} + +static void arg_to_volume_mono(unsigned int volume, int *aleft) +{ + int left; + + left = volume & 0x00ff; + if (left > 100) + left = 100; + *aleft = left; +} + +static void arg_to_volume_stereo(unsigned int volume, int *aleft, int *aright) +{ + arg_to_volume_mono(volume, aleft); + arg_to_volume_mono(volume >> 8, aright); +} + +static int ret_vol_mono(int left) +{ + return ((left << 8) | left); +} + +static int ret_vol_stereo(int left, int right) +{ + return ((right << 8) | left); +} + +static int call_ad_mixer(pss_confdata *devc,unsigned int cmd, caddr_t arg) +{ + if (devc->ad_mixer_dev != NO_WSS_MIXER) + return mixer_devs[devc->ad_mixer_dev]->ioctl(devc->ad_mixer_dev, cmd, arg); + else + return -EINVAL; +} + +static int pss_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +{ + pss_confdata *devc = mixer_devs[dev]->devc; + int cmdf = cmd & 0xff; + + if ((cmdf != SOUND_MIXER_VOLUME) && (cmdf != SOUND_MIXER_BASS) && + (cmdf != SOUND_MIXER_TREBLE) && (cmdf != SOUND_MIXER_SYNTH) && + (cmdf != SOUND_MIXER_DEVMASK) && (cmdf != SOUND_MIXER_STEREODEVS) && + (cmdf != SOUND_MIXER_RECMASK) && (cmdf != SOUND_MIXER_CAPS) && + (cmdf != SOUND_MIXER_RECSRC)) + { + return call_ad_mixer(devc, cmd, arg); + } + + if (((cmd >> 8) & 0xff) != 'M') + return -EINVAL; + + if (_SIOC_DIR (cmd) & _SIOC_WRITE) + { + switch (cmdf) + { + case SOUND_MIXER_RECSRC: + if (devc->ad_mixer_dev != NO_WSS_MIXER) + return call_ad_mixer(devc, cmd, arg); + else + { + if (*(int *)arg != 0) + return -EINVAL; + return 0; + } + case SOUND_MIXER_VOLUME: + arg_to_volume_stereo(*(unsigned int *)arg, &devc->mixer.volume_l, + &devc->mixer.volume_r); + set_master_volume(devc, devc->mixer.volume_l, + devc->mixer.volume_r); + return ret_vol_stereo(devc->mixer.volume_l, + devc->mixer.volume_r); + + case SOUND_MIXER_BASS: + arg_to_volume_mono(*(unsigned int *)arg, + &devc->mixer.bass); + set_bass(devc, devc->mixer.bass); + return ret_vol_mono(devc->mixer.bass); + + case SOUND_MIXER_TREBLE: + arg_to_volume_mono(*(unsigned int *)arg, + &devc->mixer.treble); + set_treble(devc, devc->mixer.treble); + return ret_vol_mono(devc->mixer.treble); + + case SOUND_MIXER_SYNTH: + arg_to_volume_mono(*(unsigned int *)arg, + &devc->mixer.synth); + set_synth_volume(devc, devc->mixer.synth); + return ret_vol_mono(devc->mixer.synth); + + default: + return -EINVAL; + } + } + else + { + /* + * Return parameters + */ + switch (cmdf) + { + + case SOUND_MIXER_DEVMASK: + if (call_ad_mixer(devc, cmd, arg) == -EINVAL) + *(int *)arg = 0; /* no mixer devices */ + return (*(int *)arg |= SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_SYNTH); + + case SOUND_MIXER_STEREODEVS: + if (call_ad_mixer(devc, cmd, arg) == -EINVAL) + *(int *)arg = 0; /* no stereo devices */ + return (*(int *)arg |= SOUND_MASK_VOLUME); + + case SOUND_MIXER_RECMASK: + if (devc->ad_mixer_dev != NO_WSS_MIXER) + return call_ad_mixer(devc, cmd, arg); + else + return (*(int *)arg = 0); /* no record devices */ + + case SOUND_MIXER_CAPS: + if (devc->ad_mixer_dev != NO_WSS_MIXER) + return call_ad_mixer(devc, cmd, arg); + else + return (*(int *)arg = SOUND_CAP_EXCL_INPUT); + + case SOUND_MIXER_RECSRC: + if (devc->ad_mixer_dev != NO_WSS_MIXER) + return call_ad_mixer(devc, cmd, arg); + else + return (*(int *)arg = 0); /* no record source */ + + case SOUND_MIXER_VOLUME: + return (*(int *)arg = ret_vol_stereo(devc->mixer.volume_l, devc->mixer.volume_r)); + + case SOUND_MIXER_BASS: + return (*(int *)arg = ret_vol_mono(devc->mixer.bass)); + + case SOUND_MIXER_TREBLE: + return (*(int *)arg = ret_vol_mono(devc->mixer.treble)); + + case SOUND_MIXER_SYNTH: + return (*(int *)arg = ret_vol_mono(devc->mixer.synth)); + default: + return -EINVAL; + } + } +} + +static struct mixer_operations pss_mixer_operations = +{ + "SOUNDPORT", + "PSS-AD1848", + pss_mixer_ioctl +}; + void attach_pss(struct address_info *hw_config) { unsigned short id; @@ -318,10 +593,14 @@ devc->irq = hw_config->irq; devc->dma = hw_config->dma; devc->osp = hw_config->osp; + devc->ad_mixer_dev = NO_WSS_MIXER; if (!probe_pss(hw_config)) return; + request_region(hw_config->io_base, 0x10, "PSS mixer, SB emulation"); + request_region(hw_config->io_base + 0x10, 0x9, "PSS config"); + id = inw(REG(PSS_ID)) & 0x00ff; /* @@ -356,21 +635,6 @@ conf_printf(tmp, hw_config); } -static void pss_init_speaker(void) -{ -/* Don't ask what are these commands. I really don't know */ - pss_write(0x0010); - pss_write(0x0000 | 252); /* Left master volume */ - pss_write(0x0010); - pss_write(0x0100 | 252); /* Right master volume */ - pss_write(0x0010); - pss_write(0x0200 | 246); /* Bass */ - pss_write(0x0010); - pss_write(0x0300 | 246); /* Treble */ - pss_write(0x0010); - pss_write(0x0800 | 0x00ce); /* Stereo switch? */ -} - int probe_pss_mpu(struct address_info *hw_config) { int timeout; @@ -380,17 +644,17 @@ if (check_region(hw_config->io_base, 2)) { - printk("PSS: MPU I/O port conflict\n"); + printk(KERN_ERR "PSS: MPU I/O port conflict\n"); return 0; } if (!set_io_base(devc, CONF_MIDI, hw_config->io_base)) { - printk("PSS: MIDI base could not be set.\n"); + printk(KERN_ERR "PSS: MIDI base could not be set.\n"); return 0; } if (!set_irq(devc, CONF_MIDI, hw_config->irq)) { - printk("PSS: MIDI IRQ allocation error.\n"); + printk(KERN_ERR "PSS: MIDI IRQ allocation error.\n"); return 0; } if (!pss_synthLen) @@ -403,7 +667,6 @@ printk(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n"); return 0; } - pss_init_speaker(); /* * Finally wait until the DSP algorithm has initialized itself and @@ -709,28 +972,51 @@ * downloaded to the ADSP2115 spends some time initializing the card. * Let's try to wait until it finishes this task. */ - for (timeout = 0; - timeout < 100000 && (inb(hw_config->io_base + 3) & 0x3f) != 0x04; - timeout++); - - outb((0x0b), hw_config->io_base + 4); /* Required by some cards */ - - for (timeout = 0; - timeout < 100000; - timeout++); + for (timeout = 0; timeout < 100000 && (inb(hw_config->io_base + WSS_INDEX) & WSS_INITIALIZING); timeout++); + + outb((0x0b), hw_config->io_base + WSS_INDEX); /* Required by some cards */ + + for (timeout = 0; (inb(hw_config->io_base + WSS_DATA) & WSS_AUTOCALIBRATION) && (timeout < 100000); timeout++); + return probe_ms_sound(hw_config); } void attach_pss_mss(struct address_info *hw_config) { + int my_mix = -999; /* gcc shut up */ + + devc->ad_mixer_dev = NO_WSS_MIXER; + if (pss_mixer) + { + if ((my_mix = sound_install_mixer (MIXER_DRIVER_VERSION, + "PSS-SPEAKERS and AD1848 (through MSS audio codec)", + &pss_mixer_operations, + sizeof (struct mixer_operations), + devc)) < 0) + { + printk(KERN_ERR "Could not install PSS mixer\n"); + return; + } + } + pss_mixer_reset(devc); attach_ms_sound(hw_config); /* Slot 0 */ - if (hw_config->slots[0] != -1) /* The MSS driver installed itself */ + if (hw_config->slots[0] != -1) + { + /* The MSS driver installed itself */ audio_devs[hw_config->slots[0]]->coproc = &pss_coproc_operations; + if (pss_mixer && (num_mixers == (my_mix + 2))) + { + /* The MSS mixer installed */ + devc->ad_mixer_dev = audio_devs[hw_config->slots[0]]->mixer_dev; + } + } } void unload_pss(struct address_info *hw_config) { + release_region(hw_config->io_base, 0x10); + release_region(hw_config->io_base+0x10, 0x9); } void unload_pss_mpu(struct address_info *hw_config) @@ -761,11 +1047,21 @@ struct address_info cfgmss = { 0 /* mss_io */, 0 /* mss_irq */, 0 /* mss_dma */, -1 }; MODULE_PARM(pss_io, "i"); +MODULE_PARM_DESC(pss_io, "Set i/o base of PSS card (probably 0x220 or 0x240)"); MODULE_PARM(mss_io, "i"); +MODULE_PARM_DESC(mss_io, "Set WSS (audio) i/o base (0x530, 0x604, 0xE80, 0xF40, or other. Address must end in 0 or 4 and must be from 0x100 to 0xFF4)"); MODULE_PARM(mss_irq, "i"); +MODULE_PARM_DESC(mss_irq, "Set WSS (audio) IRQ (3, 5, 7, 9, 10, 11, 12)"); MODULE_PARM(mss_dma, "i"); +MODULE_PARM_DESC(mss_dma, "Set WSS (audio) DMA (0, 1, 3)"); MODULE_PARM(mpu_io, "i"); +MODULE_PARM_DESC(mpu_io, "Set MIDI i/o base (0x330 or other. Address must be on 4 location boundaries and must be from 0x100 to 0xFFC)"); MODULE_PARM(mpu_irq, "i"); +MODULE_PARM_DESC(mpu_irq, "Set MIDI IRQ (3, 5, 7, 9, 10, 11, 12)"); +MODULE_PARM(pss_mixer, "b"); +MODULE_PARM_DESC(pss_mixer, "Enable (1) or disable (0) PSS mixer (controlling of output volume, bass, treble synth volume). The mixer is not available on all PSS cards."); +MODULE_AUTHOR("Hannu Savolainen, Vladimir Michl"); +MODULE_DESCRIPTION("Module for PSS sound cards (based on AD1848, ADSP-2115 and ESC614). This module includes control of output amplifier and synth volume of the Beethoven ADSP-16 card (this may work with other PSS cards).\n"); static int fw_load = 0; static int pssmpu = 0, pssmss = 0; @@ -816,7 +1112,7 @@ void cleanup_module(void) { if (fw_load && pss_synth) - kfree(pss_synth); + vfree(pss_synth); if (pssmss) unload_pss_mss(&cfgmss); if (pssmpu) @@ -825,5 +1121,4 @@ SOUND_LOCK_END; } #endif - #endif diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sb.h linux/drivers/sound/sb.h --- v2.1.93/linux/drivers/sound/sb.h Tue Dec 23 13:52:02 1997 +++ linux/drivers/sound/sb.h Wed Apr 8 17:24:48 1998 @@ -47,6 +47,8 @@ #define MDL_ES1868MIDI 14 /* MIDI port of ESS1868 */ #define MDL_AEDSP 15 /* Audio Excel DSP 16 */ +#define SUBMDL_ALS007 42 /* ALS-007 differs from SB16 only in mixer */ + /* register assignment */ /* * Config flags */ diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sb_audio.c linux/drivers/sound/sb_audio.c --- v2.1.93/linux/drivers/sound/sb_audio.c Tue Mar 17 22:18:15 1998 +++ linux/drivers/sound/sb_audio.c Wed Apr 8 17:24:48 1998 @@ -2,17 +2,22 @@ * sound/sb_audio.c * * Audio routines for Sound Blaster compatible cards. - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. + * + * Changes + * Alan Cox : Formatting and clean ups + * + * Status + * Mostly working. mmap bug still present (swaps channels) */ -#include - +#include #include "sound_config.h" #if defined(CONFIG_SBDSP) || defined(MODULE) @@ -20,67 +25,84 @@ #include "sb_mixer.h" #include "sb.h" -static int -sb_audio_open(int dev, int mode) +static int sb_audio_open(int dev, int mode) { - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; if (devc == NULL) - { - printk("SB: Incomplete initialization\n"); + { + printk(KERN_ERR "SB: Incomplete initialization\n"); return -ENXIO; - } + } if (devc->caps & SB_NO_RECORDING && mode & OPEN_READ) - { - printk("Notice: Recording is not possible with /dev/dsp%d\n", dev); - if (mode == OPEN_READ) - return -EPERM; - } + { + if (mode == OPEN_READ) + return -EPERM; + } save_flags(flags); cli(); if (devc->opened) - { + { restore_flags(flags); return -EBUSY; - } + } if (devc->dma16 != -1 && devc->dma16 != devc->dma8) - { - if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit")) - { - restore_flags(flags); - return -EBUSY; - } - } + { + if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit")) + { + restore_flags(flags); + return -EBUSY; + } + } devc->opened = mode; restore_flags(flags); devc->irq_mode = IMODE_NONE; sb_dsp_reset(devc); + /* The ALS007 seems to require that the DSP be removed from the output */ + /* in order for recording to be activated properly. This is done by */ + /* setting the appropriate bits of the output control register 4ch to */ + /* zero. This code assumes that the output control registers are not */ + /* used anywhere else and therefore the DSP bits are *always* ON for */ + /* output and OFF for sampling. */ + + if (devc->submodel == SUBMDL_ALS007) + { + if (mode & OPEN_READ) + sb_setmixer(devc,ALS007_OUTPUT_CTRL2, + sb_getmixer(devc,ALS007_OUTPUT_CTRL2) & 0xf9); + else + sb_setmixer(devc,ALS007_OUTPUT_CTRL2, + sb_getmixer(devc,ALS007_OUTPUT_CTRL2) | 0x06); + } return 0; } -static void -sb_audio_close(int dev) +static void sb_audio_close(int dev) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - audio_devs[dev]->dmap_in->dma = - audio_devs[dev]->dmap_out->dma = - devc->dma8; + audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma = devc->dma8; if (devc->dma16 != -1 && devc->dma16 != devc->dma8) sound_close_dma(devc->dma16); + /* For ALS007, turn DSP output back on if closing the device for read */ + + if ((devc->submodel == SUBMDL_ALS007) && (devc->opened & OPEN_READ)) + { + sb_setmixer(devc,ALS007_OUTPUT_CTRL2, + sb_getmixer(devc,ALS007_OUTPUT_CTRL2) | 0x06); + } devc->opened = 0; } -static void -sb_set_output_parms(int dev, unsigned long buf, int nr_bytes, +static void sb_set_output_parms(int dev, unsigned long buf, int nr_bytes, int intrflag) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; devc->trg_buf = buf; devc->trg_bytes = nr_bytes; @@ -88,10 +110,9 @@ devc->irq_mode = IMODE_OUTPUT; } -static void -sb_set_input_parms(int dev, unsigned long buf, int count, int intrflag) +static void sb_set_input_parms(int dev, unsigned long buf, int count, int intrflag) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; devc->trg_buf = buf; devc->trg_bytes = count; @@ -103,13 +124,11 @@ * SB1.x compatible routines */ -static void -sb1_audio_output_block(int dev, unsigned long buf, int nr_bytes, - int intrflag) +static void sb1_audio_output_block(int dev, unsigned long buf, int nr_bytes, int intrflag) { - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ @@ -122,21 +141,21 @@ save_flags(flags); cli(); if (sb_dsp_command(devc, 0x14)) /* 8 bit DAC using DMA */ - { - sb_dsp_command(devc, (unsigned char) (count & 0xff)); - sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); - } else - printk("SB: Unable to start DAC\n"); + { + sb_dsp_command(devc, (unsigned char) (count & 0xff)); + sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); + } + else + printk(KERN_WARNING "soundblaster: Unable to start DAC\n"); restore_flags(flags); devc->intr_active = 1; } -static void -sb1_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag) +static void sb1_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag) { - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; /* * Start a DMA input to the buffer pointed by dmaqtail @@ -153,49 +172,47 @@ save_flags(flags); cli(); if (sb_dsp_command(devc, 0x24)) /* 8 bit ADC using DMA */ - { - sb_dsp_command(devc, (unsigned char) (count & 0xff)); - sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); - } else - printk("SB Error: Unable to start ADC\n"); + { + sb_dsp_command(devc, (unsigned char) (count & 0xff)); + sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); + } + else + printk(KERN_ERR "soundblaster: Unable to start ADC\n"); restore_flags(flags); devc->intr_active = 1; } -static void -sb1_audio_trigger(int dev, int bits) +static void sb1_audio_trigger(int dev, int bits) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; bits &= devc->irq_mode; if (!bits) sb_dsp_command(devc, 0xd0); /* Halt DMA */ else - { - switch (devc->irq_mode) - { - case IMODE_INPUT: - sb1_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - - case IMODE_OUTPUT: - sb1_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - } - } + { + switch (devc->irq_mode) + { + case IMODE_INPUT: + sb1_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + case IMODE_OUTPUT: + sb1_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; + } + } devc->trigger_bits = bits; } -static int -sb1_audio_prepare_for_input(int dev, int bsize, int bcount) +static int sb1_audio_prepare_for_input(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; save_flags(flags); cli(); @@ -208,11 +225,10 @@ return 0; } -static int -sb1_audio_prepare_for_output(int dev, int bsize, int bcount) +static int sb1_audio_prepare_for_output(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; save_flags(flags); cli(); @@ -224,55 +240,48 @@ return 0; } -static int -sb1_audio_set_speed(int dev, int speed) +static int sb1_audio_set_speed(int dev, int speed) { - int max_speed = 23000; - sb_devc *devc = audio_devs[dev]->devc; - int tmp; + int max_speed = 23000; + sb_devc *devc = audio_devs[dev]->devc; + int tmp; if (devc->opened & OPEN_READ) max_speed = 13000; if (speed > 0) - { - if (speed < 4000) - speed = 4000; - - if (speed > max_speed) - speed = max_speed; + { + if (speed < 4000) + speed = 4000; - devc->tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; + if (speed > max_speed) + speed = max_speed; - tmp = 256 - devc->tconst; - speed = (1000000 + tmp / 2) / tmp; + devc->tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; + tmp = 256 - devc->tconst; + speed = (1000000 + tmp / 2) / tmp; - devc->speed = speed; - } + devc->speed = speed; + } return devc->speed; } -static short -sb1_audio_set_channels(int dev, short channels) +static short sb1_audio_set_channels(int dev, short channels) { - sb_devc *devc = audio_devs[dev]->devc; - + sb_devc *devc = audio_devs[dev]->devc; return devc->channels = 1; } -static unsigned int -sb1_audio_set_bits(int dev, unsigned int bits) +static unsigned int sb1_audio_set_bits(int dev, unsigned int bits) { sb_devc *devc = audio_devs[dev]->devc; - return devc->bits = 8; } -static void -sb1_audio_halt_xfer(int dev) +static void sb1_audio_halt_xfer(int dev) { - unsigned long flags; - sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + sb_devc *devc = audio_devs[dev]->devc; save_flags(flags); cli(); @@ -284,14 +293,13 @@ * SB 2.0 and SB 2.01 compatible routines */ -static void -sb20_audio_output_block(int dev, unsigned long buf, int nr_bytes, +static void sb20_audio_output_block(int dev, unsigned long buf, int nr_bytes, int intrflag) { - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - unsigned char cmd; + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + unsigned char cmd; /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ @@ -304,31 +312,30 @@ save_flags(flags); cli(); if (sb_dsp_command(devc, 0x48)) /* DSP Block size */ - { - sb_dsp_command(devc, (unsigned char) (count & 0xff)); - sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); - - if (devc->speed * devc->channels <= 23000) - cmd = 0x1c; /* 8 bit PCM output */ - else - cmd = 0x90; /* 8 bit high speed PCM output (SB2.01/Pro) */ + { + sb_dsp_command(devc, (unsigned char) (count & 0xff)); + sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); - if (!sb_dsp_command(devc, cmd)) - printk("SB: Unable to start DAC\n"); + if (devc->speed * devc->channels <= 23000) + cmd = 0x1c; /* 8 bit PCM output */ + else + cmd = 0x90; /* 8 bit high speed PCM output (SB2.01/Pro) */ - } else - printk("SB: Unable to start DAC\n"); + if (!sb_dsp_command(devc, cmd)) + printk(KERN_ERR "soundblaster: Unable to start DAC\n"); + } + else + printk(KERN_ERR "soundblaster: Unable to start DAC\n"); restore_flags(flags); devc->intr_active = 1; } -static void -sb20_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag) +static void sb20_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag) { - unsigned long flags; - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - unsigned char cmd; + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + unsigned char cmd; /* * Start a DMA input to the buffer pointed by dmaqtail @@ -345,49 +352,46 @@ save_flags(flags); cli(); if (sb_dsp_command(devc, 0x48)) /* DSP Block size */ - { - sb_dsp_command(devc, (unsigned char) (count & 0xff)); - sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); - - if (devc->speed * devc->channels <= (devc->major == 3 ? 23000 : 13000)) - cmd = 0x2c; /* 8 bit PCM input */ - else - cmd = 0x98; /* 8 bit high speed PCM input (SB2.01/Pro) */ - - if (!sb_dsp_command(devc, cmd)) - printk("SB: Unable to start ADC\n"); - } else - printk("SB Error: Unable to start ADC\n"); - restore_flags(flags); + { + sb_dsp_command(devc, (unsigned char) (count & 0xff)); + sb_dsp_command(devc, (unsigned char) ((count >> 8) & 0xff)); + if (devc->speed * devc->channels <= (devc->major == 3 ? 23000 : 13000)) + cmd = 0x2c; /* 8 bit PCM input */ + else + cmd = 0x98; /* 8 bit high speed PCM input (SB2.01/Pro) */ + + if (!sb_dsp_command(devc, cmd)) + printk(KERN_ERR "soundblaster: Unable to start ADC\n"); + } + else + printk(KERN_ERR "soundblaster: Unable to start ADC\n"); + restore_flags(flags); devc->intr_active = 1; } -static void -sb20_audio_trigger(int dev, int bits) +static void sb20_audio_trigger(int dev, int bits) { - sb_devc *devc = audio_devs[dev]->devc; - + sb_devc *devc = audio_devs[dev]->devc; bits &= devc->irq_mode; if (!bits) sb_dsp_command(devc, 0xd0); /* Halt DMA */ else - { - switch (devc->irq_mode) - { - case IMODE_INPUT: - sb20_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; + { + switch (devc->irq_mode) + { + case IMODE_INPUT: + sb20_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); + break; - case IMODE_OUTPUT: - sb20_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); + case IMODE_OUTPUT: + sb20_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag); break; - } - } - + } + } devc->trigger_bits = bits; } @@ -395,32 +399,26 @@ * SB2.01 specific speed setup */ -static int -sb201_audio_set_speed(int dev, int speed) +static int sb201_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; - int tmp; - int s = speed * devc->channels; + sb_devc *devc = audio_devs[dev]->devc; + int tmp; + int s = speed * devc->channels; if (speed > 0) - { - if (speed < 4000) - speed = 4000; - - if (speed > 44100) - speed = 44100; - - if (devc->opened & OPEN_READ && speed > 15000) - speed = 15000; - - devc->tconst = ((65536 - ((256000000 + s / 2) / - s)) >> 8) & 0xff; - - tmp = 256 - devc->tconst; - speed = ((1000000 + tmp / 2) / tmp) / devc->channels; + { + if (speed < 4000) + speed = 4000; + if (speed > 44100) + speed = 44100; + if (devc->opened & OPEN_READ && speed > 15000) + speed = 15000; + devc->tconst = ((65536 - ((256000000 + s / 2) / s)) >> 8) & 0xff; + tmp = 256 - devc->tconst; + speed = ((1000000 + tmp / 2) / tmp) / devc->channels; - devc->speed = speed; - } + devc->speed = speed; + } return devc->speed; } @@ -428,17 +426,15 @@ * SB Pro specific routines */ -static int -sbpro_audio_prepare_for_input(int dev, int bsize, int bcount) +static int sbpro_audio_prepare_for_input(int dev, int bsize, int bcount) { /* For SB Pro and Jazz16 */ - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - unsigned char bits = 0; + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + unsigned char bits = 0; if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) - audio_devs[dev]->dmap_out->dma = - audio_devs[dev]->dmap_in->dma = - devc->bits == 16 ? devc->dma16 : devc->dma8; + audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma = + devc->bits == 16 ? devc->dma16 : devc->dma8; if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) if (devc->bits == AFMT_S16_LE) @@ -459,18 +455,15 @@ return 0; } -static int -sbpro_audio_prepare_for_output(int dev, int bsize, int bcount) +static int sbpro_audio_prepare_for_output(int dev, int bsize, int bcount) { /* For SB Pro and Jazz16 */ - sb_devc *devc = audio_devs[dev]->devc; - unsigned long flags; - unsigned char tmp; - unsigned char bits = 0; + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + unsigned char tmp; + unsigned char bits = 0; if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) - audio_devs[dev]->dmap_out->dma = - audio_devs[dev]->dmap_in->dma = - devc->bits == 16 ? devc->dma16 : devc->dma8; + audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma = devc->bits == 16 ? devc->dma16 : devc->dma8; if (devc->model == MDL_SBPRO) sb_mixer_set_stereo(devc, devc->channels == 2); @@ -481,92 +474,83 @@ sb_dsp_command(devc, DSP_CMD_SPKON); if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) - { - if (devc->bits == AFMT_S16_LE) - bits = 0x04; /* 16 bit mode */ - - if (devc->channels == 1) - sb_dsp_command(devc, 0xa0 | bits); /* Mono output */ - else - sb_dsp_command(devc, 0xa8 | bits); /* Stereo output */ - } else - { - tmp = sb_getmixer(devc, 0x0e); - if (devc->channels == 1) - tmp &= ~0x02; - else - tmp |= 0x02; - sb_setmixer(devc, 0x0e, tmp); - } + { + if (devc->bits == AFMT_S16_LE) + bits = 0x04; /* 16 bit mode */ + + if (devc->channels == 1) + sb_dsp_command(devc, 0xa0 | bits); /* Mono output */ + else + sb_dsp_command(devc, 0xa8 | bits); /* Stereo output */ + } + else + { + tmp = sb_getmixer(devc, 0x0e); + if (devc->channels == 1) + tmp &= ~0x02; + else + tmp |= 0x02; + sb_setmixer(devc, 0x0e, tmp); + } restore_flags(flags); devc->trigger_bits = 0; return 0; } -static int -sbpro_audio_set_speed(int dev, int speed) +static int sbpro_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; if (speed > 0) - { - if (speed < 4000) - speed = 4000; - - if (speed > 44100) - speed = 44100; - - if (devc->channels > 1 && speed > 22050) - speed = 22050; - - sb201_audio_set_speed(dev, speed); - } + { + if (speed < 4000) + speed = 4000; + if (speed > 44100) + speed = 44100; + if (devc->channels > 1 && speed > 22050) + speed = 22050; + sb201_audio_set_speed(dev, speed); + } return devc->speed; } -static short -sbpro_audio_set_channels(int dev, short channels) +static short sbpro_audio_set_channels(int dev, short channels) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; if (channels == 1 || channels == 2) + { if (channels != devc->channels) - { - devc->channels = channels; - if (devc->model == MDL_SBPRO && devc->channels == 2) - { - if (devc->speed > 22050) - printk("OSS: Application error. Wrong ioctl call order.\n"); - sbpro_audio_set_speed(dev, devc->speed); - } - } + { + devc->channels = channels; + if (devc->model == MDL_SBPRO && devc->channels == 2) + sbpro_audio_set_speed(dev, devc->speed); + } + } return devc->channels; } -static int -jazz16_audio_set_speed(int dev, int speed) +static int jazz16_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; if (speed > 0) - { - int tmp; - int s = speed * devc->channels; - - if (speed < 5000) - speed = 4000; + { + int tmp; + int s = speed * devc->channels; - if (speed > 44100) - speed = 44100; + if (speed < 5000) + speed = 5000; + if (speed > 44100) + speed = 44100; - devc->tconst = ((65536 - ((256000000 + s / 2) / - s)) >> 8) & 0xff; + devc->tconst = ((65536 - ((256000000 + s / 2) / s)) >> 8) & 0xff; - tmp = 256 - devc->tconst; - speed = ((1000000 + tmp / 2) / tmp) / devc->channels; + tmp = 256 - devc->tconst; + speed = ((1000000 + tmp / 2) / tmp) / devc->channels; - devc->speed = speed; - } + devc->speed = speed; + } return devc->speed; } @@ -574,124 +558,123 @@ * ESS specific routines */ -static int -ess_audio_set_speed(int dev, int speed) +static int ess_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; - int divider; + sb_devc *devc = audio_devs[dev]->devc; + int divider; if (speed > 0) - { - if (speed < 5000) - speed = 4000; - - if (speed > 48000) - speed = 48000; - - if (speed > 22000) - { - divider = (795500 + speed / 2) / speed; - speed = (795500 + divider / 2) / divider; - } else - { - divider = (397700 + speed / 2) / speed; - speed = (397700 + divider / 2) / divider; - } + { + if (speed < 5000) + speed = 5000; + if (speed > 48000) + speed = 48000; - devc->speed = speed; - } + if (speed > 22000) + { + divider = (795500 + speed / 2) / speed; + speed = (795500 + divider / 2) / divider; + } + else + { + divider = (397700 + speed / 2) / speed; + speed = (397700 + divider / 2) / divider; + } + devc->speed = speed; + } return devc->speed; } -static void -ess_speed(sb_devc * devc) +static void ess_speed(sb_devc * devc) { - int divider; - unsigned char bits = 0; - int speed = devc->speed; + int divider; + unsigned char bits = 0; + int speed = devc->speed; if (speed < 4000) speed = 4000; else if (speed > 48000) speed = 48000; - + if (speed > 22000) - { - bits = 0x80; - divider = 256 - (795500 + speed / 2) / speed; - } else - { - divider = 128 - (397700 + speed / 2) / speed; - } + { + bits = 0x80; + divider = 256 - (795500 + speed / 2) / speed; + } + else + { + divider = 128 - (397700 + speed / 2) / speed; + } bits |= (unsigned char) divider; ess_write(devc, 0xa1, bits); -/* - * Set filter divider register - */ + /* + * Set filter divider register + */ speed = (speed * 9) / 20; /* Set filter roll-off to 90% of speed/2 */ divider = 256 - 7160000 / (speed * 82); ess_write(devc, 0xa2, divider); - return; } -static int -ess_audio_prepare_for_input(int dev, int bsize, int bcount) +static int ess_audio_prepare_for_input(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; - + sb_devc *devc = audio_devs[dev]->devc; ess_speed(devc); sb_dsp_command(devc, DSP_CMD_SPKOFF); ess_write(devc, 0xb8, 0x0e); /* Auto init DMA mode */ - ess_write(devc, 0xa8, (ess_read(devc, 0xa8) & ~0x03) | - (3 - devc->channels)); /* Mono/stereo */ + ess_write(devc, 0xa8, (ess_read(devc, 0xa8) & ~0x03) | (3 - devc->channels)); /* Mono/stereo */ ess_write(devc, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */ if (devc->channels == 1) - { - if (devc->bits == AFMT_U8) - { /* 8 bit mono */ - ess_write(devc, 0xb7, 0x51); - ess_write(devc, 0xb7, 0xd0); - } else - { /* 16 bit mono */ - ess_write(devc, 0xb7, 0x71); - ess_write(devc, 0xb7, 0xf4); - } - } else - { /* Stereo */ - if (devc->bits == AFMT_U8) - { /* 8 bit stereo */ - ess_write(devc, 0xb7, 0x51); - ess_write(devc, 0xb7, 0x98); - } else - { /* 16 bit stereo */ - ess_write(devc, 0xb7, 0x71); - ess_write(devc, 0xb7, 0xbc); - } - } - + { + if (devc->bits == AFMT_U8) + { + /* 8 bit mono */ + ess_write(devc, 0xb7, 0x51); + ess_write(devc, 0xb7, 0xd0); + } + else + { + /* 16 bit mono */ + ess_write(devc, 0xb7, 0x71); + ess_write(devc, 0xb7, 0xf4); + } + } + else + { + /* Stereo */ + if (devc->bits == AFMT_U8) + { + /* 8 bit stereo */ + ess_write(devc, 0xb7, 0x51); + ess_write(devc, 0xb7, 0x98); + } + else + { + /* 16 bit stereo */ + ess_write(devc, 0xb7, 0x71); + ess_write(devc, 0xb7, 0xbc); + } + } ess_write(devc, 0xb1, (ess_read(devc, 0xb1) & 0x0f) | 0x50); ess_write(devc, 0xb2, (ess_read(devc, 0xb2) & 0x0f) | 0x50); - devc->trigger_bits = 0; return 0; } static int ess_audio_prepare_for_output(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; sb_dsp_reset(devc); ess_speed(devc); ess_write(devc, 0xb8, 4); /* Auto init DMA mode */ - ess_write(devc, 0xa8, (ess_read(devc, 0xa8) & ~0x03) | - (3 - devc->channels)); /* Mono/stereo */ + ess_write(devc, 0xa8, (ess_read(devc, 0xa8) & ~0x03) | (3 - devc->channels)); /* Mono/stereo */ ess_write(devc, 0xb9, 2); /* Demand mode (4 bytes/request) */ if (devc->channels == 1) @@ -701,7 +684,8 @@ ess_write(devc, 0xb6, 0x80); ess_write(devc, 0xb7, 0x51); ess_write(devc, 0xb7, 0xd0); - } else + } + else { /* 16 bit mono */ ess_write(devc, 0xb6, 0x00); ess_write(devc, 0xb7, 0x71); @@ -733,11 +717,11 @@ } static void ess_audio_output_block(int dev, unsigned long buf, int nr_bytes, - int intrflag) + int intrflag) { - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - short c = -nr_bytes; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + short c = -nr_bytes; /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); */ @@ -756,9 +740,9 @@ static void ess_audio_start_input(int dev, unsigned long buf, int nr_bytes, int intrflag) { - int count = nr_bytes; - sb_devc *devc = audio_devs[dev]->devc; - short c = -nr_bytes; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + short c = -nr_bytes; /* * Start a DMA input to the buffer pointed by dmaqtail @@ -781,7 +765,7 @@ static void ess_audio_trigger(int dev, int bits) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; bits &= devc->irq_mode; @@ -812,7 +796,7 @@ static int sb16_audio_set_speed(int dev, int speed) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; if (speed > 0) { @@ -829,7 +813,7 @@ static unsigned int sb16_audio_set_bits(int dev, unsigned int bits) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; if (bits != 0) { @@ -844,7 +828,7 @@ static int sb16_audio_prepare_for_input(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma = @@ -856,11 +840,10 @@ static int sb16_audio_prepare_for_output(int dev, int bsize, int bcount) { - sb_devc *devc = audio_devs[dev]->devc; + sb_devc *devc = audio_devs[dev]->devc; - audio_devs[dev]->dmap_out->dma = - audio_devs[dev]->dmap_in->dma = - devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; + audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma = + devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; devc->trigger_bits = 0; return 0; @@ -1098,8 +1081,8 @@ void sb_audio_init(sb_devc * devc, char *name) { - int audio_flags = 0; - int format_mask = AFMT_U8; + int audio_flags = 0; + int format_mask = AFMT_U8; struct audio_driver *driver = &sb1_audio_driver; @@ -1151,14 +1134,9 @@ } if ((devc->my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, - name, - driver, - sizeof(struct audio_driver), - audio_flags, - format_mask, - devc, - devc->dma8, - devc->dma8)) < 0) + name,driver, sizeof(struct audio_driver), + audio_flags, format_mask, devc, + devc->dma8, devc->dma8)) < 0) { printk(KERN_ERR "sb: unable to install audio.\n"); return; diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.1.93/linux/drivers/sound/sb_card.c Tue Mar 17 22:18:15 1998 +++ linux/drivers/sound/sb_card.c Wed Apr 8 17:24:48 1998 @@ -2,18 +2,18 @@ * sound/sb_card.c * * Detection routine for the Sound Blaster cards. - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. */ + #include #include - #include "sound_config.h" #include "soundmodule.h" @@ -22,31 +22,30 @@ #include "sb_mixer.h" #include "sb.h" -void -attach_sb_card(struct address_info *hw_config) +void attach_sb_card(struct address_info *hw_config) { #if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI) sb_dsp_init(hw_config); #endif } -int -probe_sb(struct address_info *hw_config) +int probe_sb(struct address_info *hw_config) { if (check_region(hw_config->io_base, 16)) { - printk("\n\nsb_card.c: I/O port %x is already in use\n\n", hw_config->io_base); + printk(KERN_ERR "sb_card: I/O port %x is already in use\n\n", hw_config->io_base); return 0; } return sb_dsp_detect(hw_config); } -void -unload_sb(struct address_info *hw_config) +void unload_sb(struct address_info *hw_config) { sb_dsp_unload(hw_config); } +int sb_be_quiet=0; + #ifdef MODULE static struct address_info config; @@ -58,18 +57,17 @@ * to the 8bit channel. */ -int mpu_io = 0; -int io = -1; -int irq = -1; -int dma = -1; -int dma16 = -1; /* Set this for modules that need it */ -int type = 0; /* Can set this to a specific card type */ -int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ -int trix = 0; /* Set trix=1 to load this as support for trix */ -int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ -int sm_games = 0; /* Mixer - see sb_mixer.c */ -int acer = 0; /* Do acer notebook init */ -int mwave_bug = 0; /* Using the dreadful mwave sb emulation */ +int mpu_io = 0; +int io = -1; +int irq = -1; +int dma = -1; +int dma16 = -1; /* Set this for modules that need it */ +int type = 0; /* Can set this to a specific card type */ +int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ +int trix = 0; /* Set trix=1 to load this as support for trix */ +int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ +int sm_games = 0; /* Mixer - see sb_mixer.c */ +int acer = 0; /* Do acer notebook init */ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); @@ -81,7 +79,6 @@ MODULE_PARM(trix, "i"); MODULE_PARM(pas2, "i"); MODULE_PARM(sm_games, "i"); -MODULE_PARM(mwave_bug, "i"); static int sbmpu = 0; @@ -124,7 +121,7 @@ void cleanup_module(void) { if (smw_free) - kfree(smw_free); + vfree(smw_free); if (!mad16 && !trix && !pas2) unload_sb(&config); if (sbmpu) @@ -144,11 +141,6 @@ #else int acer = 0; #endif -#ifdef CONFIG_SB_MWAVE -int mwave_bug = 1; -#else -int mwave_bug = 0; -#endif #endif #endif @@ -159,3 +151,4 @@ EXPORT_SYMBOL(attach_sb_card); EXPORT_SYMBOL(probe_sb); EXPORT_SYMBOL(unload_sb); +EXPORT_SYMBOL(sb_be_quiet); diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.1.93/linux/drivers/sound/sb_common.c Tue Mar 17 22:18:15 1998 +++ linux/drivers/sound/sb_common.c Wed Apr 8 17:24:48 1998 @@ -2,17 +2,18 @@ * sound/sb_common.c * * Common routines for Sound Blaster compatible cards. - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. */ + #include #include - +#include #include "sound_config.h" #include "sound_firmware.h" @@ -28,9 +29,11 @@ static sb_devc *detected_devc = NULL; /* For communication from probe to init */ static sb_devc *last_devc = NULL; /* For MPU401 initialization */ + static unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6 }; + static unsigned char jazz_dma_bits[] = { 0, 1, 0, 2, 0, 3, 0, 4 }; @@ -39,7 +42,7 @@ * Jazz16 chipset specific control variables */ -static int jazz16_base = 0; /* Not detected */ +static int jazz16_base = 0; /* Not detected */ static unsigned char jazz16_bits = 0; /* I/O relocation bits */ /* @@ -57,10 +60,11 @@ int sb_dsp_command(sb_devc * devc, unsigned char val) { - int i; - unsigned long limit; + int i; + unsigned long limit; limit = jiffies + HZ / 10; /* Timeout */ + /* * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes * called while interrupts are disabled. This means that the timer is @@ -69,7 +73,7 @@ * loops. */ - for (i = 0; i < 500000 && jiffies < limit; i++) + for (i = 0; i < 500000 && (limit-jiffies)>0; i++) { if ((inb(DSP_STATUS) & 0x80) == 0) { @@ -77,20 +81,19 @@ return 1; } } - - printk(KERN_WARNING "Sound Blaster: DSP Command(%x) Timeout.\n", val); + printk(KERN_WARNING "soundblaster: DSP Command(%x) Timeout.\n", val); return 0; } static int sb_dsp_get_byte(sb_devc * devc) { - int i; + int i; for (i = 1000; i; i--) + { if (inb(DSP_DATA_AVAIL) & 0x80) - { return inb(DSP_READ); - } + } return 0xffff; } @@ -107,7 +110,6 @@ int ess_read(sb_devc * devc, unsigned char reg) { /* Read a byte from an extended mode register of ES1688 */ - if (!sb_dsp_command(devc, 0xc0)) /* Read register command */ return -1; @@ -239,7 +241,7 @@ if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3) { - printk(KERN_ERR "SB16: Invalid 8 bit DMA (%d)\n", devc->dma8); + printk(KERN_ERR "sb16: Invalid 8 bit DMA (%d)\n", devc->dma8); return 0; } bits = (1 << devc->dma8); @@ -355,14 +357,12 @@ /* * OK so far. Now configure the IRQ and DMA channel used by the card. */ - if (hw_config->irq < 1 || hw_config->irq > 15 || - jazz_irq_bits[hw_config->irq] == 0) + if (hw_config->irq < 1 || hw_config->irq > 15 || jazz_irq_bits[hw_config->irq] == 0) { printk(KERN_ERR "Jazz16: Invalid interrupt (IRQ%d)\n", hw_config->irq); return 0; } - if (hw_config->dma < 0 || hw_config->dma > 3 || - jazz_dma_bits[hw_config->dma] == 0) + if (hw_config->dma < 0 || hw_config->dma > 3 || jazz_dma_bits[hw_config->dma] == 0) { printk(KERN_ERR "Jazz16: Invalid 8 bit DMA (DMA%d)\n", hw_config->dma); return 0; @@ -372,8 +372,7 @@ printk(KERN_ERR "Jazz16: No 16 bit DMA channel defined\n"); return 0; } - if (hw_config->dma2 < 5 || hw_config->dma2 > 7 || - jazz_dma_bits[hw_config->dma2] == 0) + if (hw_config->dma2 < 5 || hw_config->dma2 > 7 || jazz_dma_bits[hw_config->dma2] == 0) { printk(KERN_ERR "Jazz16: Invalid 16 bit DMA (DMA%d)\n", hw_config->dma2); return 0; @@ -384,7 +383,7 @@ return 0; if (!sb_dsp_command(devc, jazz_dma_bits[hw_config->dma] | - (jazz_dma_bits[hw_config->dma2] << 4))) + (jazz_dma_bits[hw_config->dma2] << 4))) return 0; if (!sb_dsp_command(devc, jazz_irq_bits[hw_config->irq])) @@ -683,11 +682,7 @@ */ - detected_devc = (sb_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(sb_devc))); - sound_mem_sizes[sound_nblocks] = sizeof(sb_devc); - if (sound_nblocks < 1024) - sound_nblocks++;; - + detected_devc = (sb_devc *)kmalloc(sizeof(sb_devc), GFP_KERNEL); if (detected_devc == NULL) { printk(KERN_ERR "sb: Can't allocate memory for device information\n"); @@ -703,8 +698,8 @@ sb_devc *devc; char name[100]; extern int sb_be_quiet; - extern int mwave_bug; - + int mixer3c, mixer4c; + /* * Check if we had detected a SB device earlier */ @@ -769,7 +764,7 @@ /* Skip IRQ detection if SMP (doesn't work) */ devc->irq_ok = 1; #else - if ((devc->major == 4 && devc->minor <= 11 ) || mwave_bug ) /* Won't work */ + if (devc->major == 4 && devc->minor <= 11 ) /* Won't work */ devc->irq_ok = 1; else { @@ -819,7 +814,23 @@ case 4: devc->model = hw_config->card_subtype = MDL_SB16; - if (hw_config->name == NULL) + /* + * The ALS007 seems to return DSP version 4.2. In addition it has 2 + * output control registers (at 0x3c and 0x4c). Both of these should + * be !=0 after a reset which forms the basis of the ALS007 test + * since a "standard" SoundBlaster does not have a register at 0x4c. + */ + mixer3c = sb_getmixer(devc,0x3c); + mixer4c = sb_getmixer(devc,0x4c); + if ((devc->minor == 2) && (mixer3c != 0) && (mixer4c != 0)) + { + sb_setmixer(devc,0x3c,0x1f); /* Enable all inputs */ + sb_setmixer(devc,0x4c,0x1f); + devc->submodel = SUBMDL_ALS007; + if (hw_config->name == NULL) + hw_config->name = "Sound Blaster (ALS-007)"; + } + else if (hw_config->name == NULL) hw_config->name = "Sound Blaster 16"; if (hw_config->dma2 == -1) @@ -885,15 +896,15 @@ printk(KERN_WARNING "SB: Can't allocate 8 bit DMA channel %d\n", devc->dma8); } if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) + { if (sound_alloc_dma(devc->dma16, "SoundBlaster16")) - { - printk(KERN_WARNING "SB: Can't allocate 16 bit DMA channel %d\n", devc->dma16); - } + printk(KERN_WARNING "soundblaster: Can't allocate 16 bit DMA channel %d\n", devc->dma16); + } sb_audio_init(devc, name); } else { - MDB(printk("sb: No audio devices found.\n")); + MDB(printk("soundblaster: No audio devices found.\n")); } } @@ -932,6 +943,8 @@ } else release_region(hw_config->io_base, 16); + if(detected_devc) + kfree(detected_devc); } /* @@ -940,7 +953,7 @@ void sb_setmixer(sb_devc * devc, unsigned int port, unsigned int value) { - unsigned long flags; + unsigned long flags; save_flags(flags); cli(); @@ -1318,5 +1331,4 @@ { } #endif - #endif diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c --- v2.1.93/linux/drivers/sound/sb_midi.c Tue Dec 30 10:59:17 1997 +++ linux/drivers/sound/sb_midi.c Wed Apr 8 17:24:48 1998 @@ -2,17 +2,16 @@ * sound/sb_dsp.c * * The low level driver for the Sound Blaster DS chips. - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. */ -#include - +#include #include "sound_config.h" #ifdef CONFIG_SBDSP @@ -30,14 +29,13 @@ */ -static int -sb_midi_open(int dev, int mode, +static int sb_midi_open(int dev, int mode, void (*input) (int dev, unsigned char data), void (*output) (int dev) ) { - sb_devc *devc = midi_devs[dev]->devc; - unsigned long flags; + sb_devc *devc = midi_devs[dev]->devc; + unsigned long flags; if (devc == NULL) return -ENXIO; @@ -45,10 +43,10 @@ save_flags(flags); cli(); if (devc->opened) - { - restore_flags(flags); - return -EBUSY; - } + { + restore_flags(flags); + return -EBUSY; + } devc->opened = 1; restore_flags(flags); @@ -58,25 +56,24 @@ sb_dsp_reset(devc); if (!sb_dsp_command(devc, 0x35)) /* Start MIDI UART mode */ - { + { devc->opened = 0; return -EIO; - } + } devc->intr_active = 1; if (mode & OPEN_READ) - { - devc->input_opened = 1; - devc->midi_input_intr = input; - } + { + devc->input_opened = 1; + devc->midi_input_intr = input; + } return 0; } -static void -sb_midi_close(int dev) +static void sb_midi_close(int dev) { - sb_devc *devc = midi_devs[dev]->devc; - unsigned long flags; + sb_devc *devc = midi_devs[dev]->devc; + unsigned long flags; if (devc == NULL) return; @@ -90,10 +87,9 @@ restore_flags(flags); } -static int -sb_midi_out(int dev, unsigned char midi_byte) +static int sb_midi_out(int dev, unsigned char midi_byte) { - sb_devc *devc = midi_devs[dev]->devc; + sb_devc *devc = midi_devs[dev]->devc; if (devc == NULL) return 1; @@ -102,23 +98,21 @@ return 1; if (!sb_dsp_command(devc, midi_byte)) - { - devc->midi_broken = 1; - return 1; - } + { + devc->midi_broken = 1; + return 1; + } return 1; } -static int -sb_midi_start_read(int dev) +static int sb_midi_start_read(int dev) { return 0; } -static int -sb_midi_end_read(int dev) +static int sb_midi_end_read(int dev) { - sb_devc *devc = midi_devs[dev]->devc; + sb_devc *devc = midi_devs[dev]->devc; if (devc == NULL) return -ENXIO; @@ -128,14 +122,12 @@ return 0; } -/* why -EPERM and not -EINVAL?? */ static int sb_midi_ioctl(int dev, unsigned cmd, caddr_t arg) { - return -EPERM; + return -EINVAL; } -void -sb_midi_interrupt(sb_devc * devc) +void sb_midi_interrupt(sb_devc * devc) { unsigned long flags; unsigned char data; @@ -159,7 +151,9 @@ static struct midi_operations sb_midi_operations = { - {"Sound Blaster", 0, 0, SNDCARD_SB}, + { + "Sound Blaster", 0, 0, SNDCARD_SB + }, &std_midi_synth, {0}, sb_midi_open, @@ -174,10 +168,9 @@ NULL }; -void -sb_dsp_midi_init(sb_devc * devc) +void sb_dsp_midi_init(sb_devc * devc) { - int dev; + int dev; if (devc->model < 2) /* No MIDI support for SB 1.x */ return; @@ -185,45 +178,34 @@ dev = sound_alloc_mididev(); if (dev == -1) - { - printk("Sound: Too many midi devices detected\n"); - return; - } + { + printk("Sound: Too many midi devices detected\n"); + return; + } std_midi_synth.midi_dev = dev; devc->my_mididev = dev; - std_midi_synth.midi_dev = devc->my_mididev = dev; - - - midi_devs[dev] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct midi_operations))); - sound_mem_sizes[sound_nblocks] = sizeof(struct midi_operations); - - if (sound_nblocks < 1024) - sound_nblocks++;; + midi_devs[dev] = (struct midi_operations *)kmalloc(sizeof(struct midi_operations), GFP_KERNEL); if (midi_devs[dev] == NULL) - { - printk(KERN_WARNING "sb MIDI: Failed to allocate memory\n"); - sound_unload_mididev(dev); + { + printk(KERN_WARNING "soundblaster: Failed to allocate MIDI memory.\n"); + sound_unload_mididev(dev); return; - } + } memcpy((char *) midi_devs[dev], (char *) &sb_midi_operations, sizeof(struct midi_operations)); midi_devs[dev]->devc = devc; - midi_devs[dev]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct synth_operations))); - sound_mem_sizes[sound_nblocks] = sizeof(struct synth_operations); - - if (sound_nblocks < 1024) - sound_nblocks++;; - + midi_devs[dev]->converter = (struct synth_operations *)kmalloc(sizeof(struct synth_operations), GFP_KERNEL); if (midi_devs[dev]->converter == NULL) - { - printk(KERN_WARNING "sb MIDI: Failed to allocate memory\n"); + { + printk(KERN_WARNING "soundblaster: Failed to allocate MIDI memory.\n"); + kfree(midi_devs[dev]); sound_unload_mididev(dev); return; - } + } memcpy((char *) midi_devs[dev]->converter, (char *) &std_midi_synth, sizeof(struct synth_operations)); diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c --- v2.1.93/linux/drivers/sound/sb_mixer.c Mon Jan 5 09:39:52 1998 +++ linux/drivers/sound/sb_mixer.c Wed Apr 8 17:24:48 1998 @@ -10,13 +10,12 @@ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. - */ -/* + * + * * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) */ -#include - +#include #include "sound_config.h" #if defined(CONFIG_SBDSP) || defined(MODULE) @@ -29,25 +28,22 @@ static void sb_mixer_reset(sb_devc * devc); -void -sb_mixer_set_stereo(sb_devc * devc, int mode) +void sb_mixer_set_stereo(sb_devc * devc, int mode) { sb_setmixer(devc, OUT_FILTER, ((sb_getmixer(devc, OUT_FILTER) & ~STEREO_DAC) | (mode ? STEREO_DAC : MONO_DAC))); } -static int -detect_mixer(sb_devc * devc) +static int detect_mixer(sb_devc * devc) { /* Just trust the mixer is there */ return 1; } -static void -change_bits(sb_devc * devc, unsigned char *regval, int dev, int chn, int newval) +static void change_bits(sb_devc * devc, unsigned char *regval, int dev, int chn, int newval) { - unsigned char mask; - int shift; + unsigned char mask; + int shift; mask = (1 << (*devc->iomap)[dev][chn].nbits) - 1; newval = (int) ((newval * mask) + 50) / 100; /* Scale */ @@ -58,19 +54,16 @@ *regval |= (newval & mask) << shift; /* Set the new value */ } -static int -sb_mixer_get(sb_devc * devc, int dev) +static int sb_mixer_get(sb_devc * devc, int dev) { if (!((1 << dev) & devc->supported_devices)) return -EINVAL; - return devc->levels[dev]; } -void -smw_mixer_init(sb_devc * devc) +void smw_mixer_init(sb_devc * devc) { - int i; + int i; sb_setmixer(devc, 0x00, 0x18); /* Mute unused (Telephone) line */ sb_setmixer(devc, 0x10, 0x38); /* Config register 2 */ @@ -81,18 +74,15 @@ devc->supported_devices |= (1 << i); devc->supported_rec_devices = devc->supported_devices & - ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | - SOUND_MASK_VOLUME); - + ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | SOUND_MASK_VOLUME); sb_mixer_reset(devc); } -static int -smw_mixer_set(sb_devc * devc, int dev, int value) +static int smw_mixer_set(sb_devc * devc, int dev, int value) { - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; - int reg, val; + int left = value & 0x000000ff; + int right = (value & 0x0000ff00) >> 8; + int reg, val; if (left > 100) left = 100; @@ -106,46 +96,45 @@ return -EINVAL; switch (dev) - { - case SOUND_MIXER_VOLUME: - sb_setmixer(devc, 0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ - sb_setmixer(devc, 0x0c, 96 - (96 * right / 100)); - break; - - case SOUND_MIXER_BASS: - case SOUND_MIXER_TREBLE: - devc->levels[dev] = left | (right << 8); - - /* Set left bass and treble values */ - val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4; - val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f; - sb_setmixer(devc, 0x0d, val); - - /* Set right bass and treble values */ - val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4; - val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f; - sb_setmixer(devc, 0x0e, val); - break; - - default: - reg = smw_mix_regs[dev]; - if (reg == 0) - return -EINVAL; - sb_setmixer(devc, reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ - sb_setmixer(devc, reg + 1, (24 - (24 * right / 100)) | 0x40); - } + { + case SOUND_MIXER_VOLUME: + sb_setmixer(devc, 0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ + sb_setmixer(devc, 0x0c, 96 - (96 * right / 100)); + break; + + case SOUND_MIXER_BASS: + case SOUND_MIXER_TREBLE: + devc->levels[dev] = left | (right << 8); + /* Set left bass and treble values */ + val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4; + val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f; + sb_setmixer(devc, 0x0d, val); + + /* Set right bass and treble values */ + val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4; + val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f; + sb_setmixer(devc, 0x0e, val); + + break; + + default: + reg = smw_mix_regs[dev]; + if (reg == 0) + return -EINVAL; + sb_setmixer(devc, reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ + sb_setmixer(devc, reg + 1, (24 - (24 * right / 100)) | 0x40); + } devc->levels[dev] = left | (right << 8); return left | (right << 8); } -static int -sb_mixer_set(sb_devc * devc, int dev, int value) +static int sb_mixer_set(sb_devc * devc, int dev, int value) { - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; + int left = value & 0x000000ff; + int right = (value & 0x0000ff00) >> 8; - int regoffs; + int regoffs; unsigned char val; if (devc->model == MDL_SMW) @@ -177,21 +166,21 @@ if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /* * Change register */ - { - sb_setmixer(devc, regoffs, val); /* + { + sb_setmixer(devc, regoffs, val); /* * Save the old one */ - regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno; + regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno; - if (regoffs == 0) - return left | (left << 8); /* + if (regoffs == 0) + return left | (left << 8); /* * Just left channel present */ - val = sb_getmixer(devc, regoffs); /* - * Read the new one + val = sb_getmixer(devc, regoffs); /* + * Read the new one */ - } + } change_bits(devc, &val, dev, RIGHT_CHN, right); sb_setmixer(devc, regoffs, val); @@ -200,86 +189,107 @@ return left | (right << 8); } -static void -set_recsrc(sb_devc * devc, int src) +static void set_recsrc(sb_devc * devc, int src) { sb_setmixer(devc, RECORD_SRC, (sb_getmixer(devc, RECORD_SRC) & ~7) | (src & 0x7)); } -static int -set_recmask(sb_devc * devc, int mask) +static int set_recmask(sb_devc * devc, int mask) { - int devmask, i; - unsigned char regimageL, regimageR; + int devmask, i; + unsigned char regimageL, regimageR; devmask = mask & devc->supported_rec_devices; switch (devc->model) - { - case MDL_SBPRO: - case MDL_ESS: - case MDL_JAZZ: - case MDL_SMW: - - if (devmask != SOUND_MASK_MIC && - devmask != SOUND_MASK_LINE && - devmask != SOUND_MASK_CD) - { /* - * More than one devices selected. Drop the * + { + case MDL_SBPRO: + case MDL_ESS: + case MDL_JAZZ: + case MDL_SMW: + + if (devmask != SOUND_MASK_MIC && + devmask != SOUND_MASK_LINE && + devmask != SOUND_MASK_CD) + { + /* + * More than one device selected. Drop the * previous selection */ - devmask &= ~devc->recmask; - } - if (devmask != SOUND_MASK_MIC && - devmask != SOUND_MASK_LINE && - devmask != SOUND_MASK_CD) - { /* - * More than one devices selected. Default to - * * mic + devmask &= ~devc->recmask; + } + if (devmask != SOUND_MASK_MIC && + devmask != SOUND_MASK_LINE && + devmask != SOUND_MASK_CD) + { + /* + * More than one device selected. Default to + * mic */ - devmask = SOUND_MASK_MIC; - } - if (devmask ^ devc->recmask) /* - * Input source changed - */ - { - switch (devmask) - { - - case SOUND_MASK_MIC: - set_recsrc(devc, SRC__MIC); - break; - - case SOUND_MASK_LINE: - set_recsrc(devc, SRC__LINE); - break; - - case SOUND_MASK_CD: - set_recsrc(devc, SRC__CD); - break; - - default: - set_recsrc(devc, SRC__MIC); - } - } - break; - - case MDL_SB16: - if (!devmask) - devmask = SOUND_MASK_MIC; - - regimageL = regimageR = 0; - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if ((1 << i) & devmask) - { - regimageL |= sb16_recmasks_L[i]; - regimageR |= sb16_recmasks_R[i]; - } - sb_setmixer(devc, SB16_IMASK_L, regimageL); - sb_setmixer(devc, SB16_IMASK_R, regimageR); - break; - } + devmask = SOUND_MASK_MIC; + } + if (devmask ^ devc->recmask) /* + * Input source changed + */ + { + switch (devmask) + { + case SOUND_MASK_MIC: + set_recsrc(devc, SRC__MIC); + break; + + case SOUND_MASK_LINE: + set_recsrc(devc, SRC__LINE); + break; + + case SOUND_MASK_CD: + set_recsrc(devc, SRC__CD); + break; + + default: + set_recsrc(devc, SRC__MIC); + } + } + break; + case MDL_SB16: + if (!devmask) + devmask = SOUND_MASK_MIC; + + if (devc->submodel == SUBMDL_ALS007) + { + switch (devmask) + { + case SOUND_MASK_LINE: + sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_LINE); + break; + case SOUND_MASK_CD: + sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_CD); + break; + case SOUND_MASK_SYNTH: + sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_SYNTH); + break; + default: /* Also takes care of SOUND_MASK_MIC case */ + sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_MIC); + break; + } + } + else + { + regimageL = regimageR = 0; + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + { + if ((1 << i) & devmask) + { + regimageL |= sb16_recmasks_L[i]; + regimageR |= sb16_recmasks_R[i]; + } + sb_setmixer (devc, SB16_IMASK_L, regimageL); + sb_setmixer (devc, SB16_IMASK_R, regimageR); + } + } + break; + } devc->recmask = devmask; return devc->recmask; } @@ -292,52 +302,57 @@ /* * Use ioctl(fd, SOUND_MIXER_PRIVATE1, &mode) to turn AGC off (0) or on (1). */ - if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) { + if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) + { if (get_user(val, (int *)arg)) return -EFAULT; sb_setmixer(devc, 0x43, (~val) & 0x01); return 0; } - if (((cmd >> 8) & 0xff) == 'M') { - if (_SIOC_DIR(cmd) & _SIOC_WRITE) { + if (((cmd >> 8) & 0xff) == 'M') + { + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + { if (get_user(val, (int *)arg)) return -EFAULT; - switch (cmd & 0xff) { - case SOUND_MIXER_RECSRC: - ret = set_recmask(devc, val); - break; + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + ret = set_recmask(devc, val); + break; - default: - ret = sb_mixer_set(devc, cmd & 0xff, val); + default: + ret = sb_mixer_set(devc, cmd & 0xff, val); } - } else - switch (cmd & 0xff) { - case SOUND_MIXER_RECSRC: - ret = devc->recmask; - break; + } + else switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + ret = devc->recmask; + break; - case SOUND_MIXER_DEVMASK: - ret = devc->supported_devices; - break; + case SOUND_MIXER_DEVMASK: + ret = devc->supported_devices; + break; - case SOUND_MIXER_STEREODEVS: - ret = devc->supported_devices; - if (devc->model != MDL_JAZZ && devc->model != MDL_SMW) - ret &= ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); - break; + case SOUND_MIXER_STEREODEVS: + ret = devc->supported_devices; + if (devc->model != MDL_JAZZ && devc->model != MDL_SMW) + ret &= ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); + break; - case SOUND_MIXER_RECMASK: - ret = devc->supported_rec_devices; - break; + case SOUND_MIXER_RECMASK: + ret = devc->supported_rec_devices; + break; - case SOUND_MIXER_CAPS: - ret = devc->mixer_caps; - break; + case SOUND_MIXER_CAPS: + ret = devc->mixer_caps; + break; - default: - ret = sb_mixer_get(devc, cmd & 0xff); - break; - } + default: + ret = sb_mixer_get(devc, cmd & 0xff); + break; + } return put_user(ret, (int *)arg); } else return -EINVAL; @@ -350,12 +365,18 @@ sb_mixer_ioctl }; -static void -sb_mixer_reset(sb_devc * devc) +static struct mixer_operations als007_mixer_operations = { - char name[32]; - int i; - extern int sm_games; + "ALS007", + "Avance ALS-007", + sb_mixer_ioctl +}; + +static void sb_mixer_reset(sb_devc * devc) +{ + char name[32]; + int i; + extern int sm_games; sprintf(name, "SB_%d", devc->sbmixnum); @@ -366,15 +387,13 @@ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) sb_mixer_set(devc, i, devc->levels[i]); - set_recmask(devc, SOUND_MASK_MIC); } -int -sb_mixer_init(sb_devc * devc) +int sb_mixer_init(sb_devc * devc) { - int mixer_type = 0; - int m; + int mixer_type = 0; + int m; devc->sbmixnum = sbmixnum++; devc->levels = NULL; @@ -385,64 +404,69 @@ return 0; /* No mixer. Why? */ switch (devc->model) - { - case MDL_SBPRO: - case MDL_AZTECH: - case MDL_JAZZ: - devc->mixer_caps = SOUND_CAP_EXCL_INPUT; - devc->supported_devices = SBPRO_MIXER_DEVICES; - devc->supported_rec_devices = SBPRO_RECORDING_DEVICES; - devc->iomap = &sbpro_mix; - break; - - case MDL_ESS: - devc->mixer_caps = SOUND_CAP_EXCL_INPUT; - devc->supported_devices = ES688_MIXER_DEVICES; - devc->supported_rec_devices = ES688_RECORDING_DEVICES; - devc->iomap = &es688_mix; - break; - - case MDL_SMW: - devc->mixer_caps = SOUND_CAP_EXCL_INPUT; - devc->supported_devices = 0; - devc->supported_rec_devices = 0; - devc->iomap = &sbpro_mix; - smw_mixer_init(devc); - break; - - case MDL_SB16: - devc->mixer_caps = 0; - devc->supported_devices = SB16_MIXER_DEVICES; - devc->supported_rec_devices = SB16_RECORDING_DEVICES; - devc->iomap = &sb16_mix; - break; - - default: - printk("SB Warning: Unsupported mixer type %d\n", devc->model); - return 0; - } + { + case MDL_SBPRO: + case MDL_AZTECH: + case MDL_JAZZ: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = SBPRO_MIXER_DEVICES; + devc->supported_rec_devices = SBPRO_RECORDING_DEVICES; + devc->iomap = &sbpro_mix; + break; + + case MDL_ESS: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = ES688_MIXER_DEVICES; + devc->supported_rec_devices = ES688_RECORDING_DEVICES; + devc->iomap = &es688_mix; + break; + + case MDL_SMW: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = 0; + devc->supported_rec_devices = 0; + devc->iomap = &sbpro_mix; + smw_mixer_init(devc); + break; + + case MDL_SB16: + devc->mixer_caps = 0; + devc->supported_rec_devices = SB16_RECORDING_DEVICES; + if (devc->submodel != SUBMDL_ALS007) + { + devc->supported_devices = SB16_MIXER_DEVICES; + devc->iomap = &sb16_mix; + } + else + { + devc->supported_devices = ALS007_MIXER_DEVICES; + devc->iomap = &als007_mix; + } + break; + + default: + printk(KERN_WARNING "sb_mixer: Unsupported mixer type %d\n", devc->model); + return 0; + } m = sound_alloc_mixerdev(); if (m == -1) return 0; - - mixer_devs[m] = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations))); - sound_mem_sizes[sound_nblocks] = sizeof(struct mixer_operations); - - if (sound_nblocks < 1024) - sound_nblocks++;; + mixer_devs[m] = (struct mixer_operations *)kmalloc(sizeof(struct mixer_operations), GFP_KERNEL); if (mixer_devs[m] == NULL) - { - printk(KERN_ERR "sb_mixer: Can't allocate memory\n"); - sound_unload_mixerdev(m); - return 0; - } - memcpy((char *) mixer_devs[m], (char *) &sb_mixer_operations, - sizeof(struct mixer_operations)); + { + printk(KERN_ERR "sb_mixer: Can't allocate memory\n"); + sound_unload_mixerdev(m); + return 0; + } - mixer_devs[m]->devc = devc; + if (devc->submodel != SUBMDL_ALS007) + memcpy ((char *) mixer_devs[m], (char *) &sb_mixer_operations, sizeof (struct mixer_operations)); + else + memcpy ((char *) mixer_devs[m], (char *) &als007_mixer_operations, sizeof (struct mixer_operations)); + mixer_devs[m]->devc = devc; devc->my_mixerdev = m; sb_mixer_reset(devc); return 1; diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h --- v2.1.93/linux/drivers/sound/sb_mixer.h Fri Jan 30 11:28:08 1998 +++ linux/drivers/sound/sb_mixer.h Wed Apr 8 17:24:48 1998 @@ -49,6 +49,13 @@ SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | \ SOUND_MASK_IMIX) +/* These are the only devices that are working at the moment. Others could + * be added once they are identified and a method is found to control them. + */ +#define ALS007_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | \ + SOUND_MASK_PCM | SOUND_MASK_MIC | \ + SOUND_MASK_CD | \ + SOUND_MASK_VOLUME) /* * Mixer registers * @@ -97,6 +104,13 @@ #define LEFT_CHN 0 #define RIGHT_CHN 1 +/* + * Mixer registers of ALS007 + */ +#define ALS007_RECORD_SRC 0x6c +#define ALS007_OUTPUT_CTRL1 0x3c +#define ALS007_OUTPUT_CTRL2 0x4c + #define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r) \ {{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}} @@ -173,6 +187,25 @@ MIX_ENT(SOUND_MIXER_OGAIN, 0x41, 7, 2, 0x42, 7, 2) }; +static mixer_tab als007_mix = +{ +MIX_ENT(SOUND_MIXER_VOLUME, 0x62, 7, 4, 0x62, 3, 4), +MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_SYNTH, 0x66, 7, 4, 0x66, 3, 4), +MIX_ENT(SOUND_MIXER_PCM, 0x64, 7, 4, 0x64, 3, 4), +MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_LINE, 0x6e, 7, 4, 0x6e, 3, 4), +MIX_ENT(SOUND_MIXER_MIC, 0x6a, 6, 3, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_CD, 0x68, 7, 4, 0x68, 3, 4), +MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0), /* Obsolete. Use IGAIN */ +MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0) +}; + + /* SM_GAMES Master volume is lower and PCM & FM volumes higher than with SB Pro. This improves the sound quality */ @@ -283,6 +316,15 @@ #define SRC__MIC 1 /* Select Microphone recording source */ #define SRC__CD 3 /* Select CD recording source */ #define SRC__LINE 7 /* Use Line-in for recording source */ + +/* + * Recording sources for ALS-007 + */ + +#define ALS007_MIC 4 +#define ALS007_LINE 6 +#define ALS007_CD 2 +#define ALS007_SYNTH 7 #endif #endif diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c --- v2.1.93/linux/drivers/sound/sequencer.c Tue Mar 10 10:03:33 1998 +++ linux/drivers/sound/sequencer.c Wed Apr 8 17:24:48 1998 @@ -16,6 +16,10 @@ */ #include +#ifdef CONFIG_KMOD +#include +#endif + #define SEQUENCER_C #include "sound_config.h" @@ -478,7 +482,7 @@ parm = 64; } } - + switch (cmd) { case MIDI_NOTEON: @@ -950,7 +954,7 @@ synth_devs[max_synthdev++] = midi_devs[dev]->converter; } } - + for (dev = 0; dev < max_synthdev; dev++) { int chn; @@ -993,15 +997,20 @@ return -ENXIO; } if (dev) /* Patch manager device (obsolete) */ - return -ENXIO; + return -ENXIO; + +#ifdef CONFIG_KMOD + if(synth_devs[dev] == NULL) + request_module("synth0"); +#endif if (mode == OPEN_READ) { if (!num_midis) { - /*printk("Sequencer: No MIDI devices. Input not possible\n");*/ - sequencer_busy = 0; - return -ENXIO; + /*printk("Sequencer: No MIDI devices. Input not possible\n");*/ + sequencer_busy = 0; + return -ENXIO; } } save_flags(flags); @@ -1033,8 +1042,8 @@ for (i = 0; i < num_sound_timers; i++) if (sound_timer_devs[i] && sound_timer_devs[i]->priority > best) { - tmr_no = i; - best = sound_timer_devs[i]->priority; + tmr_no = i; + best = sound_timer_devs[i]->priority; } if (tmr_no == -1) /* Should not be */ tmr_no = 0; @@ -1066,7 +1075,7 @@ { if (synth_devs[i]==NULL) continue; - + if ((tmp = synth_devs[i]->open(i, mode)) < 0) { printk(KERN_WARNING "Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); @@ -1096,7 +1105,7 @@ /* * Initialize midi input devices */ - + for (i = 0; i < max_mididev; i++) if (!midi_opened[i]) { @@ -1140,7 +1149,7 @@ /* * Let's have a delay */ - + if (n) { current->timeout = jiffies + HZ / 10; interruptible_sleep_on(&seq_sleeper); @@ -1173,7 +1182,7 @@ /* Extra delay */ } } - + if (mode != OPEN_READ) seq_drain_midi_queues(); /* * Ensure the output queues are empty @@ -1201,7 +1210,7 @@ for (i = 0; i < max_mididev; i++) { if (midi_opened[i]) - midi_devs[i]->close(i); + midi_devs[i]->close(i); } if (seq_mode == SEQ_2) @@ -1329,7 +1338,7 @@ save_flags(flags); cli(); - + if (waitqueue_active(&seq_sleeper)) { /* printk( "Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ wake_up(&seq_sleeper); @@ -1368,7 +1377,7 @@ orig_dev = dev = dev >> 4; - switch (cmd) + switch (cmd) { case SNDCTL_TMR_TIMEBASE: case SNDCTL_TMR_TEMPO: @@ -1380,13 +1389,13 @@ if (seq_mode != SEQ_2) return -EINVAL; return tmr->ioctl(tmr_no, cmd, arg); - + case SNDCTL_TMR_SELECT: if (seq_mode != SEQ_2) return -EINVAL; if (get_user(pending_timer, (int *)arg)) return -EFAULT; - if (pending_timer < 0 || pending_timer >= num_sound_timers || sound_timer_devs[pending_timer] == NULL) + if (pending_timer < 0 || pending_timer >= num_sound_timers || sound_timer_devs[pending_timer] == NULL) { pending_timer = -1; return -EINVAL; @@ -1397,14 +1406,14 @@ case SNDCTL_SEQ_PANIC: seq_panic(); return -EINVAL; - + case SNDCTL_SEQ_SYNC: if (mode == OPEN_READ) return 0; while (qlen > 0 && !signal_pending(current)) seq_sync(); return qlen ? -EINTR : 0; - + case SNDCTL_SEQ_RESET: seq_reset(); return 0; @@ -1414,8 +1423,8 @@ return -EFAULT; if (midi_dev < 0 || midi_dev >= max_mididev) return -ENXIO; - - if (!midi_opened[midi_dev] && + + if (!midi_opened[midi_dev] && (err = midi_devs[midi_dev]->open(midi_dev, mode, sequencer_midi_input, sequencer_midi_output)) < 0) return err; @@ -1427,13 +1436,13 @@ return 0; val = iqlen; break; - + case SNDCTL_SEQ_GETOUTCOUNT: if (mode == OPEN_READ) return 0; val = SEQ_MAX_QUEUE - qlen; break; - + case SNDCTL_SEQ_GETTIME: if (seq_mode == SEQ_2) return tmr->ioctl(tmr_no, cmd, arg); @@ -1442,14 +1451,14 @@ else val = jiffies - seq_time; break; - + case SNDCTL_SEQ_CTRLRATE: /* * If *arg == 0, just return the current rate */ if (seq_mode == SEQ_2) return tmr->ioctl(tmr_no, cmd, arg); - + if (get_user(val, (int *)arg)) return -EFAULT; if (val != 0) @@ -1504,7 +1513,7 @@ if (!(synth_open_mask & (1 << dev)) && !orig_dev) return -EBUSY; return synth_devs[dev]->ioctl(dev, cmd, arg); - + /* Like SYNTH_INFO but returns ID in the name field */ case SNDCTL_SYNTH_ID: if (get_user(dev, (int *)(&(((struct synth_info *)arg)->device)))) @@ -1517,7 +1526,7 @@ strncpy(inf.name, synth_devs[dev]->id, sizeof(inf.name)); inf.device = dev; return copy_to_user(arg, &inf, sizeof(inf))?-EFAULT:0; - + case SNDCTL_SEQ_OUTOFBAND: if (copy_from_user(&event_rec, arg, sizeof(event_rec))) return -EFAULT; @@ -1526,7 +1535,7 @@ play_event(event_rec.arr); restore_flags(flags); return 0; - + case SNDCTL_MIDI_INFO: if (get_user(dev, (int *)(&(((struct synth_info *)arg)->device)))) return -EFAULT; @@ -1534,7 +1543,7 @@ return -ENXIO; midi_devs[dev]->info.device = dev; return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct synth_info))?-EFAULT:0; - + case SNDCTL_SEQ_THRESHOLD: if (get_user(val, (int *)arg)) return -EFAULT; @@ -1544,7 +1553,7 @@ val = SEQ_MAX_QUEUE - 1; output_threshold = val; return 0; - + case SNDCTL_MIDI_PRETIME: if (get_user(val, (int *)arg)) return -EFAULT; @@ -1584,7 +1593,7 @@ /* output */ poll_wait(file, &seq_sleeper, wait); - if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) mask |= POLLOUT | POLLWRNORM; restore_flags(flags); return mask; @@ -1665,8 +1674,8 @@ */ while (bend > 2399) { - multiplier *= 4; - bend -= 2400; + multiplier *= 4; + bend -= 2400; } semitones = bend / 100; @@ -1693,8 +1702,8 @@ queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ); if (queue == NULL) { - printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n"); - return; + printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n"); + return; } iqueue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * IEV_SZ); if (iqueue == NULL) diff -u --recursive --new-file v2.1.93/linux/drivers/sound/softoss.c linux/drivers/sound/softoss.c --- v2.1.93/linux/drivers/sound/softoss.c Mon Feb 23 18:12:09 1998 +++ linux/drivers/sound/softoss.c Wed Apr 8 17:24:48 1998 @@ -2,15 +2,15 @@ * sound/softoss.c * * Software based MIDI synthsesizer driver. - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. - */ -/* + * + * * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) */ #include @@ -35,14 +35,15 @@ #include "softoss.h" #include -int softsynth_disabled = 0; +int softsynth_disabled = 0; static volatile int intr_pending = 0; #ifdef POLLED_MODE -static struct timer_list poll_timer = -{NULL, NULL, 0, 0, softsyn_poll}; +static struct timer_list poll_timer = { + NULL, NULL, 0, 0, softsyn_poll +}; #else #endif @@ -101,11 +102,14 @@ static volatile int is_running = 0; static int softsynth_loaded = 0; -static struct synth_info softsyn_info = -{"SoftOSS", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH}; +static struct synth_info softsyn_info = { + "SoftOSS", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH +}; + +static struct softsyn_devc sdev_info = { + 0 +}; -static struct softsyn_devc sdev_info = -{0}; softsyn_devc *devc = &sdev_info; /* used in softoss_rs.c */ static struct voice_alloc_info *voice_alloc; @@ -118,10 +122,9 @@ static int voice_limit = 24; -static void -set_max_voices(int nr) +static void set_max_voices(int nr) { - int i; + int i; if (nr < 4) nr = 4; @@ -134,19 +137,18 @@ for (i = 31; i > 0; i--) if (nr & (1 << i)) - { - devc->afterscale = i + 1; - return; - } + { + devc->afterscale = i + 1; + return; + } } -static void -update_vibrato(int voice) +static void update_vibrato(int voice) { - voice_info *v = &softoss_voices[voice]; + voice_info *v = &softoss_voices[voice]; #ifdef HANDLE_LFO - int x; + int x; x = vibrato_table[v->vibrato_phase >> 8]; v->vibrato_phase = (v->vibrato_phase + v->vibrato_step) & 0x7fff; @@ -161,11 +163,10 @@ } #ifdef HANDLE_LFO -static void -update_tremolo(int voice) +static void update_tremolo(int voice) { - voice_info *v = &softoss_voices[voice]; - int x; + voice_info *v = &softoss_voices[voice]; + int x; x = tremolo_table[v->tremolo_phase >> 8]; v->tremolo_phase = (v->tremolo_phase + v->tremolo_step) & 0x7fff; @@ -174,11 +175,10 @@ } #endif -static void -start_vibrato(int voice) +static void start_vibrato(int voice) { - voice_info *v = &softoss_voices[voice]; - int rate; + voice_info *v = &softoss_voices[voice]; + int rate; if (!v->vibrato_depth) return; @@ -189,11 +189,10 @@ devc->vibratomap |= (1 << voice); /* Enable vibrato */ } -static void -start_tremolo(int voice) +static void start_tremolo(int voice) { - voice_info *v = &softoss_voices[voice]; - int rate; + voice_info *v = &softoss_voices[voice]; + int rate; if (!v->tremolo_depth) return; @@ -204,43 +203,43 @@ devc->tremolomap |= (1 << voice); /* Enable tremolo */ } -static void -update_volume(int voice) +static void update_volume(int voice) { - voice_info *v = &softoss_voices[voice]; - unsigned int vol; + voice_info *v = &softoss_voices[voice]; + unsigned int vol; -/* - * Compute plain volume - */ + /* + * Compute plain volume + */ vol = (v->velocity * v->expression_vol * v->main_vol) >> 12; #ifdef HANDLE_LFO -/* - * Handle LFO - */ + /* + * Handle LFO + */ if (devc->tremolomap & (1 << voice)) - { - int t; + { + int t; - t = 32768 - v->tremolo_level; - vol = (vol * t) >> 15; - update_tremolo(voice); - } + t = 32768 - v->tremolo_level; + vol = (vol * t) >> 15; + update_tremolo(voice); + } #endif -/* - * Envelope - */ + /* + * Envelope + */ + if (v->mode & WAVE_ENVELOPES && !v->percussive_voice) vol = (vol * (v->envelope_vol >> 16)) >> 19; else vol >>= 4; -/* - * Handle panning - */ + /* + * Handle panning + */ if (v->panning < 0) /* Pan left */ v->rightvol = (vol * (128 + v->panning)) / 128; @@ -253,45 +252,47 @@ v->leftvol = vol; } -static void -step_envelope(int voice, int do_release, int velocity) +static void step_envelope(int voice, int do_release, int velocity) { - voice_info *v = &softoss_voices[voice]; - int r, rate, time, dif; - unsigned int vol; - unsigned long flags; + voice_info *v = &softoss_voices[voice]; + int r, rate, time, dif; + unsigned int vol; + unsigned long flags; save_flags(flags); cli(); if (!voice_active[voice] || v->sample == NULL) - { - restore_flags(flags); - return; - } + { + restore_flags(flags); + return; + } if (!do_release) + { if (v->mode & WAVE_SUSTAIN_ON && v->envelope_phase == 2) - { /* Stop envelope until note off */ - v->envelope_volstep = 0; - v->envelope_time = 0x7fffffff; - if (v->mode & WAVE_VIBRATO) - start_vibrato(voice); - if (v->mode & WAVE_TREMOLO) - start_tremolo(voice); - restore_flags(flags); - return; - } + { + /* Stop envelope until note off */ + v->envelope_volstep = 0; + v->envelope_time = 0x7fffffff; + if (v->mode & WAVE_VIBRATO) + start_vibrato(voice); + if (v->mode & WAVE_TREMOLO) + start_tremolo(voice); + restore_flags(flags); + return; + } + } if (do_release) v->envelope_phase = 3; else v->envelope_phase++; if (v->envelope_phase >= 5) /* Finished */ - { - init_voice(devc, voice); - restore_flags(flags); - return; - } + { + init_voice(devc, voice); + restore_flags(flags); + return; + } vol = v->envelope_target = v->sample->env_offset[v->envelope_phase] << 22; @@ -308,72 +309,69 @@ if (dif < 0) dif *= -1; if (dif < rate * 2) /* Too close */ - { - step_envelope(voice, 0, 60); - restore_flags(flags); - return; - } + { + step_envelope(voice, 0, 60); + restore_flags(flags); + return; + } + if (vol > v->envelope_vol) - { - v->envelope_volstep = rate; - time = (vol - v->envelope_vol) / rate; - } else - { - v->envelope_volstep = -rate; - time = (v->envelope_vol - vol) / rate; - } + { + v->envelope_volstep = rate; + time = (vol - v->envelope_vol) / rate; + } + else + { + v->envelope_volstep = -rate; + time = (v->envelope_vol - vol) / rate; + } time--; if (time <= 0) time = 1; - v->envelope_time = time; - - restore_flags(flags); } -static void -step_envelope_lfo(int voice) +static void step_envelope_lfo(int voice) { - voice_info *v = &softoss_voices[voice]; + voice_info *v = &softoss_voices[voice]; -/* - * Update pitch (vibrato) LFO - */ + /* + * Update pitch (vibrato) LFO + */ if (devc->vibratomap & (1 << voice)) update_vibrato(voice); -/* - * Update envelope - */ + /* + * Update envelope + */ if (v->mode & WAVE_ENVELOPES) - { - v->envelope_vol += v->envelope_volstep; - /* Overshoot protection */ - if (v->envelope_vol < 0) - { - v->envelope_vol = v->envelope_target; - v->envelope_volstep = 0; - } - if (v->envelope_time-- <= 0) - { - v->envelope_vol = v->envelope_target; - step_envelope(voice, 0, 60); - } - } + { + v->envelope_vol += v->envelope_volstep; + /* Overshoot protection */ + if (v->envelope_vol < 0) + { + v->envelope_vol = v->envelope_target; + v->envelope_volstep = 0; + } + if (v->envelope_time-- <= 0) + { + v->envelope_vol = v->envelope_target; + step_envelope(voice, 0, 60); + } + } } -static void -compute_step(int voice) +static void compute_step(int voice) { - voice_info *v = &softoss_voices[voice]; + voice_info *v = &softoss_voices[voice]; /* - * Since the pitch bender may have been set before playing the note, we - * have to calculate the bending now. + * Since the pitch bender may have been set before playing the note, we + * have to calculate the bending now. */ v->current_freq = compute_finetune(v->orig_freq, @@ -386,11 +384,10 @@ v->step *= -1; /* Reversed playback */ } -static void -init_voice(softsyn_devc * devc, int voice) +static void init_voice(softsyn_devc * devc, int voice) { - voice_info *v = &softoss_voices[voice]; - unsigned long flags; + voice_info *v = &softoss_voices[voice]; + unsigned long flags; save_flags(flags); cli(); @@ -433,18 +430,17 @@ restore_flags(flags); } -static void -reset_samples(softsyn_devc * devc) +static void reset_samples(softsyn_devc * devc) { - int i; + int i; for (i = 0; i < MAX_VOICE; i++) voice_active[i] = 0; for (i = 0; i < devc->maxvoice; i++) - { - init_voice(devc, i); - softoss_voices[i].instr = 0; - } + { + init_voice(devc, i); + softoss_voices[i].instr = 0; + } devc->ram_used = 0; @@ -452,20 +448,18 @@ devc->programs[i] = NO_SAMPLE; for (i = 0; i < devc->nrsamples; i++) - { - vfree(devc->samples[i]); - vfree(devc->wave[i]); - devc->samples[i] = NULL; - devc->wave[i] = NULL; - } - + { + vfree(devc->samples[i]); + vfree(devc->wave[i]); + devc->samples[i] = NULL; + devc->wave[i] = NULL; + } devc->nrsamples = 0; } -static void -init_engine(softsyn_devc * devc) +static void init_engine(softsyn_devc * devc) { - int i, fz, srate, sz = devc->channels; + int i, fz, srate, sz = devc->channels; set_max_voices(devc->default_max_voices); voice_alloc->timestamp = 0; @@ -480,16 +474,15 @@ devc->usecs_per_frag = (1000000 * fz) / devc->speed; for (i = 0; i < devc->maxvoice; i++) - { - init_voice(devc, i); - softoss_voices[i].instr = 0; - } - + { + init_voice(devc, i); + softoss_voices[i].instr = 0; + } devc->engine_state = ES_STOPPED; -/* - * Initialize delay - */ + /* + * Initialize delay + */ for (i = 0; i < DELAY_SIZE; i++) left_delay[i] = right_delay[i] = 0; @@ -502,34 +495,35 @@ devc->delay_size = DELAY_SIZE; } -void -softsyn_control_loop(void) +void softsyn_control_loop(void) { - int voice; + int voice; -/* - * Recompute envlope, LFO, etc. - */ + /* + * Recompute envlope, LFO, etc. + */ for (voice = 0; voice < devc->maxvoice; voice++) + { if (voice_active[voice]) - { - update_volume(voice); - step_envelope_lfo(voice); - } else + { + update_volume(voice); + step_envelope_lfo(voice); + } + else voice_alloc->map[voice] = 0; + } } -static void start_engine(softsyn_devc * devc); +static void start_engine(softsyn_devc * devc); -static void -do_resample(int dummy) +static void do_resample(int dummy) { struct dma_buffparms *dmap = audio_devs[devc->audiodev]->dmap_out; struct voice_info *vinfo; unsigned long flags, jif; - int voice, loops; - short *buf; + int voice, loops; + short *buf; if (softsynth_disabled) return; @@ -538,68 +532,70 @@ cli(); if (is_running) - { - printk("SoftOSS: Playback overrun\n"); - restore_flags(flags); - return; - } + { + printk(KERN_WARNING "SoftOSS: Playback overrun\n"); + restore_flags(flags); + return; + } jif = jiffies; if (jif == last_resample_jiffies) - { - if (resample_counter++ > 50) - { - for (voice = 0; voice < devc->maxvoice; voice++) - init_voice(devc, voice); - voice_limit--; - resample_counter = 0; - printk("SoftOSS: CPU overload. Limiting # of voices to %d\n", voice_limit); - - if (voice_limit < 10) - { - voice_limit = 10; - devc->speed = (devc->speed * 2) / 3; - - printk("SoftOSS: Dropping sampling rate and stopping the device.\n"); - softsynth_disabled = 1; - } - } - } else - { - last_resample_jiffies = jif; - resample_counter = 0; - } + { + if (resample_counter++ > 50) + { + for (voice = 0; voice < devc->maxvoice; voice++) + init_voice(devc, voice); + voice_limit--; + resample_counter = 0; + printk(KERN_WARNING "SoftOSS: CPU overload. Limiting # of voices to %d\n", voice_limit); + + if (voice_limit < 10) + { + voice_limit = 10; + devc->speed = (devc->speed * 2) / 3; + + printk(KERN_WARNING "SoftOSS: Dropping sampling rate and stopping the device.\n"); + softsynth_disabled = 1; + } + } + } + else + { + last_resample_jiffies = jif; + resample_counter = 0; + } /* is_running = 1; */ if (dmap->qlen > devc->max_playahead) - { - printk("SoftOSS: audio buffers full\n"); - is_running = 0; - restore_flags(flags); - return; - } -/* - * First verify that all active voices are valid (do this just once per block). - */ + { + printk(KERN_WARNING "SoftOSS: audio buffers full\n"); + is_running = 0; + restore_flags(flags); + return; + } + /* + * First verify that all active voices are valid (do this just once per block). + */ + for (voice = 0; voice < devc->maxvoice; voice++) + { if (voice_active[voice]) - { - int ptr; + { + int ptr; - vinfo = &softoss_voices[voice]; - ptr = vinfo->ptr >> 9; + vinfo = &softoss_voices[voice]; + ptr = vinfo->ptr >> 9; - if (vinfo->wave == NULL || - ptr < 0 || - ptr > vinfo->sample->len) - init_voice(devc, voice); - else if (!(vinfo->mode & WAVE_LOOPING) && - (vinfo->ptr + vinfo->step) > vinfo->endloop) + if (vinfo->wave == NULL || ptr < 0 || ptr > vinfo->sample->len) + init_voice(devc, voice); + else if (!(vinfo->mode & WAVE_LOOPING) && (vinfo->ptr + vinfo->step) > vinfo->endloop) voice_active[voice] = 0; - } -/* - * Start the resampling process - */ + } + } + + /* + * Start the resampling process + */ loops = devc->samples_per_fragment; buf = (short *) (dmap->raw_buf + (dmap->qtail * dmap->fragment_size)); @@ -613,54 +609,51 @@ devc->usecs += devc->usecs_per_frag; if (tmr_running) - { - sound_timer_interrupt(); - } -/* - * Execute timer - */ + sound_timer_interrupt(); + /* + * Execute timer + */ if (!tmr_running) + { if (devc->usecs >= devc->next_event_usecs) - { - devc->next_event_usecs = ~0; - sequencer_timer(0); - } + { + devc->next_event_usecs = ~0; + sequencer_timer(0); + } + } + is_running = 0; restore_flags(flags); } -static void -delayed_resample(int dummy) +static void delayed_resample(int dummy) { struct dma_buffparms *dmap = audio_devs[devc->audiodev]->dmap_out; - int n = 0; + int n = 0; if (is_running) return; - while (devc->engine_state != ES_STOPPED && - dmap->qlen < devc->max_playahead && n++ < 2) + while (devc->engine_state != ES_STOPPED && dmap->qlen < devc->max_playahead && n++ < 2) do_resample(0); intr_pending = 0; } #ifdef POLLED_MODE -static void -softsyn_poll(unsigned long dummy) +static void softsyn_poll(unsigned long dummy) { delayed_resample(0); if (devc->engine_state != ES_STOPPED) - - { - poll_timer.expires = (1) + jiffies; + { + poll_timer.expires = jiffies+1; add_timer(&poll_timer); - }; + } } + #else -static void -softsyn_callback(int dev, int parm) +static void softsyn_callback(int dev, int parm) { delayed_resample(0); } @@ -686,13 +679,14 @@ devc->control_rate = 64; devc->control_counter = 0; - if (devc->engine_state == ES_STOPPED) { + if (devc->engine_state == ES_STOPPED) + { n = trig = 0; fs = get_fs(); set_fs(get_ds()); dma_ioctl(devc->audiodev, SNDCTL_DSP_SETTRIGGER, (caddr_t)&trig); #ifdef POLLED_MODE - poll_timer.expires = (1) + jiffies; + poll_timer.expires = jiffies+1; add_timer(&poll_timer); /* Start polling */ #else @@ -711,13 +705,11 @@ } } -static void -stop_engine(softsyn_devc * devc) +static void stop_engine(softsyn_devc * devc) { } -static void -request_engine(softsyn_devc * devc, int ticks) +static void request_engine(softsyn_devc * devc, int ticks) { if (ticks < 0) /* Relative time */ devc->next_event_usecs = devc->usecs - ticks * (1000000 / HZ); @@ -728,74 +720,72 @@ /* * Softsync hook serves mode1 (timing) calls made by sequencer.c */ -static int -softsynth_hook(int cmd, int parm1, int parm2, unsigned long parm3) + +static int softsynth_hook(int cmd, int parm1, int parm2, unsigned long parm3) { switch (cmd) - { - case SSYN_START: - start_engine(devc); - break; - - case SSYN_STOP: - stop_engine(devc); - break; - - case SSYN_REQUEST: - request_engine(devc, parm1); - break; - - case SSYN_GETTIME: - return devc->usecs / (1000000 / HZ); - break; - - default: - printk("SoftOSS: Unknown request %d\n", cmd); - } + { + case SSYN_START: + start_engine(devc); + break; + + case SSYN_STOP: + stop_engine(devc); + break; + + case SSYN_REQUEST: + request_engine(devc, parm1); + break; + + case SSYN_GETTIME: + return devc->usecs / (1000000 / HZ); + break; + default: + printk(KERN_WARNING "SoftOSS: Unknown request %d\n", cmd); + } return 0; } static int softsyn_ioctl(int dev, unsigned int cmd, caddr_t arg) { - switch (cmd) { - - case SNDCTL_SYNTH_INFO: - softsyn_info.nr_voices = devc->maxvoice; - if (__copy_to_user(arg, &softsyn_info, sizeof(softsyn_info))) - return -EFAULT; - return 0; - - case SNDCTL_SEQ_RESETSAMPLES: - stop_engine(devc); - reset_samples(devc); - return 0; + switch (cmd) + { + case SNDCTL_SYNTH_INFO: + softsyn_info.nr_voices = devc->maxvoice; + if (copy_to_user(arg, &softsyn_info, sizeof(softsyn_info))) + return -EFAULT; + return 0; + + case SNDCTL_SEQ_RESETSAMPLES: + stop_engine(devc); + reset_samples(devc); + return 0; - case SNDCTL_SYNTH_MEMAVL: - return devc->ram_size - devc->ram_used; + case SNDCTL_SYNTH_MEMAVL: + return devc->ram_size - devc->ram_used; - default: - return -EINVAL; + default: + return -EINVAL; } } -static int -softsyn_kill_note(int devno, int voice, int note, int velocity) +static int softsyn_kill_note(int devno, int voice, int note, int velocity) { if (voice < 0 || voice > devc->maxvoice) return 0; voice_alloc->map[voice] = 0xffff; /* Releasing */ if (softoss_voices[voice].sustain_mode & 1) /* Sustain controller on */ - { - softoss_voices[voice].sustain_mode = 3; /* Note off pending */ - return 0; - } + { + softoss_voices[voice].sustain_mode = 3; /* Note off pending */ + return 0; + } if (velocity > 127 || softoss_voices[voice].mode & WAVE_FAST_RELEASE) - { - init_voice(devc, voice); /* Mark it inactive */ - return 0; - } + { + init_voice(devc, voice); /* Mark it inactive */ + return 0; + } if (softoss_voices[voice].mode & WAVE_ENVELOPES) step_envelope(voice, 1, velocity); /* Enter sustain phase */ else @@ -803,29 +793,26 @@ return 0; } -static int -softsyn_set_instr(int dev, int voice, int instr) +static int softsyn_set_instr(int dev, int voice, int instr) { if (voice < 0 || voice > devc->maxvoice) return 0; if (instr < 0 || instr > MAX_PATCH) - { - printk("SoftOSS: Invalid instrument number %d\n", instr); - return 0; - } + { + printk(KERN_ERR "SoftOSS: Invalid instrument number %d\n", instr); + return 0; + } softoss_voices[voice].instr = instr; - return 0; } -static int -softsyn_start_note(int dev, int voice, int note, int volume) +static int softsyn_start_note(int dev, int voice, int note, int volume) { - int instr = 0; - int best_sample, best_delta, delta_freq, selected; - unsigned long note_freq, freq, base_note, flags; - voice_info *v = &softoss_voices[voice]; + int instr = 0; + int best_sample, best_delta, delta_freq, selected; + unsigned long note_freq, freq, base_note, flags; + voice_info *v = &softoss_voices[voice]; struct patch_info *sample; @@ -839,32 +826,32 @@ cli(); if (note == 255) - { /* Just volume update */ - v->velocity = volume; - if (voice_active[voice]) - update_volume(voice); - restore_flags(flags); - return 0; - } + { /* Just volume update */ + v->velocity = volume; + if (voice_active[voice]) + update_volume(voice); + restore_flags(flags); + return 0; + } voice_active[voice] = 0; /* Stop the voice for a while */ devc->vibratomap &= ~(1 << voice); devc->tremolomap &= ~(1 << voice); instr = v->instr; if (instr < 0 || instr > MAX_PATCH || devc->programs[instr] == NO_SAMPLE) - { - printk("SoftOSS: Undefined MIDI instrument %d\n", instr); - restore_flags(flags); - return 0; - } + { + printk(KERN_WARNING "SoftOSS: Undefined MIDI instrument %d\n", instr); + restore_flags(flags); + return 0; + } instr = devc->programs[instr]; if (instr < 0 || instr >= devc->nrsamples) - { - printk("SoftOSS: Corrupted MIDI instrument %d (%d)\n", v->instr, instr); - restore_flags(flags); - return 0; - } + { + printk(KERN_WARNING "SoftOSS: Corrupted MIDI instrument %d (%d)\n", v->instr, instr); + restore_flags(flags); + return 0; + } note_freq = note_to_freq(note); selected = -1; @@ -873,25 +860,26 @@ best_delta = 1000000; while (instr != NO_SAMPLE && instr >= 0 && selected == -1) - { - delta_freq = note_freq - devc->samples[instr]->base_note; + { + delta_freq = note_freq - devc->samples[instr]->base_note; + + if (delta_freq < 0) + delta_freq = -delta_freq; + if (delta_freq < best_delta) + { + best_sample = instr; + best_delta = delta_freq; + } + if (devc->samples[instr]->low_note <= note_freq && + note_freq <= devc->samples[instr]->high_note) + { + selected = instr; + } + else instr = devc->samples[instr]->key; /* Link to next sample */ - if (delta_freq < 0) - delta_freq = -delta_freq; - if (delta_freq < best_delta) - { - best_sample = instr; - best_delta = delta_freq; - } - if (devc->samples[instr]->low_note <= note_freq && - note_freq <= devc->samples[instr]->high_note) - selected = instr; - else - instr = devc->samples[instr]->key; /* Link to next sample */ - - if (instr < 0 || instr >= devc->nrsamples) - instr = NO_SAMPLE; - } + if (instr < 0 || instr >= devc->nrsamples) + instr = NO_SAMPLE; + } if (selected == -1) instr = best_sample; @@ -899,37 +887,33 @@ instr = selected; if (instr < 0 || instr == NO_SAMPLE || instr > devc->nrsamples) - { - printk("SoftOSS: Unresolved MIDI instrument %d\n", v->instr); - restore_flags(flags); - return 0; - } + { + printk(KERN_WARNING "SoftOSS: Unresolved MIDI instrument %d\n", v->instr); + restore_flags(flags); + return 0; + } sample = devc->samples[instr]; v->sample = sample; if (v->percussive_voice) /* No key tracking */ - { v->orig_freq = sample->base_freq; /* Fixed pitch */ - } else - { - base_note = sample->base_note / 100; - note_freq /= 100; - - freq = sample->base_freq * note_freq / base_note; - v->orig_freq = freq; - } + else + { + base_note = sample->base_note / 100; + note_freq /= 100; + + freq = sample->base_freq * note_freq / base_note; + v->orig_freq = freq; + } if (!(sample->mode & WAVE_LOOPING)) - { - sample->loop_end = sample->len; - } - v->wave = devc->wave[instr]; + sample->loop_end = sample->len; + v->wave = devc->wave[instr]; if (volume < 0) volume = 0; else if (volume > 127) volume = 127; - v->ptr = 0; v->startloop = sample->loop_start * 512; v->startbackloop = 0; @@ -954,40 +938,39 @@ if (!(v->mode & WAVE_LOOPING)) v->mode &= ~(WAVE_BIDIR_LOOP | WAVE_LOOP_BACK); else if (v->mode & WAVE_LOOP_BACK) - { - v->ptr = sample->len; - v->startbackloop = v->startloop; - } + { + v->ptr = sample->len; + v->startbackloop = v->startloop; + } if (v->mode & WAVE_VIBRATO) - { - v->vibrato_rate = sample->vibrato_rate; - v->vibrato_depth = sample->vibrato_depth; - } + { + v->vibrato_rate = sample->vibrato_rate; + v->vibrato_depth = sample->vibrato_depth; + } if (v->mode & WAVE_TREMOLO) - { - v->tremolo_rate = sample->tremolo_rate; - v->tremolo_depth = sample->tremolo_depth; - } + { + v->tremolo_rate = sample->tremolo_rate; + v->tremolo_depth = sample->tremolo_depth; + } if (v->mode & WAVE_ENVELOPES) - { - v->envelope_phase = -1; - v->envelope_vol = 0; - step_envelope(voice, 0, 60); - } + { + v->envelope_phase = -1; + v->envelope_vol = 0; + step_envelope(voice, 0, 60); + } update_volume(voice); compute_step(voice); voice_active[voice] = 1; /* Mark it active */ - restore_flags(flags); return 0; } static int softsyn_open(int synthdev, int mode) { - int err; - extern int softoss_dev; - int frags = 0x7fff0007; /* fragment size of 128 bytes */ + int err; + extern int softoss_dev; + int frags = 0x7fff0007; /* fragment size of 128 bytes */ mm_segment_t fs; if (devc->audio_opened) /* Already opened */ @@ -1007,10 +990,10 @@ devc->audiodev = softoss_dev; if (!(audio_devs[devc->audiodev]->format_mask & AFMT_S16_LE)) - { - printk("SoftOSS: The audio device doesn't support 16 bits\n"); - return -ENXIO; - } + { +/* printk(KERN_ERR "SoftOSS: The audio device doesn't support 16 bits\n"); */ + return -ENXIO; + } if ((err = audio_open((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo)) < 0) return err; @@ -1023,7 +1006,6 @@ DDB(printk("SoftOSS: Using audio dev %d, speed %d, bits %d, channels %d\n", devc->audiodev, devc->speed, devc->bits, devc->channels)); - fs = get_fs(); set_fs(get_ds()); dma_ioctl(devc->audiodev, SNDCTL_DSP_SETFRAGMENT, (caddr_t) & frags); @@ -1031,11 +1013,11 @@ set_fs(fs); if (devc->bits != 16 || devc->channels != 2) - { - audio_release((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo); - printk("SoftOSS: A 16 bit stereo soundcard is required\n"); - return 0; - } + { + audio_release((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo); +/* printk("SoftOSS: A 16 bit stereo soundcard is required\n");*/ + return -EINVAL; + } if (devc->max_playahead >= audio_devs[devc->audiodev]->dmap_out->nbufs) devc->max_playahead = audio_devs[devc->audiodev]->dmap_out->nbufs; @@ -1064,12 +1046,11 @@ devc->audio_opened = 0; } -static void -softsyn_hw_control(int dev, unsigned char *event_rec) +static void softsyn_hw_control(int dev, unsigned char *event_rec) { - int voice, cmd; - unsigned short p1, p2; - unsigned int plong; + int voice, cmd; + unsigned short p1, p2; + unsigned int plong; cmd = event_rec[2]; voice = event_rec[3]; @@ -1078,48 +1059,47 @@ plong = *(unsigned int *) &event_rec[4]; switch (cmd) - { + { - case _GUS_NUMVOICES: - set_max_voices(p1); - break; + case _GUS_NUMVOICES: + set_max_voices(p1); + break; - - default:; - } + default:; + } } -static int -softsyn_load_patch(int dev, int format, const char *addr, +static int softsyn_load_patch(int dev, int format, const char *addr, int offs, int count, int pmgr_flag) { struct patch_info *patch = NULL; - int i, p, instr; - long sizeof_patch; - int memlen, adj; + int i, p, instr; + long sizeof_patch; + int memlen, adj; unsigned short data; - short *wave = NULL; + short *wave = NULL; sizeof_patch = (long) &patch->data[0] - (long) patch; /* Header size */ if (format != GUS_PATCH) - { - printk("SoftOSS: Invalid patch format (key) 0x%x\n", format); - return -EINVAL; - } + { +/* printk(KERN_ERR "SoftOSS: Invalid patch format (key) 0x%x\n", format);*/ + return -EINVAL; + } if (count < sizeof_patch) - { - printk("SoftOSS: Patch header too short\n"); - return -EINVAL; - } + { +/* printk(KERN_ERR "SoftOSS: Patch header too short\n");*/ + return -EINVAL; + } count -= sizeof_patch; if (devc->nrsamples >= MAX_SAMPLE) - { - printk("SoftOSS: Sample table full\n"); - return -ENOSPC; - } + { +/* printk(KERN_ERR "SoftOSS: Sample table full\n");*/ + return -ENOBUFS; + } + /* * Copy the header from user space but ignore the first bytes which have * been transferred already. @@ -1128,54 +1108,55 @@ patch = vmalloc(sizeof(*patch)); if (patch == NULL) - { - printk("SoftOSS: Out of memory\n"); - return -ENOSPC; - } - copy_from_user(&((char *) patch)[offs], &(addr)[offs], sizeof_patch - offs); + { +/* printk(KERN_ERR "SoftOSS: Out of memory\n");*/ + return -ENOMEM; + } + if(copy_from_user(&((char *) patch)[offs], &(addr)[offs], sizeof_patch - offs)) + return -EFAULT; if (patch->mode & WAVE_ROM) - { - vfree(patch); - return -EINVAL; - } + { + vfree(patch); + return -EINVAL; + } instr = patch->instr_no; if (instr < 0 || instr > MAX_PATCH) - { - printk("SoftOSS: Invalid patch number %d\n", instr); - vfree(patch); - return -EINVAL; - } + { +/* printk(KERN_ERR "SoftOSS: Invalid patch number %d\n", instr);*/ + vfree(patch); + return -EINVAL; + } if (count < patch->len) - { - printk("SoftOSS: Patch record too short (%d<%d)\n", count, (int) patch->len); - patch->len = count; - } + { +/* printk(KERN_ERR "SoftOSS: Patch record too short (%d<%d)\n", count, (int) patch->len);*/ + patch->len = count; + } if (patch->len <= 0 || patch->len > (devc->ram_size - devc->ram_used)) - { - printk("SoftOSS: Invalid sample length %d\n", (int) patch->len); - vfree(patch); - return -EINVAL; - } + { +/* printk(KERN_ERR "SoftOSS: Invalid sample length %d\n", (int) patch->len); */ + vfree(patch); + return -EINVAL; + } if (patch->mode & WAVE_LOOPING) - { - if (patch->loop_start < 0 || patch->loop_start >= patch->len) - { - printk("SoftOSS: Invalid loop start %d\n", patch->loop_start); - vfree(patch); - return -EINVAL; - } - if (patch->loop_end < patch->loop_start || patch->loop_end > patch->len) - { - printk("SoftOSS: Invalid loop start or end point (%d, %d)\n", patch->loop_start, patch->loop_end); - vfree(patch); - return -EINVAL; - } - } -/* - * Next load the wave data to memory - */ + { + if (patch->loop_start < 0 || patch->loop_start >= patch->len) + { +/* printk(KERN_ERR "SoftOSS: Invalid loop start %d\n", patch->loop_start);*/ + vfree(patch); + return -EINVAL; + } + if (patch->loop_end < patch->loop_start || patch->loop_end > patch->len) + { +/* printk(KERN_ERR "SoftOSS: Invalid loop start or end point (%d, %d)\n", patch->loop_start, patch->loop_end);*/ + vfree(patch); + return -EINVAL; + } + } + /* + * Next load the wave data to memory + */ memlen = patch->len; adj = 1; @@ -1188,48 +1169,47 @@ wave = vmalloc(memlen); if (wave == NULL) - { - printk("SoftOSS: Can't allocate %d bytes of mem for a sample\n", memlen); - vfree(patch); - return -ENOSPC; - } + { +/* printk(KERN_ERR "SoftOSS: Can't allocate %d bytes of mem for a sample\n", memlen);*/ + vfree(patch); + return -ENOMEM; + } p = 0; for (i = 0; i < memlen / 2; i++) /* Handle words */ - { - unsigned char tmp; - - data = 0; - - if (patch->mode & WAVE_16_BITS) - { - get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); /* Get lsb */ - data = tmp; - get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); /* Get msb */ - if (patch->mode & WAVE_UNSIGNED) - tmp ^= 0x80; /* Convert to signed */ - data |= (tmp << 8); - } else - { - get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); - if (patch->mode & WAVE_UNSIGNED) - tmp ^= 0x80; /* Convert to signed */ + { + unsigned char tmp; + data = 0; + if (patch->mode & WAVE_16_BITS) + { + get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); /* Get lsb */ + data = tmp; + get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); /* Get msb */ + if (patch->mode & WAVE_UNSIGNED) + tmp ^= 0x80; /* Convert to signed */ + data |= (tmp << 8); + } + else + { + get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); + if (patch->mode & WAVE_UNSIGNED) + tmp ^= 0x80; /* Convert to signed */ data = (tmp << 8); /* Convert to 16 bits */ - } - - wave[i] = (short) data; - } + } + wave[i] = (short) data; + } devc->ram_used += patch->len; -/* - * Convert pointers to 16 bit indexes - */ + + /* + * Convert pointers to 16 bit indexes + */ patch->len /= adj; patch->loop_start /= adj; patch->loop_end /= adj; -/* - * Finally link the loaded patch to the chain - */ + /* + * Finally link the loaded patch to the chain + */ patch->key = devc->programs[instr]; devc->programs[instr] = devc->nrsamples; @@ -1239,8 +1219,7 @@ return 0; } -static void -softsyn_panning(int dev, int voice, int pan) +static void softsyn_panning(int dev, int voice, int pan) { if (voice < 0 || voice > devc->maxvoice) return; @@ -1255,13 +1234,11 @@ update_volume(voice); } -static void -softsyn_volume_method(int dev, int mode) +static void softsyn_volume_method(int dev, int mode) { } -static void -softsyn_aftertouch(int dev, int voice, int pressure) +static void softsyn_aftertouch(int dev, int voice, int pressure) { if (voice < 0 || voice > devc->maxvoice) return; @@ -1270,10 +1247,9 @@ update_volume(voice); } -static void -softsyn_controller(int dev, int voice, int ctrl_num, int value) +static void softsyn_controller(int dev, int voice, int ctrl_num, int value) { - unsigned long flags; + unsigned long flags; if (voice < 0 || voice > devc->maxvoice) return; @@ -1281,48 +1257,46 @@ cli(); switch (ctrl_num) - { - case CTRL_PITCH_BENDER: - softoss_voices[voice].bender = value; - - if (voice_active[voice]) - compute_step(voice); /* Update pitch */ - break; - - - case CTRL_PITCH_BENDER_RANGE: - softoss_voices[voice].bender_range = value; - break; - case CTL_EXPRESSION: - value /= 128; - case CTRL_EXPRESSION: - softoss_voices[voice].expression_vol = value; - if (voice_active[voice]) - update_volume(voice); - break; - - case CTL_PAN: - softsyn_panning(dev, voice, (value * 2) - 128); - break; - - case CTL_MAIN_VOLUME: - value = (value * 100) / 16383; - - case CTRL_MAIN_VOLUME: - softoss_voices[voice].main_vol = value; - if (voice_active[voice]) - update_volume(voice); - break; - - default: - break; - } + { + case CTRL_PITCH_BENDER: + softoss_voices[voice].bender = value; + if (voice_active[voice]) + compute_step(voice); /* Update pitch */ + break; + + + case CTRL_PITCH_BENDER_RANGE: + softoss_voices[voice].bender_range = value; + break; + + case CTL_EXPRESSION: + value /= 128; + case CTRL_EXPRESSION: + softoss_voices[voice].expression_vol = value; + if (voice_active[voice]) + update_volume(voice); + break; + + case CTL_PAN: + softsyn_panning(dev, voice, (value * 2) - 128); + break; + + case CTL_MAIN_VOLUME: + value = (value * 100) / 16383; + + case CTRL_MAIN_VOLUME: + softoss_voices[voice].main_vol = value; + if (voice_active[voice]) + update_volume(voice); + break; + default: + break; + } restore_flags(flags); } -static void -softsyn_bender(int dev, int voice, int value) +static void softsyn_bender(int dev, int voice, int value) { if (voice < 0 || voice > devc->maxvoice) return; @@ -1332,46 +1306,46 @@ compute_step(voice); /* Update pitch */ } -static int -softsyn_alloc_voice(int dev, int chn, int note, struct voice_alloc_info *alloc) +static int softsyn_alloc_voice(int dev, int chn, int note, struct voice_alloc_info *alloc) { - int i, p, best = -1, best_time = 0x7fffffff; + int i, p, best = -1, best_time = 0x7fffffff; p = alloc->ptr; + /* - * First look for a completely stopped voice + * First look for a completely stopped voice */ for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0) - { - alloc->ptr = p; - voice_active[p] = 0; - return p; - } - if (alloc->alloc_times[p] < best_time) - { - best = p; - best_time = alloc->alloc_times[p]; - } - p = (p + 1) % alloc->max_voice; - } + { + if (alloc->map[p] == 0) + { + alloc->ptr = p; + voice_active[p] = 0; + return p; + } + if (alloc->alloc_times[p] < best_time) + { + best = p; + best_time = alloc->alloc_times[p]; + } + p = (p + 1) % alloc->max_voice; + } /* - * Then look for a releasing voice + * Then look for a releasing voice */ for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0xffff) - { - alloc->ptr = p; - voice_active[p] = 0; - return p; - } - p = (p + 1) % alloc->max_voice; - } + { + if (alloc->map[p] == 0xffff) + { + alloc->ptr = p; + voice_active[p] = 0; + return p; + } + p = (p + 1) % alloc->max_voice; + } if (best >= 0) p = best; @@ -1381,23 +1355,20 @@ return p; } -static void -softsyn_setup_voice(int dev, int voice, int chn) +static void softsyn_setup_voice(int dev, int voice, int chn) { - unsigned long flags; + unsigned long flags; - struct channel_info *info = - &synth_devs[dev]->chn_info[chn]; + struct channel_info *info = &synth_devs[dev]->chn_info[chn]; save_flags(flags); cli(); + /* init_voice(devc, voice); */ softsyn_set_instr(dev, voice, info->pgm_num); - softoss_voices[voice].expression_vol = - info->controllers[CTL_EXPRESSION]; /* Just MSB */ - softoss_voices[voice].main_vol = - (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; + softoss_voices[voice].expression_vol = info->controllers[CTL_EXPRESSION]; /* Just MSB */ + softoss_voices[voice].main_vol = (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; softsyn_panning(dev, voice, (info->controllers[CTL_PAN] * 2) - 128); softoss_voices[voice].bender = 0; /* info->bender_value; */ softoss_voices[voice].bender_range = info->bender_range; @@ -1407,11 +1378,10 @@ restore_flags(flags); } -static void -softsyn_reset(int devno) +static void softsyn_reset(int devno) { - int i; - unsigned long flags; + int i; + unsigned long flags; save_flags(flags); cli(); @@ -1450,23 +1420,20 @@ * Timer stuff (for /dev/music). */ -static unsigned int -soft_tmr_start(int dev, unsigned int usecs) +static unsigned int soft_tmr_start(int dev, unsigned int usecs) { tmr_running = 1; start_engine(devc); return devc->usecs_per_frag; } -static void -soft_tmr_disable(int dev) +static void soft_tmr_disable(int dev) { stop_engine(devc); tmr_running = 0; } -static void -soft_tmr_restart(int dev) +static void soft_tmr_restart(int dev) { tmr_running = 1; } @@ -1480,10 +1447,9 @@ soft_tmr_restart }; -int -probe_softsyn(struct address_info *hw_config) +int probe_softsyn(struct address_info *hw_config) { - int i; + int i; if (softsynth_loaded) return 0; @@ -1492,10 +1458,10 @@ devc->ram_used = 0; devc->nrsamples = 0; for (i = 0; i < MAX_PATCH; i++) - { - devc->programs[i] = NO_SAMPLE; - devc->wave[i] = NULL; - } + { + devc->programs[i] = NO_SAMPLE; + devc->wave[i] = NULL; + } devc->maxvoice = DEFAULT_VOICES; @@ -1516,15 +1482,12 @@ #else devc->default_max_voices = 32; #endif - softsynth_loaded = 1; return 1; } -void -attach_softsyn_card(struct address_info *hw_config) +void attach_softsyn_card(struct address_info *hw_config) { - voice_alloc = &softsyn_operations.alloc; synth_devs[devc->synthdev = num_synths++] = &softsyn_operations; sequencer_init(); @@ -1536,14 +1499,10 @@ #endif } -void -unload_softsyn(struct address_info *hw_config) +void unload_softsyn(struct address_info *hw_config) { if (!softsynth_loaded) return; -#ifndef POLLED_MODE -#endif - softsynthp = NULL; softsynth_loaded = 0; reset_samples(devc); @@ -1553,10 +1512,9 @@ static struct address_info config; -int -init_module(void) +int init_module(void) { - printk("SoftOSS driver Copyright (C) by Hannu Savolainen 1993-1997\n"); + printk(KERN_INFO "SoftOSS driver Copyright (C) by Hannu Savolainen 1993-1997\n"); if (!probe_softsyn(&config)) return -ENODEV; attach_softsyn_card(&config); @@ -1564,8 +1522,7 @@ return 0; } -void -cleanup_module(void) +void cleanup_module(void) { unload_softsyn(&config); sound_unload_synthdev(devc->synthdev); diff -u --recursive --new-file v2.1.93/linux/drivers/sound/softoss_rs.c linux/drivers/sound/softoss_rs.c --- v2.1.93/linux/drivers/sound/softoss_rs.c Sat Nov 29 10:33:21 1997 +++ linux/drivers/sound/softoss_rs.c Wed Apr 8 17:24:48 1998 @@ -5,8 +5,8 @@ * Software based MIDI synthsesizer driver, the actual mixing loop. * Keep the loop as simple as possible to make it easier to rewrite this * routine in assembly. - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) @@ -21,10 +21,9 @@ #if defined(CONFIG_SOFTOSS) || defined(MODULE) #include "softoss.h" -void -softsynth_resample_loop(short *buf, int loops) +void softsynth_resample_loop(short *buf, int loops) { - int iloop, voice; + int iloop, voice; volatile voice_info *v; #ifdef OSS_BIG_ENDIAN @@ -33,104 +32,102 @@ #endif for (iloop = 0; iloop < loops; iloop++) - { /* Mix one sample */ - - int accum, left = 0, right = 0; - int ix, position; - - for (voice = 0; voice < devc->maxvoice; voice++) - if (voice_active[voice]) - { /* Compute voice */ - - v = &softoss_voices[voice]; + { /* Mix one sample */ + int accum, left = 0, right = 0; + int ix, position; + + for (voice = 0; voice < devc->maxvoice; voice++) + { + if (voice_active[voice]) + { /* Compute voice */ + v = &softoss_voices[voice]; #ifdef SOFTOSS_TEST - ix = iloop << 3; - position = v->ptr; + ix = iloop << 3; + position = v->ptr; #else - ix = (position = v->ptr) >> 9; + ix = (position = v->ptr) >> 9; #endif - /* Interpolation (resolution of 512 steps) */ - { - int fract = v->ptr & 0x1f; /* 9 bits */ - - /* This method works with less arithmetic operations */ - register int v1 = v->wave[ix]; - - accum = v1 + ((((v->wave[ix + 1] - v1)) * (fract)) >> 9); - } - - left += (accum * v->leftvol); - right += (accum * v->rightvol); - - /* Update sample pointer */ - - position += v->step; - if (position <= v->endloop) - v->ptr = position; - else if (v->mode & WAVE_LOOPING) - { - if (v->mode & WAVE_BIDIR_LOOP) - { - v->mode ^= WAVE_LOOP_BACK; /* Turn around */ - v->step *= -1; - } else - { - position -= v->looplen; - v->ptr = position; - } - } - /* else leave the voice looping the current sample */ - - if (v->mode & WAVE_LOOP_BACK && position < v->startloop) - { - if (v->mode & WAVE_BIDIR_LOOP) - { - v->mode ^= WAVE_LOOP_BACK; /* Turn around */ - v->step *= -1; - } else - { - position += v->looplen; - v->ptr = position; - } - } - } /* Compute voice */ + /* Interpolation (resolution of 512 steps) */ + { + int fract = v->ptr & 0x1f; /* 9 bits */ + + /* This method works with less arithmetic operations */ + register int v1 = v->wave[ix]; + accum = v1 + ((((v->wave[ix + 1] - v1)) * (fract)) >> 9); + } + + left += (accum * v->leftvol); + right += (accum * v->rightvol); + + /* Update sample pointer */ + position += v->step; + if (position <= v->endloop) + v->ptr = position; + else if (v->mode & WAVE_LOOPING) + { + if (v->mode & WAVE_BIDIR_LOOP) + { v->mode ^= WAVE_LOOP_BACK; /* Turn around */ + v->step *= -1; + } + else + { + position -= v->looplen; + v->ptr = position; + } + } + /* else leave the voice looping the current sample */ + + if (v->mode & WAVE_LOOP_BACK && position < v->startloop) + { + if (v->mode & WAVE_BIDIR_LOOP) + { v->mode ^= WAVE_LOOP_BACK; /* Turn around */ + v->step *= -1; + } + else + { + position += v->looplen; + v->ptr = position; + } + } + } /* Compute voice */ + } #if 1 /* Delay */ - left += left_delay[delayp]; - right += right_delay[delayp]; + left += left_delay[delayp]; + right += right_delay[delayp]; - left_delay[delayp] = right >> 2; - right_delay[delayp] = left >> 2; - delayp = (delayp + 1) % devc->delay_size; + left_delay[delayp] = right >> 2; + right_delay[delayp] = left >> 2; + delayp = (delayp + 1) % devc->delay_size; #endif #define AFTERSCALE devc->afterscale; - left >>= AFTERSCALE; - right >>= AFTERSCALE; + left >>= AFTERSCALE; + right >>= AFTERSCALE; - if (left > 32767) - left = 32767; - if (left < -32768) - left = -32768; - if (right > 32767) - right = 32767; - if (right < -32768) - right = -32768; + if (left > 32767) + left = 32767; + if (left < -32768) + left = -32768; + if (right > 32767) + right = 32767; + if (right < -32768) + right = -32768; #ifdef OSS_BIG_ENDIAN - *cbuf++ = left & 0xff; - *cbuf++ = (left >> 8) & 0xff; - *cbuf++ = right & 0xff; - *cbuf++ = (right >> 8) & 0xff; + *cbuf++ = left & 0xff; + *cbuf++ = (left >> 8) & 0xff; + *cbuf++ = right & 0xff; + *cbuf++ = (right >> 8) & 0xff; #else - *buf++ = left; - *buf++ = right; + *buf++ = left; + *buf++ = right; #endif - if (devc->control_counter++ >= devc->control_rate) - { - devc->control_counter = 0; - softsyn_control_loop(); - } - } /* Mix one sample */ + if (devc->control_counter++ >= devc->control_rate) + { + devc->control_counter = 0; + softsyn_control_loop(); + } + } /* Mix one sample */ } #endif diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h --- v2.1.93/linux/drivers/sound/sound_calls.h Tue Mar 17 22:18:15 1998 +++ linux/drivers/sound/sound_calls.h Wed Apr 8 17:24:48 1998 @@ -11,6 +11,7 @@ int DMAbuf_move_wrpointer(int dev, int l); /* int DMAbuf_ioctl(int dev, unsigned int cmd, caddr_t arg, int local); */ void DMAbuf_init(int dev, int dma1, int dma2); +void DMAbuf_deinit(int dev); int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); int DMAbuf_open_dma (int dev); void DMAbuf_close_dma (int dev); @@ -83,15 +84,8 @@ /* From soundcard.c */ void request_sound_timer (int count); void sound_stop_timer(void); -/* These two are about to die.. */ -int snd_set_irq_handler (int interrupt_level, void(*iproc)(int, void*, struct pt_regs *), char *name, int *osp, void *dev_id); -void snd_release_irq(int vect, void *ptr); -void sound_dma_malloc(int dev); -void sound_dma_free(int dev); void conf_printf(char *name, struct address_info *hw_config); void conf_printf2(char *name, int base, int irq, int dma, int dma2); -int ioctl_in(caddr_t arg); -int ioctl_out(caddr_t arg, int result); /* From opl3.c */ int opl3_detect (int ioaddr, int *osp); @@ -187,7 +181,7 @@ #define AD_F_CS4231 0x0001 /* Returned if a CS4232 (or compatible) detected */ #define AD_F_CS4248 0x0001 /* Returned if a CS4248 (or compatible) detected */ -void ad1848_control(int cmd, int arg); +int ad1848_control(int cmd, int arg); #define AD1848_SET_XTAL 1 #define AD1848_MIXER_REROUTE 2 #define AD1848_REROUTE(oldctl, newctl) \ @@ -196,9 +190,6 @@ void adintr(int irq, void *dev_id, struct pt_regs * dummy); void attach_ms_sound(struct address_info * hw_config); int probe_ms_sound(struct address_info *hw_config); -void attach_pnp_ad1848(struct address_info * hw_config); -int probe_pnp_ad1848(struct address_info *hw_config); -void unload_pnp_ad1848(struct address_info *hw_info); /* From pss.c */ int probe_pss (struct address_info *hw_config); @@ -235,7 +226,6 @@ int probe_mad16 (struct address_info *hw_config); void attach_mad16_mpu (struct address_info *hw_config); int probe_mad16_mpu (struct address_info *hw_config); -int mad16_sb_dsp_detect (struct address_info *hw_config); /* Unload routines from various source files*/ void unload_pss(struct address_info *hw_info); @@ -278,3 +268,7 @@ int probe_v_midi (struct address_info *hw_config); void unload_v_midi (struct address_info *hw_config); +/* From vidc.c */ +void attach_vidc(struct address_info *hw_config); +int probe_vidc(struct address_info *hw_config); +void unload_vidc(struct address_info *hw_config); diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sound_firmware.c linux/drivers/sound/sound_firmware.c --- v2.1.93/linux/drivers/sound/sound_firmware.c Tue Mar 10 10:03:33 1998 +++ linux/drivers/sound/sound_firmware.c Wed Apr 8 17:24:48 1998 @@ -1,3 +1,4 @@ +#include "os.h" #define __KERNEL_SYSCALLS__ #include #include @@ -19,14 +20,14 @@ return 0; } l = lseek(fd, 0L, 2); - if (l <= 0 || l > 65535) + if (l <= 0 || l > 131072) { printk(KERN_INFO "Invalid firmware '%s'\n", fn); sys_close(fd); - return 0; + return 0; } lseek(fd, 0L, 0); - dp = kmalloc(l, GFP_KERNEL); + dp = vmalloc(l); if (dp == NULL) { printk(KERN_INFO "Out of memory loading '%s'.\n", fn); @@ -36,7 +37,7 @@ if (read(fd, dp, l) != l) { printk(KERN_INFO "Failed to read '%s'.\n", fn); - kfree(dp); + vfree(dp); sys_close(fd); return 0; } @@ -45,7 +46,7 @@ return (int) l; } -int mod_firmware_load(const char *fn, char **fp) +int mod_firmware_load(const char *fn, char **fp) { int r; mm_segment_t fs = get_fs(); @@ -55,3 +56,4 @@ set_fs(fs); return r; } + diff -u --recursive --new-file v2.1.93/linux/drivers/sound/sound_syms.c linux/drivers/sound/sound_syms.c --- v2.1.93/linux/drivers/sound/sound_syms.c Mon Dec 29 10:22:46 1997 +++ linux/drivers/sound/sound_syms.c Wed Apr 8 17:24:48 1998 @@ -1,6 +1,6 @@ /* - * The sound core exports the following symbols to the rest of - * modulespace. + * The sound core exports the following symbols to the rest of + * modulespace. * * (C) Copyright 1997 Alan Cox, Licensed under the GNU GPL */ @@ -9,6 +9,8 @@ #include "sound_config.h" #define _MIDI_SYNTH_C_ #include "midi_synth.h" +#define _SEQUENCER_C_ +#include "tuning.h" #include #include "sound_firmware.h" @@ -31,16 +33,13 @@ EXPORT_SYMBOL(sound_install_mixer); EXPORT_SYMBOL(sound_alloc_dma); EXPORT_SYMBOL(sound_free_dma); -EXPORT_SYMBOL(snd_set_irq_handler); -EXPORT_SYMBOL(snd_release_irq); +EXPORT_SYMBOL(sound_open_dma); +EXPORT_SYMBOL(sound_close_dma); EXPORT_SYMBOL(sound_alloc_audiodev); EXPORT_SYMBOL(sound_alloc_mididev); EXPORT_SYMBOL(sound_alloc_mixerdev); EXPORT_SYMBOL(sound_alloc_timerdev); EXPORT_SYMBOL(sound_alloc_synthdev); -EXPORT_SYMBOL(sound_mem_blocks); -EXPORT_SYMBOL(sound_mem_sizes); -EXPORT_SYMBOL(sound_nblocks); EXPORT_SYMBOL(sound_unload_audiodev); EXPORT_SYMBOL(sound_unload_mididev); EXPORT_SYMBOL(sound_unload_mixerdev); @@ -90,3 +89,14 @@ EXPORT_SYMBOL(midi_synth_bender); EXPORT_SYMBOL(midi_synth_load_patch); +/* Firmware */ + +EXPORT_SYMBOL(mod_firmware_load); + +/* Tuning */ + +EXPORT_SYMBOL(cent_tuning); +EXPORT_SYMBOL(semitone_tuning); + +MODULE_DESCRIPTION("Sound subsystem"); +MODULE_AUTHOR("Hannu Savolainen, et al."); diff -u --recursive --new-file v2.1.93/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.1.93/linux/drivers/sound/soundcard.c Tue Mar 17 22:18:15 1998 +++ linux/drivers/sound/soundcard.c Wed Apr 8 17:24:48 1998 @@ -16,8 +16,8 @@ * Stefan Reinauer : integrated /proc/sound (equals to /dev/sndstat, * which should disappear in the near future) */ -#include +#include #include "sound_config.h" #include @@ -28,6 +28,7 @@ #include #include #ifdef __KERNEL__ +#include #include #include #include @@ -48,6 +49,13 @@ #define modular 0 #endif +/* + * This ought to be moved into include/asm/dma.h + */ +#ifndef valid_dma +#define valid_dma(n) ((n) >= 0 && (n) < MAX_DMA_CHANNELS && (n) != 4) +#endif + static int chrdev_registered = 0; static int sound_major = SOUND_MAJOR; @@ -57,12 +65,11 @@ * Table for permanently allocated memory (used when unloading the module) */ caddr_t sound_mem_blocks[1024]; -int sound_mem_sizes[1024]; int sound_nblocks = 0; static int soundcard_configured = 0; -static char dma_alloc_map[8] = +static char dma_alloc_map[MAX_DMA_CHANNELS] = {0}; #define DMA_MAP_UNAVAIL 0 @@ -788,31 +795,9 @@ } -static unsigned int irqs = 0; - -#ifdef MODULE -static void -free_all_irqs(void) -{ - int i; - - for (i = 0; i < 31; i++) - { - if (irqs & (1ul << i)) - { - printk(KERN_WARNING "Sound warning: IRQ%d was left allocated - fixed.\n", i); - snd_release_irq(i, NULL); - } - } - irqs = 0; -} - -char kernel_version[] = UTS_RELEASE; - -#endif - -static int sound[20] = -{0}; +static int sound[20] = { + 0 +}; int init_module(void) { @@ -876,10 +861,9 @@ } #endif sound_unload_drivers(); - free_all_irqs(); /* If something was left allocated by accident */ sequencer_unload(); - for (i = 0; i < 8; i++) + for (i = 0; i < MAX_DMA_CHANNELS; i++) { if (dma_alloc_map[i] != DMA_MAP_UNAVAIL) { @@ -895,35 +879,6 @@ } #endif -int snd_set_irq_handler(int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp, void *dev_id) -{ - int retcode; - unsigned long flags; - - save_flags(flags); - cli(); - retcode = request_irq(interrupt_level, iproc, 0, name, dev_id); - - if (retcode < 0) - { - printk(KERN_ERR "Sound: IRQ%d already in use\n", interrupt_level); - } - else - irqs |= (1ul << interrupt_level); - - restore_flags(flags); - return retcode; -} - -void snd_release_irq(int vect, void *dev_id) -{ - if (!(irqs & (1ul << vect))) - return; - - irqs &= ~(1ul << vect); - free_irq(vect, dev_id); -} - int sound_alloc_dma(int chn, char *deviceID) { int err; @@ -940,7 +895,7 @@ { unsigned long flags; - if (chn < 0 || chn > 7 || chn == 4) + if (!valid_dma(chn)) { printk(KERN_ERR "sound_open_dma: Invalid DMA channel %d\n", chn); return 1; diff -u --recursive --new-file v2.1.93/linux/drivers/sound/trix.c linux/drivers/sound/trix.c --- v2.1.93/linux/drivers/sound/trix.c Tue Feb 17 13:12:47 1998 +++ linux/drivers/sound/trix.c Wed Apr 8 17:24:48 1998 @@ -3,14 +3,18 @@ * * Low level driver for the MediaTrix AudioTrix Pro * (MT-0002-PC Control Chip) - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. + * + * Changes + * Alan Cox Modularisation, cleanup. */ + #include #include @@ -35,30 +39,27 @@ #endif -static int kilroy_was_here = 0; /* Don't detect twice */ -static int sb_initialized = 0; -static int mpu_initialized = 0; +static int kilroy_was_here = 0; /* Don't detect twice */ +static int sb_initialized = 0; +static int mpu_initialized = 0; -static int *trix_osp = NULL; +static int *trix_osp = NULL; -static unsigned char -trix_read(int addr) +static unsigned char trix_read(int addr) { outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ return inb(0x391); /* MT-0002-PC ASIC data */ } -static void -trix_write(int addr, int data) +static void trix_write(int addr, int data) { outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ outb(((unsigned char) data), 0x391); /* MT-0002-PC ASIC data */ } -static void -download_boot(int base) +static void download_boot(int base) { - int i = 0, n = trix_boot_len; + int i = 0, n = trix_boot_len; if (trix_boot_len == 0) return; @@ -83,24 +84,23 @@ } -static int -trix_set_wss_port(struct address_info *hw_config) +static int trix_set_wss_port(struct address_info *hw_config) { unsigned char addr_bits; if (check_region(0x390, 2)) - { - printk(KERN_ERR "AudioTrix: Config port I/O conflict\n"); - return 0; - } + { + printk(KERN_ERR "AudioTrix: Config port I/O conflict\n"); + return 0; + } if (kilroy_was_here) /* Already initialized */ return 0; if (trix_read(0x15) != 0x71) /* No ASIC signature */ - { - MDB(printk("No AudioTrix ASIC signature found\n")); - return 0; - } + { + MDB(printk(KERN_ERR "No AudioTrix ASIC signature found\n")); + return 0; + } kilroy_was_here = 1; /* @@ -111,26 +111,26 @@ trix_write(0x14, 0); /* - * Configure the ASIC to place the codec to the proper I/O location + * Configure the ASIC to place the codec to the proper I/O location */ switch (hw_config->io_base) - { - case 0x530: - addr_bits = 0; - break; - case 0x604: - addr_bits = 1; - break; - case 0xE80: - addr_bits = 2; - break; - case 0xF40: - addr_bits = 3; - break; - default: - return 0; - } + { + case 0x530: + addr_bits = 0; + break; + case 0x604: + addr_bits = 1; + break; + case 0xE80: + addr_bits = 2; + break; + case 0xF40: + addr_bits = 3; + break; + default: + return 0; + } trix_write(0x19, (trix_read(0x19) & 0x03) | addr_bits); return 1; @@ -141,120 +141,123 @@ * AudioTrix Pro */ -int -probe_trix_wss(struct address_info *hw_config) +int probe_trix_wss(struct address_info *hw_config) { - int ret; + int ret; /* - * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTrix Pro for example) - * return 0x00. + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (AudioTrix Pro for example) + * return 0x00. */ if (check_region(hw_config->io_base, 8)) - { - printk("AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } + { + printk(KERN_ERR "AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } trix_osp = hw_config->osp; if (!trix_set_wss_port(hw_config)) return 0; if ((inb(hw_config->io_base + 3) & 0x3f) != 0x00) - { - MDB(printk("No MSS signature detected on port 0x%x\n", hw_config->io_base)); - return 0; - } + { + MDB(printk(KERN_ERR "No MSS signature detected on port 0x%x\n", hw_config->io_base)); + return 0; + } if (hw_config->irq > 11) - { - printk("AudioTrix: Bad WSS IRQ %d\n", hw_config->irq); - return 0; - } + { + printk(KERN_ERR "AudioTrix: Bad WSS IRQ %d\n", hw_config->irq); + return 0; + } if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) - { - printk("AudioTrix: Bad WSS DMA %d\n", hw_config->dma); - return 0; - } + { + printk(KERN_ERR "AudioTrix: Bad WSS DMA %d\n", hw_config->dma); + return 0; + } if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) if (hw_config->dma2 != 0 && hw_config->dma2 != 1 && hw_config->dma2 != 3) - { - printk("AudioTrix: Bad capture DMA %d\n", hw_config->dma2); + { + printk(KERN_ERR "AudioTrix: Bad capture DMA %d\n", hw_config->dma2); return 0; - } + } /* - * Check that DMA0 is not in use with a 8 bit board. + * Check that DMA0 is not in use with a 8 bit board. */ if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) - { - printk("AudioTrix: Can't use DMA0 with a 8 bit card slot\n"); - return 0; - } + { + printk(KERN_ERR "AudioTrix: Can't use DMA0 with a 8 bit card slot\n"); + return 0; + } if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80) - { - printk("AudioTrix: Can't use IRQ%d with a 8 bit card slot\n", hw_config->irq); - return 0; - } + { + printk(KERN_ERR "AudioTrix: Can't use IRQ%d with a 8 bit card slot\n", hw_config->irq); + return 0; + } ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp); if (ret) - { + { #ifdef TRIX_ENABLE_JOYSTICK - trix_write(0x15, 0x80); + trix_write(0x15, 0x80); #endif - request_region(0x390, 2, "AudioTrix"); - } + request_region(0x390, 2, "AudioTrix"); + } return ret; } void attach_trix_wss(struct address_info *hw_config) { - static unsigned char interrupt_bits[12] = - {0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x10, 0x18, 0x20}; - char bits; - - static unsigned char dma_bits[4] = - {1, 2, 0, 3}; - - int config_port = hw_config->io_base + 0; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; - int old_num_mixers = num_mixers; + static unsigned char interrupt_bits[12] = { + 0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x10, 0x18, 0x20 + }; + char bits; + + static unsigned char dma_bits[4] = { + 1, 2, 0, 3 + }; + + int config_port = hw_config->io_base + 0; + int dma1 = hw_config->dma, dma2 = hw_config->dma2; + int old_num_mixers = num_mixers; trix_osp = hw_config->osp; if (!kilroy_was_here) - { - DDB(printk("AudioTrix: Attach called but not probed yet???\n")); - return; - } + { + DDB(printk("AudioTrix: Attach called but not probed yet???\n")); + return; + } + /* - * Set the IRQ and DMA addresses. + * Set the IRQ and DMA addresses. */ bits = interrupt_bits[hw_config->irq]; if (bits == 0) - { - printk("AudioTrix: Bad IRQ (%d)\n", hw_config->irq); - return; - } + { + printk("AudioTrix: Bad IRQ (%d)\n", hw_config->irq); + return; + } outb((bits | 0x40), config_port); if (hw_config->dma2 == -1 || hw_config->dma2 == hw_config->dma) - { + { bits |= dma_bits[dma1]; dma2 = dma1; - } else - { - unsigned char tmp; - - tmp = trix_read(0x13) & ~30; - trix_write(0x13, tmp | 0x80 | (dma1 << 4)); - - tmp = trix_read(0x14) & ~30; - trix_write(0x14, tmp | 0x80 | (dma2 << 4)); - } + } + else + { + unsigned char tmp; + + tmp = trix_read(0x13) & ~30; + trix_write(0x13, tmp | 0x80 | (dma1 << 4)); + + tmp = trix_read(0x14) & ~30; + trix_write(0x14, tmp | 0x80 | (dma2 << 4)); + } outb((bits), config_port); /* Write IRQ+DMA setup */ @@ -267,22 +270,22 @@ request_region(hw_config->io_base, 4, "MSS config"); if (num_mixers > old_num_mixers) /* Mixer got installed */ - { - AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); /* Line in */ - AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); - AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* OPL4 */ - AD1848_REROUTE(SOUND_MIXER_SPEAKER, SOUND_MIXER_ALTPCM); /* SB */ - } -} - -int -probe_trix_sb(struct address_info *hw_config) -{ - - int tmp; - unsigned char conf; - static char irq_translate[] = - {-1, -1, -1, 0, 1, 2, -1, 3}; + { + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); /* Line in */ + AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); + AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* OPL4 */ + AD1848_REROUTE(SOUND_MIXER_SPEAKER, SOUND_MIXER_ALTPCM); /* SB */ + } +} + +int probe_trix_sb(struct address_info *hw_config) +{ + + int tmp; + unsigned char conf; + static char irq_translate[] = { + -1, -1, -1, 0, 1, 2, -1, 3 + }; if (trix_boot_len == 0) return 0; /* No boot code -> no fun */ @@ -294,10 +297,10 @@ return 0; if (check_region(hw_config->io_base, 16)) - { - printk("AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } + { + printk(KERN_ERR "AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } if ((hw_config->io_base & 0xffffff8f) != 0x200) return 0; @@ -329,11 +332,10 @@ #endif } -void -attach_trix_sb(struct address_info *hw_config) +void attach_trix_sb(struct address_info *hw_config) { - extern int sb_be_quiet; - int old_quiet; + extern int sb_be_quiet; + int old_quiet; #ifdef CONFIG_SBDSP hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING; @@ -348,8 +350,7 @@ #endif } -void -attach_trix_mpu(struct address_info *hw_config) +void attach_trix_mpu(struct address_info *hw_config) { #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) hw_config->name = "AudioTrix Pro"; @@ -357,78 +358,74 @@ #endif } -int -probe_trix_mpu(struct address_info *hw_config) +int probe_trix_mpu(struct address_info *hw_config) { #ifdef DO_MIDI - unsigned char conf; - static char irq_bits[] = - {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5}; + unsigned char conf; + static char irq_bits[] = { + -1, -1, -1, 1, 2, 3, -1, 4, -1, 5 + }; if (!kilroy_was_here) - { - DDB(printk("Trix: WSS and SB modes must be initialized before MPU\n")); - return 0; /* AudioTrix Pro has not been detected earlier */ - } + { + DDB(printk("Trix: WSS and SB modes must be initialized before MPU\n")); + return 0; /* AudioTrix Pro has not been detected earlier */ + } if (!sb_initialized) - { - DDB(printk("Trix: SB mode must be initialized before MPU\n")); - return 0; - } + { + DDB(printk("Trix: SB mode must be initialized before MPU\n")); + return 0; + } if (mpu_initialized) - { - DDB(printk("Trix: MPU mode already initialized\n")); - return 0; - } + { + DDB(printk("Trix: MPU mode already initialized\n")); + return 0; + } if (check_region(hw_config->io_base, 4)) - { - printk("AudioTrix: MPU I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } + { + printk(KERN_ERR "AudioTrix: MPU I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } if (hw_config->irq > 9) - { - printk("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } + { + printk(KERN_ERR "AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); + return 0; + } if (irq_bits[hw_config->irq] == -1) - { - printk("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); - return 0; - } + { + printk(KERN_ERR "AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); + return 0; + } switch (hw_config->io_base) - { - case 0x330: - conf = 0x00; - break; - case 0x370: - conf = 0x04; - break; - case 0x3b0: - conf = 0x08; - break; - case 0x3f0: - conf = 0x0c; - break; - default: - return 0; /* Invalid port */ - } + { + case 0x330: + conf = 0x00; + break; + case 0x370: + conf = 0x04; + break; + case 0x3b0: + conf = 0x08; + break; + case 0x3f0: + conf = 0x0c; + break; + default: + return 0; /* Invalid port */ + } conf |= irq_bits[hw_config->irq] << 4; - trix_write(0x19, (trix_read(0x19) & 0x83) | conf); - mpu_initialized = 1; - return probe_uart401(hw_config); #else return 0; #endif } -void -unload_trix_wss(struct address_info *hw_config) +void unload_trix_wss(struct address_info *hw_config) { - int dma2 = hw_config->dma2; + int dma2 = hw_config->dma2; if (dma2 == -1) dma2 = hw_config->dma; @@ -444,15 +441,14 @@ sound_unload_audiodev(hw_config->slots[0]); } -void -unload_trix_mpu(struct address_info *hw_config) +void unload_trix_mpu(struct address_info *hw_config) { #ifdef DO_MIDI unload_uart401(hw_config); #endif } -void -unload_trix_sb(struct address_info *hw_config) + +void unload_trix_sb(struct address_info *hw_config) { #ifdef CONFIG_SBDSP sb_dsp_unload(hw_config); @@ -473,6 +469,18 @@ int mpu_io = -1; int mpu_irq = -1; +EXPORT_NO_SYMBOLS; + +MODULE_PARM(io,"i"); +MODULE_PARM(irq,"i"); +MODULE_PARM(dma,"i"); +MODULE_PARM(dma2,"i"); +MODULE_PARM(sb_io,"i"); +MODULE_PARM(sb_dma,"i"); +MODULE_PARM(sb_irq,"i"); +MODULE_PARM(mpu_io,"i"); +MODULE_PARM(mpu_irq,"i"); + struct address_info config; struct address_info sb_config; struct address_info mpu_config; @@ -482,16 +490,15 @@ static int fw_load; -int -init_module(void) +int init_module(void) { - printk("MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + printk(KERN_INFO "MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); if (io == -1 || dma == -1 || irq == -1) - { - printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); - return -EINVAL; - } + { + printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); + return -EINVAL; + } config.io_base = io; config.irq = irq; config.dma = dma; @@ -505,21 +512,21 @@ mpu_config.irq = mpu_irq; if (sb_io != -1 && (sb_irq == -1 || sb_dma == -1)) - { - printk(KERN_INFO "CONFIG_SB_IRQ and CONFIG_SB_DMA must be specified if SB_IO is set.\n"); - return -EINVAL; - } + { + printk(KERN_INFO "CONFIG_SB_IRQ and CONFIG_SB_DMA must be specified if SB_IO is set.\n"); + return -EINVAL; + } if (mpu_io != -1 && mpu_irq == -1) - { - printk(KERN_INFO "CONFIG_MPU_IRQ must be specified if MPU_IO is set.\n"); - return -EINVAL; - } + { + printk(KERN_INFO "CONFIG_MPU_IRQ must be specified if MPU_IO is set.\n"); + return -EINVAL; + } if (!trix_boot) - { - fw_load = 1; - trix_boot_len = mod_firmware_load("/etc/sound/trxpro.bin", + { + fw_load = 1; + trix_boot_len = mod_firmware_load("/etc/sound/trxpro.bin", (char **) &trix_boot); - } + } if (!probe_trix_wss(&config)) return -ENODEV; attach_trix_wss(&config); @@ -530,26 +537,26 @@ */ if (sb_io != -1) - { - sb = probe_trix_sb(&sb_config); - if (sb) - attach_trix_sb(&sb_config); - } + { + sb = probe_trix_sb(&sb_config); + if (sb) + attach_trix_sb(&sb_config); + } + if (mpu_io != -1) - { - mpu = probe_trix_mpu(&mpu_config); - if (mpu) - attach_trix_mpu(&mpu_config); - } + { + mpu = probe_trix_mpu(&mpu_config); + if (mpu) + attach_trix_mpu(&mpu_config); + } SOUND_LOCK; return 0; } -void -cleanup_module(void) +void cleanup_module(void) { if (fw_load && trix_boot) - kfree(trix_boot); + vfree(trix_boot); if (sb) unload_trix_sb(&sb_config); if (mpu) diff -u --recursive --new-file v2.1.93/linux/drivers/sound/uart401.c linux/drivers/sound/uart401.c --- v2.1.93/linux/drivers/sound/uart401.c Tue Mar 17 22:18:15 1998 +++ linux/drivers/sound/uart401.c Wed Apr 8 17:24:48 1998 @@ -12,7 +12,8 @@ * * Changes: * Alan Cox Reformatted, removed sound_mem usage, use normal Linux - * interrupt allocation. + * interrupt allocation. Protect against bogus unload + * Fixed to allow IRQ > 15 * * Status: * Untested @@ -244,6 +245,7 @@ uart401_devc *devc; char *name = "MPU-401 (UART) MIDI"; + if (hw_config->name) name = hw_config->name; @@ -269,12 +271,6 @@ else devc->share_irq = 0; - if (devc->irq < 1 || devc->irq > 15) - { - kfree(devc); - return; - } - if (!devc->share_irq) { if (request_irq(devc->irq, uart401intr, 0, "MPU-401 UART", devc) < 0) @@ -345,6 +341,7 @@ for (timeout = 30000; timeout > 0 && !output_ready(devc); timeout--); devc->input_byte = 0; uart401_cmd(devc, MPU_RESET); + /* * Wait at least 25 msec. This method is not accurate so let's make the * loop bit longer. Cannot sleep since this is called during boot. @@ -387,6 +384,8 @@ DDB(printk("Entered probe_uart401()\n")); + /* Default to "not found" */ + hw_config->slots[4] = -1; detected_devc = NULL; if (check_region(hw_config->io_base, 4)) @@ -415,6 +414,14 @@ void unload_uart401(struct address_info *hw_config) { uart401_devc *devc; + int n=hw_config->slots[4]; + + /* Not set up */ + if(n==-1 || midi_devs[n]==NULL) + return; + + /* Not allocated (erm ??) */ + devc = midi_devs[hw_config->slots[4]]->devc; if (devc == NULL) return; diff -u --recursive --new-file v2.1.93/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c --- v2.1.93/linux/drivers/sound/uart6850.c Tue Mar 17 22:18:15 1998 +++ linux/drivers/sound/uart6850.c Wed Apr 8 17:24:48 1998 @@ -325,6 +325,8 @@ MODULE_PARM(io,"i"); MODULE_PARM(irq,"i"); +EXPORT_NO_SYMBOLS; + struct address_info cfg; int init_module(void) diff -u --recursive --new-file v2.1.93/linux/drivers/sound/vidc.c linux/drivers/sound/vidc.c --- v2.1.93/linux/drivers/sound/vidc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/vidc.c Wed Apr 8 17:24:48 1998 @@ -0,0 +1,83 @@ +/* + * drivers/sound/vidc.c + * + * Detection routine for the VIDC. + * + * Copyright (C) 1997 by Russell King + */ + +#include +#include +#include +#include "sound_config.h" + +#include "vidc.h" + +int vidc_busy; + +void vidc_update_filler(int bits, int channels) +{ + int filltype; + + filltype = bits + channels; + switch (filltype) + { + default: + case 9: + vidc_filler = vidc_fill_1x8; + break; + case 10: + vidc_filler = vidc_fill_2x8; + break; + case 17: + vidc_filler = vidc_fill_1x16; + break; + case 18: + vidc_filler = vidc_fill_2x16; + break; + } +} + +void attach_vidc(struct address_info *hw_config) +{ + char name[32]; + int i; + + sprintf(name, "VIDC %d-bit sound", hw_config->card_subtype); + conf_printf(name, hw_config); + + for (i = 0; i < 2; i++) + { + dma_buf[i] = get_free_page(GFP_KERNEL); + dma_pbuf[i] = virt_to_phys(dma_buf[i]); + } + + if (sound_alloc_dma(hw_config->dma, "VIDCsound")) + { + 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)) + { + printk(KERN_ERR "VIDCsound: can't allocate DMA interrupt\n"); + return; + } + vidc_synth_init(hw_config); + vidc_audio_init(hw_config); + vidc_mixer_init(hw_config); +} + +int probe_vidc(struct address_info *hw_config) +{ + hw_config->irq = IRQ_DMAS0; + hw_config->dma = DMA_VIRTUAL_SOUND; + hw_config->dma2 = -1; + hw_config->card_subtype = 16; + return 1; +} + +void unload_vidc(struct address_info *hw_config) +{ + free_irq(hw_config->irq, NULL); + sound_free_dma(hw_config->dma); +} diff -u --recursive --new-file v2.1.93/linux/drivers/sound/vidc.h linux/drivers/sound/vidc.h --- v2.1.93/linux/drivers/sound/vidc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/vidc.h Wed Apr 8 17:24:48 1998 @@ -0,0 +1,68 @@ +/* + * drivers/sound/vidc.h + * + * VIDC sound function prototypes + * + * Copyright (C) 1997 Russell King + */ + +/* vidc.c */ + +extern int vidc_busy; + +/* vidc_fill.S */ + +/* + * 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); + +/* + * DMA Interrupt handler + */ + +extern void vidc_sound_dma_irq(int irqnr, void *ref, struct pt_regs *regs); + +/* + * Filler routine pointer + */ + +extern unsigned long (*vidc_filler) (unsigned long ibuf, unsigned long iend, + unsigned long obuf, int mask); + +/* + * Virtual DMA buffer exhausted + */ + +extern void (*dma_interrupt) (void); + +/* + * Virtual DMA buffer addresses + */ + +extern unsigned long dma_start, dma_count, dma_bufsize; +extern unsigned long dma_buf[2], dma_pbuf[2]; + +/* vidc_audio.c */ + +extern void vidc_audio_init(struct address_info *hw_config); +extern int vidc_audio_get_volume(void); +extern int vidc_audio_set_volume(int vol); + +/* vidc_mixer.c */ + +extern void vidc_mixer_init(struct address_info *hw_config); + +/* vidc_synth.c */ + +extern void vidc_synth_init(struct address_info *hw_config); +extern int vidc_synth_get_volume(void); +extern int vidc_synth_set_volume(int vol); diff -u --recursive --new-file v2.1.93/linux/drivers/sound/vidc_audio.c linux/drivers/sound/vidc_audio.c --- v2.1.93/linux/drivers/sound/vidc_audio.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/vidc_audio.c Wed Apr 8 17:24:48 1998 @@ -0,0 +1,322 @@ +/* + * drivers/sound/vidc_audio.c + * + * Audio routines for the VIDC + * + * Copyright (C) 1997 Russell King + */ + +#include +#include "sound_config.h" +#include +#include + +#include "vidc.h" + +/* + * VIDC sound + * + * When using SERIAL SOUND mode (external DAC), the number of physical + * channels is fixed at 2. Therefore, the sample rate = vidc sample rate. + */ + +static int vidc_adev; + +static int vidc_audio_volume; +static int vidc_audio_rate; +static char vidc_audio_bits; +static char vidc_audio_channels; + +extern void vidc_update_filler(int bits, int channels); + +int vidc_audio_get_volume(void) +{ + return vidc_audio_volume; +} + +int vidc_audio_set_volume(int newvol) +{ + vidc_audio_volume = newvol; + return vidc_audio_volume; +} + +static int vidc_audio_set_bits(int bits) +{ + switch (bits) + { + case AFMT_QUERY: + break; + case AFMT_U8: + case AFMT_S16_LE: + vidc_audio_bits = bits; + vidc_update_filler(vidc_audio_bits, vidc_audio_channels); + break; + default: + vidc_audio_bits = 16; + vidc_update_filler(vidc_audio_bits, vidc_audio_channels); + break; + } + return vidc_audio_bits; +} + +static int vidc_audio_set_rate(int rate) +{ + if (rate) + { + int newsize, new2size; + + vidc_audio_rate = ((500000 / rate) + 1) >> 1; + if (vidc_audio_rate < 3) + 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); + newsize = (10000 / vidc_audio_rate) & ~3; + if (newsize < 208) + newsize = 208; + if (newsize > 4096) + newsize = 4096; + for (new2size = 128; new2size < newsize; new2size <<= 1); + if (new2size - newsize > newsize - (new2size >> 1)) + new2size >>= 1; + dma_bufsize = new2size; + } + return 250000 / vidc_audio_rate; +} + +static int vidc_audio_set_channels(int channels) +{ + switch (channels) + { + case 0: + break; + case 1: + case 2: + vidc_audio_channels = channels; + vidc_update_filler(vidc_audio_bits, vidc_audio_channels); + break; + default: + vidc_audio_channels = 2; + vidc_update_filler(vidc_audio_bits, vidc_audio_channels); + break; + } + return vidc_audio_channels; +} + +/* + * Open the device + * + * dev - device + * mode - mode to open device (logical OR of OPEN_READ and OPEN_WRITE) + * + * Called when opening the DMAbuf (dmabuf.c:259) + */ + +static int vidc_audio_open(int dev, int mode) +{ + if (vidc_busy) + return -EBUSY; + + if ((mode & OPEN_READ) && (!mode & OPEN_WRITE)) + { + /* This audio device doesn't have recording capability */ + return -EIO; + } + vidc_busy = 1; + return 0; +} + +/* + * Close the device + * + * dev - device + * + * Called when closing the DMAbuf (dmabuf.c:477) + * after halt_xfer + */ + +static void vidc_audio_close(int dev) +{ + vidc_busy = 0; +} + +static int vidc_audio_ioctl(int dev, unsigned int cmd, caddr_t arg) +{ + int ret; + + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + if (get_user(ret, (int *) arg)) + return -EFAULT; + ret = vidc_audio_set_rate(ret); + break; + + case SOUND_PCM_READ_RATE: + ret = vidc_audio_set_rate(0); + break; + + case SNDCTL_DSP_STEREO: + if (get_user(ret, (int *) arg)) + return -EFAULT; + ret = vidc_audio_set_channels(ret + 1) - 1; + break; + + case SOUND_PCM_WRITE_CHANNELS: + if (get_user(ret, (int *) arg)) + return -EFAULT; + ret = vidc_audio_set_channels(ret); + break; + + case SOUND_PCM_READ_CHANNELS: + ret = vidc_audio_set_channels(0); + break; + + case SNDCTL_DSP_SETFMT: + if (get_user(ret, (int *) arg)) + return -EFAULT; + ret = vidc_audio_set_bits(ret); + break; + + case SOUND_PCM_READ_BITS: + ret = vidc_audio_set_bits(0); + break; + + case SOUND_PCM_WRITE_FILTER: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + + default: + return -EINVAL; + } + return put_user(ret, (int *) arg); +} + +/* + * Output a block via DMA to sound device + * + * dev - device number + * buf - physical address of buffer + * total_count - total byte count in buffer + * intrflag - set if this has been called from an interrupt (via DMAbuf_outputintr) + * restart_dma - set if DMA needs to be re-initialised + * + * Called when: + * 1. Starting output (dmabuf.c:1327) + * 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; + dma_count = total_count; + + if (!intrflag) + { + dma_interrupt = vidc_audio_dma_interrupt; + vidc_sound_dma_irq(0, NULL, NULL); + outb(DMA_CR_D | DMA_CR_E, IOMD_SD0CR); + } +} + +static void vidc_audio_start_input(int dev, unsigned long buf, int count, + int intrflag) +{ +} + +static int vidc_audio_prepare_for_input(int dev, int bsize, int bcount) +{ + return -EINVAL; +} + +/* + * Prepare for outputting samples to `dev' + * + * Each buffer that will be passed will be `bsize' bytes long, + * with a total of `bcount' buffers. + * + * Called when: + * 1. A trigger enables audio output (dmabuf.c:978) + * 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) +{ + 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) + */ + +static void vidc_audio_halt_xfer(int dev) +{ + dma_count = 0; +} + +static int vidc_audio_local_qlen(int dev) +{ + return dma_count != 0; +} + +static struct audio_driver vidc_audio_driver = +{ + vidc_audio_open, /* open */ + vidc_audio_close, /* close */ + vidc_audio_output_block, /* output_block */ + vidc_audio_start_input, /* start_input */ + vidc_audio_ioctl, /* ioctl */ + 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, /*+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) + { + 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 -u --recursive --new-file v2.1.93/linux/drivers/sound/vidc_fill.S linux/drivers/sound/vidc_fill.S --- v2.1.93/linux/drivers/sound/vidc_fill.S Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/vidc_fill.S Wed Apr 8 17:24:48 1998 @@ -0,0 +1,184 @@ +/* + * sound/vidc_fill.S + * + * Filler routines for DMA buffers + * + * Copyright (C) 1997 Russell King + */ +#define __ASSEMBLY__ +#include +#include +#include + + .text + +ENTRY(vidc_fill_1x8) + 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) + 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) + mov ip, #0xff00 + orr ip, ip, ip, lsr #8 +1: cmp r0, r1 + bge SYMBOL_NAME(vidc_clear) + ldr r5, [r0], #2 + and r4, r5, ip + orr r4, r4, r4, lsl #16 + str r4, [r2], #4 + cmp r0, r1 + addlt r0, r0, #2 + andlt r4, r5, ip, lsl #16 + orrlt r4, r4, r4, lsr #16 + strlt r4, [r2], #4 + cmp r2, r3 + blt 1b + mov pc, lr + +ENTRY(vidc_fill_2x16) + mov ip, #0xff00 + orr ip, ip, ip, lsr #8 +1: cmp r0, r1 + bge SYMBOL_NAME(vidc_clear) + ldr r4, [r0], #4 + str r4, [r2], #4 + cmp r0, r1 + ldrlt r4, [r0], #4 + strlt r4, [r2], #4 + cmp r2, r3 + blt 1b + mov pc, lr + +ENTRY(vidc_fill_noaudio) + mov r0, #0 + mov r1, #0 +2: mov r4, #0 + mov r5, #0 +1: cmp r2, r3 + stmltia r2!, {r0, r1, r4, r5} + blt 1b + mov pc, lr + +ENTRY(vidc_clear) + mov r0, #0 + mov r1, #0 + tst r2, #4 + str r0, [r2], #4 + tst r2, #8 + stmia r2!, {r0, r1} + b 2b + +/* + * Call filler routines with: + * r0 = phys address + * r1 = phys end + * r2 = buffer + * Returns: + * r0 = new buffer address + * r2 = new buffer finish + * r4 = corrupted + * r5 = corrupted + * ip = corrupted + */ + +ENTRY(vidc_sound_dma_irq) + stmfd sp!, {r4 - r9, lr} + ldr r9, =SYMBOL_NAME(dma_start) + ldmia r9, {r0, r1, r2, r3, r4, r5} + teq r1, #0 + adreq r4, SYMBOL_NAME(vidc_fill_noaudio) + moveq r8, #1 << 31 + movne r8, #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 + 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 + sub r1, r1, r0 @ Remaining length + stmia r9, {r0, r1} + mov r0, #0 + tst r2, #4 @ Round buffer up to 4 words + strne r0, [r2], #4 + tst r2, #8 + strne r0, [r2], #4 + strne r0, [r2], #4 + sub r2, r2, #16 + 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 + 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 + bne 1f + tst r7, #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 + mov r0, #0x10 + strneb r0, [ip, #IOMD_SD0CR] + teqeq r1, #0 + ldmfd sp!, {r4 - r9, lr} + moveq pc, r3 @ Call interrupt routine + mov pc, lr + + .data + .globl SYMBOL_NAME(dma_interrupt) +SYMBOL_NAME(dma_interrupt): + .long 0 + .globl SYMBOL_NAME(dma_pbuf) +SYMBOL_NAME(dma_pbuf): + .long 0 + .long 0 + .globl SYMBOL_NAME(dma_start) +SYMBOL_NAME(dma_start): + .long 0 + .globl SYMBOL_NAME(dma_count) +SYMBOL_NAME(dma_count): + .long 0 + .globl SYMBOL_NAME(dma_buf) +SYMBOL_NAME(dma_buf): + .long 0 + .long 0 + .globl SYMBOL_NAME(vidc_filler) +SYMBOL_NAME(vidc_filler): + .long SYMBOL_NAME(vidc_fill_noaudio) + .globl SYMBOL_NAME(dma_bufsize) +SYMBOL_NAME(dma_bufsize): + .long 0x1000 diff -u --recursive --new-file v2.1.93/linux/drivers/sound/vidc_mixer.c linux/drivers/sound/vidc_mixer.c --- v2.1.93/linux/drivers/sound/vidc_mixer.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/vidc_mixer.c Wed Apr 8 17:24:48 1998 @@ -0,0 +1,151 @@ +/* + * drivers/sound/vidc_mixer.c + * + * Mixer routines for VIDC + * + * Copyright (C) 1997 Russell King + */ + +#include +#include "sound_config.h" + +#include "vidc.h" + +int vidc_volume; + +static int vidc_get_volume(void) +{ + return vidc_volume; +} + +static int vidc_set_volume(int newvol) +{ + vidc_volume = newvol; +/* printk ("vidc_set_volume: %X\n", newvol); */ + return newvol; +} + +static int vidc_default_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) +{ + int ret; + + switch (cmd) + { + case SOUND_MIXER_READ_VOLUME: + ret = vidc_get_volume(); + break; + + case SOUND_MIXER_WRITE_VOLUME: + if (get_user(ret, (int *) arg)) + return -EINVAL; + ret = vidc_set_volume(ret); + break; + + case SOUND_MIXER_READ_BASS: + case SOUND_MIXER_WRITE_BASS: + case SOUND_MIXER_READ_TREBLE: + case SOUND_MIXER_WRITE_TREBLE: + ret = 50; + break; + + case SOUND_MIXER_READ_SYNTH: + ret = vidc_synth_get_volume(); + break; + + case SOUND_MIXER_WRITE_SYNTH: + if (get_user(ret, (int *) arg)) + return -EINVAL; + ret = vidc_synth_set_volume(ret); + break; + + case SOUND_MIXER_READ_PCM: + ret = vidc_audio_get_volume(); + break; + + case SOUND_MIXER_WRITE_PCM: + if (get_user(ret, (int *) arg)) + return -EINVAL; + ret = vidc_audio_set_volume(ret); + break; + + case SOUND_MIXER_READ_SPEAKER: + ret = 100; + break; + + case SOUND_MIXER_WRITE_SPEAKER: + ret = 100; + break; + + case SOUND_MIXER_READ_LINE: + case SOUND_MIXER_WRITE_LINE: + case SOUND_MIXER_READ_MIC: + case SOUND_MIXER_WRITE_MIC: + ret = 0; + break; + + case SOUND_MIXER_READ_CD: + case SOUND_MIXER_WRITE_CD: + ret = 100 | (100 << 8); + break; + + case SOUND_MIXER_READ_IMIX: + case SOUND_MIXER_WRITE_IMIX: + case SOUND_MIXER_READ_ALTPCM: + case SOUND_MIXER_WRITE_ALTPCM: + case SOUND_MIXER_READ_LINE1: + case SOUND_MIXER_WRITE_LINE1: + case SOUND_MIXER_READ_LINE2: + case SOUND_MIXER_WRITE_LINE2: + case SOUND_MIXER_READ_LINE3: + case SOUND_MIXER_WRITE_LINE3: + ret = 0; + break; + + case SOUND_MIXER_READ_RECSRC: + ret = 0; + break; + + case SOUND_MIXER_WRITE_RECSRC: + return -EINVAL; + break; + + case SOUND_MIXER_READ_DEVMASK: + ret = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH; + break; + + case SOUND_MIXER_READ_RECMASK: + ret = 0; + break; + + case SOUND_MIXER_READ_STEREODEVS: + ret = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH; + break; + + case SOUND_MIXER_READ_CAPS: + ret = 0; + break; + + case SOUND_MIXER_READ_MUTE: + return -EINVAL; + break; + + default: + return -EINVAL; + break; + } + return put_user(ret, (int *) arg); +} + +static struct mixer_operations vidc_mixer_operations = { + "VIDC", + "VIDCsound", + vidc_default_mixer_ioctl /* ioctl */ +}; + +void vidc_mixer_init(struct address_info *hw_config) +{ + int vidc_mixer = sound_alloc_mixerdev(); + vidc_volume = 100 | (100 << 8); + if (num_mixers < MAX_MIXER_DEV) + mixer_devs[vidc_mixer] = &vidc_mixer_operations; +} diff -u --recursive --new-file v2.1.93/linux/drivers/sound/vidc_synth.c linux/drivers/sound/vidc_synth.c --- v2.1.93/linux/drivers/sound/vidc_synth.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/vidc_synth.c Wed Apr 8 17:24:48 1998 @@ -0,0 +1,90 @@ +/* + * drivers/sound/vidc_synth.c + * + * Synthesizer routines for the VIDC + * + * Copyright (C) 1997 Russell King + */ +#include +#include "sound_config.h" + +#include "vidc.h" + +static struct synth_info vidc_info = +{ + "VIDCsound", /* name */ + 0, /* device */ + SYNTH_TYPE_SAMPLE, /* synth_type */ + 0, /* synth_subtype */ + 0, /* perc_mode */ + 16, /* nr_voices */ + 0, /* nr_drums */ + 0, /* instr_bank_size */ + 0, /* capabilities */ +}; + +int vidc_sdev; +int vidc_synth_volume; + +static int vidc_synth_open(int dev, int mode) +{ + if (vidc_busy) + return -EBUSY; + + vidc_busy = 1; + return 0; +} + +static void vidc_synth_close(int dev) +{ + vidc_busy = 0; +} + + +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] */ +}; + +int vidc_synth_get_volume(void) +{ + return vidc_synth_volume; +} + +int vidc_synth_set_volume(int newvol) +{ + return vidc_synth_volume = newvol; +} + +void vidc_synth_init(struct address_info *hw_config) +{ + vidc_synth_volume = 100 | (100 << 8); + if ((vidc_sdev=sound_alloc_synthdev())!=-1) + synth_devs[vidc_sdev] = &vidc_synth_operations; + else + printk(KERN_ERR "VIDCsound: Too many synthesizers\n"); +} diff -u --recursive --new-file v2.1.93/linux/drivers/video/cyberfb.c linux/drivers/video/cyberfb.c --- v2.1.93/linux/drivers/video/cyberfb.c Thu Mar 26 15:57:04 1998 +++ linux/drivers/video/cyberfb.c Tue Apr 7 07:52:04 1998 @@ -20,7 +20,7 @@ * for more details. */ - +#include #include #include #include diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-afb.c linux/drivers/video/fbcon-afb.c --- v2.1.93/linux/drivers/video/fbcon-afb.c Thu Mar 26 15:57:04 1998 +++ linux/drivers/video/fbcon-afb.c Tue Apr 7 07:52:04 1998 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-cfb16.c linux/drivers/video/fbcon-cfb16.c --- v2.1.93/linux/drivers/video/fbcon-cfb16.c Thu Mar 26 15:57:04 1998 +++ linux/drivers/video/fbcon-cfb16.c Tue Apr 7 07:52:04 1998 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-cfb2.c linux/drivers/video/fbcon-cfb2.c --- v2.1.93/linux/drivers/video/fbcon-cfb2.c Thu Mar 26 15:57:04 1998 +++ linux/drivers/video/fbcon-cfb2.c Tue Apr 7 07:52:04 1998 @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-cfb24.c linux/drivers/video/fbcon-cfb24.c --- v2.1.93/linux/drivers/video/fbcon-cfb24.c Thu Mar 26 15:57:04 1998 +++ linux/drivers/video/fbcon-cfb24.c Tue Apr 7 07:52:04 1998 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-cfb32.c linux/drivers/video/fbcon-cfb32.c --- v2.1.93/linux/drivers/video/fbcon-cfb32.c Thu Mar 26 15:57:04 1998 +++ linux/drivers/video/fbcon-cfb32.c Tue Apr 7 07:52:04 1998 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-cfb4.c linux/drivers/video/fbcon-cfb4.c --- v2.1.93/linux/drivers/video/fbcon-cfb4.c Thu Mar 26 15:57:04 1998 +++ linux/drivers/video/fbcon-cfb4.c Tue Apr 7 07:52:04 1998 @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-cfb8.c linux/drivers/video/fbcon-cfb8.c --- v2.1.93/linux/drivers/video/fbcon-cfb8.c Thu Mar 26 15:57:04 1998 +++ linux/drivers/video/fbcon-cfb8.c Tue Apr 7 07:52:05 1998 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-mac.c linux/drivers/video/fbcon-mac.c --- v2.1.93/linux/drivers/video/fbcon-mac.c Thu Mar 26 15:57:04 1998 +++ linux/drivers/video/fbcon-mac.c Tue Apr 7 07:52:05 1998 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff -u --recursive --new-file v2.1.93/linux/drivers/video/fbcon-mfb.c linux/drivers/video/fbcon-mfb.c --- v2.1.93/linux/drivers/video/fbcon-mfb.c Thu Mar 26 15:57:04 1998 +++ linux/drivers/video/fbcon-mfb.c Tue Apr 7 07:52:05 1998 @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "fbcon.h" diff -u --recursive --new-file v2.1.93/linux/drivers/video/skeletonfb.c linux/drivers/video/skeletonfb.c --- v2.1.93/linux/drivers/video/skeletonfb.c Thu Mar 26 15:57:04 1998 +++ linux/drivers/video/skeletonfb.c Tue Apr 7 07:52:05 1998 @@ -8,6 +8,7 @@ * for more details. */ +#include #include #include #include diff -u --recursive --new-file v2.1.93/linux/fs/buffer.c linux/fs/buffer.c --- v2.1.93/linux/fs/buffer.c Wed Apr 1 20:11:53 1998 +++ linux/fs/buffer.c Mon Apr 6 17:48:34 1998 @@ -1335,6 +1335,8 @@ atomic_read(&nr_async_pages)); #endif } + if (test_and_clear_bit(PG_swap_unlock_after, &page->flags)) + swap_after_unlock_page(page->offset); if (test_and_clear_bit(PG_free_after, &page->flags)) __free_page(page); } diff -u --recursive --new-file v2.1.93/linux/fs/devpts/root.c linux/fs/devpts/root.c --- v2.1.93/linux/fs/devpts/root.c Mon Apr 6 17:41:00 1998 +++ linux/fs/devpts/root.c Tue Apr 7 08:05:05 1998 @@ -13,6 +13,7 @@ #include #include #include +#include #include "devpts_i.h" static int devpts_root_readdir(struct file *,void *,filldir_t); diff -u --recursive --new-file v2.1.93/linux/fs/ext2/file.c linux/fs/ext2/file.c --- v2.1.93/linux/fs/ext2/file.c Mon Apr 6 17:41:00 1998 +++ linux/fs/ext2/file.c Wed Apr 8 11:36:53 1998 @@ -205,21 +205,23 @@ return -EFBIG; } #else - off_t max = ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(sb)]; + { + off_t max = ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(sb)]; - if (pos + count > max) { - count = max - pos; - if (!count) - return -EFBIG; - } - if (((pos + count) >> 32) && - !(sb->u.ext2_sb.s_es->s_feature_ro_compat & - cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE))) { - /* If this is the first large file created, add a flag - to the superblock */ - sb->u.ext2_sb.s_es->s_feature_ro_compat |= - cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + if (pos + count > max) { + count = max - pos; + if (!count) + return -EFBIG; + } + if (((pos + count) >> 32) && + !(sb->u.ext2_sb.s_es->s_feature_ro_compat & + cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE))) { + /* If this is the first large file created, add a flag + to the superblock */ + sb->u.ext2_sb.s_es->s_feature_ro_compat |= + cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + } } #endif diff -u --recursive --new-file v2.1.93/linux/fs/sysv/inode.c linux/fs/sysv/inode.c --- v2.1.93/linux/fs/sysv/inode.c Mon Apr 6 17:41:01 1998 +++ linux/fs/sysv/inode.c Tue Apr 7 07:22:23 1998 @@ -495,7 +495,7 @@ if (!sb->s_root) { printk("SysV FS: get root inode failed\n"); sysv_put_super(sb); - sb->sb_dev = 0; + sb->s_dev = 0; unlock_super(sb); return NULL; } diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/README-WIP.txt linux/fs/umsdos/README-WIP.txt --- v2.1.93/linux/fs/umsdos/README-WIP.txt Tue Mar 17 22:18:15 1998 +++ linux/fs/umsdos/README-WIP.txt Wed Apr 8 11:39:46 1998 @@ -8,7 +8,7 @@ YOU'VE BEEN WARNED. --------- WARNING --------- WARNING --------- WARNING ----------- -Current status (980220) - UMSDOS dentry-WIP-Beta 0.82-1: +Current status (980220) - UMSDOS dentry-WIP-Beta 0.82-3: (1) pure MSDOS (no --linux-.--- EMD file): @@ -19,7 +19,7 @@ - creat file - works - write file - works - mkdir - works -- rmdir - questionable. probable problem on non-empty dirs. +- rmdir - QUESTIONABLE. probable problem on non-empty dirs. Notes: possible very minor problems with dentry/inode/... kernel structures (very rare) @@ -42,28 +42,29 @@ - other ioctls - MOSTLY UNTESTED - dangling symlink - UNTESTED ! -- create symlink - works on short names, but fails (gets - truncated on long ones) (also - due to some dentries problems, it may not - be visible right away always - eg. before - umount/mount) +- create symlink - seems to work both on short & long names now ! - create hardlink - WARNING: NOT FIXED YET! -- create file - creates short names, but probs with long ones ? -- create special file - seems to work on short names. -- write to file - seems to work on short names. +- create file - seems to work both on short & long names now ! +- create special file - seems to work both on short & long names now ! +- write to file - seems to work both on short & long names now ! - rename file (same dir) - WARNING: NOT FIXED YET! - rename file (dif. dir) - WARNING: NOT FIXED YET! - rename dir (same dir) - WARNING: NOT FIXED YET! - rename dir (dif. dir) - WARNING: NOT FIXED YET! -- delete file - WARNING: NOT FIXED YET! +- delete file - seems to work fully now! - notify_change (chown,perms) - seems to work! - delete hardlink - WARNING: NOT FIXED YET! -- mkdir - seems to work, even with long names ! (but - due to some dentries problems, it may not - be visible right away always - eg. before - umount/mount) +- mkdir - seems to work both on short & long names now ! - rmdir - WARNING: NOT FIXED YET! -- umssyncing - does something :-), but NEEDS EXTENSIVE TESTING +- umssyncing - seems to work, but NEEDS EXTENSIVE TESTING + +- CVF-FAT stuff (compressed DOS filesystem) - there is some support from + Frank Gockel to use it even under + umsdosfs. But I have no way of testing it -- please let me know if there + are problems that are specific to umsdos (eg. it works under msdosfs, but + not under umsdosfs) + + Notes: moderate dentry/inode kernel structures trashing. Probably some other kernel structures compromised. Have SysRq support compiled in, and use @@ -77,16 +78,18 @@ is supposed to be fixed enough to work, but I haven't got the time to test it. -Note4: on failure of creating of long filenames: MSDOS filename gets -created, and EMD entry gets created. Check: either they mismatch, or EMD -entry contains some wrong flags. - -Note5: rmdir(2) probably fails because do_rmdir calls lock_parent, which -uses dentry->d_parent, which we neglect to set, so it returns -ENOENT. -Probably same problem on unlink(2) ? What to do ? How to set -dentry->d_parent to something useful ?? Must I recurse down whole pathname -and set one by one all directory components ?! or only last one is really -needed ? help ! +Note5: rmdir(2) fails with EBUSY - sdir->i_count > 1 (like 7 ??). It must be +some error with dir->i_count++, or something related to iput() ? See if +number changes if we access the dir in different ways.. + +Note6: there is problem with unmounting umsdosfs, it seems to stay +registered or something. Remounting same device on any mount point with +different fstype (like msdos or vfat) ignores fstype and umsdosfs kicks back +in. + +Note7: also we screwed umount(2)-ing the fs at times (EBUSY), by removing +all those iput/dput's. When rest of code is fixed, we'll put them back at +(hopefully) correct places. ------------------------------------------------------------------------------ @@ -110,10 +113,10 @@ dput them ? I'm unfortunatelly somewhat out of time to read linux-kernel, but I do check -for any messages having UMSDOS in subject, and read them. I should reply to -any direct Email in few days. If I don't - probably I never got your -message. You can try mnalis@open.hr or mnalis@voyager.hr; however -mnalis@jagor.srce.hr is preferable one. +for any messages having UMSDOS in subject, and read them. I might miss it in +all that volume, though. I should reply to any direct Email in few days. If +I don't - probably I never got your message. You can try mnalis@open.hr or +mnalis@voyager.hr; however mnalis@jagor.srce.hr is preferable one. ------------------------------------------------------------------------------ @@ -122,7 +125,7 @@ + hardlinks/symlinks. test with files in not_the_same_dir - also test not_the_same_dir for other file operations like rename etc. - iput: device 00:00 inode 318 still has aliases! problem. Check in iput() - for device 0,0. Probably null pointer passed arount when it shouldn't be ? + for device 0,0. Probably null pointer passed around when it shouldn't be ? - dput/iput problem... - what about .dotfiles ? working ? multiple dots ? etc.... - fix stuff like dir->i_count++ to atomic_inc(&dir->i_count) and simular? @@ -133,11 +136,23 @@ - when should dput()/iput() be used ?!! -- probably problem with filename mangling somewhere, since both create and - write to file work on short filenames, but fail on long ones. Path - components may be of any size (eg. mkfifo /mnt/Very_long_dir2/blah1 will - succeed, but mkfifo /mnt/very_long_filename.txt won't) - - - what is dir->i_count++ ? locking directory ? should this be lock_parent or something ? + +- i_binary=2 is for CVF (compressed filesystem). + +- SECURITY WARNING: short dentries should be invalidated, or they could be + accessed instead of proper long names. + +- as for iput() : (my only pointer so far. anyone else ?) + +>development I only know about iput. All functions that get an inode as +>argument and don't return it have to call iput on it before exit, i.e. when +>it is no longer needed and the code returns to vfs layer. The rest is quite +>new to me, but it might be similar for dput. Typical side effect of a +>missing iput was a memory runout (but no crash). You also couldn't unmount +>the filesystem later though no process was using it. On the other hand, one +>iput too much lead to serious pointer corruption and crashed the system +>very soon. I used to look at the FAT filesystem and copy those pieces of +> +> Frank diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c --- v2.1.93/linux/fs/umsdos/dir.c Tue Mar 17 22:18:15 1998 +++ linux/fs/umsdos/dir.c Wed Apr 8 11:39:46 1998 @@ -36,7 +36,7 @@ int rv; struct dentry *dentry; - dentry = creat_dentry (name, len, NULL); + dentry = creat_dentry (name, len, NULL, NULL); rv = umsdos_real_lookup(dir,dentry); if (inode) *inode = dentry->d_inode; kill_dentry (dentry); @@ -50,7 +50,7 @@ int rv; struct dentry *dentry; - dentry = creat_dentry (name, len, NULL); + dentry = creat_dentry (name, len, NULL, NULL); rv = msdos_create(dir,dentry,mode); if(inode != NULL) *inode = dentry->d_inode; @@ -270,10 +270,10 @@ } Printk (("Trouve ino %ld ",inode->i_ino)); if (u_entry != NULL) *u_entry = entry; - iput (inode); + /* iput (inode); FIXME */ break; } - iput (inode); + /* iput (inode); FIXME */ }else{ /* #Specification: umsdos / readdir / not in MSDOS During a readdir operation, if the file is not @@ -295,7 +295,7 @@ the special offset. */ if (filp->f_pos == 0) filp->f_pos = start_fpos; - iput(emd_dir); + /* iput(emd_dir); FIXME */ } } umsdos_endlookup(dir); @@ -530,7 +530,7 @@ ret = 0; }else{ struct inode *emddir = umsdos_emd_dir_lookup(dir,0); - iput (emddir); + /* iput (emddir); FIXME */ if (emddir == NULL){ /* This is a DOS directory */ struct UMSDOS_DIR_SEARCH bufk; @@ -639,7 +639,7 @@ while (dir != root_inode){ struct inode *adir; ret = umsdos_locate_ancestor (dir,&adir,&entry); - iput (dir); + /* iput (dir); FIXME */ dir = NULL; Printk (("ancestor %d ",ret)); if (ret == 0){ @@ -657,7 +657,7 @@ kfree (bpath); } Printk (("\n")); - iput (dir); + /* iput (dir); FIXME */ return ret; } @@ -697,12 +697,16 @@ struct inode *pseudo_root_inode=NULL; int len = dentry->d_name.len; const char *name = dentry->d_name.name; + + Printk ((KERN_DEBUG "umsdos_lookup_x: /mn/ name=%.*s, dir=%lu, d_parent=%p\n", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino, dentry->d_parent)); /* FIXME /mn/ debug only */ + if (dentry->d_parent) Printk ((KERN_DEBUG " d_parent is %.*s\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name)); /* FIXME : delme /mn/ */ + root_inode = iget(dir->i_sb,UMSDOS_ROOT_INO); /* pseudo_root_inode = iget( ... ) ? */ dentry->d_inode = NULL; - umsdos_startlookup(dir); + umsdos_startlookup(dir); if (len == 1 && name[0] == '.'){ - dentry->d_inode = dir; + d_add (dentry, dir); dir->i_count++; ret = 0; }else if (len == 2 && name[0] == '.' && name[1] == '.'){ @@ -713,7 +717,7 @@ pseudo root is returned. */ ret = 0; - dentry->d_inode = pseudo_root; + d_add (dentry, pseudo_root); pseudo_root->i_count++; }else{ /* #Specification: locating .. / strategy @@ -735,7 +739,7 @@ struct inode *aadir; struct umsdos_dirent entry; ret = umsdos_locate_ancestor (dentry->d_inode,&aadir,&entry); - iput (aadir); + /* iput (aadir); FIXME */ } } }else if (umsdos_is_pseudodos(dir,dentry)){ @@ -743,7 +747,7 @@ A lookup of DOS in the pseudo root will always succeed and return the inode of the real root. */ - dentry->d_inode = root_inode; + d_add (dentry, root_inode); (dentry->d_inode)->i_count++; ret = 0; }else{ @@ -776,7 +780,7 @@ Printk ((KERN_DEBUG "umsdos_lookup_x /mn/ debug: ino=%li\n", inode->i_ino)); /* we've found it. now get inode and put it in dentry. Is this ok /mn/ ? */ - dentry->d_inode = iget(dir->i_sb, inode->i_ino); + d_add (dentry, iget(dir->i_sb, inode->i_ino)); umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos); Printk (("lookup ino %ld flags %d\n",inode->i_ino @@ -796,7 +800,7 @@ mode. */ Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ Pseudo_root thingy\n")); - iput (pseudo_root); + /* iput (pseudo_root); FIXME */ dentry->d_inode = NULL; ret = -ENOENT; } @@ -804,7 +808,7 @@ } } umsdos_endlookup(dir); - iput (dir); + /* iput (dir); FIXME */ Printk ((KERN_DEBUG "umsdos_lookup_x: returning %d\n", ret)); return ret; } @@ -858,7 +862,7 @@ *result = NULL; if (path == NULL){ ret = -ENOMEM; - iput (hlink); + /* iput (hlink); FIXME */ }else{ struct file filp; loff_t offs = 0; @@ -866,7 +870,7 @@ fill_new_filp (&filp, NULL); - dentry_src = creat_dentry ("hlink-mn", 8, hlink); + dentry_src = creat_dentry ("hlink-mn", 8, hlink, NULL); memset (&filp, 0, sizeof (filp)); @@ -894,7 +898,7 @@ if (*pt == '/') *pt++ = '\0'; /* FIXME. /mn/ fixed ? */ - dentry_dst = creat_dentry (start, len, NULL); + dentry_dst = creat_dentry (start, len, NULL, NULL); if (dir->u.umsdos_i.i_emd_dir == 0){ /* This is a DOS directory */ @@ -917,7 +921,7 @@ } }else{ Printk (("umsdos_hlink2inode: all those iput's() frighten me /mn/. Whatabout dput() ? FIXME!\n")); - iput (hlink); /* FIXME */ + /* iput (hlink); / * FIXME */ } Printk (("hlink2inode ret = %d %p -> %p\n", ret, hlink, *result)); kfree (path); diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c --- v2.1.93/linux/fs/umsdos/emd.c Tue Mar 17 22:18:15 1998 +++ linux/fs/umsdos/emd.c Wed Apr 8 11:39:46 1998 @@ -52,9 +52,11 @@ * */ -struct dentry *creat_dentry (const char *name, const int len, struct inode *inode) +struct dentry *creat_dentry (const char *name, const int len, struct inode *inode, struct dentry *parent) { - struct dentry *ret, *parent=NULL; /* FIXME /mn/: whatis parent ?? */ +/* FIXME /mn/: parent is not passed many times... if it is not, dentry should be destroyed before someone else gets to use it */ + + struct dentry *ret; struct qstr qname; if (inode) @@ -71,10 +73,10 @@ if (inode) d_add (ret, inode); -/* ret->d_inode = inode; /mn/ FIXME this was old, replaced by d_add, delete this ! */ return ret; } + /* * removes temporary dentry created by creat_dentry * @@ -123,7 +125,7 @@ set_fs (KERNEL_DS); old_dentry=filp->f_dentry; /* save it */ - filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir); + filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir, NULL); *offs = filp->f_pos; PRINTK ((KERN_DEBUG "umsdos_file_read_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs)); @@ -138,6 +140,7 @@ PRINTK ((KERN_DEBUG " f_version=%ld\n", filp->f_version)); PRINTK ((KERN_DEBUG " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); + MSDOS_I(filp->f_dentry->d_inode)->i_binary=2; ret = fat_file_read(filp,buf,count,offs); PRINTK ((KERN_DEBUG "fat_file_read returned with %d!\n", ret)); @@ -195,21 +198,28 @@ set_fs (KERNEL_DS); - Printk ((KERN_ERR "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs)); - Printk ((KERN_ERR " struct dentry=%p\n", filp->f_dentry)); - Printk ((KERN_ERR " struct inode=%p\n", filp->f_dentry->d_inode)); - Printk ((KERN_ERR " inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size)); - Printk ((KERN_ERR " ofs=%ld\n",(unsigned long) *offs)); - Printk ((KERN_ERR " f_pos=%Lu\n", filp->f_pos)); - Printk ((KERN_ERR " name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name)); - Printk ((KERN_ERR " i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary )); - Printk ((KERN_ERR " f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); - Printk ((KERN_ERR " f_owner=%d\n", filp->f_owner.uid)); - Printk ((KERN_ERR " f_version=%ld\n", filp->f_version)); - Printk ((KERN_ERR " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); + Printk ((KERN_DEBUG "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs)); + Printk ((KERN_DEBUG " struct dentry=%p\n", filp->f_dentry)); + Printk ((KERN_DEBUG " struct inode=%p\n", filp->f_dentry->d_inode)); + Printk ((KERN_DEBUG " inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size)); + Printk ((KERN_DEBUG " ofs=%ld\n",(unsigned long) *offs)); + Printk ((KERN_DEBUG " f_pos=%Lu\n", filp->f_pos)); + Printk ((KERN_DEBUG " name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name)); + Printk ((KERN_DEBUG " i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary )); + Printk ((KERN_DEBUG " f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags)); + Printk ((KERN_DEBUG " f_owner=%d\n", filp->f_owner.uid)); + Printk ((KERN_DEBUG " f_version=%ld\n", filp->f_version)); + Printk ((KERN_DEBUG " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); + + /* note: i_binary=2 is for CVF-FAT. We put it here, instead of + umsdos_file_write_kmem, since it is also wise not to compress symlinks + (in unlikely event that they are > 512 bytes and can be compressed + FIXME: should we set it when reading symlink too ? */ + MSDOS_I(filp->f_dentry->d_inode)->i_binary=2; + ret = fat_file_write (filp, buf, count, offs); - PRINTK ((KERN_ERR "fat_file_write returned with %ld!\n", ret)); + PRINTK ((KERN_DEBUG "fat_file_write returned with %ld!\n", ret)); set_fs (old_fs); return ret; @@ -231,11 +241,11 @@ struct dentry *old_dentry; - Printk ((KERN_ERR " STARTED WRITE_KMEM /mn/\n")); - Printk ((KERN_ERR " using emd=%ld\n", emd_dir->i_ino)); + Printk ((KERN_DEBUG " STARTED WRITE_KMEM /mn/\n")); + Printk ((KERN_DEBUG " using emd=%ld\n", emd_dir->i_ino)); old_dentry=filp->f_dentry; /* save it */ - filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir); + filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir, NULL); *offs = filp->f_pos; /* FIXME, in read_kmem also: offs is not used so why pass it ?!!! /mn/ */ @@ -500,7 +510,7 @@ fill_new_filp (&filp, NULL); Printk (("umsdos_writeentry /mn/: entering...\n")); - emd_dentry=creat_dentry ("wremd_mn", 8, emd_dir); + emd_dentry=creat_dentry ("wremd_mn", 8, emd_dir, NULL); if (free_entry){ /* #Specification: EMD file / empty entries @@ -650,7 +660,7 @@ memset (&buf.filp, 0, sizeof (buf.filp)); - dentry = creat_dentry ("umsfind-mn", 10, emd_dir); + dentry = creat_dentry ("umsfind-mn", 10, emd_dir, NULL); fill_new_filp (&buf.filp, dentry); @@ -743,7 +753,7 @@ ret = umsdos_writeentry(dir,emd_dir,info,0); Printk (("umsdos_newentry EMD ret = %d\n",ret)); } - iput (emd_dir); + /* iput (emd_dir); FIXME */ return ret; } @@ -760,7 +770,7 @@ umsdos_parse ("..LINK",6,info); info->entry.name_len = 0; ret = umsdos_find (dir,info,&emd_dir); - iput (emd_dir); + /* iput (emd_dir); FIXME */ if (ret == -ENOENT || ret == 0){ /* #Specification: hard link / hidden name When a hard link is created, the original file is renamed @@ -799,7 +809,7 @@ } } } - iput(emd_dir); + /* iput(emd_dir); FIXME */ return ret; } @@ -824,7 +834,7 @@ /* Find an empty slot */ memset (&filp, 0, sizeof (filp)); - dentry = creat_dentry ("isempty-mn", 10, dir); + dentry = creat_dentry ("isempty-mn", 10, dir, NULL); filp.f_pos = 0; filp.f_reada = 1; @@ -843,7 +853,7 @@ break; } } - iput (emd_dir); + /* iput (emd_dir); FIXME */ } return ret; } @@ -870,7 +880,7 @@ } } } - iput (emd_dir); + /* iput (emd_dir); FIXME */ Printk (("umsdos_findentry: returning %d\n", ret)); return ret; } diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/file.c linux/fs/umsdos/file.c --- v2.1.93/linux/fs/umsdos/file.c Tue Feb 17 13:12:48 1998 +++ linux/fs/umsdos/file.c Wed Apr 8 11:39:46 1998 @@ -144,3 +144,38 @@ NULL, /* smap */ }; +/* For other with larger and unaligned file system with readpage */ +struct file_operations umsdos_file_operations_readpage = { + NULL, /* lseek - default */ + UMSDOS_file_read, /* read */ + UMSDOS_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* poll - default */ + NULL, /* ioctl - default */ + generic_file_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + file_fsync /* fsync */ +}; + +struct inode_operations umsdos_file_inode_operations_readpage = { + &umsdos_file_operations_readpage, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow link */ + fat_readpage, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + UMSDOS_truncate, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ +}; + diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c --- v2.1.93/linux/fs/umsdos/inode.c Tue Mar 17 22:18:15 1998 +++ linux/fs/umsdos/inode.c Wed Apr 8 11:39:46 1998 @@ -125,7 +125,7 @@ Printk (("umsdos_set_dirinfo: emd_owner is %lu for dir %lu\n", emd_owner->i_ino, dir->i_ino)); inode->u.umsdos_i.i_dir_owner = dir->i_ino; inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino; - iput (emd_owner); + /* iput (emd_owner); FIXME */ inode->u.umsdos_i.pos = f_pos; } @@ -176,12 +176,22 @@ if (!umsdos_isinit(inode)){ inode->u.umsdos_i.i_emd_dir = 0; if (S_ISREG(inode->i_mode)){ - if (inode->i_op->bmap != NULL){ - Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations\n")); - inode->i_op = &umsdos_file_inode_operations; - }else{ - Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n")); - inode->i_op = &umsdos_file_inode_operations_no_bmap; + if (MSDOS_SB(inode->i_sb)->cvf_format){ + if (MSDOS_SB(inode->i_sb)->cvf_format->flags&CVF_USE_READPAGE){ + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_readpage\n")); + inode->i_op = &umsdos_file_inode_operations_readpage; + }else{ + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n")); + inode->i_op = &umsdos_file_inode_operations_no_bmap; + } + }else{ + if (inode->i_op->bmap != NULL){ + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations\n")); + inode->i_op = &umsdos_file_inode_operations; + }else{ + Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n")); + inode->i_op = &umsdos_file_inode_operations_no_bmap; + } } }else if (S_ISDIR(inode->i_mode)){ if (dir != NULL){ @@ -223,7 +233,7 @@ struct inode *emd_owner; Printk ((KERN_WARNING "umsdos_patch_inode: /mn/ Warning: untested emd_owner thingy...\n")); emd_owner = umsdos_emd_dir_lookup(dir,1); - iput (emd_owner); + /* iput (emd_owner); FIXME */ if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner){ printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld " ,inode->i_ino,emd_owner->i_ino,inode->u.umsdos_i.i_emd_owner); @@ -323,7 +333,7 @@ { int ret = 0; - Printk ((KERN_ERR "UMSDOS_notify_change: /mn/ completly untested\n")); + PRINTK ((KERN_DEBUG "UMSDOS_notify_change: entering\n")); if ((ret = inode_change_ok(inode, attr)) != 0) return ret; @@ -366,7 +376,7 @@ struct dentry *emd_dentry; loff_t offs; - emd_dentry = creat_dentry ("notify_emd", 10, emd_owner); + emd_dentry = creat_dentry ("notify_emd", 10, emd_owner, NULL); fill_new_filp (&filp, emd_dentry); filp.f_pos = inode->u.umsdos_i.pos; @@ -403,7 +413,7 @@ EMD file. The msdos fs is not even called. */ } - iput (emd_owner); + /* iput (emd_owner); FIXME */ } Printk (("\n")); } @@ -472,7 +482,7 @@ PRINTK ((KERN_DEBUG "UMSDOS /mn/: sb = %p\n",sb)); res = msdos_read_super(sb,data,silent); PRINTK ((KERN_DEBUG "UMSDOS /mn/: res = %p\n",res)); - printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-2 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE); + printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-3 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE); if (res == NULL) { MOD_DEC_USE_COUNT; return NULL; } @@ -480,7 +490,7 @@ res->s_op = &umsdos_sops; Printk ((KERN_DEBUG "umsdos /mn/: here goes the iget ROOT_INO\n")); - pseudo = iget(res,UMSDOS_ROOT_INO); + pseudo = iget(res,UMSDOS_ROOT_INO); Printk ((KERN_DEBUG "umsdos_read_super %p\n",pseudo)); umsdos_setup_dir_inode (pseudo); @@ -521,8 +531,8 @@ */ struct dentry *root, *etc, *etc_rc, *init, *sbin; - root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen(UMSDOS_PSDROOT_NAME), NULL); - sbin = creat_dentry ("sbin", 4, NULL); + root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen(UMSDOS_PSDROOT_NAME), NULL, NULL); + sbin = creat_dentry ("sbin", 4, NULL, NULL); Printk ((KERN_DEBUG "Mounting root\n")); if (umsdos_real_lookup (pseudo,root)==0 @@ -531,7 +541,7 @@ int pseudo_ok = 0; Printk ((KERN_DEBUG "/%s is there\n",UMSDOS_PSDROOT_NAME)); - etc = creat_dentry ("etc", 3, NULL); + etc = creat_dentry ("etc", 3, NULL, NULL); /* if (umsdos_real_lookup (pseudo,"etc",3,etc)==0 */ @@ -540,8 +550,8 @@ Printk ((KERN_DEBUG "/%s/etc is there\n",UMSDOS_PSDROOT_NAME)); - init = creat_dentry ("init", 4, NULL); - etc_rc = creat_dentry ("rc", 2, NULL); + init = creat_dentry ("init", 4, NULL, NULL); + etc_rc = creat_dentry ("rc", 2, NULL, NULL); /* if ((umsdos_real_lookup (etc,"init",4,init)==0*/ if((umsdos_real_lookup(pseudo, init) == 0 @@ -585,7 +595,7 @@ Printk ((KERN_WARNING "umsdos_read_super /mn/: Pseudo should be iput-ed here...\n")); - iput (pseudo); /* FIXME */ + /* iput (pseudo); / * FIXME */ } #endif /* disabled */ diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c --- v2.1.93/linux/fs/umsdos/ioctl.c Tue Feb 17 13:12:48 1998 +++ linux/fs/umsdos/ioctl.c Wed Apr 8 11:39:46 1998 @@ -60,6 +60,21 @@ { int ret = -EPERM; int err; + + /* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */ + if(cmd!=UMSDOS_GETVERSION + &&cmd!=UMSDOS_READDIR_DOS + &&cmd!=UMSDOS_READDIR_EMD + &&cmd!=UMSDOS_INIT_EMD + &&cmd!=UMSDOS_CREAT_EMD + &&cmd!=UMSDOS_RENAME_DOS + &&cmd!=UMSDOS_UNLINK_EMD + &&cmd!=UMSDOS_UNLINK_DOS + &&cmd!=UMSDOS_RMDIR_DOS + &&cmd!=UMSDOS_STAT_DOS + &&cmd!=UMSDOS_DOS_SETUP) + return fat_dir_ioctl(dir,filp,cmd,data); + /* #Specification: ioctl / acces Only root (effective id) is allowed to do IOCTL on directory in UMSDOS. EPERM is returned for other user. @@ -162,7 +177,7 @@ } } } - iput (emd_dir); + /* iput (emd_dir); FIXME */ }else{ /* The absence of the EMD is simply seen as an EOF */ ret = 0; @@ -182,7 +197,7 @@ extern struct inode_operations umsdos_rdir_inode_operations; struct inode *emd_dir = umsdos_emd_dir_lookup (dir,1); ret = emd_dir != NULL; - iput (emd_dir); + /* iput (emd_dir); FIXME */ dir->i_op = ret ? &umsdos_dir_inode_operations @@ -225,8 +240,8 @@ ,dir ,data.umsdos_dirent.name,data.umsdos_dirent.name_len); */ - old_dentry = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, NULL); - new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL); + old_dentry = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, NULL, NULL); /* FIXME: prolly should fill inode part */ + new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL, NULL); ret = msdos_rename(dir,old_dentry,dir,new_dentry); }else if (cmd == UMSDOS_UNLINK_EMD){ /* #Specification: ioctl / UMSDOS_UNLINK_EMD @@ -297,7 +312,7 @@ data.stat.st_ctime = inode->i_ctime; data.stat.st_mtime = inode->i_mtime; copy_to_user (&idata->stat,&data.stat,sizeof(data.stat)); - iput (inode); + /* iput (inode); FIXME */ } }else if (cmd == UMSDOS_DOS_SETUP){ /* #Specification: ioctl / UMSDOS_DOS_SETUP diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c --- v2.1.93/linux/fs/umsdos/namei.c Tue Mar 17 22:18:15 1998 +++ linux/fs/umsdos/namei.c Wed Apr 8 11:39:46 1998 @@ -216,6 +216,7 @@ { int ret; + struct dentry *fake; Printk (("umsdos_create_any /mn/: create %.*s in dir=%lu - nevercreat=/", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino)); ret = umsdos_nevercreat(dir,dentry,-EEXIST); @@ -238,17 +239,16 @@ ret = umsdos_newentry (dir,&info); if (ret == 0){ dir->i_count++; - /* FIXME - ret = msdos_create (dir,info.fake.fname,info.fake.len - ,S_IFREG|0777,result); - */ - ret =msdos_create(dir,dentry,S_IFREG|0777); + fake = creat_dentry (info.fake.fname, info.fake.len, NULL, dentry->d_parent); /* create short name dentry */ + ret = msdos_create (dir, fake, S_IFREG|0777); if (ret == 0){ - struct inode *inode = dentry->d_inode; + struct inode *inode = fake->d_inode; umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos); Printk (("inode %p[%lu], count=%d ",inode, inode->i_ino, inode->i_count)); Printk (("Creation OK: [dir %lu] %.*s pid=%d pos %ld\n", dir->i_ino, info.fake.len, info.fake.fname, current->pid, info.f_pos)); + + d_instantiate(dentry, inode); /* long name also gets inode info */ }else{ /* #Specification: create / file exist in DOS Here is a situation. Trying to create a file with @@ -367,8 +367,8 @@ PRINTK (("ret %d %d ",ret,new_info.fake.len)); if (ret == 0){ struct dentry *old, *new; - old = creat_dentry (old_info.fake.fname, old_info.fake.len, NULL); - new = creat_dentry (new_info.fake.fname, new_info.fake.len, NULL); + old = creat_dentry (old_info.fake.fname, old_info.fake.len, NULL, NULL); + new = creat_dentry (new_info.fake.fname, new_info.fake.len, NULL, NULL); PRINTK (("msdos_rename ")); old_dir->i_count++; @@ -471,7 +471,7 @@ fill_new_filp (&filp, dentry); /* Make the inode acceptable to MSDOS FIXME */ - Printk ((KERN_ERR "umsdos_symlink_x: FIXME /mn/ Here goes the crash.. known wrong code...\n")); + Printk ((KERN_WARNING "umsdos_symlink_x: /mn/ Is this ok?\n")); Printk ((KERN_WARNING " symname=%s ; dentry name=%.*s (ino=%lu)\n", symname, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino)); ret = umsdos_file_write_kmem_real (&filp, symname, len, &myofs); /* dput(dentry); ?? where did this come from FIXME */ @@ -489,7 +489,7 @@ dir = NULL; } } - d_instantiate(dentry,dir); + /* d_instantiate(dentry,dir); //already done in umsdos_create_any */ Printk (("\n")); return ret; } @@ -634,7 +634,7 @@ ret = -ENOMEM; }else{ struct dentry *temp; - temp = creat_dentry (entry.name, entry.name_len, NULL); + temp = creat_dentry (entry.name, entry.name_len, NULL, NULL); Printk (("olddir[%d] ",olddir->i_count)); ret = umsdos_locate_path (oldinode,path); Printk (("olddir[%d] ",olddir->i_count)); @@ -673,7 +673,7 @@ umsdos_unlockcreate(olddir); umsdos_unlockcreate(dir); } - iput (olddir); + /* iput (olddir); FIXME */ } if (ret == 0){ struct iattr newattrs; @@ -681,8 +681,10 @@ newattrs.ia_valid = 0; ret = UMSDOS_notify_change(olddentry, &newattrs); } - dput (olddentry); - dput (dentry); + +/* dput (olddentry); + dput (dentry); FIXME.... */ + Printk (("umsdos_link %d\n",ret)); return ret; } @@ -735,10 +737,12 @@ ret = umsdos_newentry (dir,&info); Printk (("newentry %d ",ret)); if (ret == 0){ - struct dentry *temp; - temp = creat_dentry (info.fake.fname, info.fake.len, NULL); + struct dentry *temp, *tdir; + tdir = creat_dentry ("mkd-dir", 7, dir, NULL); + temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir); dir->i_count++; ret = msdos_mkdir (dir, temp, mode); + if (ret != 0){ umsdos_delentry (dir,&info,1); /* #Specification: mkdir / Directory already exist in DOS @@ -756,17 +760,22 @@ ret = compat_umsdos_real_lookup (dir,info.fake.fname, info.fake.len,&subdir); if (ret == 0){ -/* struct inode *result; FIXME /mn/ hmmm what is this supposed to be ? */ - struct dentry *tdentry; - tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL); - - ret = msdos_create (subdir, tdentry,S_IFREG|0777); + struct dentry *tdentry, *tdsub; + tdsub = creat_dentry ("mkd-emd", 7, subdir, NULL); + tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tdsub); + ret = msdos_create (subdir, tdentry, S_IFREG|0777); + kill_dentry (tdentry); /* we don't want empty EMD file to be visible ! too bad kill_dentry does nothing at the moment :-) FIXME */ + kill_dentry (tdsub); + umsdos_setup_dir_inode (subdir); /* this should setup dir so it is promoted to EMD, and EMD file is not visible inside it */ subdir = NULL; + d_instantiate(dentry, temp->d_inode); /* iput (result); FIXME */ } if (ret < 0){ printk ("UMSDOS: Can't create empty --linux-.---\n"); } + + /* iput (subdir); FIXME */ } } @@ -774,7 +783,7 @@ } } Printk (("umsdos_mkdir %d\n",ret)); -/* dput (dentry); FIXME /mn/ */ + /* dput (dentry); / * FIXME /mn/ */ return ret; } @@ -803,7 +812,7 @@ */ int ret = umsdos_create_any (dir,dentry,mode,rdev,0); -/* dput(dentry); /mn/ FIXME! */ + /* dput(dentry); / * /mn/ FIXME! */ return ret; } @@ -902,7 +911,9 @@ as possible. */ - int ret = umsdos_nevercreat(dir,dentry,-EPERM); + int ret; + + ret = umsdos_nevercreat(dir,dentry,-EPERM); if (ret == 0){ volatile struct inode *sdir; dir->i_count++; @@ -913,18 +924,22 @@ int empty; umsdos_lockcreate(dir); if (sdir->i_count > 1){ + Printk ((" /mn/ rmdir: FIXME EBUSY: hmmm, i_count is %d > 1\n", sdir->i_count)); ret = -EBUSY; }else if ((empty = umsdos_isempty (sdir)) != 0){ - struct dentry *tdentry; - tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL); + struct dentry *tdentry, *tedir; + tedir = creat_dentry ("emd-rmd", 7, dir, NULL); + tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tedir); + umsdos_real_lookup (dir, tdentry); /* fill inode part */ Printk (("isempty %d i_count %d ",empty,sdir->i_count)); /* check sticky bit */ if ( !(dir->i_mode & S_ISVTX) || fsuser() || current->fsuid == sdir->i_uid || current->fsuid == dir->i_uid ) { if (empty == 1){ - /* We have to removed the EMD file */ + /* We have to remove the EMD file */ ret = msdos_unlink (sdir, tdentry); + Printk (("UMSDOS_rmdir: unlinking empty EMD ret=%d", ret)); sdir = NULL; } /* sdir must be free before msdos_rmdir() */ @@ -933,17 +948,34 @@ Printk (("isempty ret %d nlink %d ",ret,dir->i_nlink)); if (ret == 0){ struct umsdos_info info; - struct dentry *temp; + struct dentry *temp, *tdir; dir->i_count++; umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info); /* The findentry is there only to complete */ /* the mangling */ umsdos_findentry (dir,&info,2); - temp = creat_dentry (info.fake.fname, info.fake.len, NULL); - + + tdir = creat_dentry ("dir-rmd", 7, dir, NULL); + temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir); + umsdos_real_lookup (dir, temp); /* fill inode part */ + + Printk ((KERN_ERR " rmdir start dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb)); /* FIXME: /mn/ debug only */ + Printk ((KERN_ERR " dentry=%.*s d_count=%d ino=%lu\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode->i_ino)); + Printk ((KERN_ERR " d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino)); + ret = msdos_rmdir (dir, temp); + + Printk ((KERN_ERR " rmdir passed %d\n", ret)); /* FIXME: /mn/ debug only */ + Printk ((KERN_ERR " rmdir end dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb)); + Printk ((KERN_ERR " dentry=%.*s d_count=%d ino=%p\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode)); + Printk ((KERN_ERR " d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino)); + + kill_dentry (tdir); + kill_dentry (temp); + if (ret == 0){ ret = umsdos_delentry (dir,&info,1); + d_delete (dentry); } } }else{ @@ -961,7 +993,7 @@ umsdos_unlockcreate(dir); } } - dput(dentry); + /* dput(dentry); FIXME /mn/ */ Printk (("umsdos_rmdir %d\n",ret)); return ret; } @@ -1036,13 +1068,21 @@ if (ret == 0){ ret = umsdos_delentry (dir,&info,0); if (ret == 0){ - struct dentry *temp; + struct dentry *temp, *tdir; Printk (("Avant msdos_unlink %.*s ",info.fake.len,info.fake.fname)); - dir->i_count++; - temp = creat_dentry (info.fake.fname, info.fake.len, NULL); + dir->i_count++; /* FIXME /mn/ is this needed anymore now that msdos_unlink locks dir using d_parent ? */ + tdir = creat_dentry ("dir-del", 7, dir, NULL); /* FIXME /mn/: do we need iget(dir->i_ino) or would dir itself suffice ? */ + temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir); + umsdos_real_lookup (dir, temp); /* fill inode part */ + ret = msdos_unlink_umsdos (dir, temp); Printk (("msdos_unlink %.*s %o ret %d ",info.fake.len,info.fake.fname ,info.entry.mode,ret)); + + d_delete (dentry); + + kill_dentry (tdir); + kill_dentry (temp); } } }else{ @@ -1054,7 +1094,7 @@ umsdos_unlockcreate(dir); } } - dput(dentry); + /* dput(dentry); FIXME: shouldn't this be done in msdos_unlink ? */ Printk (("umsdos_unlink %d\n",ret)); return ret; } @@ -1140,8 +1180,9 @@ } } } + /* dput (new_dentry); - dput (old_dentry); + dput (old_dentry); FIXME /mn/ */ return ret; } diff -u --recursive --new-file v2.1.93/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c --- v2.1.93/linux/fs/umsdos/rdir.c Mon Feb 23 18:12:11 1998 +++ linux/fs/umsdos/rdir.c Wed Apr 8 11:39:46 1998 @@ -135,7 +135,7 @@ */ Printk ((KERN_WARNING "umsdos_rlookup_x: do the pseudo-thingy...\n")); ret = -ENOENT; - iput (pseudo_root); + /* iput (pseudo_root); FIXME */ }else if (S_ISDIR(inode->i_mode)){ /* We must place the proper function table */ @@ -145,7 +145,7 @@ } } } - iput (dir); + /* iput (dir); FIXME */ PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret)); return ret; } @@ -215,7 +215,7 @@ }else if (empty == 1){ /* We have to removed the EMD file */ struct dentry *temp; - temp = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL); + temp = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, NULL); /* FIXME: prolly should fill inode part ? */ ret = msdos_unlink(sdir, temp); sdir = NULL; if (ret == 0){ @@ -226,12 +226,12 @@ }else{ ret = -ENOTEMPTY; } - iput (sdir); + /* iput (sdir); FIXME */ } } umsdos_unlockcreate (dir); } - iput (dir); + /* iput (dir); FIXME */ return ret; } diff -u --recursive --new-file v2.1.93/linux/include/asm-alpha/lca.h linux/include/asm-alpha/lca.h --- v2.1.93/linux/include/asm-alpha/lca.h Wed Apr 1 20:11:53 1998 +++ linux/include/asm-alpha/lca.h Tue Apr 7 07:52:05 1998 @@ -52,6 +52,7 @@ * ugh). */ +#include #include #ifdef CONFIG_ALPHA_SRM_SETUP diff -u --recursive --new-file v2.1.93/linux/include/asm-alpha/string.h linux/include/asm-alpha/string.h --- v2.1.93/linux/include/asm-alpha/string.h Fri Oct 18 01:53:20 1996 +++ linux/include/asm-alpha/string.h Tue Apr 7 08:05:05 1998 @@ -3,29 +3,40 @@ #ifdef __KERNEL__ -extern void * __constant_c_memset(void *, unsigned long, long); -extern void * __memset(void *, char, size_t); - /* - * Ugh. Gcc uses "bcopy()" internally for structure assignments. + * GCC of any recent vintage doesn't do stupid things with bcopy. Of + * EGCS-devel vintage, it knows all about expanding memcpy inline. + * For things other than EGCS-devel but still recent, GCC will expand + * __builtin_memcpy as a simple call to memcpy. + * + * Similarly for a memset with data = 0. */ -#define __HAVE_ARCH_BCOPY -/* - * Define "memcpy()" to something else, otherwise gcc will - * corrupt that too into a "bcopy". Also, some day we might - * want to do a separate inlined constant-size memcpy (for 8 - * and 16 byte user<->kernel structure copying). - */ #define __HAVE_ARCH_MEMCPY +/* For backward compatibility with modules. Unused otherwise. */ extern void * __memcpy(void *, const void *, size_t); -#define memcpy __memcpy + +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 8 +#define memcpy __builtin_memcpy +#endif #define __HAVE_ARCH_MEMSET -#define memset(s, c, count) \ -(__builtin_constant_p(c) ? \ - __constant_c_memset((s),(0x0101010101010101UL*(unsigned char)c),(count)) : \ - __memset((s),(c),(count))) +extern void * __constant_c_memset(void *, unsigned long, long); +extern void * __memset(void *, char, size_t); + +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 8 +#define memset(s, c, n) \ +(__builtin_constant_p(c) \ + ? (__builtin_constant_p(n) && (c) == 0 \ + ? __builtin_memset((s),0,(n)) \ + : __constant_c_memset((s),0x0101010101010101UL*(unsigned char)(c),(n))) \ + : __memset((s),(c),(n))) +#else +#define memset(s, c, n) \ +(__builtin_constant_p(c) \ + ? __constant_c_memset((s),0x0101010101010101UL*(unsigned char)(c),(n)) \ + : __memset((s),(c),(n))) +#endif #define __HAVE_ARCH_STRCPY #define __HAVE_ARCH_STRNCPY diff -u --recursive --new-file v2.1.93/linux/include/asm-alpha/termios.h linux/include/asm-alpha/termios.h --- v2.1.93/linux/include/asm-alpha/termios.h Fri Apr 4 08:52:25 1997 +++ linux/include/asm-alpha/termios.h Wed Apr 8 17:31:27 1998 @@ -72,6 +72,8 @@ #define N_MOUSE 2 #define N_PPP 3 #define N_AX25 5 +#define N_X25 6 +#define N_6PACK 7 #ifdef __KERNEL__ /* eof=^D eol=\0 eol2=\0 erase=del diff -u --recursive --new-file v2.1.93/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h --- v2.1.93/linux/include/asm-alpha/unistd.h Thu Mar 26 15:57:05 1998 +++ linux/include/asm-alpha/unistd.h Tue Apr 7 08:05:05 1998 @@ -421,12 +421,6 @@ return sys_read(fd, buf, nr); } -extern int sys_fork(void); -static inline int fork(void) -{ - return sys_fork(); -} - extern int __kernel_execve(char *, char **, char **, struct pt_regs *); static inline int execve(char * file, char ** argvp, char ** envp) { diff -u --recursive --new-file v2.1.93/linux/include/asm-arm/proc-armo/pgtable.h linux/include/asm-arm/proc-armo/pgtable.h --- v2.1.93/linux/include/asm-arm/proc-armo/pgtable.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/proc-armo/pgtable.h Wed Apr 8 15:44:24 1998 @@ -9,6 +9,7 @@ #include #include +#include /* For TASK_SIZE */ #define LIBRARY_TEXT_START 0x0c000000 @@ -116,6 +117,7 @@ #define PTRS_PER_PTE 32 #define PTRS_PER_PMD 1 #define PTRS_PER_PGD 32 +#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SHIFT) /* Just any arbitrary offset to the start of the vmalloc VM area: the * current 8MB value just means that there will be a 8MB "hole" after the @@ -321,43 +323,111 @@ * used to allocate a kernel page table - this turns on ASN bits * if any. */ -#define pte_free_kernel(pte) pte_free((pte)) -#define pte_alloc_kernel(pmd,address) pte_alloc((pmd),(address)) -/* - * allocating and freeing a pmd is trivial: the 1-entry pmd is - * inside the pgd, so has no extra memory associated with it. - */ -#define pmd_free_kernel(pmdp) -#define pmd_alloc_kernel(pgd,address) ((pmd_t *)(pgd)) +#ifndef __SMP__ +extern struct pgtable_cache_struct { + unsigned long *pgd_cache; + unsigned long *pte_cache; + unsigned long pgtable_cache_sz; +} quicklists; + +#define pmd_quicklist ((unsigned long *)0) +#define pte_quicklist (quicklists.pte_cache) +#define pgd_quicklist (quicklists.pgd_cache) +#define pgtable_cache_size (quicklists.pgtable_cache_sz) + +#else +#error Pgtable caches have to be per-CPU, so that no locking is needed. +#endif + +extern pgd_t *get_pgd_slow(void); + +extern __inline__ pgd_t *get_pgd_fast(void) +{ + unsigned long *ret; + + if((ret = pgd_quicklist) != NULL) { + pgd_quicklist = (unsigned long *)(*ret); + ret[0] = ret[1]; + pgtable_cache_size--; + } else + ret = (unsigned long *)get_pgd_slow(); + return (pgd_t *)ret; +} + +extern __inline__ void free_pgd_fast(pgd_t *pgd) +{ + *(unsigned long *)pgd = (unsigned long) pgd_quicklist; + pgd_quicklist = (unsigned long *) pgd; + pgtable_cache_size++; +} + +extern __inline__ void free_pgd_slow(pgd_t *pgd) +{ + kfree(pgd); +} + +extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); + +extern __inline__ pte_t *get_pte_fast(void) +{ + unsigned long *ret; + + if((ret = (unsigned long *)pte_quicklist) != NULL) { + pte_quicklist = (unsigned long *)(*ret); + ret[0] = ret[1]; + pgtable_cache_size--; + } + return (pte_t *)ret; +} -extern __inline__ void pte_free(pte_t * pte) +extern __inline__ void free_pte_fast(pte_t *pte) { - kfree (pte); + *(unsigned long *)pte = (unsigned long) pte_quicklist; + pte_quicklist = (unsigned long *) pte; + pgtable_cache_size++; } -extern const char bad_pmd_string[]; +extern __inline__ void free_pte_slow(pte_t *pte) +{ + kfree(pte); +} + +/* We don't use pmd cache, so this is a dummy routine */ +extern __inline__ pmd_t *get_pmd_fast(void) +{ + return (pmd_t *)0; +} + +extern __inline__ void free_pmd_fast(pmd_t *pmd) +{ +} + +extern __inline__ void free_pmd_slow(pmd_t *pmd) +{ +} + +extern void __bad_pte(pmd_t *pmd); + +#define pte_free_kernel(pte) free_pte_fast(pte) +#define pte_free(pte) free_pte_fast(pte) +#define pgd_free(pgd) free_pgd_fast(pgd) +#define pgd_alloc() get_pgd_fast() extern __inline__ pte_t *pte_alloc(pmd_t * pmd, unsigned long address) { address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); if (pmd_none (*pmd)) { - pte_t *page = (pte_t *) kmalloc (PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL); - if (pmd_none (*pmd)) { - if (page) { - memzero (page, PTRS_PER_PTE * BYTES_PER_PTR); - set_pmd(pmd, mk_pmd(page)); - return page + address; - } - set_pmd (pmd, mk_pmd (BAD_PAGETABLE)); - return NULL; - } - kfree (page); + pte_t *page = (pte_t *) get_pte_fast(); + + if (!page) + return get_pte_slow(pmd, address); + set_pmd(pmd, mk_pmd(page)); + return page + address; } if (pmd_bad (*pmd)) { - printk(bad_pmd_string, pmd_val(*pmd)); - set_pmd (pmd, mk_pmd (BAD_PAGETABLE)); + __bad_pte(pmd); return NULL; } return (pte_t *) pmd_page(*pmd) + address; @@ -367,28 +437,33 @@ * allocating and freeing a pmd is trivial: the 1-entry pmd is * inside the pgd, so has no extra memory associated with it. */ -#define pmd_free(pmd) -#define pmd_alloc(pgd,address) ((pmd_t *)(pgd)) +extern __inline__ void pmd_free(pmd_t *pmd) +{ +} -/* - * Free a page directory. Takes the virtual address. - */ -extern __inline__ void pgd_free(pgd_t * pgd) +extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address) { - kfree ((void *)pgd); + return (pmd_t *) pgd; } -/* - * Allocate a new page directory. Return the virtual address of it. - */ -extern __inline__ pgd_t * pgd_alloc(void) +#define pmd_free_kernel pmd_free +#define pmd_alloc_kernel pmd_alloc +#define pte_alloc_kernel pte_alloc + +extern __inline__ void set_pgdir(unsigned long address, pgd_t entry) { + struct task_struct * p; pgd_t *pgd; - - pgd = (pgd_t *) kmalloc(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL); - if (pgd) - memzero (pgd, PTRS_PER_PGD * BYTES_PER_PTR); - return pgd; + + read_lock(&tasklist_lock); + for_each_task(p) { + if (!p->mm) + continue; + *pgd_offset(p->mm,address) = entry; + } + read_unlock(&tasklist_lock); + for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd) + pgd[address >> PGDIR_SHIFT)] = entry; } extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; diff -u --recursive --new-file v2.1.93/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h --- v2.1.93/linux/include/asm-arm/proc-armv/pgtable.h Tue Jan 20 16:39:43 1998 +++ linux/include/asm-arm/proc-armv/pgtable.h Wed Apr 8 15:44:24 1998 @@ -10,6 +10,7 @@ #define __ASM_PROC_PGTABLE_H #include +#include /* For TASK_SIZE */ #define LIBRARY_TEXT_START 0x0c000000 @@ -132,6 +133,7 @@ #define PTRS_PER_PTE 256 #define PTRS_PER_PMD 1 #define PTRS_PER_PGD 4096 +#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE) /* Just any arbitrary offset to the start of the vmalloc VM area: the * current 8MB value just means that there will be a 8MB "hole" after the @@ -263,6 +265,9 @@ extern __inline__ int pte_present(pte_t pte) { +#if 0 + /* This is what it really does, the else + part is just to make it easier for the compiler */ switch (pte_val(pte) & PTE_TYPE_MASK) { case PTE_TYPE_LARGE: case PTE_TYPE_SMALL: @@ -270,6 +275,9 @@ default: return 0; } +#else + return ((pte_val(pmd) + 1) & PMD_TYPE_MASK); +#endif } extern __inline__ int pmd_none(pmd_t pmd) @@ -281,6 +289,9 @@ extern __inline__ int pmd_bad(pmd_t pmd) { +#if 0 + /* This is what it really does, the else + part is just to make it easier for the compiler */ switch (pmd_val(pmd) & PMD_TYPE_MASK) { case PMD_TYPE_FAULT: case PMD_TYPE_TABLE: @@ -288,6 +299,9 @@ default: return 1; } +#else + return (pmd_val(pmd) & PMD_TYPE_SECT); +#endif } extern __inline__ int pmd_present(pmd_t pmd) @@ -479,7 +493,7 @@ /* to find an entry in a page-table-directory */ extern __inline__ pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) { - return mm->pgd + (address >> PGDIR_SHIFT); + return mm->pgd + (address >> PGDIR_SHIFT); } /* Find an entry in the second-level page table.. */ @@ -488,7 +502,7 @@ /* Find an entry in the third-level page table.. */ extern __inline__ pte_t * pte_offset(pmd_t * dir, unsigned long address) { - return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); + return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); } extern unsigned long get_small_page(int priority); @@ -499,69 +513,129 @@ * used to allocate a kernel page table - this turns on ASN bits * if any. */ -extern __inline__ void pte_free_kernel(pte_t * pte) + +#ifndef __SMP__ +extern struct pgtable_cache_struct { + unsigned long *pgd_cache; + unsigned long *pte_cache; + unsigned long pgtable_cache_sz; +} quicklists; +#define pgd_quicklist (quicklists.pgd_cache) +#define pmd_quicklist ((unsigned long *)0) +#define pte_quicklist (quicklists.pte_cache) +#define pgtable_cache_size (quicklists.pgtable_cache_sz) +#else +#error Pgtable caches have to be per-CPU, so that no locking is needed. +#endif + +extern pgd_t *get_pgd_slow(void); + +extern __inline__ pgd_t *get_pgd_fast(void) +{ + unsigned long *ret; + + if((ret = pgd_quicklist) != NULL) { + pgd_quicklist = (unsigned long *)(*ret); + ret[0] = ret[1]; + pgtable_cache_size--; + } else + ret = (unsigned long *)get_pgd_slow(); + return (pgd_t *)ret; +} + +extern __inline__ void free_pgd_fast(pgd_t *pgd) +{ + *(unsigned long *)pgd = (unsigned long) pgd_quicklist; + pgd_quicklist = (unsigned long *) pgd; + pgtable_cache_size++; +} + +extern __inline__ void free_pgd_slow(pgd_t *pgd) +{ + free_pages((unsigned long) pgd, 2); +} + +extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); +extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted); + +extern __inline__ pte_t *get_pte_fast(void) +{ + unsigned long *ret; + + if((ret = (unsigned long *)pte_quicklist) != NULL) { + pte_quicklist = (unsigned long *)(*ret); + ret[0] = ret[1]; + pgtable_cache_size--; + } + return (pte_t *)ret; +} + +extern __inline__ void free_pte_fast(pte_t *pte) +{ + *(unsigned long *)pte = (unsigned long) pte_quicklist; + pte_quicklist = (unsigned long *) pte; + pgtable_cache_size++; +} + +extern __inline__ void free_pte_slow(pte_t *pte) +{ + free_small_page((unsigned long)pte); +} + +/* We don't use pmd cache, so this is a dummy routine */ +extern __inline__ pmd_t *get_pmd_fast(void) { - free_small_page((unsigned long) pte); + return (pmd_t *)0; } -extern const char bad_pmd_string[]; +extern __inline__ void free_pmd_fast(pmd_t *pmd) +{ +} + +extern __inline__ void free_pmd_slow(pmd_t *pmd) +{ +} + +extern void __bad_pte(pmd_t *pmd); +extern void __bad_pte_kernel(pmd_t *pmd); + +#define pte_free_kernel(pte) free_pte_fast(pte) +#define pte_free(pte) free_pte_fast(pte) +#define pgd_free(pgd) free_pgd_fast(pgd) +#define pgd_alloc() get_pgd_fast() extern __inline__ pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address) { address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); if (pmd_none(*pmd)) { - pte_t *page = (pte_t *) get_small_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (page) { - memzero (page, PTRS_PER_PTE * BYTES_PER_PTR); - set_pmd(pmd, mk_kernel_pmd(page)); - return page + address; - } - set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); - return NULL; - } - free_small_page((unsigned long) page); + pte_t *page = (pte_t *) get_pte_fast(); + + if (!page) + return get_pte_kernel_slow(pmd, address); + set_pmd(pmd, mk_kernel_pmd(page)); + return page + address; } if (pmd_bad(*pmd)) { - printk(bad_pmd_string, pmd_val(*pmd)); - set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); + __bad_pte_kernel(pmd); return NULL; } return (pte_t *) pmd_page(*pmd) + address; } -/* - * allocating and freeing a pmd is trivial: the 1-entry pmd is - * inside the pgd, so has no extra memory associated with it. - */ -#define pmd_free_kernel(pmdp) pmd_val(*(pmdp)) = 0; -#define pmd_alloc_kernel(pgdp, address) ((pmd_t *)(pgdp)) - -extern __inline__ void pte_free(pte_t * pte) -{ - free_small_page((unsigned long) pte); -} - extern __inline__ pte_t * pte_alloc(pmd_t * pmd, unsigned long address) { address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); if (pmd_none(*pmd)) { - pte_t *page = (pte_t *) get_small_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (page) { - memzero (page, PTRS_PER_PTE * BYTES_PER_PTR); - set_pmd(pmd, mk_user_pmd(page)); - return page + address; - } - set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); - return NULL; - } - free_small_page ((unsigned long) page); + pte_t *page = (pte_t *) get_pte_fast(); + + if (!page) + return get_pte_slow(pmd, address); + set_pmd(pmd, mk_user_pmd(page); + return page + address; } if (pmd_bad(*pmd)) { - printk(bad_pmd_string, pmd_val(*pmd)); - set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); + __bad_pte(pmd); return NULL; } return (pte_t *) pmd_page(*pmd) + address; @@ -571,31 +645,32 @@ * allocating and freeing a pmd is trivial: the 1-entry pmd is * inside the pgd, so has no extra memory associated with it. */ -#define pmd_free(pmdp) pmd_val(*(pmdp)) = 0; -#define pmd_alloc(pgdp, address) ((pmd_t *)(pgdp)) +extern __inline__ void pmd_free(pmd_t *pmd) +{ +} -/* - * Free a page directory. Takes the virtual address. - */ -extern __inline__ void pgd_free(pgd_t * pgd) +extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address) { - free_pages((unsigned long) pgd, 2); + return (pmd_t *) pgd; } -/* - * Allocate a new page directory. Return the virtual address of it. - */ -extern __inline__ pgd_t * pgd_alloc(void) +#define pmd_free_kernel pmd_free +#define pmd_alloc_kernel pmd_alloc + +extern __inline__ void set_pgdir(unsigned long address, pgd_t entry) { - unsigned long pgd; + struct task_struct * p; + pgd_t *pgd; - /* - * need to get a 16k page for level 1 - */ - pgd = __get_free_pages(GFP_KERNEL,2,0); - if (pgd) - memzero ((void *)pgd, PTRS_PER_PGD * BYTES_PER_PTR); - return (pgd_t *)pgd; + read_lock(&tasklist_lock); + for_each_task(p) { + if (!p->mm) + continue; + *pgd_offset(p->mm,address) = entry; + } + read_unlock(&tasklist_lock); + for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd) + pgd[address >> PGDIR_SHIFT] = entry; } extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; diff -u --recursive --new-file v2.1.93/linux/include/asm-arm/proc-armv/processor.h linux/include/asm-arm/proc-armv/processor.h --- v2.1.93/linux/include/asm-arm/proc-armv/processor.h Tue Jan 20 16:39:43 1998 +++ linux/include/asm-arm/proc-armv/processor.h Wed Apr 8 15:44:24 1998 @@ -95,7 +95,7 @@ * NOTE! The task struct and the stack go together */ #define alloc_task_struct() \ - ((struct task_struct *) __get_free_pages(GFP_KERNEL,1,0)) + ((struct task_struct *) __get_free_pages(GFP_KERNEL,1)) #define free_task_struct(p) free_pages((unsigned long)(p),1) #endif diff -u --recursive --new-file v2.1.93/linux/include/asm-arm/stat.h linux/include/asm-arm/stat.h --- v2.1.93/linux/include/asm-arm/stat.h Tue Jan 20 16:39:43 1998 +++ linux/include/asm-arm/stat.h Wed Apr 8 15:44:24 1998 @@ -38,4 +38,40 @@ unsigned long __unused5; }; +typedef struct { + unsigned int minor; + unsigned int major; +} __new_dev_t; + +struct stat64 { + __new_dev_t st_dev; + __u64 st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + __new_dev_t st_rdev; + __s64 st_size; + __u64 st_blocks; + unsigned long st_atime; + unsigned long __unused1; + unsigned long st_mtime; + unsigned long __unused2; + unsigned long st_ctime; + unsigned long __unused3; + unsigned long st_blksize; + unsigned long __unused4; +}; + +#define __XSTAT_VER_1 1 +#define __XSTAT_VER_2 2 +#define __XSTAT_VER_MASK 0xff + +#define __XSTAT_VER_XSTAT 0x000 +#define __XSTAT_VER_LXSTAT 0x100 +#define __XSTAT_VER_FXSTAT 0x200 +#define __XSTAT_VER_TYPEMASK 0xff00 + +#define __XMKNOD_VER_1 1 + #endif diff -u --recursive --new-file v2.1.93/linux/include/asm-arm/termios.h linux/include/asm-arm/termios.h --- v2.1.93/linux/include/asm-arm/termios.h Tue Jan 20 16:39:43 1998 +++ linux/include/asm-arm/termios.h Wed Apr 8 17:31:27 1998 @@ -54,6 +54,7 @@ #define N_STRIP 4 #define N_AX25 5 #define N_X25 6 /* X.25 async */ +#define N_6PACK 7 #ifdef __KERNEL__ diff -u --recursive --new-file v2.1.93/linux/include/asm-arm/unistd.h linux/include/asm-arm/unistd.h --- v2.1.93/linux/include/asm-arm/unistd.h Thu Mar 26 15:57:05 1998 +++ linux/include/asm-arm/unistd.h Wed Apr 8 15:44:24 1998 @@ -189,6 +189,8 @@ #define __NR_rt_sigsuspend (__NR_SYSCALL_BASE+179) #define __NR_pread (__NR_SYSCALL_BASE+180) #define __NR_pwrite (__NR_SYSCALL_BASE+181) +#define __NR_xstat (__NR_SYSCALL_BASE+182) +#define __NR_xmknod (__NR_SYSCALL_BASE+183) #define __sys2(x) #x #define __sys1(x) __sys2(x) @@ -311,8 +313,6 @@ */ #define __NR__exit __NR_exit static inline _syscall0(int,idle); -static inline _syscall0(int,fork); -static inline _syscall2(int,clone,unsigned long,flags,char *,esp); static inline _syscall0(int,pause); static inline _syscall1(int,setup,int,magic); static inline _syscall0(int,sync); diff -u --recursive --new-file v2.1.93/linux/include/asm-arm/xstat.h linux/include/asm-arm/xstat.h --- v2.1.93/linux/include/asm-arm/xstat.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/xstat.h Wed Apr 8 15:44:24 1998 @@ -0,0 +1,35 @@ +/* $Id: xstat.h,v 1.1 1998/02/06 12:52:45 jj Exp $ + * xstat.h: sys_xstat/xmknod architecture dependent stuff. + * + * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +extern __inline__ int cp_xstat(struct inode *inode, struct stat64 *s, unsigned long blocks, int blksize) +{ + struct stat64 tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.st_dev.major = MAJOR(inode->i_dev); + tmp.st_dev.minor = MINOR(inode->i_dev); + tmp.st_ino = inode->i_ino; + tmp.st_mode = inode->i_mode; + tmp.st_nlink = inode->i_nlink; + tmp.st_uid = inode->i_uid; + tmp.st_gid = inode->i_gid; + tmp.st_rdev.major = MAJOR(inode->i_rdev); + tmp.st_rdev.minor = MINOR(inode->i_rdev); + tmp.st_size = inode->i_size; + tmp.st_blksize = blksize; + tmp.st_blocks = blocks; + tmp.st_atime = inode->i_atime; + tmp.st_mtime = inode->i_mtime; + tmp.st_ctime = inode->i_ctime; + return copy_to_user(s,&tmp,sizeof(tmp)); +} + +extern __inline__ int get_user_new_dev_t(kdev_t *kdev, __new_dev_t *udev) { + __new_dev_t ndev; + if (copy_from_user (&ndev, udev, sizeof(__new_dev_t))) return -EFAULT; + *kdev = MKDEV(ndev.major, ndev.minor); + return 0; +} diff -u --recursive --new-file v2.1.93/linux/include/asm-i386/page.h linux/include/asm-i386/page.h --- v2.1.93/linux/include/asm-i386/page.h Tue Mar 17 22:18:15 1998 +++ linux/include/asm-i386/page.h Wed Apr 8 18:05:18 1998 @@ -1,8 +1,6 @@ #ifndef _I386_PAGE_H #define _I386_PAGE_H -#include - /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #define PAGE_SIZE (1UL << PAGE_SHIFT) @@ -60,8 +58,30 @@ /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) -/* This handles the memory map.. */ -#define __PAGE_OFFSET ((0x1000-CONFIG_MAX_MEMSIZE)<<20) +/* + * This handles the memory map.. We could make this a config + * option, but too many people screw it up, and too few need + * it. + * + * A __PAGE_OFFSET of 0xC0000000 means that the kernel has + * a virtual address space of one gigabyte, which limits the + * amount of physical memory you can use to about 950MB. If + * you want to use more physical memory, change this define. + * + * For example, if you have 2GB worth of physical memory, you + * could change this define to 0x70000000, which gives the + * kernel slightly more than 2GB of virtual memory (enough to + * map all your physical memory + a bit extra for various + * io-memory mappings) + * + * IF YOU CHANGE THIS, PLEASE ALSO CHANGE + * + * arch/i386/vmlinux.lds + * + * which has the same constant encoded.. + */ +#define __PAGE_OFFSET (0xC0000000) + #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) diff -u --recursive --new-file v2.1.93/linux/include/asm-i386/termios.h linux/include/asm-i386/termios.h --- v2.1.93/linux/include/asm-i386/termios.h Tue Dec 9 00:07:19 1997 +++ linux/include/asm-i386/termios.h Wed Apr 8 17:31:27 1998 @@ -46,6 +46,7 @@ #define N_STRIP 4 #define N_AX25 5 #define N_X25 6 /* X.25 async */ +#define N_6PACK 7 #ifdef __KERNEL__ diff -u --recursive --new-file v2.1.93/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h --- v2.1.93/linux/include/asm-i386/unistd.h Wed Apr 1 20:11:54 1998 +++ linux/include/asm-i386/unistd.h Tue Apr 7 08:05:05 1998 @@ -282,8 +282,6 @@ */ #define __NR__exit __NR_exit static inline _syscall0(int,idle) -static inline _syscall0(int,fork) -static inline _syscall2(int,clone,unsigned long,flags,char *,esp) static inline _syscall0(int,pause) static inline _syscall1(int,setup,int,magic) static inline _syscall0(int,sync) diff -u --recursive --new-file v2.1.93/linux/include/asm-m68k/termios.h linux/include/asm-m68k/termios.h --- v2.1.93/linux/include/asm-m68k/termios.h Wed Apr 23 19:01:28 1997 +++ linux/include/asm-m68k/termios.h Wed Apr 8 17:31:27 1998 @@ -54,6 +54,7 @@ #define N_STRIP 4 #define N_AX25 5 #define N_X25 6 /* X.25 async */ +#define N_6PACK 7 #ifdef __KERNEL__ diff -u --recursive --new-file v2.1.93/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h --- v2.1.93/linux/include/asm-m68k/unistd.h Thu Mar 26 15:57:05 1998 +++ linux/include/asm-m68k/unistd.h Tue Apr 7 08:05:05 1998 @@ -303,8 +303,6 @@ */ #define __NR__exit __NR_exit static inline _syscall0(int,idle) -static inline _syscall0(int,fork) -static inline _syscall2(int,clone,unsigned long,flags,char *,usp) static inline _syscall0(int,pause) static inline _syscall1(int,setup,int,magic) static inline _syscall0(int,sync) diff -u --recursive --new-file v2.1.93/linux/include/asm-mips/termios.h linux/include/asm-mips/termios.h --- v2.1.93/linux/include/asm-mips/termios.h Thu Jun 26 12:33:40 1997 +++ linux/include/asm-mips/termios.h Wed Apr 8 17:31:27 1998 @@ -92,6 +92,7 @@ #define N_STRIP 4 #define N_AX25 5 #define N_X25 6 /* X.25 async */ +#define N_6PACK 7 #ifdef __KERNEL__ diff -u --recursive --new-file v2.1.93/linux/include/asm-mips/unistd.h linux/include/asm-mips/unistd.h --- v2.1.93/linux/include/asm-mips/unistd.h Thu Mar 26 15:57:05 1998 +++ linux/include/asm-mips/unistd.h Tue Apr 7 08:05:05 1998 @@ -1397,8 +1397,6 @@ */ #define __NR__exit __NR_exit static inline _syscall0(int,idle) -static inline _syscall0(int,fork) -static inline _syscall2(int,clone,unsigned long,flags,char *,esp) static inline _syscall0(int,pause) static inline _syscall1(int,setup,int,magic) static inline _syscall0(int,sync) diff -u --recursive --new-file v2.1.93/linux/include/asm-sparc/termios.h linux/include/asm-sparc/termios.h --- v2.1.93/linux/include/asm-sparc/termios.h Mon Mar 17 14:54:33 1997 +++ linux/include/asm-sparc/termios.h Wed Apr 8 17:31:27 1998 @@ -61,6 +61,8 @@ #define N_PPP 3 #define N_STRIP 4 #define N_AX25 5 +#define N_X25 6 +#define N_6PACK 7 #ifdef __KERNEL__ diff -u --recursive --new-file v2.1.93/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h --- v2.1.93/linux/include/asm-sparc/unistd.h Thu Mar 26 15:57:05 1998 +++ linux/include/asm-sparc/unistd.h Tue Apr 7 08:05:05 1998 @@ -425,8 +425,6 @@ */ #define __NR__exit __NR_exit static __inline__ _syscall0(int,idle) -static __inline__ _syscall0(int,fork) -static __inline__ _syscall2(int,clone,unsigned long,flags,char *,ksp) static __inline__ _syscall0(int,pause) static __inline__ _syscall1(int,setup,int,magic) static __inline__ _syscall0(int,sync) diff -u --recursive --new-file v2.1.93/linux/include/asm-sparc64/termios.h linux/include/asm-sparc64/termios.h --- v2.1.93/linux/include/asm-sparc64/termios.h Thu Mar 27 14:40:09 1997 +++ linux/include/asm-sparc64/termios.h Wed Apr 8 17:31:27 1998 @@ -61,6 +61,8 @@ #define N_PPP 3 #define N_STRIP 4 #define N_AX25 5 +#define N_X25 6 +#define N_6PACK 7 #ifdef __KERNEL__ diff -u --recursive --new-file v2.1.93/linux/include/asm-sparc64/unistd.h linux/include/asm-sparc64/unistd.h --- v2.1.93/linux/include/asm-sparc64/unistd.h Thu Mar 26 15:57:05 1998 +++ linux/include/asm-sparc64/unistd.h Tue Apr 7 08:05:05 1998 @@ -413,8 +413,6 @@ */ #define __NR__exit __NR_exit static __inline__ _syscall0(int,idle) -static __inline__ _syscall0(int,fork) -static __inline__ _syscall2(int,clone,unsigned long,flags,char *,ksp) static __inline__ _syscall0(int,pause) static __inline__ _syscall1(int,setup,int,magic) static __inline__ _syscall0(int,sync) diff -u --recursive --new-file v2.1.93/linux/include/linux/binfmts.h linux/include/linux/binfmts.h --- v2.1.93/linux/include/linux/binfmts.h Wed Apr 1 20:11:54 1998 +++ linux/include/linux/binfmts.h Wed Apr 8 18:15:11 1998 @@ -11,6 +11,8 @@ */ #define MAX_ARG_PAGES 32 +#ifdef __KERNEL__ + /* * This structure is used to hold the arguments that are used when loading binaries. */ @@ -70,4 +72,5 @@ /* this eventually goes away */ #define change_ldt(a,b) setup_arg_pages(a,b) -#endif +#endif /* __KERNEL__ */ +#endif /* _LINUX_BINFMTS_H */ diff -u --recursive --new-file v2.1.93/linux/include/linux/joystick.h linux/include/linux/joystick.h --- v2.1.93/linux/include/linux/joystick.h Fri Feb 6 15:33:20 1998 +++ linux/include/linux/joystick.h Wed Apr 8 17:24:48 1998 @@ -2,19 +2,18 @@ #define _LINUX_JOYSTICK_H /* - * $Id: joystick.h,v 1.2 1997/10/31 19:11:57 mj Exp $ + * $Id: joystick.h,v 1.3 1998/03/30 11:10:40 mj Exp $ * - * Copyright (C) 1997 Vojtech Pavlik + * Copyright (C) 1997, 1998 Vojtech Pavlik */ -#include #include /* * Version */ -#define JS_VERSION 0x00010006L /* 1.0.6 BCD */ +#define JS_VERSION 0x00010007L /* 1.0.7 BCD */ /* * IOCTL commands for joystick driver diff -u --recursive --new-file v2.1.93/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.1.93/linux/include/linux/mm.h Thu Mar 26 15:57:05 1998 +++ linux/include/linux/mm.h Wed Apr 8 18:15:11 1998 @@ -133,7 +133,7 @@ #define PG_uptodate 3 #define PG_free_after 4 #define PG_decr_after 5 -/* Unused 6 */ +#define PG_swap_unlock_after 6 #define PG_DMA 7 #define PG_Slab 8 #define PG_swap_cache 9 @@ -146,6 +146,7 @@ #define PageUptodate(page) (test_bit(PG_uptodate, &(page)->flags)) #define PageFreeAfter(page) (test_bit(PG_free_after, &(page)->flags)) #define PageDecrAfter(page) (test_bit(PG_decr_after, &(page)->flags)) +#define PageSwapUnlockAfter(page) (test_bit(PG_swap_unlock_after, &(page)->flags)) #define PageDMA(page) (test_bit(PG_DMA, &(page)->flags)) #define PageSlab(page) (test_bit(PG_Slab, &(page)->flags)) #define PageSwapCache(page) (test_bit(PG_swap_cache, &(page)->flags)) diff -u --recursive --new-file v2.1.93/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.1.93/linux/include/linux/pci.h Mon Apr 6 17:41:01 1998 +++ linux/include/linux/pci.h Tue Apr 7 08:05:05 1998 @@ -977,6 +977,9 @@ #ifdef __KERNEL__ +/* Create an index into the pci_dev base_address[] array from an offset. */ +#define PCI_BASE_INDEX(o) (((o)-PCI_BASE_ADDRESS_0)>>2) + /* * Error values that may be returned by the PCI bios. Use * pcibios_strerror() to convert to a printable string. diff -u --recursive --new-file v2.1.93/linux/include/linux/swap.h linux/include/linux/swap.h --- v2.1.93/linux/include/linux/swap.h Thu Mar 26 15:57:06 1998 +++ linux/include/linux/swap.h Mon Apr 6 17:48:34 1998 @@ -23,6 +23,7 @@ kdev_t swap_device; struct dentry * swap_file; unsigned char * swap_map; + unsigned char * swap_lockmap; unsigned int lowest_bit; unsigned int highest_bit; unsigned int cluster_next; @@ -64,6 +65,7 @@ extern void show_swap_cache_info(void); extern int add_to_swap_cache(struct page *, unsigned long); extern void swap_duplicate(unsigned long); +extern void swap_after_unlock_page (unsigned long entry); extern struct page * read_swap_cache_async(unsigned long, int); #define read_swap_cache(entry) read_swap_cache_async(entry, 1); diff -u --recursive --new-file v2.1.93/linux/include/linux/umsdos_fs.h linux/include/linux/umsdos_fs.h --- v2.1.93/linux/include/linux/umsdos_fs.h Tue Feb 17 13:12:49 1998 +++ linux/include/linux/umsdos_fs.h Wed Apr 8 18:17:22 1998 @@ -141,6 +141,7 @@ extern struct file_operations umsdos_file_operations; extern struct inode_operations umsdos_file_inode_operations; extern struct inode_operations umsdos_file_inode_operations_no_bmap; +extern struct inode_operations umsdos_file_inode_operations_readpage; extern struct inode_operations umsdos_symlink_inode_operations; extern int init_umsdos_fs(void); diff -u --recursive --new-file v2.1.93/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p --- v2.1.93/linux/include/linux/umsdos_fs.p Tue Mar 17 22:18:15 1998 +++ linux/include/linux/umsdos_fs.p Wed Apr 8 11:39:46 1998 @@ -31,7 +31,8 @@ void kill_dentry (struct dentry *dentry); struct dentry *creat_dentry (const char *name, const int len, - struct inode *inode); + struct inode *inode, + struct dentry *parent); ssize_t umsdos_file_write_kmem_real (struct file *filp, const char *buf, size_t count, diff -u --recursive --new-file v2.1.93/linux/include/linux/videodev.h linux/include/linux/videodev.h --- v2.1.93/linux/include/linux/videodev.h Fri Jan 23 18:10:32 1998 +++ linux/include/linux/videodev.h Wed Apr 8 17:24:48 1998 @@ -17,14 +17,20 @@ int (*ioctl)(struct video_device *, unsigned int , void *); int (*mmap)(struct video_device *, const char *, unsigned long); int (*initialize)(struct video_device *); - void *private; + void *priv; /* Used to be 'private' but that upsets C++ */ int busy; int minor; }; extern int videodev_init(void); #define VIDEO_MAJOR 81 -extern int video_register_device(struct video_device *); +extern int video_register_device(struct video_device *, int type); + +#define VFL_TYPE_GRABBER 0 +#define VFL_TYPE_VBI 1 +#define VFL_TYPE_RADIO 2 +#define VFL_TYPE_VTX 3 + extern void video_unregister_device(struct video_device *); #endif @@ -39,10 +45,9 @@ #define VID_TYPE_SCALES 128 /* Scalable */ #define VID_TYPE_MONOCHROME 256 /* Monochrome only */ - struct video_capability { - char name[32]; + char name[32]; int type; int channels; /* Num channels */ int audios; /* Num audio devices */ @@ -111,6 +116,11 @@ #define VIDEO_AUDIO_BASS 8 #define VIDEO_AUDIO_TREBLE 16 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; }; struct video_clip @@ -139,6 +149,12 @@ int bytesperline; }; +struct video_mmap +{ + unsigned int frame; /* Frame (0 or 1) for double buffer */ + int height,width; + unsigned int format; +}; struct video_key { @@ -163,6 +179,8 @@ #define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */ #define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */ #define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */ +#define VIDIOCSYNC _IO('v',18) /* Sync with mmap grabbing */ +#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */ #define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */ @@ -172,6 +190,8 @@ #define VID_HARDWARE_QCAM_BW 2 #define VID_HARDWARE_PMS 3 #define VID_HARDWARE_QCAM_C 4 +#define VID_HARDWARE_PSEUDO 5 +#define VID_HARDWARE_SAA5249 6 /* * Initialiser list diff -u --recursive --new-file v2.1.93/linux/include/linux/videotext.h linux/include/linux/videotext.h --- v2.1.93/linux/include/linux/videotext.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/videotext.h Wed Apr 8 17:24:48 1998 @@ -0,0 +1,144 @@ +#ifndef _VTX_H +#define _VTX_H + +/* $Id: videotext.h,v 1.1 1998/03/30 22:26:39 alan Exp $ + * + * Copyright (c) 1994-97 Martin Buck + * Read COPYING for more information + * + */ + + +/* + * Videotext ioctls + */ +#define VTXIOCGETINFO 0x7101 /* get version of driver & capabilities of vtx-chipset */ +#define VTXIOCCLRPAGE 0x7102 /* clear page-buffer */ +#define VTXIOCCLRFOUND 0x7103 /* clear bits indicating that page was found */ +#define VTXIOCPAGEREQ 0x7104 /* search for page */ +#define VTXIOCGETSTAT 0x7105 /* get status of page-buffer */ +#define VTXIOCGETPAGE 0x7106 /* get contents of page-buffer */ +#define VTXIOCSTOPDAU 0x7107 /* stop data acquisition unit */ +#define VTXIOCPUTPAGE 0x7108 /* display page on TV-screen */ +#define VTXIOCSETDISP 0x7109 /* set TV-mode */ +#define VTXIOCPUTSTAT 0x710a /* set status of TV-output-buffer */ +#define VTXIOCCLRCACHE 0x710b /* clear cache on VTX-interface (if avail.) */ +#define VTXIOCSETVIRT 0x710c /* turn on virtual mode (this disables TV-display) */ + + +/* + * Definitions for VTXIOCGETINFO + */ + +#define SAA5243 0 +#define SAA5246 1 +#define SAA5249 2 +#define SAA5248 3 +#define XSTV5346 4 + +typedef struct { + int version_major, version_minor; /* version of driver; if version_major changes, driver */ + /* is not backward compatible!!! CHECK THIS!!! */ + int numpages; /* number of page-buffers of vtx-chipset */ + int cct_type; /* type of vtx-chipset (SAA5243, SAA5246, SAA5248 or + * SAA5249) */ +} +vtx_info_t; + + +/* + * Definitions for VTXIOC{CLRPAGE,CLRFOUND,PAGEREQ,GETSTAT,GETPAGE,STOPDAU,PUTPAGE,SETDISP} + */ + +#define MIN_UNIT (1<<0) +#define MIN_TEN (1<<1) +#define HR_UNIT (1<<2) +#define HR_TEN (1<<3) +#define PG_UNIT (1<<4) +#define PG_TEN (1<<5) +#define PG_HUND (1<<6) +#define PGMASK_MAX (1<<7) +#define PGMASK_PAGE (PG_HUND | PG_TEN | PG_UNIT) +#define PGMASK_HOUR (HR_TEN | HR_UNIT) +#define PGMASK_MINUTE (MIN_TEN | MIN_UNIT) + +typedef struct +{ + int page; /* number of requested page (hexadecimal) */ + int hour; /* requested hour (hexadecimal) */ + int minute; /* requested minute (hexadecimal) */ + int pagemask; /* mask defining which values of the above are set */ + int pgbuf; /* buffer where page will be stored */ + int start; /* start of requested part of page */ + int end; /* end of requested part of page */ + void *buffer; /* pointer to beginning of destination buffer */ +} +vtx_pagereq_t; + + +/* + * Definitions for VTXIOC{GETSTAT,PUTSTAT} + */ + +#define VTX_PAGESIZE (40 * 24) +#define VTX_VIRTUALSIZE (40 * 49) + +typedef struct +{ + int pagenum; /* number of page (hexadecimal) */ + int hour; /* hour (hexadecimal) */ + int minute; /* minute (hexadecimal) */ + int charset; /* national charset */ + unsigned delete : 1; /* delete page (C4) */ + unsigned headline : 1; /* insert headline (C5) */ + unsigned subtitle : 1; /* insert subtitle (C6) */ + unsigned supp_header : 1; /* suppress header (C7) */ + unsigned update : 1; /* update page (C8) */ + unsigned inter_seq : 1; /* interrupted sequence (C9) */ + unsigned dis_disp : 1; /* disable/suppress display (C10) */ + unsigned serial : 1; /* serial mode (C11) */ + unsigned notfound : 1; /* /FOUND */ + unsigned pblf : 1; /* PBLF */ + unsigned hamming : 1; /* hamming-error occured */ +} +vtx_pageinfo_t; + + +/* + * Definitions for VTXIOCSETDISP + */ + +typedef enum { + DISPOFF, DISPNORM, DISPTRANS, DISPINS, INTERLACE_OFFSET +} vtxdisp_t; + + + +/* + * Tuner ioctls + */ + +#define TUNIOCGETINFO 0x7201 /* get version of driver & capabilities of tuner */ +#define TUNIOCRESET 0x7202 /* reset tuner */ +#define TUNIOCSETFREQ 0x7203 /* set tuning frequency (unit: kHz) */ +#define TUNIOCGETFREQ 0x7204 /* get tuning frequency (unit: kHz) */ +#define TUNIOCSETCHAN 0x7205 /* set tuning channel */ +#define TUNIOCGETCHAN 0x7206 /* get tuning channel */ + + +typedef struct +{ + int version_major, version_minor; /* version of driver; if version_major changes, driver */ + /* is not backward compatible!!! CHECK THIS!!! */ + unsigned freq : 1; /* tuner can be set to given frequency */ + unsigned chan : 1; /* tuner stores several channels */ + unsigned scan : 1; /* tuner supports scanning */ + unsigned autoscan : 1; /* tuner supports scanning with automatic stop */ + unsigned afc : 1; /* tuner supports AFC */ + unsigned dummy1, dummy2, dummy3, dummy4, dummy5, dummy6, dummy7, dummy8, dummy9, dummy10, + dummy11 : 1; + int dummy12, dummy13, dummy14, dummy15, dummy16, dummy17, dummy18, dummy19; +} tuner_info_t; + + +#endif /* _VTX_H */ diff -u --recursive --new-file v2.1.93/linux/include/net/ip.h linux/include/net/ip.h --- v2.1.93/linux/include/net/ip.h Mon Apr 6 17:41:01 1998 +++ linux/include/net/ip.h Wed Apr 8 18:17:32 1998 @@ -142,15 +142,7 @@ skb->protocol = __constant_htons(ETH_P_IP); if (hh) { -#ifdef __alpha__ - /* Alpha has disguisting memcpy. Help it. */ - u64 *aligned_hdr = (u64*)(skb->data - 16); - u64 *aligned_hdr0 = hh->hh_data; - aligned_hdr[0] = aligned_hdr0[0]; - aligned_hdr[1] = aligned_hdr0[1]; -#else memcpy(skb->data - 16, hh->hh_data, 16); -#endif skb_push(skb, dev->hard_header_len); return hh->hh_output(skb); } else if (dst->neighbour) diff -u --recursive --new-file v2.1.93/linux/init/main.c linux/init/main.c --- v2.1.93/linux/init/main.c Mon Apr 6 17:41:01 1998 +++ linux/init/main.c Wed Apr 8 18:10:01 1998 @@ -70,7 +70,7 @@ extern long console_init(long, long); extern void sock_init(void); extern void uidcache_init(void); -extern long mca_init(long, long); +extern void mca_init(void); extern long sbus_init(long, long); extern long powermac_init(unsigned long, unsigned long); extern void sysctl_init(void); @@ -1012,6 +1012,12 @@ sched_init(); time_init(); parse_options(command_line); + + /* + * HACK ALERT! This is early. We're enabling the console before + * we've done PCI setups etc, and console_init() must be aware of + * this. But we do want output early, in case something goes wrong. + */ memory_start = console_init(memory_start,memory_end); #ifdef CONFIG_MODULES init_modules(); @@ -1027,14 +1033,6 @@ } #endif -/* - * HACK ALERT! This is early. We're enabling the console before - * we've done PCI setups etc, and console_init() must be aware of - * this. But we do want output early, in case something goes wrong. - */ -#if HACK - memory_start = console_init(memory_start,memory_end); -#endif memory_start = kmem_cache_init(memory_start, memory_end); sti(); calibrate_delay(); diff -u --recursive --new-file v2.1.93/linux/kernel/kmod.c linux/kernel/kmod.c --- v2.1.93/linux/kernel/kmod.c Thu Mar 26 15:57:06 1998 +++ linux/kernel/kmod.c Tue Apr 7 08:05:05 1998 @@ -15,8 +15,8 @@ int kmod_unload_delay = 60; char modprobe_path[256] = "/sbin/modprobe"; static char module_name[64] = ""; -static char * argv[] = { "modprobe", "-k", module_name, NULL, }; -static char * envp[] = { "HOME=/", "TERM=linux", NULL, }; +static char * argv[] = { modprobe_path, "-s", "-k", module_name, NULL }; +static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL }; /* kmod_queue synchronizes the kmod thread and the rest of the system @@ -27,10 +27,23 @@ static struct timer_list kmod_unload_timer; /* + It is not easy to implement a full fork in kernel-space on some + systems (Alpha), and it is not necessary for us here. This is + a new thread that does the exec. +*/ +static int kmod_exec_modprobe(void * data) +{ + sigemptyset(¤t->blocked); + execve(modprobe_path, argv, envp); + printk(KERN_ERR "kmod: failed to load module %s\n", module_name); + return 0; +} + +/* kmod_thread is the thread that does most of the work. kmod_unload and request_module tell it to wake up and do work. */ -int kmod_thread(void * data) +static int kmod_thread(void * data) { int pid; @@ -60,24 +73,13 @@ if (module_name[0] == '\0') { delete_module(NULL); } else { - pid = fork(); + pid = kernel_thread(kmod_exec_modprobe, NULL, SIGCHLD); if (pid > 0) { waitpid(pid, NULL, 0); module_name[0] = '\0'; wake_up(&kmod_queue); - } else - if (pid == 0) { - - /* - Call modprobe with module_name. If execve returns, - print out an error. - */ - execve(modprobe_path, argv, envp); - - printk("kmod: failed to load module %s\n", module_name); - _exit(0); } else { - printk("error, fork failed in kmod\n"); + printk(KERN_ERR "kmod: fork failed, errno %d\n", -pid); } } } @@ -104,7 +106,7 @@ int kmod_init(void) { - printk ("Starting kmod\n"); + printk("Starting kmod\n"); kernel_thread(kmod_thread, NULL, 0); diff -u --recursive --new-file v2.1.93/linux/mm/page_io.c linux/mm/page_io.c --- v2.1.93/linux/mm/page_io.c Tue Mar 10 10:03:36 1998 +++ linux/mm/page_io.c Mon Apr 6 17:48:34 1998 @@ -28,6 +28,8 @@ #include #include +static struct wait_queue * lock_queue = NULL; + /* * Reads or writes a swap page. * wait=1: start I/O and wait for completion. wait=0: start asynchronous I/O. @@ -87,6 +89,12 @@ return; } + /* Make sure we are the only process doing I/O with this swap page. */ + while (test_and_set_bit(offset,p->swap_lockmap)) { + run_task_queue(&tq_disk); + sleep_on(&lock_queue); + } + if (rw == READ) { clear_bit(PG_uptodate, &page->flags); kstat.pswpin++; @@ -115,6 +123,7 @@ if (!wait) { set_bit(PG_free_after, &page->flags); set_bit(PG_decr_after, &page->flags); + set_bit(PG_swap_unlock_after, &page->flags); atomic_inc(&nr_async_pages); } ll_rw_page(rw,p->swap_device,offset,buf); @@ -173,11 +182,36 @@ printk("rw_swap_page: no swap file or device\n"); atomic_dec(&page->count); + if (offset && !test_and_clear_bit(offset,p->swap_lockmap)) + printk("rw_swap_page: lock already cleared\n"); + wake_up(&lock_queue); #ifdef DEBUG_SWAP printk ("DebugVM: %s_swap_page finished on page %p (count %d)\n", (rw == READ) ? "read" : "write", buf, atomic_read(&page->count)); #endif +} + +/* This is run when asynchronous page I/O has completed. */ +void swap_after_unlock_page (unsigned long entry) +{ + unsigned long type, offset; + struct swap_info_struct * p; + + type = SWP_TYPE(entry); + if (type >= nr_swapfiles) { + printk("swap_after_unlock_page: bad swap-device\n"); + return; + } + p = &swap_info[type]; + offset = SWP_OFFSET(entry); + if (offset >= p->max) { + printk("swap_after_unlock_page: weirdness\n"); + return; + } + if (!test_and_clear_bit(offset,p->swap_lockmap)) + printk("swap_after_unlock_page: lock already cleared\n"); + wake_up(&lock_queue); } /* diff -u --recursive --new-file v2.1.93/linux/mm/simp.c linux/mm/simp.c --- v2.1.93/linux/mm/simp.c Thu Jan 15 20:44:18 1998 +++ linux/mm/simp.c Tue Apr 7 08:05:05 1998 @@ -70,7 +70,8 @@ /* next cache line */ struct header * usable_list; spinlock_t lock; - char fill[sizeof(void*) - sizeof(spinlock_t)]; + /* This value is negative on Alpha SMP. */ + /* char fill[sizeof(void*) - sizeof(spinlock_t)]; */ long real_size; long max_elems; structor again_ctor; diff -u --recursive --new-file v2.1.93/linux/mm/swapfile.c linux/mm/swapfile.c --- v2.1.93/linux/mm/swapfile.c Tue Mar 10 10:03:36 1998 +++ linux/mm/swapfile.c Mon Apr 6 17:48:34 1998 @@ -52,6 +52,8 @@ offset = si->cluster_next++; if (si->swap_map[offset]) continue; + if (test_bit(offset, si->swap_lockmap)) + continue; si->cluster_nr--; goto got_page; } @@ -60,6 +62,8 @@ for (offset = si->lowest_bit; offset <= si->highest_bit ; offset++) { if (si->swap_map[offset]) continue; + if (test_bit(offset, si->swap_lockmap)) + continue; si->lowest_bit = offset; got_page: si->swap_map[offset] = 1; @@ -424,6 +428,8 @@ p->swap_device = 0; vfree(p->swap_map); p->swap_map = NULL; + free_page((long) p->swap_lockmap); + p->swap_lockmap = NULL; p->flags = 0; err = 0; out: @@ -483,7 +489,6 @@ int error = -EPERM; struct file filp; static int least_priority = 0; - unsigned char *avail_map = 0; lock_kernel(); if (!suser()) @@ -501,6 +506,7 @@ p->swap_file = NULL; p->swap_device = 0; p->swap_map = NULL; + p->swap_lockmap = NULL; p->lowest_bit = 0; p->highest_bit = 0; p->cluster_nr = 0; @@ -543,24 +549,24 @@ } } else if (!S_ISREG(swap_dentry->d_inode->i_mode)) goto bad_swap; - avail_map = (unsigned char *) get_free_page(GFP_USER); - if (!avail_map) { + p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER); + if (!p->swap_lockmap) { printk("Unable to start swapping: out of memory :-)\n"); error = -ENOMEM; goto bad_swap; } - rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) avail_map); - if (memcmp("SWAP-SPACE",avail_map+PAGE_SIZE-10,10)) { + rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) p->swap_lockmap); + if (memcmp("SWAP-SPACE",p->swap_lockmap+PAGE_SIZE-10,10)) { printk("Unable to find swap-space signature\n"); error = -EINVAL; goto bad_swap; } - memset(avail_map+PAGE_SIZE-10,0,10); + memset(p->swap_lockmap+PAGE_SIZE-10,0,10); j = 0; p->lowest_bit = 0; p->highest_bit = 0; for (i = 1 ; i < 8*PAGE_SIZE ; i++) { - if (test_bit(i,avail_map)) { + if (test_bit(i,p->swap_lockmap)) { if (!p->lowest_bit) p->lowest_bit = i; p->highest_bit = i; @@ -579,12 +585,13 @@ goto bad_swap; } for (i = 1 ; i < p->max ; i++) { - if (test_bit(i,avail_map)) + if (test_bit(i,p->swap_lockmap)) p->swap_map[i] = 0; else p->swap_map[i] = 0x80; } p->swap_map[0] = 0x80; + memset(p->swap_lockmap,0,PAGE_SIZE); p->flags = SWP_WRITEOK; p->pages = j; nr_swap_pages += j; @@ -611,15 +618,15 @@ if(filp.f_op && filp.f_op->release) filp.f_op->release(filp.f_dentry->d_inode,&filp); bad_swap_2: + free_page((long) p->swap_lockmap); vfree(p->swap_map); dput(p->swap_file); p->swap_device = 0; p->swap_file = NULL; p->swap_map = NULL; + p->swap_lockmap = NULL; p->flags = 0; out: - if (avail_map) - free_page((long) avail_map); unlock_kernel(); return error; } diff -u --recursive --new-file v2.1.93/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.1.93/linux/net/ipv4/tcp_ipv4.c Mon Apr 6 17:41:01 1998 +++ linux/net/ipv4/tcp_ipv4.c Tue Apr 7 07:48:54 1998 @@ -1483,7 +1483,7 @@ skb->csum = csum_partial((char *)th, len, 0); case CHECKSUM_HW: if (tcp_v4_check(th,len,skb->nh.iph->saddr,skb->nh.iph->daddr,skb->csum)) { - printk(KERN_DEBUG "TCPv4 bad checksum from %d.%d.%d.%d:%04x to %d.%d.%d.%d:%04x, " + printk(KERN_DEBUG "TCPv4 bad checksum from %ld.%ld.%ld.%ld:%04x to %ld.%ld.%ld.%ld:%04x, " "len=%d/%d/%d\n", NIPQUAD(ntohl(skb->nh.iph->saddr)), ntohs(th->source),