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
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
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
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
D: Written kmalloc/kfree
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
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
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
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 <tom@lpsg.demon.co.uk>.
-
-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
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
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
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).
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,
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
Say Y have if you the black and white version of the QuickCam
+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.
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):
--- /dev/null
+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
--- /dev/null
+From: Nicola Bernardelli <nbern@mail.protos.it>
+
+ 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/<sounduser>/.aumixrc) to
+# restore mixer device levels and a call to 'sfxload <path to
+# soundfont bank>' 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
+ -----
+
--- /dev/null
+From: Shaw Carruthers <shaw@shawc.demon.co.uk>
+
+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
--- /dev/null
+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 <stdio.h>
+#include <fcntl.h>
+#include <linux/soundcard.h>
+
+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;
+}
+
--- /dev/null
+ 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)
+_/ _/_/_/_/
+ _/
+_/ _/
+ _/_/
+===========================================================
+
+
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
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
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)
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
SOUND
P: Alan Cox
-M: Alan Cox@linux.org
+M: Alan.Cox@linux.org
S: Maintained
SPARC:
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
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 93
+SUBLEVEL = 94
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
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
#include <linux/string.h>
#include <linux/version.h>
#include <linux/mm.h>
-#include <linux/config.h>
#include <asm/system.h>
#include <asm/console.h>
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'
#define __KERNEL_SYSCALLS__
#include <asm/unistd.h>
-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 *);
* 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);
EXPORT_SYMBOL_NOVERS(__remqu);
EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memset);
-
-#if CONFIG_PCI
-EXPORT_SYMBOL(pci_devices);
-#endif
}
-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;
}
/*
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)
tga_console_init();
#endif
#endif
-
- return mem_start;
}
*/
#define __ASSEMBLY__
-#include <linux/config.h>
#include <asm/system.h>
#define halt call_pal PAL_halt
}
}
-unsigned long mcpcia_fixup(unsigned long memory_start,
- unsigned long memory_end)
+void mcpcia_fixup(void)
{
struct linux_hose_info *hose;
for (hose = mcpcia_root; hose; hose = hose->next) {
mcpcia_probe(hose, &memory_start);
}
-
- return memory_start;
}
#endif /* CONFIG_ALPHA_MCPCIA */
"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
** 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
** 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
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
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);
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");
# 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
CONFIG_ETHER1=m
CONFIG_ETHER3=m
CONFIG_ETHERH=m
+CONFIG_CDROM=y
#
# Filesystems
#include <asm/dma.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
+#include <asm/irq.h>
extern void dump_thread(struct pt_regs *, struct user *);
extern int dump_fpu(struct pt_regs *, struct user_fp_struct *);
/* processor dependencies */
EXPORT_SYMBOL(processor);
+/* irq */
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
+
/* io */
EXPORT_SYMBOL(outswb);
EXPORT_SYMBOL(outsw);
*/
#ifndef NR_SYSCALLS
#define NR_syscalls 256
-#define NR_SYSCALLS 182
+#define NR_SYSCALLS 184
#else
/* 0 */ .long SYMBOL_NAME(sys_setup)
.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
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);
}
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;
#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,
#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,
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;
+++ /dev/null
-__kernel_offset__ = (0x1000-1024)*1024*1024;
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
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:
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
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,
.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.
*
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)
/*--------------------------------------------------------------------*/
#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 *);
/*--------------------------------------------------------------------*/
-__initfunc(long mca_init(long memory_start, long memory_end))
+__initfunc(void mca_init(void))
{
unsigned int i, j;
int foundscsi = 0;
*/
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
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;
}
/*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------*/
-__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,
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;
proc_register( &proc_mca, node );
}
- return memory_start;
} /* mca_do_proc_init() */
/*--------------------------------------------------------------------*/
/* 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);
}
local_flush_tlb();
- printk("IO APIC ID: %d\n", *(int *)0xFEC00000);
- printk("APIC ID: %d\n", *(int *)0xFEE00000);
}
#endif
local_flush_tlb();
/* ld script to make i386 Linux kernel
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*/
-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)
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/zorro.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/ptrace.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/ptrace.h>
#include <asm/traps.h>
bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT
fi
-bool 'ADFS partition support' CONFIG_BLK_DEV_PART
-
endmenu
* card slots if someone tries this)!
*
* 17/1/97:RMK: Upgraded to 2.1 kernels.
+ *
+ * 4/3/98:RMK: Changed major number to 21.
*/
/*
#include <linux/major.h>
#include <linux/ioport.h>
+#define MAJOR_NR MFM_ACORN_MAJOR
+#include <linux/blk.h>
+
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq-no.h>
#include <asm/hardware.h>
#include <asm/ecard.h>
-#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
*/
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 */
static unsigned int mfm_irqenable; /* Podule IRQ enable location */
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/string.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
#include <linux/errno.h>
-
+#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
#include <asm/ecard.h>
#define __ETHER1_C
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
#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;
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;
* 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;
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;
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;
}
}
}
-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;
}
}
}
-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;
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",
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);
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;
i = ether1_ramtest (dev, 0x1e);
if (i <= 0)
- return -ENODEV;
+ return -ENODEV;
dev->mem_end = i;
return 0;
*/
/* 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
/* 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,
};
#define RBD_SIZE (0x0a)
-static rbd_t init_rbd = {
+static rbd_t init_rbd = {
0,
0,
0,
#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;
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;
* 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;
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;
/* 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;
}
/* 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),
}
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),
}
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
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;
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;
}
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;
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;
}
/* ------------------------------------------------------------------------- */
-static void ether1_addr (struct device *dev)
+__initfunc(static void
+ether1_addr (struct device *dev))
{
int i;
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;
dev->irq = ec->irq;
ecard_claim (ec);
+
#endif
ether1_addr (dev);
/* ------------------------------------------------------------------------- */
-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)
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;
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
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.
* 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;
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;
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)
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;
}
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;
}
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;
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);
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 ++;
}
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);
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.
* 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)
{
}
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], " ");
i = 0;
- ecard_startfind();
+ ecard_startfind ();
- do
- {
+ do {
if ((ec[i] = ecard_find(0, ether1_cids)) == NULL)
break;
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;
}
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);
#endif
my_ethers[i] = NULL;
}
- if (ec[i])
- {
+ if (ec[i]) {
ecard_release (ec[i]);
ec[i] = NULL;
}
* 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";
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/bitops.h>
#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
* 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};
/* --------------------------------------------------------------------------- */
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;
}
* 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)
* 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;
}
} else {
if (bad != -1) {
- if (bad != i - 1)
+ if (bad != i - 1)
printk(" - 0x%04X", i - 1);
printk("\n");
bad = -1;
/* ------------------------------------------------------------------------------- */
-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
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);
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);
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);
/*
* 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));
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);
#endif
return 0;
}
- failed:
+
+failed:
kfree(dev->priv);
dev->priv = NULL;
release_region(dev->base_addr, 128);
}
#ifndef MODULE
-int ether3_probe(struct device *dev)
+__initfunc(int
+ether3_probe(struct device *dev))
{
struct expansion_card *ec;
* 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);
#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
/*
* 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);
}
/*
- * 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;
}
*/
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;
/*
* 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;
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);
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)) {
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);
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);
* 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
dev->interrupt = 0;
#if NET_DEBUG > 1
- if (net_debug & DEBUG_INT)
+ if(net_debug & DEBUG_INT)
printk("done\n");
#endif
}
/*
* 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);
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;
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;
/*
* 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
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 ++;
}
/*
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], " ");
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];
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;
}
}
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 */
#include <asm/io.h>
#include <asm/irq.h>
-#include "8390.h"
+#include "../../net/8390.h"
#define NET_DEBUG 0
#define DEBUG_INIT 2
*/
/*
- * $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 <linux/module.h>
*/
/*
- * $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
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))
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))
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))
*/
/*
- * $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 <linux/module.h>
*/
/*
- * $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
#define FAS216_C
-#include "scsi.h"
-#include "hosts.h"
+#include "../../scsi/scsi.h"
+#include "../../scsi/hosts.h"
#include "fas216.h"
#define VER_MAJOR 0
if (value < 4)
value = 4;
- else if value > 35)
+ else if (value > 35)
value = 35;
return value & 31;
*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.
#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;
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));
}
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);
}
- outb(CNTL3_IDENABLE, REG_CNTL3(info));
+ outb(CNTL3_ADIDCHK, REG_CNTL3(info));
outb(0, REG_CNTL3(info));
outb(CMD_RESETCHIP, REG_CMD(info));
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)
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 {
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 */
/*
* $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 <linux/module.h>
*/
/*
- * $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
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
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",
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
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
L_OBJS += pms.o
else
ifeq ($(CONFIG_VIDEO_PMS),m)
- M_OBJS += pms.o
+ M_OBJS += pms.o
endif
endif
/*
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
#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 */
/*
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
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 <linux/module.h>
#include <linux/bios32.h>
+#include <linux/config.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <asm/segment.h>
#include <linux/types.h>
-#include <linux/videodev.h>
+#include <linux/wrapper.h>
+#include <linux/videodev.h>
#include <linux/version.h>
#include <asm/uaccess.h>
+#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; /* remap Bt848 */
+static unsigned int vidmem=0; /* manually set video mem address */
+static int triton1=0;
+static int radio=0;
-static unsigned int remap=0;
-static unsigned int vidmem=0;
-static unsigned int tuner=0; /* Default tuner */
-MODULE_PARM(tuner,"i");
+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);
/* 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 */
/*******************************/
/* 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!)
*/
{
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;
}
/* 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);
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;
}
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");
}
}
-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;
}
}
+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] =
-{
- { 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??? */
+static unsigned char audiomuxs[][5] =
+{
+ { 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;
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);
}
#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));
*(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);
*(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<width)
+ {
+ flags|=BT848_RISC_BYTE_ALL;
+ command=BT848_RISC_WRITE;
+ }
+ }
+ else
+ if (command==BT848_RISC_WRITEC)
+ command=BT848_RISC_WRITE;
+ flags|=BT848_RISC_SOL;
+ }
+ if (*x+dx==width)
+ flags|=BT848_RISC_EOL;
+ *((*rp)++)=command|flags|len;
+ if (command==BT848_RISC_WRITE)
+ *((*rp)++)=line_adr+*x*bpp;
+ *x+=dx;
}
/*
* www.brooktree.com - nicely done those folks.
*/
-static void bt848_set_size(struct bttv *btv)
+struct tvnorm
+{
+ u16 cropwidth, cropheight;
+ u16 totalwidth;
+ u8 adelay, bdelay, iform;
+ u32 scaledtwidth;
+ u16 hdelayx1, hactivex1;
+ u16 vdelay;
+};
+
+static struct tvnorm tvnorms[] = {
+ /* PAL-BDGHI */
+ { 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+ 944, 186, 922, 0x20},
+ /* NTSC */
+ { 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
+ 780, 135, 754, 0x16},
+ /* SECAM */
+ { 768, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
+ 944, 186, 922, 0x20},
+ /* PAL-M */
+ { 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
+ 780, 186, 922, 0x16},
+ /* PAL-N */
+ { 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
+ 944, 186, 922, 0x20},
+};
+#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
+
+
+/* set geometry for even/odd frames
+ just if you are wondering:
+ handling of even and odd frames will be separated, e.g. for grabbing
+ the even ones as RGB into videomem and the others as YUV in main memory for
+ compressing and sending to the video conferencing partner.
+
+*/
+static inline void bt848_set_eogeo(struct bttv *btv, int odd, u8 vtc,
+ u16 hscale, u16 vscale,
+ u16 hactive, u16 vactive,
+ u16 hdelay, u16 vdelay,
+ u8 crop)
+{
+ int off = odd ? 0x80 : 0x00;
+
+ btwrite(vtc, BT848_E_VTC+off);
+ btwrite(hscale>>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;
+ u8 crop, vtc;
+ struct tvnorm *tvn;
+
+ if (!width || !height)
+ return;
- /*
- * No window , no try...
- */
-
- if (!btv->win.width)
- return;
- if (!btv->win.height)
- return;
-
+ tvn=&tvnorms[btv->win.norm];
+
+ 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;
- 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;
- }
-
- /*
- * 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);
- }
+ 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
+int bpp2fmt[4] = {
+ BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16,
+ BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32
+};
- /*
- * 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
+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)
{
todo-=q;
buf+=q;
-/* btv->vbip=0; */
cli();
if (todo && q==VBIBUF_SIZE-btv->vbip)
{
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;
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 */
/***********************************/
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;
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;
btaor(datahi, ~1, BT848_O_CONTROL);
}
+
/*
* Cliprect -> risc table.
*
}
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
* 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))
{
/* 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;
}
}
/*
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;
/* 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:
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;
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! */
*/
write_risc_data(btv,vcp, vw.clipcount);
vfree(vcp);
- if(on)
+ if(on && btv->win.vidadr!=0)
bt848_cap(btv,1);
return 0;
}
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;
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;
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:
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;
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;
}
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",
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,
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;
};
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;
return found;
}
+
+
#define TRITON_PCON 0x50
#define TRITON_BUS_CONCURRENCY (1<<0)
#define TRITON_STREAMING (1<<1)
{
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, "));
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);
}
-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 */
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);
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);
* 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;
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)
{
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)
{
}
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);
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
*/
}
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];
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,
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);
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++;
return bttv_num;
}
+
static void release_bttv(void)
{
u8 command;
for (i=0;i<bttv_num; i++)
{
btv=&bttvs[i];
+
/* turn off all capturing, DMA and IRQs */
+ btand(~15, BT848_GPIO_DMA_CTL);
+
/* first disable interrupts before unmapping the memory! */
btwrite(0, BT848_INT_MASK);
btwrite(0xffffffffUL,BT848_INT_STAT);
btwrite(0x0, BT848_GPIO_OUT_EN);
- bt848_cap(btv, 0);
-
+ /* unregister i2c_bus */
+ i2c_unregister_bus((&btv->i2c));
+
/* 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);
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)
if (find_bt848()<0)
return -EIO;
+ /* initialize Bt848s */
for (i=0; i<bttv_num; i++)
{
- if (init_bt848(&bttvs[i])<0)
+ if (init_bt848(i)<0)
{
release_bttv();
return -EIO;
}
- }
+ }
return 0;
}
+
+
#ifdef MODULE
void cleanup_module(void)
{
- release_bttv();
+ release_bttv();
}
#endif
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
#include <linux/types.h>
#include <linux/wait.h>
+#include "i2c.h"
+#include "msp3400.h"
#include "bt848.h"
+#include <linux/videodev.h>
-typedef unsigned int dword;
+#define MAX_CLIPRECS 100
+#define RISCMEM_LEN (32744*2)
+#define MAX_FBUF 0x144000
-struct riscprog {
- uint length;
- dword *busadr;
- dword *prog;
+struct riscprog
+{
+ unsigned int length;
+ u32 *busadr;
+ u32 *prog;
};
-/* 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;
+
+/* clipping rectangle */
+struct cliprec
+{
+ int x, y, x2, y2;
+ struct cliprec *next;
+};
+
+
+/* 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;
+};
+
+
+#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;
};
-/* 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;
+
+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))
#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
#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
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);
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);
int want_console = -1;
int kmsg_redirect = 0;
-#define CONFIG_SERIAL_ECHO
#ifdef CONFIG_SERIAL_ECHO
#include <linux/serial_reg.h>
printf("/*\n * This file is automatically generated by %s, DO NOT EDIT!\n*/\n\n",
argv[0]);
gensintbl();
- return(0);
+ exit(0);
}
/* --------------------------------------------------------------------- */
--- /dev/null
+/*
+ * Generic i2c interface for linux
+ *
+ * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/locks.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+
+#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<<i)) ? i2c_one(bus) : i2c_zero(bus);
+ if (wait_for_ack)
+ udelay(wait_for_ack);
+ ack=i2c_ack(bus);
+ I2C_DEBUG(printk("%02x%c ",(int)data,ack?'-':'+'));
+ return ack;
+}
+
+unsigned char i2c_readbyte(struct i2c_bus *bus,int last)
+{
+ int i;
+ unsigned char data=0;
+
+ I2C_SET(bus,0,1);
+ for (i=7; i>=0; i--)
+ {
+ I2C_SET(bus,1,1);
+ if (I2C_GET(bus))
+ data |= (1<<i);
+ I2C_SET(bus,0,1);
+ }
+ last ? i2c_one(bus) : i2c_zero(bus);
+ I2C_DEBUG(printk("=%02x%c ",(int)data,last?'-':'+'));
+ return data;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int i2c_read(struct i2c_bus *bus, unsigned char addr)
+{
+ int ret;
+
+ if (bus->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
--- /dev/null
+#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 */
/*
- * $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
*/
/*
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/mm.h>
-#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/malloc.h>
#include <linux/poll.h>
#include <linux/major.h>
#include <linux/joystick.h>
-
#include <asm/io.h>
-#include <asm/ptrace.h>
-#include <asm/uaccess.h>
-#include <asm/param.h>
#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 */
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 */
* 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;
}
/*
}
}
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.
*/
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;
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;
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++;
}
}
}
/*
- * 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();
}
* 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++)
t++;
}
+/*
+ * Initial axis state.
+ */
+
t = 0;
for (j = 4; j < 8 && (i < blocks) && !retval; j++)
if (jsd[minor].exist & (1 << j)) {
}
}
+/*
+ * 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)))
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);
}
sizeof(struct js_corr))) return -EFAULT;
j++;
}
- js_axis_time = 0;
+ js_bh_time = 0;
break;
case JSIOCGCORR:
j = 0;
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);
}
}
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;
* carsten@sol.wohnheim.uni-ulm.de
* Support for parport by Philip Blundell <Philip.Blundell@pobox.com>
* parport_sharing hacking by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ * Fixed kernel_(to/from)_user memory copy to check for errors
+ * by Riccardo Facchetti <fizban@tin.it>
*/
/* This driver should, in theory, work with any parallel port that has an
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)) {
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;
}
unsigned int cmd, unsigned long arg)
{
unsigned int minor = MINOR(inode->i_rdev);
+ int status;
int retval = 0;
#ifdef LP_DEBUG
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;
--- /dev/null
+/*
+ * programming the msp34* sound processor family
+ *
+ * (c) 1997,1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * 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 <pp@netppl.fi>
+ *
+ *
+ * TODO:
+ * - better SAT support
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+/* #include <asm/smp_lock.h> */
+
+/* kernel_thread */
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
+#include "i2c.h"
+#include <linux/videodev.h>
+
+#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; 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);
+ }
+ }
+ 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
+
--- /dev/null
+#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 */
*/
#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");
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)
{
shutdown_mediavision();
* -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
*/
-#include <linux/config.h>
#include <linux/module.h> /* For EXPORT_SYMBOL */
#include <linux/errno.h>
--- /dev/null
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+
+#include "i2c.h"
+#include <linux/videodev.h>
+
+#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:
+ */
#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
#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
#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
{"bw-qcam", init_bw_qcams},
#endif
#ifdef CONFIG_VIDEO_PMS
- {"PMS", init_pms_cards}, /* not defined anywhere */
+ {"PMS", init_pms_cards},
#endif
{"end", NULL}
};
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..
/*
* 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<base+VIDEO_NUM_DEVICES;i++)
+ for(i=base;i<end;i++)
{
if(video_device[i]==NULL)
{
NULL, /* readdir */
NULL, /* poll */
video_ioctl,
- NULL, /* mmap */
+ video_mmap,
video_open,
video_release
};
*
*/
-
+#include <linux/config.h>
#define __NO_VERSION__
#include "hisax.h"
#include "isac.h"
*
*/
+#include <linux/config.h>
#include "isdnloop.h"
static char
#ifdef __KERNEL__
/* Kernel includes */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/errno.h>
* Tim Waugh <tim@cyberelk.demon.co.uk>
* Philip Blundell <philb@gnu.org>
* Andrea Arcangeli <arcangeli@mbox.queen.it>
+ * Riccardo Facchetti <fizban@tin.it>
*
* based on work by Grant Guenther <grant@torque.net>
* and Philip Blundell
#include <linux/stddef.h>
#include <linux/tasks.h>
+#include <linux/ctype.h>
#include <asm/ptrace.h>
#include <asm/io.h>
#include <asm/dma.h>
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;
-
- 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);
- }
- }
+ struct pardevice *cad = pp->cad;
+ int oldirq = pp->irq;
+
+/*
+ * 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,
*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)
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) {
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;
}
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
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
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 *);
#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. */
static const char *version = "de4x5.c:V0.536 1998/3/5 davies@maniac.ultranet.com\n";
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
--- /dev/null
+/* 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 <linux/config.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+/* Kernel compatibility defines, common to David Hind's PCMCIA package.
+ This is only in the support-all-kernels source code. */
+#include <linux/version.h> /* 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 <linux/delay.h>
+#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 <becker@cesdis.gsfc.nasa.gov>");
+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
+
+\f
+
+#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;
+}
+\f
+/* 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);
+}
+
+\f
+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;
+}
+\f
+#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 */
+\f
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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 <ajk@iehk.rwth-aachen.de>
+ *
+ * Quite a lot of stuff "stolen" by Jörg Reuter from slip.c, written by
+ *
+ * Laurence Culhane, <loz@holmes.demon.co.uk>
+ * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/timer.h>
+#include <net/ax25.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_arp.h>
+#include <linux/if_slip.h>
+#include <linux/init.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+/*
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+*/
+
+#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, count<sizeof(buf)? count:sizeof(buf));
+ restore_flags(flags);
+
+ /* Read the characters out of the buffer */
+
+ count1 = count;
+ while(count)
+ {
+ count--;
+ if (fp && *fp++)
+ {
+ if (!test_and_set_bit(SIXPF_ERROR, &sp->flags)) {
+ 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; i<sp->rx_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;
+ }
+}
--- /dev/null
+/*
+ * 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 <ajk@iehk.rwth-aachen.de>
+ *
+ * This file is derived from slip.h, written by
+ * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ */
+
+#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 */
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
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
gentbl_costab(f, 6);
gentbl_afsk2400(f, 7372800);
fclose(f);
- return(0);
+ exit(0);
}
* Jan 02, 1997 Gene Kozin Initial version.
*****************************************************************************/
-#include <linux/config.h> /* OS configuration options */
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
* Jan 06, 1997 Gene Kozin Initial version.
*****************************************************************************/
-#include <linux/config.h> /* OS configuration options */
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
#error This code MUST be compiled as a kernel module!
#endif
-#include <linux/config.h> /* OS configuration options */
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
#include <linux/blk.h>
#include <linux/sched.h>
#include <linux/version.h>
-#include <linux/config.h>
#include <linux/zorro.h>
#include <asm/page.h>
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
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
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
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
fi
fi
+if [ "$CONFIG_ARM" = "y" ]; then
+ bool 'VIDC 16-bit sound' CONFIG_VIDC_SOUND
+fi
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
endif
endif
+ifdef CONFIG_VIDC_SOUND
+ifneq ($(CONFIG_AUDIO),Y)
+CONFIG_AUDIO=y
+endif
+endif
+
ifdef CONFIG_PAS
ifneq ($(CONFIG_MIDI),Y)
CONFIG_MIDI=y
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
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
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
#
+++ /dev/null
-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.
*
* 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
int irq_ok;
mixer_ents *mix_devices;
int mixer_output_port;
- int c930_password_port;
} ad1848_info;
typedef struct ad1848_port_info
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)
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;
/*
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;
{
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];
{
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);
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)
}
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)
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)
{
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)
{
if(loaded)
unload_ms_sound(&hw_config);
}
-
-#else
-
-void export_ad1848_syms(void)
-{
-}
-
#endif
#endif
/*
* sound/ad1848_mixer.h
- *
+ *
* Definitions for the mixer of AD1848 and compatible codecs.
*/
*/
#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),
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)
};
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)
};
* 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)
};
* 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 <linux/config.h>
-#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/module.h>
#include "sound_config.h"
#include "soundmodule.h"
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;
}
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;
#include <linux/config.h>
#include <linux/stddef.h>
+#include <linux/kmod.h>
#include "sound_config.h"
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;
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;
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... */
MODULE_PARM(dma,"i");
MODULE_PARM(dma2,"i");
+EXPORT_NO_SYMBOLS;
+
struct address_info cfg;
/*
#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);
}
}
+ for (i=0;i<num_audiodevs;i++)
+ DMAbuf_deinit(i);
+
if (trace_init)
printk(KERN_DEBUG "Sound unload complete\n");
}
return -(EBUSY);
}
d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_driver)));
- sound_mem_sizes[sound_nblocks] = sizeof(struct audio_driver);
if (sound_nblocks < 1024)
sound_nblocks++;
op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_operations)));
- sound_mem_sizes[sound_nblocks] = sizeof(struct audio_operations);
if (sound_nblocks < 1024)
sound_nblocks++;
until you unload sound! */
op = (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++;
*/
#define SNDCARD_DESKPROXL 27 /* Compaq Deskpro XL */
+#define SNDCARD_VIDC 28 /* ARMs VIDC */
#define SNDCARD_SBPNP 29
#define SNDCARD_OPL3SA1 38
#define SNDCARD_OPL3SA1_SB 39
#if defined(CONFIG_VMIDI) && defined(CONFIG_MIDI) && !defined(CONFIG_VMIDI_MODULE)
{"VMIDI", 0, SNDCARD_VMIDI,"Loopback MIDI Device", attach_v_midi, probe_v_midi, unload_v_midi},
+#endif
+#ifdef CONFIG_VIDC_SOUND
+ {"VIDC", 0, SNDCARD_VIDC, "ARM VIDC 16-bit D/A", attach_vidc, probe_vidc, unload_vidc },
#endif
{NULL, 0, 0, "*?*", NULL, NULL, NULL}
};
{SNDCARD_VMIDI, {0, 0, 0, -1}, SND_DEFAULT_ENABLE},
#endif
+#ifdef CONFIG_VIDC_SOUND
+ { SNDCARD_VIDC, {0, 0, 0, 0}, SND_DEFAULT_ENABLE },
+#endif
{0, {0}, 0}
};
dmap->raw_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;
}
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;
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;
}
dmap->dma_mode = DMODE_NONE;
dmap->flags &= ~DMA_BUSY;
disable_dma(dmap->dma);
- sound_free_dmap(dmap);
}
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
/*
- 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.
+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.
+/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.
+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
+History:
+1995/8/25 first release
- 1995/9/02 ++roman: fixed atari_stram_alloc() call, the timer programming
- and several race conditions
+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/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/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/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/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
+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/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/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/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 <linux/module.h>
#ifdef CONFIG_ATARI
#include <asm/atarihw.h>
#include <asm/atariints.h>
-#endif /* CONFIG_ATARI */
+#include <asm/atari_stram.h>
+#endif /* CONFIG_ATARI */
#ifdef CONFIG_AMIGA
#include <asm/amigahw.h>
#include <asm/amigaints.h>
-#endif /* CONFIG_AMIGA */
+#endif /* CONFIG_AMIGA */
#include "dmasound.h"
#include <linux/soundcard.h>
#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 *******************************************************/
#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)))
/* 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
};
/* 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,
+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_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_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;
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)
+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);
+ if (value < 0)
+ return(value);
- return put_user(value, addr);
+ 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 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
*/
#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)
-{
- long count, used;
- void *p = &frame[*frameUsed];
-
- count = min(userCount, frameLeft);
- if (sound.soft.stereo)
- count &= ~1;
- used = count;
- copy_from_user(p, userPtr, count);
- *frameUsed += used;
- return (used);
-}
-
-
-static long
-ata_ct_u8(const u_char * userPtr, unsigned long userCount,
- u_char frame[], long *frameUsed, long frameLeft)
-{
- long count, used;
-
- if (!sound.soft.stereo)
- {
- u_char *p = &frame[*frameUsed];
-
- count = min(userCount, frameLeft);
- used = count;
- while (count > 0)
- {
- u_char data;
-
- get_user(data, userPtr++);
- *p++ = data ^ 0x80;
- count--;
- }
- } else
- {
- u_short *p = (u_short *) & frame[*frameUsed];
-
- count = min(userCount, frameLeft) >> 1;
- used = count * 2;
- while (count > 0)
- {
- u_short data;
-
- get_user(data, ((u_short *) userPtr)++);
- *p++ = data ^ 0x8080;
- count--;
- }
- }
- *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)
-{
- 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)
-{
- 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)
-{
- 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)
-{
- 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)
+static long ata_ct_law(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];
+ char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+ long count, used;
+ u_char *p = &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);
+ 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_ctx_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)
{
- /* 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;
+ long count, used;
+ void *p = &frame[*frameUsed];
- 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);
+ 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_ctx_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)
{
- /* 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];
+ long count, used;
- 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);
+ 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);
}
-static long
-ata_ctx_s16le(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)
{
- /* 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];
+ long count, used;
+ u_long data;
- 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);
+ 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_ctx_u16le(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)
{
- /* 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];
+ long count, used;
+ u_long data;
- 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);
+ 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);
}
-#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 ata_ct_s16le(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;
+ long count, used;
+ u_long 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--;
- }
- }
+ 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);
+ }
+ return(used);
}
-static long
-ami_ct_s8(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;
+ long count, used;
+ u_long data;
- 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--;
- }
- }
+ 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);
+ }
+ return(used);
+}
+
+
+static long ata_ctx_law(const u_char *userPtr, unsigned long userCount,
+ u_char frame[], long *frameUsed, long frameLeft)
+{
+ char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+ /* this should help gcc to stuff everything into registers */
+ u_long data = sound.data;
+ long bal = sound.bal;
+ long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
+ long used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!sound.soft.stereo) {
+ u_char *p = &frame[*frameUsed];
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (!userCount)
+ break;
+ get_user(c, userPtr++);
+ data = table[c];
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ } else {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ while (frameLeft >= 2) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ get_user(c, userPtr++);
+ data = table[c] << 8;
+ get_user(c, userPtr++);
+ data |= table[c];
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 2;
+ bal -= sSpeed;
+ }
+ }
+ sound.bal = bal;
+ sound.data = data;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return(used);
+}
+
+
+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_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_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);
}
+#endif /* CONFIG_ATARI */
-static long
-ami_ct_u8(const u_char * userPtr, unsigned long userCount,
- u_char frame[], long *frameUsed, long frameLeft)
+#ifdef CONFIG_AMIGA
+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)
- {
- 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;
+ char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
+ long count, used;
- 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) {
+ 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_s16be(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;
- u_long data;
+ long count, 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)++);
- *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) {
+ 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_u16be(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;
+ long count, 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 ^= 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);
+ 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_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_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_s16le(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)
{
- 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;
+ u_long data;
- 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);
+ *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_u16le(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)
{
- 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;
+ u_long data;
- 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);
+ 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 *********************************************************/
* Atari (TT/Falcon)
*/
-static void *
-AtaAlloc(unsigned int size, int flags)
-{
- int order;
- unsigned int a_size;
-
- order = 0;
- a_size = PAGE_SIZE;
- while (a_size < size)
- {
- order++;
- a_size <<= 1;
- }
- return (void *) __get_dma_pages(flags, order);
-}
-
-static void
-AtaFree(void *obj, unsigned int size)
-{
- int order;
- unsigned int a_size;
-
- order = 0;
- a_size = PAGE_SIZE;
- while (a_size < size)
- {
- order++;
- a_size <<= 1;
- }
- free_pages((unsigned long) obj, order);
-}
-
-static int
-AtaIrqInit(void)
-{
- /* Set up timer A. Timer A
- will receive a signal upon end of playing from the sound
- hardware. Furthermore Timer A is able to count events
- and will cause an interrupt after a programmed number
- of events. So all we need to keep the music playing is
- to provide the sound hardware with new data upon
- an interrupt from timer A. */
- mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */
- mfp.tim_dt_a = 1; /* Cause interrupt after first event. */
- mfp.tim_ct_a = 8; /* Turn on event counting. */
- /* Register interrupt handler. */
- 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 void *AtaAlloc(unsigned int size, int flags)
+{
+ return( atari_stram_alloc( size, NULL, "dmasound" ));
+}
+
+static void AtaFree(void *obj, unsigned int size)
+{
+ atari_stram_free( obj );
+}
+
+static int AtaIrqInit(void)
+{
+ /* Set up timer A. Timer A
+ will receive a signal upon end of playing from the sound
+ hardware. Furthermore Timer A is able to count events
+ and will cause an interrupt after a programmed number
+ of events. So all we need to keep the music playing is
+ to provide the sound hardware with new data upon
+ an interrupt from timer A. */
+ mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */
+ mfp.tim_dt_a = 1; /* Cause interrupt after first event. */
+ mfp.tim_ct_a = 8; /* Turn on event counting. */
+ /* Register interrupt handler. */
+ request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW,
+ "DMA sound", ata_sq_interrupt);
+ mfp.int_en_a |= 0x20; /* Turn interrupt on. */
+ mfp.int_mk_a |= 0x20;
+ return(1);
}
#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) \
#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));
}
*/
-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 */
+ int mode, i, idx;
+ const int freq[4] = {50066, 25033, 12517, 6258};
- 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;
- }
+ /* search a frequency that fits into the allowed error range */
- tt_dmasnd.mode = (sound.hard.stereo ?
- DMASND_MODE_STEREO : DMASND_MODE_MONO) |
- DMASND_MODE_8BIT | mode;
+ 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();
- sound.bal = -sound.soft.speed;
+ return(format);
}
-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;
- }
+#define VOLUME_VOXWARE_TO_DB(v) \
+ (((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40)
+#define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2)
- 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);
+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 VOLUME_VOXWARE_TO_DB(v) \
- (((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40)
-#define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2)
-
+#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
-TTSetVolume(int volume)
+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);
}
*/
-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)
+static void FalconInit(void)
{
- int divider, i, idx;
- const int freq[8] =
- {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
+ int divider, i, idx;
+ const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
- /* search a frequency that fits into the allowed error range */
+ /* search a frequency that fits into the allowed error range */
- idx = -1;
- for (i = 0; i < arraysize(freq); i++)
- /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
- * be playable without expanding, but that now a kernel runtime
- * option
- */
- if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
- idx = i;
- if (idx > -1)
- {
- sound.soft.speed = freq[idx];
- sound.trans = &transFalconNormal;
- } else
- sound.trans = &transFalconExpanding;
-
- FalconSilence();
- sound.hard = sound.soft;
-
- if (sound.hard.size == 16)
- {
- /* the Falcon can play 16bit samples only in stereo */
- sound.hard.stereo = 1;
- }
- if (sound.hard.speed > 49170)
- {
- /* we would need to squeeze the sound, but we won't do that */
- sound.hard.speed = 49170;
- divider = 1;
- sound.trans = &transFalconNormal;
- } else if (sound.hard.speed > 32780)
- {
- sound.hard.speed = 49170;
- divider = 1;
- } else if (sound.hard.speed > 24585)
- {
- sound.hard.speed = 32780;
- divider = 2;
- } else if (sound.hard.speed > 19668)
- {
- sound.hard.speed = 24585;
- divider = 3;
- } else if (sound.hard.speed > 16390)
- {
- sound.hard.speed = 19668;
- divider = 4;
- } else if (sound.hard.speed > 12292)
- {
- sound.hard.speed = 16390;
- divider = 5;
- } else if (sound.hard.speed > 9834)
- {
- sound.hard.speed = 12292;
- divider = 7;
- } else if (sound.hard.speed > 8195)
- {
- sound.hard.speed = 9834;
- divider = 9;
- } else
- {
- sound.hard.speed = 8195;
- divider = 11;
- }
- tt_dmasnd.int_div = divider;
-
- /* Setup Falcon sound DMA for playback */
- tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
- tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
- tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
- tt_dmasnd.cbar_dst = 0x0000;
- tt_dmasnd.rec_track_select = 0;
- tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
- tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
-
- tt_dmasnd.mode = (sound.hard.stereo ?
- DMASND_MODE_STEREO : DMASND_MODE_MONO) |
- ((sound.hard.size == 8) ?
- DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
- DMASND_MODE_6KHZ;
-
- sound.bal = -sound.soft.speed;
-}
-
-
-static int
-FalconSetFormat(int format)
-{
- int size;
-
- /* Falcon sound DMA supports 8bit and 16bit modes */
-
- switch (format)
- {
- case AFMT_QUERY:
- return (sound.soft.format);
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_U8:
- case AFMT_S8:
- size = 8;
- break;
- case AFMT_S16_BE:
- case AFMT_U16_BE:
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- size = 16;
- break;
- default: /* :-) */
- size = 8;
- format = AFMT_S8;
- }
-
- sound.soft.format = format;
- sound.soft.size = size;
- if (sound.minDev == SND_DEV_DSP)
- {
- sound.dsp.format = format;
- sound.dsp.size = sound.soft.size;
- }
- FalconInit();
-
- return (format);
+ idx = -1;
+ for (i = 0; i < arraysize(freq); i++)
+ /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
+ * be playable without expanding, but that now a kernel runtime
+ * option
+ */
+ if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+ idx = i;
+ if (idx > -1) {
+ sound.soft.speed = freq[idx];
+ sound.trans = &transFalconNormal;
+ } else
+ sound.trans = &transFalconExpanding;
+
+ FalconSilence();
+ sound.hard = sound.soft;
+
+ if (sound.hard.size == 16) {
+ /* the Falcon can play 16bit samples only in stereo */
+ sound.hard.stereo = 1;
+ }
+
+ if (sound.hard.speed > 49170) {
+ /* we would need to squeeze the sound, but we won't do that */
+ sound.hard.speed = 49170;
+ divider = 1;
+ sound.trans = &transFalconNormal;
+ } else if (sound.hard.speed > 32780) {
+ sound.hard.speed = 49170;
+ divider = 1;
+ } else if (sound.hard.speed > 24585) {
+ sound.hard.speed = 32780;
+ divider = 2;
+ } else if (sound.hard.speed > 19668) {
+ sound.hard.speed = 24585;
+ divider = 3;
+ } else if (sound.hard.speed > 16390) {
+ sound.hard.speed = 19668;
+ divider = 4;
+ } else if (sound.hard.speed > 12292) {
+ sound.hard.speed = 16390;
+ divider = 5;
+ } else if (sound.hard.speed > 9834) {
+ sound.hard.speed = 12292;
+ divider = 7;
+ } else if (sound.hard.speed > 8195) {
+ sound.hard.speed = 9834;
+ divider = 9;
+ } else {
+ sound.hard.speed = 8195;
+ divider = 11;
+ }
+ tt_dmasnd.int_div = divider;
+
+ /* Setup Falcon sound DMA for playback */
+ tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
+ tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
+ tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
+ tt_dmasnd.cbar_dst = 0x0000;
+ tt_dmasnd.rec_track_select = 0;
+ tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
+ tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
+
+ tt_dmasnd.mode = (sound.hard.stereo ?
+ DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+ ((sound.hard.size == 8) ?
+ DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
+ DMASND_MODE_6KHZ;
+
+ sound.bal = -sound.soft.speed;
+}
+
+
+static int FalconSetFormat(int format)
+{
+ int size;
+ /* Falcon sound DMA supports 8bit and 16bit modes */
+
+ switch (format) {
+ case AFMT_QUERY:
+ return(sound.soft.format);
+ case AFMT_MU_LAW:
+ case AFMT_A_LAW:
+ case AFMT_U8:
+ case AFMT_S8:
+ size = 8;
+ break;
+ case AFMT_S16_BE:
+ case AFMT_U16_BE:
+ case AFMT_S16_LE:
+ case AFMT_U16_LE:
+ size = 16;
+ break;
+ default: /* :-) */
+ size = 8;
+ format = AFMT_S8;
+ }
+
+ sound.soft.format = format;
+ sound.soft.size = size;
+ if (sound.minDev == SND_DEV_DSP) {
+ sound.dsp.format = format;
+ sound.dsp.size = sound.soft.size;
+ }
+
+ FalconInit();
+
+ return(format);
}
#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;
-}
-
-
-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);
- }
+ be played, we might lose one byte here. (TO DO) */
+ sq.front = (sq.front+1) % sq.max_count;
+ sq.playing++;
+ tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
+}
+
+
+static void AtaPlay(void)
+{
+ /* ++TeSche: Note that sq.playing is no longer just a flag but holds
+ * the number of frames the DMA is currently programmed for instead,
+ * may be 0, 1 (currently being played) or 2 (pre-programmed).
+ *
+ * Changes done to sq.count and sq.playing are a bit more subtle again
+ * so now I must admit I also prefer disabling the irq here rather
+ * than considering all possible situations. But the point is that
+ * disabling the irq doesn't have any bad influence on this version of
+ * the driver as we benefit from having pre-programmed the DMA
+ * wherever possible: There's no need to reload the DMA at the exact
+ * time of an interrupt but only at some time while the pre-programmed
+ * frame is playing!
+ */
+ atari_disable_irq(IRQ_MFP_TIMA);
+
+ if (sq.playing == 2 || /* DMA is 'full' */
+ sq.count <= 0) { /* nothing to do */
atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+
+ if (sq.playing == 0) {
+ /* looks like there's nothing 'in' the DMA yet, so try
+ * to put two frames into it (at least one is available).
+ */
+ if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) {
+ /* hmmm, the only existing frame is not
+ * yet filled and we're not syncing?
+ */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ ata_sq_play_next_frame(1);
+ if (sq.count == 1) {
+ /* no more frames */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
+ /* hmmm, there were two frames, but the second
+ * one is not yet filled and we're not syncing?
+ */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ ata_sq_play_next_frame(2);
+ } else {
+ /* there's already a frame being played so we may only stuff
+ * one new into the DMA, but even if this may be the last
+ * frame existing the previous one is still on sq.count.
+ */
+ if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
+ /* hmmm, the only existing frame is not
+ * yet filled and we're not syncing?
+ */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ ata_sq_play_next_frame(2);
+ }
+ atari_enable_irq(IRQ_MFP_TIMA);
}
-static void
-ata_sq_interrupt(int irq, 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. */
-
- if ((sq.playing != 1) || (sq.count != 1))
- /* We must be a bit carefully here: sq.count indicates the
- * number of buffers used and not the number of frames to
- * be played. If sq.count==1 and sq.playing==1 that means
- * the only remaining frame was already programmed earlier
- * (and is currently running) so we mustn't call AtaPlay()
- * here, otherwise we'll play one frame too much.
- */
- AtaPlay();
+ so wake up a writing process blocked because
+ of a full queue. */
+
+ if ((sq.playing != 1) || (sq.count != 1))
+ /* We must be a bit carefully here: sq.count indicates the
+ * number of buffers used and not the number of frames to
+ * be played. If sq.count==1 and sq.playing==1 that means
+ * the only remaining frame was already programmed earlier
+ * (and is currently running) so we mustn't call AtaPlay()
+ * here, otherwise we'll play one frame too much.
+ */
+ AtaPlay();
- if (!sq.playing)
- WAKE_UP(sq.sync_queue);
+ if (!sq.playing) WAKE_UP(sq.sync_queue);
/* We are not playing after AtaPlay(), so there
- is nothing to play any more. Wake up a process
- waiting for audio output to drain. */
+ is nothing to play any more. Wake up a process
+ waiting for audio output to drain. */
}
-#endif /* CONFIG_ATARI */
+#endif /* CONFIG_ATARI */
#ifdef CONFIG_AMIGA
*/
-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();
+ AmiSilence();
- if (sound.soft.speed)
- period = amiga_colorclock / sound.soft.speed - 1;
- else
- period = amiga_audio_min_period;
- sound.hard = sound.soft;
- sound.trans = &transAmiga;
+ if (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);
+ if (period < amiga_audio_min_period) {
+ /* we would need to squeeze the sound, but we won't do that */
+ period = amiga_audio_min_period;
+ } else if (period > 65535) {
+ period = 65535;
+ }
+ sound.hard.speed = amiga_colorclock/(period+1);
- for (i = 0; i < 4; i++)
- custom.aud[i].audper = period;
- amiga_audio_period = period;
+ for (i = 0; i < 4; i++)
+ custom.aud[i].audper = period;
+ amiga_audio_period = period;
- AmiSetTreble(50); /* recommended for newer amiga models */
+ AmiSetTreble(50); /* recommended for newer amiga models */
}
-static int
-AmiSetFormat(int format)
+static int AmiSetFormat(int format)
{
- int size;
+ int size;
- /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
+ /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
- switch (format)
- {
- 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;
- }
+ 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();
+ sound.soft.format = format;
+ sound.soft.size = size;
+ if (sound.minDev == SND_DEV_DSP) {
+ sound.dsp.format = format;
+ sound.dsp.size = sound.soft.size;
+ }
+ AmiInit();
- return (format);
+ return(format);
}
(((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));
+ 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)
+static int AmiSetTreble(int treble)
{
- sound.treble = treble;
- if (treble < 50)
- ciaa.pra &= ~0x02;
- else
- ciaa.pra |= 0x02;
- return (treble);
+ sound.treble = treble;
+ if (treble < 50)
+ ciaa.pra &= ~0x02;
+ else
+ ciaa.pra |= 0x02;
+ return(treble);
}
#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;
+
+ 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)
{
- u_char *start, *ch0, *ch1, *ch2, *ch3;
- u_long size;
+ int minframes = 1;
- /* 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);
+ 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)
- {
- /* 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;
+ if (sq.playing & AMI_PLAY_LOADED)
+ /* Increase threshold: frame 1 is already being played */
+ minframes = 2;
- /* Shift the flags */
- sq.playing = (sq.playing << 1) & AMI_PLAY_MASK;
+ /* Shift the flags */
+ sq.playing = (sq.playing<<1) & AMI_PLAY_MASK;
- if (!sq.playing)
- /* No frame is playing, disable audio DMA */
- custom.dmacon = AMI_AUDIO_OFF;
+ if (!sq.playing)
+ /* No frame is playing, disable audio DMA */
+ custom.dmacon = AMI_AUDIO_OFF;
- if (sq.count >= minframes)
- /* Try to play the next frame */
- AmiPlay();
+ if (sq.count >= minframes)
+ /* Try to play the next frame */
+ AmiPlay();
- if (!sq.playing)
- /* Nothing to play anymore.
- Wake up a process waiting for audio output to drain. */
- WAKE_UP(sq.sync_queue);
+ if (!sq.playing)
+ /* Nothing to play anymore.
+ Wake up a process waiting for audio output to drain. */
+ WAKE_UP(sq.sync_queue);
}
-#endif /* CONFIG_AMIGA */
+#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)
-{
- return (sound.mach.setBass ? (*sound.mach.setBass) (bass) : 50);
-}
-#endif /* CONFIG_ATARI */
-
-
-static int
-sound_set_treble(int treble)
-{
- return (sound.mach.setTreble ? (*sound.mach.setTreble) (treble) : 50);
-}
-
-
-static long
-sound_copy_translate(const u_char * userPtr,
- 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 int sound_set_bass(int bass)
+{
+ return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50);
+}
+
+static int sound_set_gain(int gain)
+{
+ return sound.mach.setGain ? sound.mach.setGain(gain) : 100;
+}
+#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);
}
#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 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:
{
- 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));
- }
+ 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));
}
- break;
-
- case DMASND_TT:
- switch (cmd)
+ case SOUND_MIXER_WRITE_VOLUME:
+ IOCTL_IN(arg, data);
+ return(IOCTL_OUT(arg, sound_set_volume(data)));
+ case SOUND_MIXER_WRITE_SPEAKER:
{
- 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);
+ 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;
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
- case DMASND_AMIGA:
- switch (cmd)
+ }
+ 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:
{
- 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)));
+ 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);
}
- break;
-#endif /* CONFIG_AMIGA */
- }
+ 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 */
- return (-EINVAL);
+#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 */
+ }
+
+ return(-EINVAL);
}
*/
-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.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.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 */
-
- 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)
- {
+ sq.block_size_half = sq.block_size>>1;
+ sq.block_size_quarter = sq.block_size_half>>1;
+#endif /* CONFIG_AMIGA */
+
+ sound_silence();
+
+ /* whatever you like as startup mode for /dev/dsp,
+ * (/dev/audio hasn't got a startup mode). note that
+ * once changed a new open() will *not* restore these!
+ */
+ sound.dsp.format = AFMT_S8;
+ sound.dsp.stereo = 0;
+ sound.dsp.size = 8;
+
+ /* set minimum rate possible without expanding */
+ switch (sound.mach.type) {
#ifdef CONFIG_ATARI
- case DMASND_TT:
- sound.dsp.speed = 6258;
- break;
- case DMASND_FALCON:
- sound.dsp.speed = 8195;
- break;
-#endif /* CONFIG_ATARI */
+ 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)
-{
- 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);
+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);
+
+ /* 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);
}
*/
-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)
+static int state_release(void)
{
- state.busy = 0;
- return (0);
+ state.busy = 0;
+ return(0);
}
-static long
-state_read(char *dest, unsigned long count)
+static long state_read(char *dest, unsigned long count)
{
- int n = state.len - state.ptr;
-
- if (n > count)
- n = count;
- if (n <= 0)
- return (0);
- copy_to_user(dest, &state.buf[state.ptr], n);
- state.ptr += n;
- return (n);
+ int n = state.len-state.ptr;
+ if (n > count)
+ n = count;
+ if (n <= 0)
+ return(0);
+ copy_to_user(dest, &state.buf[state.ptr], n);
+ state.ptr += n;
+ return(n);
}
/*** High level stuff ********************************************************/
-static int
-sound_open(struct inode *inode, struct file *file)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
- 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;
- }
+static int sound_open(struct inode *inode, struct file *file)
+{
+ 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;
+ }
#ifdef MODULE
- if (rc >= 0)
- MOD_INC_USE_COUNT;
+ if (rc >= 0)
+ MOD_INC_USE_COUNT;
#endif
- return (rc);
-}
-
-
-static int
-sound_fsync(struct inode *inode, struct file *filp)
-{
- int dev = MINOR(inode->i_rdev) & 0x0f;
-
- switch (dev)
- {
- case SND_DEV_STATUS:
- case SND_DEV_CTL:
- return (0);
- case SND_DEV_DSP:
- case SND_DEV_AUDIO:
- return (sq_sync());
- default:
- return (unknown_minor_dev("sound_fsync", dev));
- }
-}
-
-
-static void
-sound_release(struct inode *inode, struct file *file)
-{
- int dev = MINOR(inode->i_rdev);
-
- switch (dev & 0x0f)
- {
- case SND_DEV_STATUS:
- state_release();
- 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;
- }
+ return(rc);
+}
+
+
+static int sound_fsync(struct file *filp, struct dentry *dentry)
+{
+ 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));
+ }
+}
+
+
+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);
-}
-
-
-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;
+ /* printk("%s: Unknown minor device %d\n", fname, dev); */
+ return(-ENXIO);
+}
+
+
+static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg)
+{
+ int dev = MINOR(inode->i_rdev);
+ u_long fmt;
+ int data;
+
+ 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
};
/*** 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;
-
-#endif /* CONFIG_ATARI */
+ case MACH_ATARI:
+ if (ATARIHW_PRESENT(PCM_8BIT)) {
+ if (ATARIHW_PRESENT(CODEC))
+ sound.mach = machFalcon;
+ else if (ATARIHW_PRESENT(MICROWIRE))
+ sound.mach = machTT;
+ else
+ break;
+ if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
+ has_sound = 1;
+ else
+ printk("DMA sound driver: Timer A interrupt already in use\n");
+ }
+ break;
+
+#endif /* CONFIG_ATARI */
#ifdef CONFIG_AMIGA
- case MACH_AMIGA:
- if (AMIGAHW_PRESENT(AMI_AUDIO))
- {
- sound.mach = machAmiga;
- has_sound = 1;
- }
- break;
-#endif /* CONFIG_AMIGA */
- }
- if (!has_sound)
- return;
-
- /* Set up sound queue, /dev/audio and /dev/dsp. */
- 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)
-{
- /* 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");
- }
+void dmasound_setup(char *str, int *ints)
+{
+ /* check the bootstrap parameter for "dmasound=" */
+
+ switch (ints[0]) {
+ case 3:
+ if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
+ printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
+ else
+ catchRadius = ints[3];
+ /* fall through */
+ case 2:
+ if (ints[1] < MIN_BUFFERS)
+ printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs);
+ else
+ numBufs = ints[1];
+ if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
+ printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize);
+ else
+ bufSize = ints[2];
+ break;
+ case 0:
+ break;
+ default:
+ printk("dmasound_setup: illegal number of arguments\n");
+ }
}
#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;
+ while (i < MAXARGS && dmasound[i])
+ ints[i + 1] = dmasound[i++];
+ ints[0] = i;
- if (i)
- dmasound_setup("dmasound=", ints);
+ if (i)
+ dmasound_setup("dmasound=", ints);
- err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
- if (err)
- {
- printk(KERN_ERR "dmasound: driver already loaded/included in kernel\n");
- return err;
- }
- chrdev_registered = 1;
- soundcard_init();
+ err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops);
+ if (err) {
+ printk("dmasound: driver already loaded/included in kernel\n");
+ return err;
+ }
+ chrdev_registered = 1;
+ soundcard_init();
- return 0;
+ return 0;
}
void cleanup_module(void)
{
- int i;
+ int i;
- if (MOD_IN_USE)
- return;
+ if (MOD_IN_USE)
+ return;
- if (chrdev_registered)
- unregister_chrdev(SOUND_MAJOR, "sound");
+ if (chrdev_registered)
+ unregister_chrdev(SOUND_MAJOR, "sound");
- if (irq_installed)
- {
- sound_silence();
- sound.mach.irqcleanup();
- }
- if (sound_buffers)
- {
- for (i = 0; i < numBufs; i++)
- sound.mach.dma_free(sound_buffers[i], bufSize << 10);
- kfree(sound_buffers);
- }
+ if (irq_installed) {
+ sound_silence();
+ sound.mach.irqcleanup();
+ }
+
+ if (sound_buffers) {
+ for (i = 0; i < numBufs; i++)
+ sound.mach.dma_free(sound_buffers[i], bufSize << 10);
+ kfree(sound_buffers);
+ }
}
-#endif /* MODULE */
+#endif /* MODULE */
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);
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
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);
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;
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
* 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"
#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;
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)
* 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);
}
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. */
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;
-
- 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;
- }
- }
- }
+ {
+ 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;
+
+ 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())
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);
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;
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)));
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;
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 */
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;
-
- 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;
+ { /* 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;
outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */
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;
#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;
-
- 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);
+ {
+
+#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD)
+ unsigned char tmp;
+
+ 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(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 */
*/
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);
#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]);
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)
#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 */
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");
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,
};
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
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;
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);
#include <linux/config.h>
#include <linux/module.h>
+#include <asm/init.h>
#define USE_SEQ_MACROS
#define USE_SIMPLE_MACROS
#ifdef MODULE
+MODULE_PARM(io,"i");
+MODULE_PARM(irq,"i");
+
+EXPORT_NO_SYMBOLS;
+
int io = -1;
int irq = -1;
void cleanup_module(void)
{
if (fw_load && maui_os)
- kfree(maui_os);
+ vfree(maui_os);
unload_maui(&cfg);
SOUND_LOCK_END;
}
*/
#include <linux/config.h>
#include <linux/stddef.h>
+#include <linux/kmod.h>
#define MIDIBUF_C
*
* 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 <linux/config.h>
#undef SB_OK
#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();
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();
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 */
* 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;
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)";
#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;
#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;
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);
}
#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
#include <linux/string.h>
#include <linux/fs.h>
#include <asm/dma.h>
+#include <asm/io.h>
#include <asm/param.h>
#include <linux/ptrace.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <linux/poll.h>
#include <linux/pci.h>
-#include <linux/bios32.h>
#endif
#include <linux/wrapper.h>
#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
}
else
{
- if (request_irq(pas_irq, pasintr, 0, "PAS16", NULL) < 0)
+ if (request_irq(pas_irq, pasintr, 0, "PAS16",NULL) < 0)
ok = 0;
}
}
* 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 <vladimir.michl@upol.cz>
+ * 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 <linux/config.h>
#include <linux/module.h>
*/
#define CONF_PSS 0x10
#define CONF_WSS 0x12
-#define CONF_SB 0x13
+#define CONF_SB 0x14
#define CONF_CDROM 0x16
#define CONF_MIDI 0x18
#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
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;
*/
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)
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;
}
pss_reset_dsp(devc);
}
count = 1;
- while (1)
+ while ((flags&CPF_LAST) || count<size )
{
int j;
break;
else
{
- printk("\nPSS: Download timeout problems, byte %d=%d\n", count, size);
+ printk("\n");
+ printk(KERN_ERR "PSS: Download timeout problems, byte %d=%d\n", count, size);
return 0;
}
}
/*_____ Send the next byte */
- outw(*block++, REG(PSS_DATA));
+ if (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++;
}
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;
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;
/*
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;
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)
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
* 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++);
+ 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 */
- outb((0x0b), hw_config->io_base + 4); /* Required by some cards */
+ for (timeout = 0; (inb(hw_config->io_base + WSS_DATA) & WSS_AUTOCALIBRATION) && (timeout < 100000); timeout++);
- for (timeout = 0;
- 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)
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;
void cleanup_module(void)
{
if (fw_load && pss_synth)
- kfree(pss_synth);
+ vfree(pss_synth);
if (pssmss)
unload_pss_mss(&cfgmss);
if (pssmpu)
SOUND_LOCK_END;
}
#endif
-
#endif
#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
*/
* 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 <linux/config.h>
-
+#include <linux/config.h>
#include "sound_config.h"
#if defined(CONFIG_SBDSP) || defined(MODULE)
#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;
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;
* 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); */
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
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();
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();
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();
* 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); */
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
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;
}
* 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;
}
* 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)
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);
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;
}
* 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;
- }
-
- devc->speed = speed;
- }
+ {
+ if (speed < 5000)
+ speed = 5000;
+ if (speed > 48000)
+ speed = 48000;
+
+ if (speed > 22000)
+ {
+ divider = (795500 + speed / 2) / speed;
+ speed = (795500 + divider / 2) / divider;
+ }
+ else
+ {
+ divider = (397700 + speed / 2) / speed;
+ speed = (397700 + divider / 2) / divider;
+ }
+ devc->speed = speed;
+ }
return devc->speed;
}
-static void
-ess_speed(sb_devc * devc)
+static 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)
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);
}
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); */
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
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;
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)
{
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)
{
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 =
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;
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;
}
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;
* 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 <linux/config.h>
#include <linux/module.h>
-
#include "sound_config.h"
#include "soundmodule.h"
#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;
* 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");
MODULE_PARM(trix, "i");
MODULE_PARM(pas2, "i");
MODULE_PARM(sm_games, "i");
-MODULE_PARM(mwave_bug, "i");
static int sbmpu = 0;
void cleanup_module(void)
{
if (smw_free)
- kfree(smw_free);
+ vfree(smw_free);
if (!mad16 && !trix && !pas2)
unload_sb(&config);
if (sbmpu)
#else
int acer = 0;
#endif
-#ifdef CONFIG_SB_MWAVE
-int mwave_bug = 1;
-#else
-int mwave_bug = 0;
-#endif
#endif
#endif
EXPORT_SYMBOL(attach_sb_card);
EXPORT_SYMBOL(probe_sb);
EXPORT_SYMBOL(unload_sb);
+EXPORT_SYMBOL(sb_be_quiet);
* 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 <linux/config.h>
#include <linux/delay.h>
-
+#include <asm/init.h>
#include "sound_config.h"
#include "sound_firmware.h"
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
};
* 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 */
/*
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
* loops.
*/
- for (i = 0; i < 500000 && jiffies < limit; i++)
+ for (i = 0; i < 500000 && (limit-jiffies)>0; i++)
{
if ((inb(DSP_STATUS) & 0x80) == 0)
{
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;
}
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;
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);
/*
* 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;
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;
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]))
*/
- 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");
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
*/
/* 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
{
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)
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"));
}
}
}
else
release_region(hw_config->io_base, 16);
+ if(detected_devc)
+ kfree(detected_devc);
}
/*
void sb_setmixer(sb_devc * devc, unsigned int port, unsigned int value)
{
- unsigned long flags;
+ unsigned long flags;
save_flags(flags);
cli();
{
}
#endif
-
#endif
* 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 <linux/config.h>
-
+#include <linux/config.h>
#include "sound_config.h"
#ifdef CONFIG_SBDSP
*/
-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;
save_flags(flags);
cli();
if (devc->opened)
- {
- restore_flags(flags);
- return -EBUSY;
- }
+ {
+ restore_flags(flags);
+ return -EBUSY;
+ }
devc->opened = 1;
restore_flags(flags);
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;
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;
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;
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;
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,
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;
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));
* 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 <linux/config.h>
-
+#include <linux/config.h>
#include "sound_config.h"
#if defined(CONFIG_SBDSP) || defined(MODULE)
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 */
*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 */
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;
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)
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);
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;
}
/*
* 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) {
+ switch (cmd & 0xff)
+ {
+ case SOUND_MIXER_RECSRC:
+ ret = set_recmask(devc, val);
+ break;
+
+ default:
+ ret = sb_mixer_set(devc, cmd & 0xff, val);
+ }
+ }
+ else switch (cmd & 0xff)
+ {
case SOUND_MIXER_RECSRC:
- ret = set_recmask(devc, val);
+ ret = devc->recmask;
break;
-
- default:
- ret = sb_mixer_set(devc, cmd & 0xff, val);
- }
- } 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;
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);
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;
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;
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
*
#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}}
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 */
#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
*/
#include <linux/config.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
#define SEQUENCER_C
#include "sound_config.h"
parm = 64;
}
}
-
+
switch (cmd)
{
case MIDI_NOTEON:
synth_devs[max_synthdev++] = midi_devs[dev]->converter;
}
}
-
+
for (dev = 0; dev < max_synthdev; dev++)
{
int chn;
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);
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;
{
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);
/*
* Initialize midi input devices
*/
-
+
for (i = 0; i < max_mididev; i++)
if (!midi_opened[i])
{
/*
* Let's have a delay
*/
-
+
if (n) {
current->timeout = jiffies + HZ / 10;
interruptible_sleep_on(&seq_sleeper);
/* Extra delay */
}
}
-
+
if (mode != OPEN_READ)
seq_drain_midi_queues(); /*
* Ensure the output queues are empty
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)
save_flags(flags);
cli();
-
+
if (waitqueue_active(&seq_sleeper)) {
/* printk( "Sequencer Warning: Unexpected sleeping process - Waking up\n"); */
wake_up(&seq_sleeper);
orig_dev = dev = dev >> 4;
- switch (cmd)
+ switch (cmd)
{
case SNDCTL_TMR_TIMEBASE:
case SNDCTL_TMR_TEMPO:
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;
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;
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;
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);
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)
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))))
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;
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;
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;
val = SEQ_MAX_QUEUE - 1;
output_threshold = val;
return 0;
-
+
case SNDCTL_MIDI_PRETIME:
if (get_user(val, (int *)arg))
return -EFAULT;
/* 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;
*/
while (bend > 2399)
{
- multiplier *= 4;
- bend -= 2400;
+ multiplier *= 4;
+ bend -= 2400;
}
semitones = bend / 100;
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)
* 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 <linux/config.h>
#include "softoss.h"
#include <linux/ultrasound.h>
-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
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;
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;
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;
}
#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;
}
#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;
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;
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;
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;
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,
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();
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;
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;
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;
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;
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;
-
- 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)
+ {
+ int ptr;
+
+ 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)
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));
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);
}
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
}
}
-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);
/*
* 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_START:
+ start_engine(devc);
+ break;
- case SSYN_STOP:
- stop_engine(devc);
- break;
+ case SSYN_STOP:
+ stop_engine(devc);
+ break;
- case SSYN_REQUEST:
- request_engine(devc, parm1);
- 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_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
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;
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;
best_delta = 1000000;
while (instr != NO_SAMPLE && instr >= 0 && selected == -1)
- {
- 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 (instr < 0 || instr >= devc->nrsamples)
- instr = NO_SAMPLE;
- }
+ {
+ 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 (instr < 0 || instr >= devc->nrsamples)
+ instr = NO_SAMPLE;
+ }
if (selected == -1)
instr = best_sample;
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;
+ else
+ {
+ base_note = sample->base_note / 100;
+ note_freq /= 100;
- freq = sample->base_freq * note_freq / base_note;
- v->orig_freq = freq;
- }
+ 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;
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 */
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;
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);
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;
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];
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.
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;
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;
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;
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;
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;
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;
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;
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;
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();
* 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;
}
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;
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;
#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();
#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);
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);
return 0;
}
-void
-cleanup_module(void)
+void cleanup_module(void)
{
unload_softsyn(&config);
sound_unload_synthdev(devc->synthdev);
* 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)
#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
#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
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);
/* 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);
#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) \
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);
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);
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);
+#include "os.h"
#define __KERNEL_SYSCALLS__
#include <linux/fs.h>
#include <linux/mm.h>
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);
if (read(fd, dp, l) != l)
{
printk(KERN_INFO "Failed to read '%s'.\n", fn);
- kfree(dp);
+ vfree(dp);
sys_close(fd);
return 0;
}
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();
set_fs(fs);
return r;
}
+
/*
- * 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
*/
#include "sound_config.h"
#define _MIDI_SYNTH_C_
#include "midi_synth.h"
+#define _SEQUENCER_C_
+#include "tuning.h"
#include <linux/notifier.h>
#include "sound_firmware.h"
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);
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.");
* Stefan Reinauer : integrated /proc/sound (equals to /dev/sndstat,
* which should disappear in the near future)
*/
-#include <linux/config.h>
+#include <linux/config.h>
#include "sound_config.h"
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/kmod.h>
#ifdef __KERNEL__
+#include <asm/dma.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <linux/wait.h>
#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;
* 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
}
-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)
{
}
#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)
{
}
#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;
{
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;
*
* 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 <linux/config.h>
#include <linux/module.h>
#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;
}
-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;
/*
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;
* 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 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};
+ 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;
+ 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;
+ }
+ else
+ {
+ unsigned char tmp;
- tmp = trix_read(0x13) & ~30;
- trix_write(0x13, tmp | 0x80 | (dma1 << 4));
+ tmp = trix_read(0x13) & ~30;
+ trix_write(0x13, tmp | 0x80 | (dma1 << 4));
- tmp = trix_read(0x14) & ~30;
- trix_write(0x14, tmp | 0x80 | (dma2 << 4));
- }
+ tmp = trix_read(0x14) & ~30;
+ trix_write(0x14, tmp | 0x80 | (dma2 << 4));
+ }
outb((bits), config_port); /* Write IRQ+DMA setup */
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 */
- }
+ {
+ 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 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};
+ 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 */
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;
#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;
#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";
#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;
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);
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;
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;
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);
*/
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)
*
* 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
uart401_devc *devc;
char *name = "MPU-401 (UART) MIDI";
+
if (hw_config->name)
name = hw_config->name;
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)
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.
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))
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;
MODULE_PARM(io,"i");
MODULE_PARM(irq,"i");
+EXPORT_NO_SYMBOLS;
+
struct address_info cfg;
int init_module(void)
--- /dev/null
+/*
+ * drivers/sound/vidc.c
+ *
+ * Detection routine for the VIDC.
+ *
+ * Copyright (C) 1997 by Russell King <rmk@arm.uk.linux.org>
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#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);
+}
--- /dev/null
+/*
+ * drivers/sound/vidc.h
+ *
+ * VIDC sound function prototypes
+ *
+ * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org>
+ */
+
+/* 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);
--- /dev/null
+/*
+ * drivers/sound/vidc_audio.c
+ *
+ * Audio routines for the VIDC
+ *
+ * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org>
+ */
+
+#include <linux/config.h>
+#include "sound_config.h"
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#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");
+}
--- /dev/null
+/*
+ * sound/vidc_fill.S
+ *
+ * Filler routines for DMA buffers
+ *
+ * Copyright (C) 1997 Russell King
+ */
+#define __ASSEMBLY__
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/hardware.h>
+
+ .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
--- /dev/null
+/*
+ * drivers/sound/vidc_mixer.c
+ *
+ * Mixer routines for VIDC
+ *
+ * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org>
+ */
+
+#include <linux/config.h>
+#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;
+}
--- /dev/null
+/*
+ * drivers/sound/vidc_synth.c
+ *
+ * Synthesizer routines for the VIDC
+ *
+ * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org>
+ */
+#include <linux/config.h>
+#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");
+}
* for more details.
*/
-
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
-#include <linux/config.h>
#include <linux/fb.h>
#include "fbcon.h"
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
-#include <linux/config.h>
#include <linux/fb.h>
#include "fbcon.h"
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
-#include <linux/config.h>
#include <linux/fb.h>
#include "fbcon.h"
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
-#include <linux/config.h>
#include <linux/fb.h>
#include "fbcon.h"
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
-#include <linux/config.h>
#include <linux/fb.h>
#include "fbcon.h"
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
-#include <linux/config.h>
#include <linux/fb.h>
#include "fbcon.h"
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
-#include <linux/config.h>
#include <linux/fb.h>
#include "fbcon.h"
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
-#include <linux/config.h>
#include <linux/fb.h>
#include <linux/delay.h>
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
-#include <linux/config.h>
#include <linux/fb.h>
#include "fbcon.h"
* for more details.
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
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);
}
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/param.h>
+#include <linux/string.h>
#include "devpts_i.h"
static int devpts_root_readdir(struct file *,void *,filldir_t);
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
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;
}
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):
- 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)
- 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 <gockel@sent13.uni-duisburg.de> 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
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) 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..
-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 !
+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.
------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------
+ 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?
- 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
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);
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;
}
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
the special offset.
*/
if (filp->f_pos == 0) filp->f_pos = start_fpos;
- iput(emd_dir);
+ /* iput(emd_dir); FIXME */
}
}
umsdos_endlookup(dir);
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;
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){
kfree (bpath);
}
Printk (("\n"));
- iput (dir);
+ /* iput (dir); FIXME */
return ret;
}
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] == '.'){
pseudo root is returned.
*/
ret = 0;
- dentry->d_inode = pseudo_root;
+ d_add (dentry, pseudo_root);
pseudo_root->i_count++;
}else{
/* #Specification: locating .. / strategy
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)){
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{
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
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;
}
}
}
umsdos_endlookup(dir);
- iput (dir);
+ /* iput (dir); FIXME */
Printk ((KERN_DEBUG "umsdos_lookup_x: returning %d\n", ret));
return ret;
}
*result = NULL;
if (path == NULL){
ret = -ENOMEM;
- iput (hlink);
+ /* iput (hlink); FIXME */
}else{
struct file filp;
loff_t offs = 0;
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));
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 */
}
}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);
*
*/
-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)
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
*
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));
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));
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;
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/ */
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
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);
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;
}
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
}
}
}
- iput(emd_dir);
+ /* iput(emd_dir); FIXME */
return ret;
}
/* 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;
break;
}
}
- iput (emd_dir);
+ /* iput (emd_dir); FIXME */
}
return ret;
}
}
}
}
- iput (emd_dir);
+ /* iput (emd_dir); FIXME */
Printk (("umsdos_findentry: returning %d\n", ret));
return ret;
}
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 */
+};
+
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;
}
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){
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);
{
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;
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;
EMD file. The msdos fs is not even called.
*/
}
- iput (emd_owner);
+ /* iput (emd_owner); FIXME */
}
Printk (("\n"));
}
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; }
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);
*/
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
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 */
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
Printk ((KERN_WARNING "umsdos_read_super /mn/: Pseudo should be iput-ed here...\n"));
- iput (pseudo); /* FIXME */
+ /* iput (pseudo); / * FIXME */
}
#endif /* disabled */
{
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.
}
}
}
- iput (emd_dir);
+ /* iput (emd_dir); FIXME */
}else{
/* The absence of the EMD is simply seen as an EOF */
ret = 0;
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
,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
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
{
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);
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
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++;
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 */
dir = NULL;
}
}
- d_instantiate(dentry,dir);
+ /* d_instantiate(dentry,dir); //already done in umsdos_create_any */
Printk (("\n"));
return ret;
}
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));
umsdos_unlockcreate(olddir);
umsdos_unlockcreate(dir);
}
- iput (olddir);
+ /* iput (olddir); FIXME */
}
if (ret == 0){
struct iattr newattrs;
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;
}
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
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 */
}
}
}
}
Printk (("umsdos_mkdir %d\n",ret));
-/* dput (dentry); FIXME /mn/ */
+ /* dput (dentry); / * FIXME /mn/ */
return ret;
}
*/
int ret = umsdos_create_any (dir,dentry,mode,rdev,0);
-/* dput(dentry); /mn/ FIXME! */
+ /* dput(dentry); / * /mn/ FIXME! */
return ret;
}
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++;
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() */
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{
umsdos_unlockcreate(dir);
}
}
- dput(dentry);
+ /* dput(dentry); FIXME /mn/ */
Printk (("umsdos_rmdir %d\n",ret));
return ret;
}
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{
umsdos_unlockcreate(dir);
}
}
- dput(dentry);
+ /* dput(dentry); FIXME: shouldn't this be done in msdos_unlink ? */
Printk (("umsdos_unlink %d\n",ret));
return ret;
}
}
}
}
+ /*
dput (new_dentry);
- dput (old_dentry);
+ dput (old_dentry); FIXME /mn/ */
return ret;
}
*/
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 */
}
}
}
- iput (dir);
+ /* iput (dir); FIXME */
PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret));
return ret;
}
}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){
}else{
ret = -ENOTEMPTY;
}
- iput (sdir);
+ /* iput (sdir); FIXME */
}
}
umsdos_unlockcreate (dir);
}
- iput (dir);
+ /* iput (dir); FIXME */
return ret;
}
* ugh).
*/
+#include <linux/config.h>
#include <asm/system.h>
#ifdef CONFIG_ALPHA_SRM_SETUP
#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
#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
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)
{
#include <asm/arch/mmu.h>
#include <linux/slab.h>
+#include <asm/arch/processor.h> /* For TASK_SIZE */
#define LIBRARY_TEXT_START 0x0c000000
#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
* 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 __inline__ void pte_free(pte_t * pte)
+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)
{
- kfree (pte);
+ *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+ pgd_quicklist = (unsigned long *) pgd;
+ pgtable_cache_size++;
}
-extern const char bad_pmd_string[];
+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 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)
+{
+ 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;
* 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];
#define __ASM_PROC_PGTABLE_H
#include <asm/arch/mmu.h>
+#include <asm/arch/processor.h> /* For TASK_SIZE */
#define LIBRARY_TEXT_START 0x0c000000
#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
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:
default:
return 0;
}
+#else
+ return ((pte_val(pmd) + 1) & PMD_TYPE_MASK);
+#endif
}
extern __inline__ int pmd_none(pmd_t pmd)
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:
default:
return 1;
}
+#else
+ return (pmd_val(pmd) & PMD_TYPE_SECT);
+#endif
}
extern __inline__ int pmd_present(pmd_t pmd)
/* 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.. */
/* 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);
* 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;
* 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];
* 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
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
#define N_STRIP 4
#define N_AX25 5
#define N_X25 6 /* X.25 async */
+#define N_6PACK 7
#ifdef __KERNEL__
#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)
*/
#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);
--- /dev/null
+/* $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;
+}
#ifndef _I386_PAGE_H
#define _I386_PAGE_H
-#include <linux/config.h>
-
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
/* 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))
#define N_STRIP 4
#define N_AX25 5
#define N_X25 6 /* X.25 async */
+#define N_6PACK 7
#ifdef __KERNEL__
*/
#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)
#define N_STRIP 4
#define N_AX25 5
#define N_X25 6 /* X.25 async */
+#define N_6PACK 7
#ifdef __KERNEL__
*/
#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)
#define N_STRIP 4
#define N_AX25 5
#define N_X25 6 /* X.25 async */
+#define N_6PACK 7
#ifdef __KERNEL__
*/
#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)
#define N_PPP 3
#define N_STRIP 4
#define N_AX25 5
+#define N_X25 6
+#define N_6PACK 7
#ifdef __KERNEL__
*/
#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)
#define N_PPP 3
#define N_STRIP 4
#define N_AX25 5
+#define N_X25 6
+#define N_6PACK 7
#ifdef __KERNEL__
*/
#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)
*/
#define MAX_ARG_PAGES 32
+#ifdef __KERNEL__
+
/*
* This structure is used to hold the arguments that are used when loading binaries.
*/
/* this eventually goes away */
#define change_ldt(a,b) setup_arg_pages(a,b)
-#endif
+#endif /* __KERNEL__ */
+#endif /* _LINUX_BINFMTS_H */
#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 <linux/ioctl.h>
#include <asm/types.h>
/*
* Version
*/
-#define JS_VERSION 0x00010006L /* 1.0.6 BCD */
+#define JS_VERSION 0x00010007L /* 1.0.7 BCD */
/*
* IOCTL commands for joystick driver
#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
#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))
#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.
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;
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);
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);
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,
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
#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 */
#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
int bytesperline;
};
+struct video_mmap
+{
+ unsigned int frame; /* Frame (0 or 1) for double buffer */
+ int height,width;
+ unsigned int format;
+};
struct video_key
{
#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 */
#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
--- /dev/null
+#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 <martin-2.buck@student.uni-ulm.de>
+ * 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 */
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)
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);
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();
}
#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();
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
static struct wait_queue * kmod_queue = NULL;
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;
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);
}
}
}
int kmod_init(void)
{
- printk ("Starting kmod\n");
+ printk("Starting kmod\n");
kernel_thread(kmod_thread, NULL, 0);
#include <asm/bitops.h>
#include <asm/pgtable.h>
+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.
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++;
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);
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",
#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);
+}
+
/*
* Setting up a new swap file needs a simple wrapper just to read the
* swap signature. SysV shared memory also needs a simple wrapper.
/* 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;
offset = si->cluster_next++;
if (si->swap_map[offset])
continue;
+ if (test_bit(offset, si->swap_lockmap))
+ continue;
si->cluster_nr--;
goto got_page;
}
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;
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:
int error = -EPERM;
struct file filp;
static int least_priority = 0;
- unsigned char *avail_map = 0;
lock_kernel();
if (!suser())
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;
}
} 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;
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;
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;
}
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),