diff --git a/sys/i386/isa/snd/CARDS b/sys/i386/isa/snd/CARDS deleted file mode 100644 index c8f28158d3d1..000000000000 --- a/sys/i386/isa/snd/CARDS +++ /dev/null @@ -1,359 +0,0 @@ -In this file I will try to build a database of cards supported by -this driver. I also include the command to use for manual configuration -of the card in case your BIOS is not PnP-aware. Of course it is -your responsibility to pick up free port ranges and irq and drq -channels. - -For PnP cards, I also include the vendor_id and serial numbers of -cards I have encountered. Underscores in the PnP id mean that -(I believe) there is a large variety of values in those positions, -and the code in the audio driver generally masks those bits. - -Finally, where available, I have put the URL where you can find the -data sheets of the chip. - -To my knowledge, there are the following families of audio cards: - -* WSS (also called MSS) and clones: - these are true full duplex cards, have a very nice architecture and - are well documented. Chipsets implementing these functionalities - are made from Crystal, Analog Devices, Yamaha, OPTI. - -* SB16 and clones: - these cards have a higly asymmetric architecture, and are not very - well suited to full duplex operation. Made by Creative, Realtek. - There is no documentation on the newer codecs (Vibra16X and ALS100+), - so they are not fully working. - -* ESS - ESS builds cards that implement a superset of SB16. They are - often capable of full duplex, but my driver does not support them - other than in full duplex emulation. My fault, since documentation - on these cards _is_ available. - -* PCI cards. - There are a quite few PCI audio cards around based on a number of - different chipsets. Some of them are documented (e.g. S3 Sonic - Vibes, Ensoniq ES1370), some are not (e.g. Yamaha YMF724), - work is in progress to support such cards. See the notes below. - Note that CreativeLabs has recently (fall'97) acquired Ensoniq - and the audio division of OPTI, both of which had a PCI audio - chipset. I don't know if there are other manufacturers of PCI - audio cards. - -Finally, some people wrote patches for the following chips: - - AD1816 - MAD16 - ESS --------------------------- -CHIPSET: - CS4235: PnP id 0x25__630e - CS4236: PnP id 0x36__630e 0x35__630e - CS4237: PnP id 0x37__630e - -MANUFACTURER: - A/Open (or AcerOpen) AW32, AW35, AW37 - Also, integrated on the motherboard on some machines. - -DATA SHEETS: - http://www.crystal.com/ 4237full.pdf - -PNP CONFIG: - pnp 1 0 os enable port0 0x534 port2 0x220 irq0 5 drq0 1 drq1 3 - -COMMENTS: - Work like a charm. All modes, including full duplex, supported in - MSS mode. - - Cards based on the 4237, and possibly the 4236 as well, connect - the CD to AUX2. When used in MODE1/2 (as this driver does) - there is no route in the input mixer from AUX2 to the ADC. So, - to record directly from the CD, the only way is to set the - input to SOUND_MASK_IMIX. - - Some machines with the cs4235 in non-pnp mode map the codec at 0x530 - instead of 0x534. For those machines you need an unusual config line - - device pcm0 at isa ? port 0x52C ... - - --------------------------- -CHIPSET: - CS4232: PnP id 0x3242630e - -MANUFACTURER: - ??? - -DATA SHEETS: - http://www.crystal.com/ - -PNP CONFIG: - pnp 1 0 os enable port0 0x534 port2 0x220 irq0 5 drq0 1 drq1 3 - -COMMENTS: - This chip is reported as broken in the OSS documentation. As a - matter of fact, on my Intel Zappa motherboard, I have problems in - make it use the secondary DMA channel. I have it working in - half duplex (both capture and playback) in SB3.2 emulation, - and working in playback mode in MSS emulation. - Also have reports from some user that it works ok. - --------------------------- -CHIPSET: - AD1815/1816 - -MANUFACTURER: - Analog Devices - -DOCUMENTATION: - http://www.analog.com - -COMMENTS: - This is a chip for ISA-PnP cards, and so should be configured - using the PnP interface. For full function configure port2, - irq0, drq0 and drq1 of ldn0. - The driver is contributed by German Tischler - -FORMATS: - ALAW/ULAW/8bit/16bit(le)/16bit(be),8kHz-55.2kHz,full duplex - --------------------------- -CHIPSET: - OPTi931: PnP id 0x3109143e - OPTi933: PnP id 0x3109143e (yes, it's the same) - -MANUFACTURER: - ExpertColor MED931 (europe) - Shuttle HOT-247 (uses the 933, $15 retail in the US) - -DATA SHEETS: - http://www.opti.com/ opti931_21.pdf - -PNP CONFIG: - pnp 1 1 os enable port0 0x534 port2 0x220 port3 0xe0d irq0 10 drq0 1 drq1 6 - -COMMENTS: - The data sheets of this chip are very cryptic and do not match - what the cards I have seem to do. I have it working - in WSS emulation, in full duplex and all modes. - In SB emulation mode the driver does not work yet (maybe I do - not initialize it the right way). It is not a major concern - anyways. - I am strongly convinced of a couple of bugs in the chip. I have - sent email to OPTI but got no reply so far. The bugs are: - - you cannot set both playback and capture format to use - a companded mode (ULAW, ALAW). If you do, the card will screw - up on the capture section. - The driver has a partial fix in software: when using ULAW, it - programs ULAW on the playback section, U8 on the capture, and - does a conversion in software (much like the SBPro). Of course - you lose 4-5 bits of dynamic range in the process. - - in full duplex (and single DMA mode), the card occasionally - misses interrupts, or generates spurious ones, or generates - interrupts before setting the status bits in the registers. - Spurious ints are not problematic since they can be easily - ignored, but missing interrupts are a nightmare to handle... - The only way to have this card work semi-reliably is to use - auto-dma mode (which is the default mode of operation in the - driver). - In any case, these cards are very cheap and widely available and - are a reasonable solution if you cannot find some other decent WSS - device. - -------------------------------- -CHIPSET: - SB16: PnP id 0x__008c0e - Vibra16X: PnP id 0xf0008c0e - -MANUFACTURER: - CreativeLabs - -DATA SHEETS: - http://www.creative.com sbhwpg.pdf or SBHWPG.EXE - ftp://www.creaf.com/pub/creative/devinfo/ctsbhwpg.exe - -PNP CONFIG: - pnp 1 0 os enable port0 0x220 irq0 5 drq0 1 drq1 5 - -COMMENTS: - SB16 really refers to a large number of different cards, starting - from the original, non-PnP SB16, to more modern cards (SB16PnP, - Vibra16C) and other including Wavetable Synthesis (AWE32, AWE64, - etc.). All these cards have different PnP ID. They have - different synthesis devices, which we do not support, so we - are not affected by these differences. Don't worry if the driver - identifies the card as a different SB16 than the one you have. - - BEWARE -- all recent (1998 ?) SB16 use a new codec, Vibra16X, - which is sufficiently different from the old one to not work with - this driver in capture mode or in full duplex. Documentation is - not available from Creative. I suggest to stay away from these - cards (and from SB16 in general). - - Full duplex support of this card is tricky since one channel can - work in 16-bit and the other in 8-bit mode. You will need to use - the new set of ioctl to use separate data formats on the two - channels (the vat driver does this). Of course, quality in 8-bit - is much lower than in 16-bit. - - Full duplex operation is unsupported by Creative. It seems to - work, although on my Vibra16C the command to stop DMA transfer - seems to erroneously affect both channels instead of the one - they are issued for. The driver has a workaround, but I cannot - guarantee that it works for everybody. I have had several - positive reports. - - Some docs on how to use this card with the voxware driver - are at http://multiverse.com/~rhh/awedrv - --------------------------- -CHIPSET: - ALS100, ALS110, ALS120, ... - Avance Asound 100: PnP id 0x01009305 - Avance Asound 100+: PnP id 0x10019305 - Avance Logic ALS120: PnP id 0x20019305 - -MANUFACTURER: - Realtek (also Avance Asound and possibly other names) - Asound Gold (AS007) has an ALS120 - - -DOCUMENTATION: - - http://www.realtek.com.tw/cp/cp.html - but not very useful or detailed. - -COMMENTS: - These card should be recognised as SB16 clones. Some of them - emulate the Vibra16X, so the comments above apply. - - ------------------------------- -CHIPSET: - Yamaha SA2/SA3 . Both PnP and non-PnP versions. - OPL3-SA2 Sound Chip: PnP id 0x2000a865 - OPL/SA3 : PnP id 0x3000a865 - -MANUFACTURER: - no-name cards, and also used in various laptops, e.g. Toshiba - Libretto and others. I - -DATA SHEETS: - http://www.yamaha.com ? YM711.pdf - ftp://ftp.yamahayst.com/pub/Fax_Back_Doc/Sound - http://www.imail.net.tw/qtronix/qumax_product_yamaha.htm - - This is a huge file containing a few pages scanned and converted - to pdf. Not very detailed. Luckily, this chipset appears to do a - good (i.e. bug-free) emulation of the WSS, so it is fully - supported by the driver. - - pnp 1 0 os enable port0 0x220 port1 0x530 port2 0x388 port3 0x370 irq0 5 drq0 1 drq1 0 - - this card emulates a WSS or SB. Have reports that it works, although - it has incomplete mixer support (Yamaha defines an additional set - of registers to control some mixer functions, such as the master - output volume -- this is at 0x370 or 0x310). Currently we set - the master volume to 100% for the PnP card. Will put in code to do the - same for the non PnP card as soon as I find out how to tell - the Yamaha from other cards. - Driver reported to work also on - Toshiba DynaBook Portege 300CT with OPL3SA-3(non-PNP), and on the - Libretto50CT (has the non-PnP device). - ------------------------- -CHIPSET: - ENSONIQ SoundscapeVIVO ENS4081: PnP id 0x8140d315 -MANUFACTURER: - Ensoniq Soundscape VIVO - -PNP CONFIG: - pnp 1 0 os enable port0 0x220 port1 0x530 irq0 5 drq0 1 drq1 5 - -COMMENTS: - this card emulates a WSS or SB. Have reports that it works. - -------------------------- -CHIPSET: - AMD... - -MANUFACTURER: - GusPnP: PnP id 0x0100561e - -PNP CONFIG: - pnp 1 0 os enable port0 0x220 port1 0x320 port2 0x32c irq0 5 drq0 7 drq1 5 - -COMMENTS: - It works in U8 and S16 mode, ulaw support still not working. - The Gus has been discontinued, so support for this card is only - there for historical reasons (the Gus used to be the only card - well supported in full duplex mode). - - ----- THE FOLLOWING CARDS ARE NOT FULLY SUPPORTED: ---- - -CHIPSET: - OPTI925: PnP id 0x2509143e - -COMMENTS: - there is code to recognize it as a SB clone. I have reports that - it probes ok, but not sure if it works. - -------------------------- -CHIPSET: - OPTI924: PnP - -COMMENT: - I have this card but it is still unsupported. - -------------------------- -CHIPSET: - OPTI930: - - should work as an MSS clone, but support for it is not implemented - yet. - -CHIPSET: - ESS1868 - ESS688 - - http://www.esstech.com - - pnp 1 1 os enable irq0 7 drq0 1 port0 0x220 - - There used to be documentation for the 1868 on the ESS site - (files ds1868b1.pdf and ds1868b2.pdf) but I am unable to find - it now (980122). I have asked ESS but no reply so far. - - partly supported in SB emulation. - - (the ESS688 is used on many notebooks. It is probably able to do 8 - and 16-bit, half duplex). - -------------------------- -CHIPSET: - es1370 (ensoniq) - es1371 (ensoniq) - used on SB64 PCI, Shuttle HOT-255, and maybe others - - A driver for this is in the works. - see http://www.ensoniq.com/multimedia/semi_html/index.htm - for documentation. See also http://alsa.jcu.cz/alsa/ for a Linux - driver. - -------------------------- -CHIPSET: - YMF724 - used on various Yamaha (WaveForce) and other cards. - - NOT SUPPORTED. - - There is no public docs on this card, the closest thing being - http://www.imail.net.tw/qtronix/driver/qumax/yamaha/ds1e1110.pdf - http://www.imail.net.tw/qtronix/qumax_product_yamaha.htm - which however does not document how the card works in non-legacy - mode and how to make it talk to the AC97 codec. - - --------------------------------------------------------------------- diff --git a/sys/i386/isa/snd/README b/sys/i386/isa/snd/README deleted file mode 100644 index e45bde7f2dbc..000000000000 --- a/sys/i386/isa/snd/README +++ /dev/null @@ -1,224 +0,0 @@ - --- A new FreeBSD audio driver --- - by Luigi Rizzo (luigi@iet.unipi.it) - -This is a new, completely rewritten, audio driver for FreeBSD. -Only "soundcard.h" has remained largely similar to the original -OSS/Voxware header file, mostly for compatibility with existing -applications. - -This driver tries to cover those areas where the Voxware 3.0 driver -is mostly lacking: full-duplex, audio applications, modern (mostly -PnP) cards. For backward compatibility, the driver implements most -of the Voxware ioctl() audio calls, so that many applications -- -even commercial ones -- will run unmodified with this driver. On -the other hand, at the moment this driver does not support /dev/midi -and /dev/synth, or some ioctl() used in xquake. Do not expect -/dev/synth to be supported anytime soon. - -I also have implemented a new software interface with an independent -set of ioctl(), to support some functions which were not easy to -express with the existing software interface (e.g. full duplex on -old SB16 cards). To make an effective use of the new functionalities -you need to recompile applications by replacing the audio module(s). -Such modified driver modules are present in the misc/ directory -for several applications. - -This file gives quick information on how to install the driver. -Updated versions of this code will be available at the following URL: - - http://www.iet.unipi.it/~luigi/FreeBSD.html - -Please READ CAREFULLY this file (and possibly the LaTeX documentation) -to build a working kernel. The configuration is DIFFERENT (and -hopefully much simpler) from the original Voxware driver. The -relevant steps are indicated at "---INSTALLATION---". - -CARDS: - - The driver supports most clones of WSS, SB16 and SBPro cards. - This includes those based on the Crystal CS423x, OPTI931, GUSPnP, - Yamaha, SB16/32 (both plain ISA, PnP, and the various AWExx). - Many PnP cards are directly recognized, for others you might need - manual configuration. See the file "CARDS" for more details. - -APPLICATIONS: - - In general, most applications which use /dev/audio or /dev/dsp - work unmodified or with a specially-supplied module. - - UNMODIFIED: - - raplayer (Real Audio Player), rvplayer (linux version) - - xboing - - xanim - - various mpeg players (mpg123, amp, ...); - - WITH SPECIAL DRIVER MODULE (supplied) - - speak_freely, full duplex (requires removing the definition of - HALF_DUPLEX in the Makefile); - - the realaudio player (3.0, dynamically linked); - - vat, full duplex (the version in ports is already modified); - - timidity, a software midi-to-pcm converter; - - NOT WORKING - - xquake (we do not support mmapped buffers yet); - - - ---INSTALLATION--- - - * add the following lines to your kernel configuration file: - - controller pnp0 # this is required for PnP support - - device pcm0 at isa ? port? tty irq N drq D flags F - - where - - N is the IRQ address used by the sound card, - D is the primary DMA channel used by the sound card, - F is used to specify a number of options, in particular: - bit 2..0 secondary DMA channel; - bit 4 set if the board uses two dma channels; - bit 15..8 board type, overrides autodetection; leave it - zero if don't know what to put in (and you don't, - since this is unsupported at the moment...). - - The code will probe for common port addresses (0x220, 0x240 - for SB and clones, 0x530 for WSS and clones), so you don't need - to specify them if your system uses one of them. In case you - do, note that for WSS cards the code assumes that the board - occupies 8 IO addresses, the first four used to configure - IRQ/DRQ, and the other four to access codec registers. Many - boards (including all the ones I have) do not have registers - to program IRQ and DRQ, so they really start at 0x534... yet - I decided to use the old convention for historical reasons. - - You can use multiple sound cards, in which case you need more - lines like - - device pcm1 at isa ? port? tty irq N drq D flags F - device pcm2 at isa ? port? tty irq N drq D flags F - ... - - EXAMPLES: a typical "device" line for the SB16 (full duplex) is - - device pcm0 at isa ? port? tty irq 5 drq 1 flags 0x15 - - The driver will check at the default addresses (or the one you - specify) which type of SoundBlaster you have (1.5, 2.0, 3.X - aka SBPro, 4.X aka SB16) and use the correct commands. You - _do_not_ need to specify different drivers (sb,sbpro,sbxvi) as - it was the case (and a big source of confusion) in the previous - sound driver. - - For a WSS-compatible codec (non PnP) working in full duplex using - dma channels 1 and 3, you can specify: - - device pcm0 at isa ? port 0x530 tty irq 7 drq 1 flags 0x13 - - (0x530 is a default if no port address is specified). The - "flags 0x13" specifies that you have a dual dma board with - channel 3 as secondary DMA channel. - - * build the kernel using the standard steps - - config MYKERNEL - cd /sys/compile/MYKERNEL - make depend - make - - * note for PnP cards: - - For PnP cards, only the line for "pcm0" is needed (the code - will allocate entries for more cards if found), but IT MUST - INCLUDE ALL FIELDS. You can use the following line: - - device pcm0 at isa ? port? tty irq 7 drq 1 - - NOTE that: - - the parameters for the PnP device(s) will be read from the - configuration of the card(s); they are usually assigned by - the bios, and there is no way (at the moment) to override - them, so if you have a broken (or no) PnP bios your only - chance is to patch the pnp attach code in the driver for your - card (ad1848.c, sb_dsp.c, clones.c) and write there the - parameters you want; - - The driver will assign unit numbers to the PnP cards starting - from the next free one (e.g. 1, 2, ...) same as it is done - with PCI devices which are clones of ISA devices. - - The driver assumes a working PnP bios, which will assign correct - addresses and IO and DMA channels to the devices. If you do not - have a PnP-aware BIOS, you must boot with the -c option and assign - addresses manually the first time. The general commands are described in - the pnp README file. For the card-specific commands check in the - file CARDS. - -WHAT IF THIS DRIVER DOES NOT WORK: - -If the driver does not work with your hardware, I might to help -but I need the following information: - - - relevant lines in your config file; - - dmesg output - - possibly, pnpinfo output - -Please send all the above in plain text, not as a mime attachment. - -Common mistakes: - -* you are trying to use /dev/audio0 instead of /dev/audio1 - For technical reasons, a PnP device is attached as unit 1 instead - of unit 0 -- most applications are programmed to access the audio - hardware through /dev/audio, /dev/dsp, /dev/mixer which are in turn - symlinks to the correct device entries. Check them and possibly fix - these symlinks in /dev - -* you have used a wrong config line - - The configuration of this driver is different from the Voxware one. - Please read the information in this file carefully. - -* your BIOS is leaving the card disabled. - - Some BIOSes do not initialize the card, or leave it disabled. At the - moment, the fix is to use the pnp code booting with "-c" and set the - correct port, irq, drq etc for the card. See the PnP documentation. - -* your card is not recognized. - - This driver supports a large, but still limited, number of cards, - mostly SB and WSS clones. Other cards may or may not work depending - on how closely they emulate these devices. In case, send me an email - with the info indicated above. - -* the mixer does not work well - - Different cards have different connections to the mixer, so it might - well be that to control the volume of your CD you have to use the FM - port, etc. Also, on some cards the volume might be lower than you - expect. The mixer code still does not try to exploit the features of - each card, and it just provides basic functionalities. - ---- ACKNOWLEDGMENTS --- - -Several people helped, directly or indirectly, in the development of -this driver. In particular I would like to thank: - - * Hannu Savolainen (the Voxware author) for making his code - available. It was a very good source of technical info; - * Amancio Hasty for continuous support and his work on guspnp code; - * Jim Lowe for his suggestion on the block-mode select; - * Allison Mankin and Brad Karp at ISI-East for supplying a GUS PnP - which allowed me to support this card; - * Eric J. Schwertfeger for donating an ES1868 card for writing the - driver (which i haven't done yet...). - * and many people who had the patience to try the driver - on their cards and report success/failure and useful - information. - -It was certainly helpful to have the data sheets for some of the -devices I support available on the net, especially in the (unfortunately -rare) cases where the data sheets matched the actual behavior of -the product. Too bad that no one of the chip/card manufacturers I -have contacted by email regarding missing or inconsistent documentation -on their products did even care to reply to my messages. diff --git a/sys/i386/isa/snd/ad1848.c b/sys/i386/isa/snd/ad1848.c deleted file mode 100644 index 9d0a0cfab7d0..000000000000 --- a/sys/i386/isa/snd/ad1848.c +++ /dev/null @@ -1,2339 +0,0 @@ -/* - * sound/ad1848.c - * - * Driver for Microsoft Sound System/Windows Sound System (mss) - * -compatible boards. This includes: - * - * AD1848, CS4248, CS423x, OPTi931, Yamaha OPL/SAx and many others. - * - * Copyright Luigi Rizzo, 1997,1998 - * Copyright by Hannu Savolainen 1994, 1995 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * Full data sheets in PDF format for the MSS-compatible chips - * are available at - * - * http://www.crystal.com/ for the CS42XX series, or - * http://www.opti.com/ for the OPTi931 - */ - -#include -#if NPCM > 0 - -/* - * board-specific include files - */ - -#include - -/* - * prototypes for procedures exported in the device descriptor - */ - -static int mss_probe(struct isa_device *dev); -static int mss_attach(struct isa_device *dev); - -d_open_t mss_open; /* this is a generic full-duplex open routine */ -static d_close_t mss_close; -static d_ioctl_t mss_ioctl; -static irq_proc_t mss_intr; -static irq_proc_t opti931_intr; -static snd_callback_t mss_callback; - -/* - * prototypes for local functions - */ - -static void mss_reinit(snddev_info *d); -static int AD_WAIT_INIT(snddev_info *d, int x); -static int mss_mixer_set(snddev_info *d, int dev, int value); -static int mss_set_recsrc(snddev_info *d, int mask); -static void ad1848_mixer_reset(snddev_info *d); - -static void opti_write(int io_base, u_char reg, u_char data); -static u_char opti_read(int io_base, u_char reg); -static void ad_write(snddev_info *d, int reg, u_char data); -static void ad_write_cnt(snddev_info *d, int reg, u_short data); -static int ad_read(snddev_info *d, int reg); - -#if NPNP > 0 /* the ad1816 is pnp only */ -/* ad1816 prototypes */ - -/* IO primitives */ -static int ad1816_wait_init(snddev_info * d, int x); -static u_short ad1816_read(snddev_info * d, u_int reg); -static void ad1816_write(snddev_info * d, u_int reg, u_short data); -/* intr and callback functions */ -static irq_proc_t ad1816_intr; -static snd_callback_t ad1816_callback; -/* device specific ioctl calls */ -static d_ioctl_t ad1816_ioctl; -/* parameter set functions */ -static void ad1816_reinit(snddev_info * d); -static int ad1816_mixer_set(snddev_info * d, int dev, int value); -static int ad1816_set_recsrc(snddev_info * d, int mask); -static void ad1816_mixer_reset(snddev_info * d); - -/* ad1816 prototypes end */ -#endif - -/* - * device descriptors for the boards supported by this module. - */ -snddev_info mss_op_desc = { - "mss", - - SNDCARD_MSS, - mss_probe, - mss_attach, - - mss_open, - mss_close, - NULL /* mss_read */, - NULL /* mss_write */, - mss_ioctl, - sndselect /* mss_select */, - - mss_intr, - mss_callback , - - DSP_BUFFSIZE, /* bufsize */ - - AFMT_STEREO | - AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, /* audio formats */ - /* - * the enhanced boards also have AFMT_IMA_ADPCM | AFMT_S16_BE - * but we do not use these modes. - */ -} ; - -/* - * mss_probe() is the probe routine. Note, it is not necessary to - * go through this for PnP devices, since they are already - * indentified precisely using their PnP id. - * - * The base address supplied in the device refers to the old MSS - * specs where the four 4 registers in io space contain configuration - * information. Some boards (as an example, early MSS boards) - * has such a block of registers, whereas others (generally CS42xx) - * do not. In order to distinguish between the two and do not have - * to supply two separate probe routines, the flags entry in isa_device - * has a bit to mark this. - * - */ - -static int -mss_probe(struct isa_device *dev) -{ - u_char tmp; - int irq = ffs(dev->id_irq) - 1; - - bzero(&pcm_info[dev->id_unit], sizeof(pcm_info[dev->id_unit]) ); - if (dev->id_iobase == -1) { - dev->id_iobase = 0x530; - BVDDB(printf("mss_probe: no address supplied, try default 0x%x\n", - dev->id_iobase)); - } - if (snd_conflict(dev->id_iobase)) - return 0 ; - - if ( !(dev->id_flags & DV_F_TRUE_MSS) ) /* Has no IRQ/DMA registers */ - goto mss_probe_end; - - /* - * Check if the IO port returns valid signature. The original MS - * Sound system returns 0x04 while some cards - * (AudioTriX Pro for example) return 0x00 or 0x0f. - */ - - tmp = inb(dev->id_iobase + 3); - if (tmp == 0xff) { /* Bus float */ - BVDDB(printf("I/O address inactive (%x), try pseudo_mss\n", tmp)); - dev->id_flags &= ~DV_F_TRUE_MSS ; - goto mss_probe_end; - } - tmp &= 0x3f ; - if (tmp != 0x04 && tmp != 0x0f && tmp != 0x00) { - BVDDB(printf("No MSS signature detected on port 0x%x (0x%x)\n", - dev->id_iobase, inb(dev->id_iobase + 3))); - return 0; - } - if (irq > 11) { - printf("MSS: Bad IRQ %d\n", irq); - return 0; - } - if (dev->id_drq != 0 && dev->id_drq != 1 && dev->id_drq != 3) { - printf("MSS: Bad DMA %d\n", dev->id_drq); - return 0; - } - if (inb(dev->id_iobase + 3) & 0x80) { - /* 8-bit board: only drq1/3 and irq7/9 */ - if (dev->id_drq == 0) { - printf("MSS: Can't use DMA0 with a 8 bit card/slot\n"); - return 0; - } - if (irq != 7 && irq != 9) { - printf("MSS: Can't use IRQ%d with a 8 bit card/slot\n", irq); - return 0; - } - } -mss_probe_end: - return mss_detect(dev) ? 8 : 0 ; /* mss uses 8 regs */ -} - -#if NPNP > 0 -static int -ad1816_attach(struct isa_device *dev) -{ - snddev_info *d = &(pcm_info[dev->id_unit]); - - dev->id_alive = 16; /* number of io ports */ - - if (FULL_DUPLEX(d)) - d->audio_fmt |= AFMT_FULLDUPLEX; - - ad1816_write(d, 1, 0x2);/* disable interrupts */ - ad1816_write(d, 32, 0x90F0); /* SoundSystem Mode, split format */ - - ad1816_write(d, 5, 0x8080); /* FM volume mute */ - ad1816_write(d, 6, 0x8080); /* I2S1 volume mute */ - ad1816_write(d, 7, 0x8080); /* I2S0 volume mute */ - ad1816_write(d, 17, 0x8888); /* VID Volume mute */ - ad1816_write(d, 20, 0x5050); /* Source select Mic & auto gain ctrl - * off */ - /* adc gain is set to 0 */ - ad1816_reinit(d); - ad1816_mixer_reset(d); - return 0 ; -} -#endif /* NPNP */ - -/* - * the address passed as io_base for mss_attach is also the old - * MSS base address (e.g. 0x530). The codec is four locations ahead. - * Note that the attach routine for PnP devices might support - * device-specific initializations. - */ - -static int -mss_attach(struct isa_device *dev) -{ - snddev_info *d = &(pcm_info[dev->id_unit]); - - printf("mss_attach <%s>%d at 0x%x irq %d dma %d:%d flags 0x%x\n", - d->name, dev->id_unit, - d->io_base, d->irq, d->dbuf_out.chan, d->dbuf_in.chan, dev->id_flags); - -#if NPNP > 0 - if (d->bd_id == MD_AD1816) - return ad1816_attach(dev); -#endif - dev->id_alive = 8 ; /* number of io ports */ - /* should be already set but just in case... */ - - if ( dev->id_flags & DV_F_TRUE_MSS ) { - /* has IRQ/DMA registers, set IRQ and DMA addr */ - static char interrupt_bits[12] = { - -1, -1, -1, -1, -1, 0x28, -1, 0x08, -1, 0x10, 0x18, 0x20 - }; - static char dma_bits[4] = { 1, 2, 0, 3 }; - char bits ; - - if (d->irq == -1 || (bits = interrupt_bits[d->irq]) == -1) { - dev->id_irq = 0 ; /* makk invalid irq */ - return 0 ; - } - - outb(dev->id_iobase, bits | 0x40); /* config port */ - if ((inb(dev->id_iobase + 3) & 0x40) == 0) /* version port */ - printf("[IRQ Conflict?]"); - - /* Write IRQ+DMA setup */ - if ( ! FULL_DUPLEX(d) ) /* single chan dma */ - outb(dev->id_iobase, bits | dma_bits[d->dbuf_out.chan]); - else { - if (d->dbuf_out.chan == 0 && d->dbuf_in.chan == 1) - bits |= 5 ; - else if (d->dbuf_out.chan == 1 && d->dbuf_in.chan == 0) - bits |= 6 ; - else if (d->dbuf_out.chan == 3 && d->dbuf_in.chan == 0) - bits |= 7 ; - else { - printf("invalid dual dma config %d:%d\n", - d->dbuf_out.chan, d->dbuf_in.chan); - dev->id_irq = 0 ; - dev->id_alive = 0 ; /* this makes attach fail. */ - return 0 ; - } - outb(dev->id_iobase, bits ); - } - } - if (1) { /* machine-specific code for the Toshiba Libretto */ - u_char r6, r9; - outb( 0x370, 6 /* dma config */ ); - outb( 0x371, 0xa9 /* config: DMA-B for rec, DMA-A for play */); - r6 = inb( 0x371 /* read */ ); - outb( 0x370, 0xa /* version */ ); - r9 = inb( 0x371 /* read */ ); - DEB(printf("Yamaha: ver 0x%x DMA config 0x%x\n", r6, r9);) - /* - * yamaha - set volume to max - */ - outb( 0x370, 7 /* volume left */ ); - outb( 0x371, 0 /* max level */ ); - outb( 0x370, 8 /* volume right */ ); - outb( 0x371, 0 /* max level */ ); - } - if ( FULL_DUPLEX(d) ) - d->audio_fmt |= AFMT_FULLDUPLEX ; - if (d->bd_id == MD_YM0020) { - DDB(printf("setting up yamaha registers\n")); - outb(0x370, 6 /* dma config */ ) ; - if (FULL_DUPLEX(d)) - outb(0x371, 0xa9 ); /* use both dma chans */ - else - outb(0x371, 0x8b ); /* use low dma chan */ - } - mss_reinit(d); - ad1848_mixer_reset(d); - return 0; -} - -int -mss_open(dev_t i_dev, int flags, int mode, struct proc * p) -{ - int unit; - int dev; - snddev_info *d; - u_long s; - - dev = minor(i_dev); - unit = dev >> 4 ; - dev &= 0xf ; - d = &pcm_info[unit] ; - - s = spltty(); - /* - * This was meant to support up to 2 open descriptors for the - * some device, and check proper device usage on open. - * Unfortunately, the kernel will trap all close() calls but - * the last one, with the consequence that we cannot really - * keep track of which channels are busy. - * So, the correct tests cannot be done :( and we must rely - * on the locks on concurrent operations of the same type and - * on some approximate tests... - */ - - if (dev == SND_DEV_AUDIO) - d->flags |= SND_F_BUSY_AUDIO ; - else if (dev == SND_DEV_DSP) - d->flags |= SND_F_BUSY_DSP ; - else if (dev == SND_DEV_DSP16) - d->flags |= SND_F_BUSY_DSP16 ; - if ( d->flags & SND_F_BUSY ) - splx(s); /* device was already set, no need to reinit */ - else { - /* - * device was idle. Do the necessary initialization, - * but no need keep interrupts blocked. - * will not get them - */ - - splx(s); - d->play_speed = d->rec_speed = DSP_DEFAULT_SPEED ; - d->flags |= SND_F_BUSY ; - - d->wsel.si_pid = 0; - d->wsel.si_flags = 0; - - d->rsel.si_pid = 0; - d->rsel.si_flags = 0; - - d->dbuf_out.total = d->dbuf_out.prev_total = 0 ; - d->dbuf_in.total = d->dbuf_in.prev_total = 0 ; - - if (flags & O_NONBLOCK) - d->flags |= SND_F_NBIO ; - - switch (dev) { - default : - case SND_DEV_AUDIO : - d->play_fmt = d->rec_fmt = AFMT_MU_LAW ; - break ; - case SND_DEV_DSP : - d->play_fmt = d->rec_fmt = AFMT_U8 ; - break ; - case SND_DEV_DSP16 : - d->play_fmt = d->rec_fmt = AFMT_S16_LE ; - break; - } - ask_init(d); /* and reset buffers... */ - } - return 0 ; -} - -static int -mss_close(dev_t i_dev, int flags, int mode, struct proc * p) -{ - int unit; - int dev; - snddev_info *d; - u_long s; - - dev = minor(i_dev); - unit = dev >> 4 ; - dev &= 0xf; - d = &pcm_info[unit] ; - - /* - * We will only get a single close call when the last reference - * to the device is gone. But we must handle ourselves references - * through different devices. - */ - - s = spltty(); - - if (dev == SND_DEV_AUDIO) - d->flags &= ~SND_F_BUSY_AUDIO ; - else if (dev == SND_DEV_DSP) - d->flags &= ~SND_F_BUSY_DSP ; - else if (dev == SND_DEV_DSP16) - d->flags &= ~SND_F_BUSY_DSP16 ; - if ( d->flags & SND_F_BUSY_ANY ) /* still some device open */ - splx(s); - else { /* last one */ - d->flags |= SND_F_CLOSING ; - splx(s); /* is this ok here ? */ - snd_flush(d); - /* Clear interrupt status */ - if ( d->bd_id == MD_AD1816 ) - outb(ad1816_int(d), 0); - else - outb(io_Status(d), 0); - d->flags = 0 ; - } - return 0 ; -} - -static int -mss_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p) -{ - snddev_info *d; - int unit; - int dev; - - dev = minor(i_dev); - unit = dev >> 4 ; - d = &pcm_info[unit] ; - /* - * handle mixer calls first. Reads are in the default handler, - * so do not bother about them. - */ - if ( (cmd & MIXER_WRITE(0)) == MIXER_WRITE(0) ) { - cmd &= 0xff ; - if (cmd == SOUND_MIXER_RECSRC) - return mss_set_recsrc(d, *(int *)arg) ; - else - return mss_mixer_set(d, cmd, *(int *)arg) ; - } - - return ENOSYS ; /* fallback to the default ioctl handler */ -} - - -/* - * the callback routine to handle all dma ops etc. - * With the exception of INIT, all other callbacks are invoked - * with interrupts disabled. - */ - -static int -mss_callback(snddev_info *d, int reason) -{ - u_char m; - int retry, wr, cnt; - - DEB(printf("-- mss_callback reason 0x%03x\n", reason)); - wr = reason & SND_CB_WR ; - reason &= SND_CB_REASON_MASK ; - switch (reason) { - case SND_CB_INIT : /* called with int enabled and no pending I/O */ - /* - * perform all necessary initializations for i/o - */ - d->rec_fmt = d->play_fmt ; /* no split format on the MSS */ - snd_set_blocksize(d); - mss_reinit(d); - reset_dbuf(& (d->dbuf_in), SND_CHAN_RD ); - reset_dbuf(& (d->dbuf_out), SND_CHAN_WR ); - return 1 ; - break ; - - case SND_CB_START : - cnt = wr ? d->dbuf_out.dl : d->dbuf_in.dl ; - if (d->play_fmt == AFMT_S16_LE) - cnt /= 2; - if (d->flags & SND_F_STEREO) - cnt /= 2; - cnt-- ; - - DEB(printf("-- (re)start cnt %d\n", cnt)); - m = ad_read(d,9) ; - DEB( if (m & 4) printf("OUCH! reg 9 0x%02x\n", m); ); - m |= wr ? I9_PEN : I9_CEN ; /* enable DMA */ - /* - * on the OPTi931 the enable bit seems hard to set... - */ - for (retry = 10; retry; retry--) { - ad_write(d, 9, m ); - if (ad_read(d,9) ==m) break; - } - if (retry == 0) - printf("start dma, failed to set bit 0x%02x 0x%02x\n", - m, ad_read(d, 9) ) ; - if (wr || ! FULL_DUPLEX(d) ) - ad_write_cnt(d, 14, cnt); - else - ad_write_cnt(d, 30, cnt); - - break ; - - case SND_CB_STOP : - case SND_CB_ABORT : /* XXX check this... */ - m = ad_read(d,9) ; - m &= wr ? ~I9_PEN : ~I9_CEN ; /* Stop DMA */ - /* - * on the OPTi931 the enable bit seems hard to set... - */ - for (retry = 10; retry ; retry-- ) { - ad_write(d, 9, m ); - if (ad_read(d,9) ==m) break; - } - if (retry == 0) - printf("start dma, failed to clear bit 0x%02x 0x%02x\n", - m, ad_read(d, 9) ) ; -#if 1 - /* - * try to disable DMA by clearing count registers. Not sure it - * is needed, and it might cause false interrupts when the - * DMA is re-enabled later. - */ - if (wr || ! FULL_DUPLEX(d) ) - ad_write_cnt(d, 14, 0); - else - ad_write_cnt(d, 30, 0); - break; -#endif - } - return 0 ; -} - -/* - * main irq handler for the CS423x. The OPTi931 code is - * a separate one. - * The correct way to operate for a device with multiple internal - * interrupt sources is to loop on the status register and ack - * interrupts until all interrupts are served and none are reported. At - * this point the IRQ line to the ISA IRQ controller should go low - * and be raised at the next interrupt. - * - * Since the ISA IRQ controller is sent EOI _before_ passing control - * to the isr, it might happen that we serve an interrupt early, in - * which case the status register at the next interrupt should just - * say that there are no more interrupts... - */ - -static void -mss_intr(int unit) -{ - snddev_info *d = &pcm_info[unit]; - u_char c, served = 0; - int i; - - DEB(printf("mss_intr\n")); - ad_read(d, 11); /* fake read of status bits */ - - /* - * loop until there are interrupts, but no more than 10 times. - */ - for (i=10 ; i && inb(io_Status(d)) & 1 ; i-- ) { - /* get exact reason for full-duplex boards */ - c = FULL_DUPLEX(d) ? ad_read(d, 24) : 0x30 ; - c &= ~served ; - if ( d->dbuf_out.dl && (c & 0x10) ) { - served |= 0x10 ; - dsp_wrintr(d); - } - if ( d->dbuf_in.dl && (c & 0x20) ) { - served |= 0x20 ; - dsp_rdintr(d); - } - /* - * now ack the interrupt - */ - if ( FULL_DUPLEX(d) ) - ad_write(d, 24, ~c); /* ack selectively */ - else - outb(io_Status(d), 0); /* Clear interrupt status */ - } - if (served == 0) { - printf("How strange... mss_intr with no reason!\n"); - /* - * this should not happen... I have no idea what to do now. - * maybe should do a sanity check and restart dmas ? - */ - outb(io_Status(d), 0); /* Clear interrupt status */ - } -} - -/* - * the opti931 seems to miss interrupts when working in full - * duplex, so we try some heuristics to catch them. - */ -static void -opti931_intr(int unit) -{ - snddev_info *d = &pcm_info[unit]; - u_char masked=0, i11, mc11, c=0; - u_char reason; /* b0 = playback, b1 = capture, b2 = timer */ - int loops = 10; - -#if 0 - reason = inb(io_Status(d)); - if ( ! (reason & 1) ) {/* no int, maybe a shared line ? */ - printf("opti931_intr: flag 0, mcir11 0x%02x\n", ad_read(d,11)); - return; - } -#endif - i11 = ad_read(d, 11); /* XXX what's for ? */ -again: - - c=mc11 = FULL_DUPLEX(d) ? opti_read(d->conf_base, 11) : 0xc ; - mc11 &= 0x0c ; - if (c & 0x10) { - DEB(printf("Warning: CD interrupt\n");) - mc11 |= 0x10 ; - } - if (c & 0x20) { - DEB(printf("Warning: MPU interrupt\n");) - mc11 |= 0x20 ; - } - if (mc11 & masked) - printf("irq reset failed, mc11 0x%02x, masked 0x%02x\n", mc11, masked); - masked |= mc11 ; - /* - * the nice OPTi931 sets the IRQ line before setting the bits in - * mc11. So, on some occasions I have to retry (max 10 times). - */ - if ( mc11 == 0 ) { /* perhaps can return ... */ - reason = inb(io_Status(d)); - if (reason & 1) { - DEB(printf("one more try...\n");) - if (--loops) - goto again; - else - DDB(printf("opti_intr: irq but mc11 not set!...\n");) - } - if (loops==10) - printf("ouch, intr but nothing in mcir11 0x%02x\n", mc11); - return; - } - - if ( d->dbuf_in.dl && (mc11 & 8) ) { - dsp_rdintr(d); - } - if ( d->dbuf_out.dl && (mc11 & 4) ) { - dsp_wrintr(d); - } - opti_write(d->conf_base, 11, ~mc11); /* ack */ - if (--loops) - goto again; - DEB(printf("xxx too many loops\n");) -} - -/* - * Second part of the file: functions local to this module. - * in this section a few routines to access MSS registers - * - */ - -static void -opti_write(int io_base, u_char reg, u_char value) -{ - outb(io_base, reg); - outb(io_base+1, value); -} - -static u_char -opti_read(int io_base, u_char reg) -{ - outb(io_base, reg); - return inb(io_base+1); -} - -static void -gus_write(int io_base, u_char reg, u_char value) -{ - outb(io_base + 3, reg); - outb(io_base + 5, value); -} - -#if 0 -static void -gus_writew(int io_base, u_char reg, u_short value) -{ - outb(io_base + 3, reg); - outb(io_base + 4, value); -} -#endif - -static u_char -gus_read(int io_base, u_char reg) -{ - outb(io_base+3, reg); - return inb(io_base+5); -} - -#if 0 -static u_short -gus_readw(int io_base, u_char reg) -{ - outb(io_base+3, reg); - return inw(io_base+4); -} -#endif - -/* - * AD_WAIT_INIT waits if we are initializing the board and - * we cannot modify its settings - */ -static int -AD_WAIT_INIT(snddev_info *d, int x) -{ - int arg=x, n = 0; /* to shut up the compiler... */ - for (; x-- ; ) - if ( (n=inb(io_Index_Addr(d))) & IA_BUSY) - DELAY(10); - else - return n ; - printf("AD_WAIT_INIT FAILED %d 0x%02x\n", arg, n); - return n ; -} - -static int -ad_read(snddev_info *d, int reg) -{ - u_long flags; - int x; - - flags = spltty(); - AD_WAIT_INIT(d, 201); - x = inb(io_Index_Addr(d)) & ~IA_AMASK ; - outb(io_Index_Addr(d), (u_char) (reg & IA_AMASK) | x ) ; - x = inb(io_Indexed_Data(d)); - splx(flags); - return x; -} - -static void -ad_write(snddev_info *d, int reg, u_char data) -{ - u_long flags; - - int x ; - flags = spltty(); - AD_WAIT_INIT(d, 1002); - x = inb(io_Index_Addr(d)) & ~IA_AMASK ; - outb(io_Index_Addr(d), (u_char) (reg & IA_AMASK) | x ) ; - outb(io_Indexed_Data(d), data); - splx(flags); -} - -static void -ad_write_cnt(snddev_info *d, int reg, u_short cnt) -{ - ad_write(d, reg+1, cnt & 0xff ); - ad_write(d, reg, cnt >> 8 ); /* upper base must be last */ -} - -static void -wait_for_calibration(snddev_info *d) -{ - int n, t; - - /* - * Wait until the auto calibration process has finished. - * - * 1) Wait until the chip becomes ready (reads don't return 0x80). - * 2) Wait until the ACI bit of I11 gets on - * 3) Wait until the ACI bit of I11 gets off - */ - - n = AD_WAIT_INIT(d, 1000); - if (n & IA_BUSY) - printf("mss: Auto calibration timed out(1).\n"); - - for (t = 100 ; t>0 && (ad_read(d, 11) & 0x20) == 0 ; t--) - DELAY(100); - for (t = 100 ; t>0 && ad_read(d, 11) & 0x20 ; t--) - DELAY(100); -} - -#if 0 /* unused right now... */ -static void -ad_mute(snddev_info *d) -{ - ad_write(d, 6, ad_read(d,6) | I6_MUTE); - ad_write(d, 7, ad_read(d,7) | I6_MUTE); -} - -static void -ad_unmute(snddev_info *d) -{ - ad_write(d, 6, ad_read(d,6) & ~I6_MUTE); - ad_write(d, 7, ad_read(d,7) & ~I6_MUTE); -} -#endif - -static void -ad_enter_MCE(snddev_info *d) -{ - int prev; - - d->bd_flags |= BD_F_MCE_BIT; - AD_WAIT_INIT(d, 203); - prev = inb(io_Index_Addr(d)); - prev &= ~IA_TRD ; - outb(io_Index_Addr(d), prev | IA_MCE ) ; -} - -static void -ad_leave_MCE(snddev_info *d) -{ - u_long flags; - u_char prev; - - if ( (d->bd_flags & BD_F_MCE_BIT) == 0 ) { - printf("--- hey, leave_MCE: MCE bit was not set!\n"); - return; - } - - AD_WAIT_INIT(d, 1000); - - flags = spltty(); - d->bd_flags &= ~BD_F_MCE_BIT; - - prev = inb(io_Index_Addr(d)); - prev &= ~IA_TRD ; - outb(io_Index_Addr(d), prev & ~IA_MCE ); /* Clear the MCE bit */ - wait_for_calibration(d); - splx(flags); -} - -/* - * only one source can be set... - */ -static int -mss_set_recsrc(snddev_info *d, int mask) -{ - u_char recdev; - - mask &= d->mix_rec_devs; - switch (mask) { - case SOUND_MASK_LINE: - case SOUND_MASK_LINE3: - recdev = 0; - break; - - case SOUND_MASK_CD: - case SOUND_MASK_LINE1: - recdev = 0x40; - break; - - case SOUND_MASK_IMIX: - recdev = 0xc0; - break; - - case SOUND_MASK_MIC: - default: - mask = SOUND_MASK_MIC; - recdev = 0x80; - } - - ad_write(d, 0, (ad_read(d, 0) & 0x3f) | recdev); - ad_write(d, 1, (ad_read(d, 1) & 0x3f) | recdev); - - d->mix_recsrc = mask; - return 0; -} - -/* - * there are differences in the mixer depending on the actual sound - * card. - */ -static int -mss_mixer_set(snddev_info *d, int dev, int value) -{ - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; - - int regoffs; - mixer_tab *mix_d = &mix_devices; - - u_char old, val; - - if (dev > 31) - return EINVAL; - - if (!(d->mix_devs & (1 << dev))) - return EINVAL; - - if (d->bd_id == MD_OPTI931) - mix_d = &(opti931_devices); - - if ((*mix_d)[dev][LEFT_CHN].nbits == 0) { - DEB(printf("nbits = 0 for dev %d\n", dev) ); - return EINVAL; - } - - if (left > 100) - left = 100; - if (right > 100) - right = 100; - - - if ( (*mix_d)[dev][RIGHT_CHN].nbits == 0) /* Mono control */ - right = left; - - d->mix_levels[dev] = left | (right << 8); - -#if 0 - /* Scale volumes */ - left = mix_cvt[left]; - right = mix_cvt[right]; -#endif - /* - * Set the left channel - */ - - regoffs = (*mix_d)[dev][LEFT_CHN].regno; - old = val = ad_read(d, regoffs); - /* - * if volume is 0, mute chan. Otherwise, unmute. - */ - if (regoffs != 0) /* main input is different */ - val = (left == 0 ) ? old | 0x80 : old & 0x7f ; - - change_bits(mix_d, &val, dev, LEFT_CHN, left); - ad_write(d, regoffs, val); - DEB(printf("LEFT: dev %d reg %d old 0x%02x new 0x%02x\n", - dev, regoffs, old, val)); - - if ((*mix_d)[dev][RIGHT_CHN].nbits != 0) { /* have stereo */ - /* - * Set the right channel - */ - regoffs = (*mix_d)[dev][RIGHT_CHN].regno; - old = val = ad_read(d, regoffs); - if (regoffs != 1) - val = (right == 0 ) ? old | 0x80 : old & 0x7f ; - change_bits(mix_d, &val, dev, RIGHT_CHN, right); - ad_write(d, regoffs, val); - DEB(printf("RIGHT: dev %d reg %d old 0x%02x new 0x%02x\n", - dev, regoffs, old, val)); - } - return 0; /* success */ -} - -static void -ad1848_mixer_reset(snddev_info *d) -{ - int i; - - if (d->bd_id == MD_OPTI931) - d->mix_devs = OPTI931_MIXER_DEVICES; - else if (d->bd_id != MD_AD1848) - d->mix_devs = MODE2_MIXER_DEVICES; - else - d->mix_devs = MODE1_MIXER_DEVICES; - - d->mix_rec_devs = MSS_REC_DEVICES; - - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (d->mix_devs & (1 << i)) - mss_mixer_set(d, i, default_mixer_levels[i]); - mss_set_recsrc(d, SOUND_MASK_MIC); - /* - * some device-specific things, mostly mute the mic to - * the output mixer so as to avoid hisses. In many cases this - * is the default after reset, this code is here mostly as a - * reminder that this might be necessary on other boards. - */ - switch(d->bd_id) { - case MD_OPTI931: - ad_write(d, 20, 0x88); - ad_write(d, 21, 0x88); - break; - - case MD_YM0020: - /* set master volume to max */ - DDB(printf("set yamaha master volume to max\n"); ) - outb(0x370, 7) ; - outb(0x371, 0) ; - outb(0x370, 8) ; - outb(0x371, 0) ; - break; - - case MD_GUSPNP: - /* this is only necessary in mode 3 ... */ - ad_write(d, 22, 0x88); - ad_write(d, 23, 0x88); - } -} - -/* - * mss_speed processes the value in play_speed finding the - * matching one. As a side effect, it returns the value to - * be written in the speed bits of the codec. It does _NOT_ - * set the speed of the device (but it should!) - */ - -static int -mss_speed(snddev_info *d) -{ - /* - * In the CS4231, the low 4 bits of I8 are used to hold the - * sample rate. Only a fixed number of values is allowed. This - * table lists them. The speed-setting routines scans the table - * looking for the closest match. This is the only supported method. - * - * In the CS4236, there is an alternate metod (which we do not - * support yet) which provides almost arbitrary frequency setting. - * In the AD1845, it looks like the sample rate can be - * almost arbitrary, and written directly to a register. - * In the OPTi931, there is a SB command which provides for - * almost arbitrary frequency setting. - * - */ - static int speeds[] = { - 8000, 5512, 16000, 11025, 27429, 18900, 32000, 22050, - -1, 37800, -1, 44100, 48000, 33075, 9600, 6615 - }; - - int arg, i, sel = 0; /* assume entry 0 does not contain -1 */ - - arg = d->play_speed ; - - for (i=1; i < 16 ; i++) - if (speeds[i] >0 && abs(arg-speeds[i]) < abs(arg-speeds[sel]) ) - sel = i ; - - d->play_speed = d->rec_speed = speeds[sel] ; - return sel ; -} - -/* - * mss_format checks that the format is supported (or defaults to AFMT_U8) - * and returns the bit setting for the 1848 register corresponding to - * the desired format. - * - * fixed lr970724 - */ - -static int -mss_format(snddev_info *d) -{ - int i, arg = d->play_fmt ; - - /* - * The data format uses 3 bits (just 2 on the 1848). For each - * bit setting, the following array returns the corresponding format. - * The code scans the array looking for a suitable format. In - * case it is not found, default to AFMT_U8 (not such a good - * choice, but let's do it for compatibility...). - */ - - static int fmts[] = { - AFMT_U8, AFMT_MU_LAW, AFMT_S16_LE, AFMT_A_LAW, - -1, AFMT_IMA_ADPCM, AFMT_U16_BE, -1 - }; - - if ( (arg & d->audio_fmt) == 0 ) /* unsupported fmt, default to AFMT_U8 */ - arg = AFMT_U8 ; - - /* ulaw/alaw seems broken on the opti931... */ - if (d->bd_id == MD_OPTI931 || d->bd_id == MD_GUSPNP) { - if (arg == AFMT_MU_LAW) { - arg = AFMT_U8 ; - d->flags |= SND_F_XLAT8 ; - } else - d->flags &= ~SND_F_XLAT8 ; - } - /* - * check that arg is one of the supported formats in d->format; - * otherwise fallback to AFMT_U8 - */ - - for (i=0 ; i<8 ; i++) - if (arg == fmts[i]) break; - if (i==8) { /* not found, default to AFMT_U8 */ - arg = AFMT_U8 ; - i = 0 ; - } - d->play_fmt = d->rec_fmt = arg; - - return i ; -} - -/* - * mss_detect can be used in the probe and the attach routine. - * - * We store probe information in pcm_info[unit]. This descriptor - * is reinitialized just before the attach, so all relevant - * information is lost, and mss_detect must be run again in - * the attach routine if necessary. - */ - -int -mss_detect(struct isa_device *dev) -{ - int i; - u_char tmp, tmp1, tmp2 ; - snddev_info *d = &(pcm_info[dev->id_unit]); - char *name; - - d->io_base = dev->id_iobase; - d->bd_flags |= BD_F_MCE_BIT ; - if (d->bd_id != 0) { - printf("preselected bd_id 0x%04x -- %s\n", - d->bd_id, d->name ? d->name : "???"); - return 1; - } - - name = "AD1848" ; - d->bd_id = MD_AD1848; /* AD1848 or CS4248 */ - - /* - * Check that the I/O address is in use. - * - * bit 7 of the base I/O port is known to be 0 after the chip has - * performed its power on initialization. Just assume this has - * happened before the OS is starting. - * - * If the I/O address is unused, it typically returns 0xff. - */ - - for (i=0; i<10; i++) - if (inb(io_Index_Addr(d)) & IA_BUSY) - DELAY(10000); /* maybe busy, wait & retry later */ - else - break ; - if ((inb(io_Index_Addr(d)) & IA_BUSY) != 0x00) { /* Not a AD1848 */ - BVDDB(printf("mss_detect error, busy still set (0x%02x)\n", - inb(io_Index_Addr(d)))); - return 0; - } - /* - * Test if it's possible to change contents of the indirect - * registers. Registers 0 and 1 are ADC volume registers. The bit - * 0x10 is read only so try to avoid using it. - */ - - ad_write(d, 0, 0xaa); - ad_write(d, 1, 0x45);/* 0x55 with bit 0x10 clear */ - tmp1 = ad_read(d, 0) ; - tmp2 = ad_read(d, 1) ; - if ( tmp1 != 0xaa || tmp2 != 0x45) { - BVDDB(printf("mss_detect error - IREG (0x%02x/0x%02x) want 0xaa/0x45\n", - tmp1, tmp2)); - return 0; - } - - ad_write(d, 0, 0x45); - ad_write(d, 1, 0xaa); - tmp1 = ad_read(d, 0) ; - tmp2 = ad_read(d, 1) ; - - if (tmp1 != 0x45 || tmp2 != 0xaa) { - BVDDB(printf("mss_detect error - IREG2 (%x/%x)\n", tmp1, tmp2)); - return 0; - } - - /* - * The indirect register I12 has some read only bits. Lets try to - * change them. - */ - - tmp = ad_read(d, 12); - ad_write(d, 12, (~tmp) & 0x0f); - tmp1 = ad_read(d, 12); - - if ((tmp & 0x0f) != (tmp1 & 0x0f)) { - BVDDB(printf("mss_detect error - I12 (0x%02x was 0x%02x)\n", - tmp1, tmp)); - return 0; - } - - /* - * NOTE! Last 4 bits of the reg I12 tell the chip revision. - * 0x01=RevB - * 0x0A=RevC. also CS4231/CS4231A and OPTi931 - */ - - BVDDB(printf("mss_detect - chip revision 0x%02x\n", tmp & 0x0f);) - - /* - * The original AD1848/CS4248 has just 16 indirect registers. This - * means that I0 and I16 should return the same value (etc.). Ensure - * that the Mode2 enable bit of I12 is 0. Otherwise this test fails - * with new parts. - */ - - ad_write(d, 12, 0); /* Mode2=disabled */ - - for (i = 0; i < 16; i++) - if ((tmp1 = ad_read(d, i)) != (tmp2 = ad_read(d, i + 16))) { - BVDDB(printf("mss_detect warning - I%d: 0x%02x/0x%02x\n", - i, tmp1, tmp2)); - /* - * note - this seems to fail on the 4232 on I11. So we just break - * rather than fail. - */ - break ; /* return 0; */ - } - /* - * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit - * (0x40). The bit 0x80 is always 1 in CS4248 and CS4231. - * - * On the OPTi931, however, I12 is readonly and only contains the - * chip revision ID (as in the CS4231A). The upper bits return 0. - */ - - ad_write(d, 12, 0x40); /* Set mode2, clear 0x80 */ - - tmp1 = ad_read(d, 12); - if (tmp1 & 0x80) { - name = "CS4248" ; /* Our best knowledge just now */ - } - if ((tmp1 & 0xf0) == 0x00) { - BVDDB(printf("this should be an OPTi931\n");) - } else if ((tmp1 & 0xc0) == 0xC0) { - /* - * The 4231 has bit7=1 always, and bit6 we just set to 1. - * We want to check that this is really a CS4231 - * Verify that setting I0 doesn't change I16. - */ - ad_write(d, 16, 0); /* Set I16 to known value */ - - ad_write(d, 0, 0x45); - if ((tmp1 = ad_read(d, 16)) != 0x45) { /* No change -> CS4231? */ - - ad_write(d, 0, 0xaa); - if ((tmp1 = ad_read(d, 16)) == 0xaa) { /* Rotten bits? */ - BVDDB(printf("mss_detect error - step H(%x)\n", tmp1)); - return 0; - } - /* - * Verify that some bits of I25 are read only. - */ - - tmp1 = ad_read(d, 25); /* Original bits */ - ad_write(d, 25, ~tmp1); /* Invert all bits */ - if ((ad_read(d, 25) & 0xe7) == (tmp1 & 0xe7)) { - int id; - - /* - * It's at least CS4231 - */ - name = "CS4231" ; - d->bd_id = MD_CS4231; - - /* - * It could be an AD1845 or CS4231A as well. - * CS4231 and AD1845 report the same revision info in I25 - * while the CS4231A reports different. - */ - - id = ad_read(d, 25) & 0xe7; - /* - * b7-b5 = version number; - * 100 : all CS4231 - * 101 : CS4231A - * - * b2-b0 = chip id; - */ - switch (id) { - - case 0xa0: - name = "CS4231A" ; - d->bd_id = MD_CS4231A; - break; - - case 0xa2: - name = "CS4232" ; - d->bd_id = MD_CS4232; - break; - - case 0xb2: - /* strange: the 4231 data sheet says b4-b3 are XX - * so this should be the same as 0xa2 - */ - name = "CS4232A" ; - d->bd_id = MD_CS4232A; - break; - - case 0x80: - /* - * It must be a CS4231 or AD1845. The register I23 - * of CS4231 is undefined and it appears to be read - * only. AD1845 uses I23 for setting sample rate. - * Assume the chip is AD1845 if I23 is changeable. - */ - - tmp = ad_read(d, 23); - - ad_write(d, 23, ~tmp); - if (ad_read(d, 23) != tmp) { /* AD1845 ? */ - name = "AD1845" ; - d->bd_id = MD_AD1845; - } - ad_write(d, 23, tmp); /* Restore */ - DDB(printf("... try to identify the yamaha\n") ;) - tmp = inb(0x370) ; - outb(0x370, 6 /* dma config */ ) ; - if (inb(0x370) != 6 ) /* not a yamaha... restore. */ - outb(0x370, tmp ) ; - else - d->bd_id = MD_YM0020 ; - break; - - case 0x83: /* CS4236 */ - case 0x03: /* CS4236 on Intel PR440FX motherboard XXX */ - name = "CS4236"; - d->bd_id = MD_CS4236; - break ; - - default: /* Assume CS4231 */ - BVDDB(printf("unknown id 0x%02x, assuming CS4231\n", id);) - d->bd_id = MD_CS4231; - } - } - ad_write(d, 25, tmp1); /* Restore bits */ - - } - } - BVDDB(printf("mss_detect() - Detected %s\n", name)); - snprintf(d->name, sizeof(d->name), "%s", name); - dev->id_flags &= ~DV_F_DEV_MASK ; - dev->id_flags |= (d->bd_id << DV_F_DEV_SHIFT) & DV_F_DEV_MASK ; - return 1; -} - - -/* - * mss_reinit resets registers of the codec - */ -static void -mss_reinit(snddev_info *d) -{ - u_char r; - - r = mss_speed(d) ; - r |= (mss_format(d) << 5) ; - if (d->flags & SND_F_STEREO) - r |= 0x10 ; - /* XXX check if MCE is necessary... */ - ad_enter_MCE(d); - - /* - * perhaps this is not the place to set mode2, should be done - * only once at attach time... - */ - if ( FULL_DUPLEX(d) && d->bd_id != MD_OPTI931) - /* - * set mode2 bit for dual dma op. This bit is not implemented - * on the OPTi931 - */ - ad_write(d, 12, ad_read(d, 12) | 0x40 /* mode 2 on the CS42xx */ ); - - /* - * XXX this should really go into mss-speed... - */ - if (d->bd_id == MD_AD1845) { /* Use alternate speed select regs */ - r &= 0xf0; /* Mask off the rate select bits */ - - ad_write(d, 22, (d->play_speed >> 8) & 0xff); /* Speed MSB */ - ad_write(d, 23, d->play_speed & 0xff); /* Speed LSB */ - /* - * XXX must also do something in I27 for the ad1845 - */ - } - - ad_write(d, 8, r) ; - if ( FULL_DUPLEX(d) ) { -#if 0 - if (d->bd_id == MD_GUSPNP && d->play_fmt == AFMT_MU_LAW) { - printf("warning, cannot do ulaw rec + play on the GUS\n"); - r = 0 ; /* move to U8 */ - } -#endif - ad_write(d, 28, r & 0xf0 ) ; /* capture mode */ - ad_write(d, 9, 0 /* no capture, no playback, dual dma */) ; - } else - ad_write(d, 9, 4 /* no capture, no playback, single dma */) ; - ad_leave_MCE(d); - /* - * not sure if this is really needed... - */ - ad_write_cnt(d, 14, 0 ); /* playback count */ - if ( FULL_DUPLEX(d) ) - ad_write_cnt(d, 30, 0 ); /* rec. count on dual dma */ - - ad_write(d, 10, 2 /* int enable */) ; - outb(io_Status(d), 0); /* Clear interrupt status */ - /* the following seem required on the CS4232 */ - ad_write(d, 6, ad_read(d,6) & ~I6_MUTE); - ad_write(d, 7, ad_read(d,7) & ~I6_MUTE); - - snd_set_blocksize(d); /* update blocksize if user did not force it */ -} - -/* - * here we have support for PnP cards - * - */ - -#if NPNP > 0 - -static char * cs423x_probe(u_long csn, u_long vend_id); -static void -cs423x_attach(u_long csn, u_long vend_id, char *name, - struct isa_device *dev); - -static struct pnp_device cs423x = { - "CS423x/Yamaha/AD1816", - cs423x_probe, - cs423x_attach, - &nsnd, /* use this for all sound cards */ - &tty_imask /* imask */ -}; -DATA_SET (pnpdevice_set, cs423x); - -static char * -cs423x_probe(u_long csn, u_long vend_id) -{ - char *s = NULL ; - u_long id = vend_id & 0xff00ffff; - if ( id == 0x3700630e ) - s = "CS4237" ; - else if ( id == 0x2500630e ) - s = "CS4235" ; - else if ( id == 0x3600630e ) - s = "CS4236" ; - else if ( id == 0x3500630e ) - s = "CS4236B" ; - else if ( id == 0x3200630e) - s = "CS4232" ; - else if ( id == 0x2000a865) - s = "Yamaha SA2"; - else if ( id == 0x3000a865) - s = "Yamaha SA3"; - else if ( id == 0x0000a865) - s = "Yamaha YMF719 OPL-SA3"; - else if (vend_id == 0x8140d315) - s = "SoundscapeVIVO"; - else if (vend_id == 0x1114b250) - s = "Terratec Soundsystem BASE 1"; - else if (vend_id == 0x50719304) - s = "Generic AD1815"; - if (s) { - struct pnp_cinfo d; - read_pnp_parms(&d, 0); - if (d.enable == 0) { - printf("This is a %s, but LDN 0 is disabled\n", s); - return NULL ; - } - return s; - } - - return NULL ; -} - -extern snddev_info sb_op_desc; - -static void -cs423x_attach(u_long csn, u_long vend_id, char *name, - struct isa_device *dev) -{ - struct pnp_cinfo d ; - snddev_info tmp_d ; /* patched copy of the basic snddev_info */ - int ldn = 0 ; - - if (read_pnp_parms ( &d , ldn ) == 0 ) { - printf("failed to read pnp parms\n"); - return ; - } - snddev_last_probed = &tmp_d; - - /* AD1816 */ - if (vend_id == 0x1114b250 || vend_id == 0x50719304) { - dev->id_alive = 16; /* number of io ports ? */ - - tmp_d = mss_op_desc; /* copy it */ - - tmp_d.ioctl = ad1816_ioctl; - tmp_d.isr = ad1816_intr; - tmp_d.callback = ad1816_callback; - tmp_d.audio_fmt = AFMT_STEREO | AFMT_U8 | - AFMT_A_LAW | AFMT_MU_LAW | - AFMT_S16_LE | AFMT_S16_BE; - - dev->id_iobase = d.port[2]; - tmp_d.alt_base = d.port[0]; /* soundblaster comp. but we don't - * use that */ - tmp_d.bd_id = MD_AD1816; - strcpy(tmp_d.name, name); - } else if (d.flags & DV_PNP_SBCODEC) { /* use sb-compatible codec */ - dev->id_alive = 16 ; /* number of io ports ? */ - tmp_d = sb_op_desc ; - if (vend_id==0x2000a865 || vend_id==0x3000a865 || - vend_id==0x0008a865 || vend_id==0x8140d315) { - /* Yamaha SA2/SA3 or ENSONIQ SoundscapeVIVO ENS4081 */ - dev->id_iobase = d.port[0] ; - tmp_d.alt_base = d.port[1] ; - d.irq[1] = 0 ; /* only needed for the VIVO */ - } else { - dev->id_iobase = d.port[2] ; - tmp_d.alt_base = d.port[0] - 4; - } - d.drq[1] = 4 ; /* disable, it is not used ... */ - } else { /* mss-compatible codec */ - dev->id_alive = 8 ; /* number of io ports ? */ - tmp_d = mss_op_desc ; - dev->id_iobase = d.port[0] -4 ; /* XXX old mss have 4 bytes before... */ - tmp_d.alt_base = d.port[2]; - switch (vend_id & 0xff00ffff) { - - case 0x2000a865: /* Yamaha SA2 */ - case 0x3000a865: /* Yamaha SA3 */ - case 0x0000a865: /* Yamaha TMF719 SA3 */ - dev->id_iobase = d.port[1]; - tmp_d.alt_base = d.port[0]; - tmp_d.conf_base = d.port[4]; - tmp_d.bd_id = MD_YM0020 ; - break; - - case 0x8100d315: /* ENSONIQ SoundscapeVIVO */ - dev->id_iobase = d.port[1]; - tmp_d.alt_base = d.port[0]; - tmp_d.bd_id = MD_VIVO ; - d.irq[1] = 0 ; - break; - - case 0x3700630e: /* CS4237 */ - tmp_d.bd_id = MD_CS4237 ; - break; - - case 0x2500630e: /* AOpen AW37, CS4235 */ - tmp_d.bd_id = MD_CS4237 ; - break ; - - case 0x3500630e: /* CS4236B */ - case 0x3600630e: /* CS4236 */ - tmp_d.bd_id = MD_CS4236 ; - break; - - default: - tmp_d.bd_id = MD_CS4232; /* to short-circuit the - * detect routine */ - break; - } - snprintf(tmp_d.name, sizeof(tmp_d.name), "%s", name); - tmp_d.audio_fmt |= AFMT_FULLDUPLEX ; - } - - write_pnp_parms( &d, ldn ); - enable_pnp_card(); - - if ( (vend_id & 0x0000ffff) == 0x0000a865 ) { - /* special volume setting for the Yamaha... */ - outb(tmp_d.conf_base, 7 /* volume, left */); - outb(tmp_d.conf_base+1, 0 ); - outb(tmp_d.conf_base, 8 /* volume, right */); - outb(tmp_d.conf_base+1, 0 ); - } - dev->id_drq = d.drq[0] ; /* primary dma */ - dev->id_irq = (1 << d.irq[0] ) ; - dev->id_ointr = pcmintr ; - dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ; - - tmp_d.synth_base = d.port[1]; /* XXX check this for yamaha */ - pcmattach(dev); -} - -static char *opti931_probe(u_long csn, u_long vend_id); -static void opti931_attach(u_long csn, u_long vend_id, char *name, - struct isa_device *dev); -static struct pnp_device opti931 = { - "OPTi931", - opti931_probe, - opti931_attach, - &nsnd, /* use this for all sound cards */ - &tty_imask /* imask */ -}; -DATA_SET (pnpdevice_set, opti931); - -static char * -opti931_probe(u_long csn, u_long vend_id) -{ - if (vend_id == 0x3109143e) { - struct pnp_cinfo d; - read_pnp_parms(&d, 1); - if (d.enable == 0) { - printf("This is an OPTi931, but LDN 1 is disabled\n"); - return NULL ; - } - return "OPTi931" ; - } - return NULL ; -} - -static void -opti931_attach(u_long csn, u_long vend_id, char *name, - struct isa_device *dev) -{ - struct pnp_cinfo d ; - snddev_info tmp_d ; /* patched copy of the basic snddev_info */ - int p; - - read_pnp_parms ( &d , 3 ); /* free resources taken by LDN 3 */ - d.irq[0]=0; /* free irq... */ - d.port[0]=0; /* free address... */ - d.enable = 0 ; - write_pnp_parms ( &d , 3 ); - - read_pnp_parms ( &d , 2 ); /* disable LDN 2 */ - d.enable = 0 ; - write_pnp_parms ( &d , 2 ); - - read_pnp_parms ( &d , 1 ) ; - write_pnp_parms( &d, 1 ); - enable_pnp_card(); - - snddev_last_probed = &tmp_d; - tmp_d = d.flags & DV_PNP_SBCODEC ? sb_op_desc : mss_op_desc ; - - snprintf(tmp_d.name, sizeof(tmp_d.name), "%s", name); - - /* - * My MED3931 v.1.0 allocates 3 bytes for the config space, - * whereas v.2.0 allocates 4 bytes. What I know for sure is that the - * upper two ports must be used, and they should end on a boundary - * of 4 bytes. So I need the following trick... - */ - p = tmp_d.conf_base = (d.port[3] & ~3) + 2; /* config port */ - - /* - * now set default values for both modes. - */ - dev->id_iobase = d.port[0] - 4 ; /* old mss have 4 bytes before... */ - tmp_d.io_base = dev->id_iobase; /* needed for ad_write to work... */ - tmp_d.alt_base = d.port[2]; - tmp_d.synth_base = d.port[1]; - opti_write(p, 4, 0xd6 /* fifo empty, OPL3, audio enable, SB3.2 */ ); - ad_write (&tmp_d, 10, 2); /* enable interrupts */ - - if (d.flags & DV_PNP_SBCODEC) { /* sb-compatible codec */ - /* - * the 931 is not a real SB, it has important pieces of - * hardware controlled by both the MSS and the SB port... - */ - printf("--- opti931 in sb mode ---\n"); - opti_write(p, 6, 1); /* MCIR6 mss disable, sb enable */ - /* - * swap the main and alternate iobase address since we want - * to work in sb mode. - */ - dev->id_iobase = d.port[2] ; - tmp_d.alt_base = d.port[0] - 4; - dev->id_flags = DV_F_DUAL_DMA | d.drq[1] ; - } else { /* mss-compatible codec */ - tmp_d.bd_id = MD_OPTI931 ; /* to short-circuit the detect routine */ - opti_write(p, 6 , 2); /* MCIR6: mss enable, sb disable */ - opti_write(p, 5, 0x28); /* MCIR5: codec in exp. mode,fifo */ - dev->id_flags = DV_F_DUAL_DMA | d.drq[1] ; - tmp_d.audio_fmt |= AFMT_FULLDUPLEX ; /* not really well... */ - tmp_d.isr = opti931_intr; - } - dev->id_drq = d.drq[0] ; /* primary dma */ - dev->id_irq = (1 << d.irq[0] ) ; - dev->id_ointr = pcmintr ; - pcmattach(dev); -} - -static char *opti925_probe(u_long csn, u_long vend_id); -static void opti925_attach(u_long csn, u_long vend_id, char *name, - struct isa_device *dev); - -static struct pnp_device opti925 = { - "opti925", - opti925_probe, - opti925_attach, - &nsnd, /* use this for all sound cards */ - &tty_imask /* imask */ -}; -DATA_SET (pnpdevice_set, opti925); - -static char * -opti925_probe(u_long csn, u_long vend_id) -{ - if (vend_id == 0x2509143e) { - struct pnp_cinfo d ; - read_pnp_parms ( &d , 1 ) ; - if (d.enable == 0) { - printf("This is an OPTi925, but LDN 1 is disabled\n"); - return NULL; - } - return "OPTi925" ; - } - return NULL ; -} - -static void -opti925_attach(u_long csn, u_long vend_id, char *name, - struct isa_device *dev) -{ - struct pnp_cinfo d ; - snddev_info tmp_d ; /* patched copy of the basic snddev_info */ - int the_irq = 0 ; - - tmp_d = mss_op_desc; - snddev_last_probed = &tmp_d; - - read_pnp_parms ( &d , 3 ); /* disable LDN 3 */ - the_irq = d.irq[0]; - d.port[0] = 0 ; - d.enable = 0 ; - write_pnp_parms ( &d , 3 ); - - read_pnp_parms ( &d , 2 ); /* disable LDN 2 */ - d.port[0] = 0 ; - d.enable = 0 ; - write_pnp_parms ( &d , 2 ); - - read_pnp_parms ( &d , 1 ) ; - d.irq[0] = the_irq ; - dev->id_iobase = d.port[1]; - tmp_d.alt_base = d.port[0]; - write_pnp_parms ( &d , 1 ); - enable_pnp_card(); - - tmp_d.conf_base = d.port[3]; - - dev->id_drq = d.drq[0] ; /* primary dma */ - dev->id_irq = (1 << d.irq[0] ) ; - dev->id_ointr = pcmintr ; - dev->id_flags = DV_F_DUAL_DMA | d.drq[1] ; - tmp_d.audio_fmt |= AFMT_FULLDUPLEX ; - - snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */ - - pcmattach(dev); -} - -#if 0 -static void gus_mem_cfg(snddev_info *tmp); -#endif - -static char *guspnp_probe(u_long csn, u_long vend_id); -static void guspnp_attach(u_long csn, u_long vend_id, char *name, - struct isa_device *dev); -static struct pnp_device guspnp = { - "GusPnP", - guspnp_probe, - guspnp_attach, - &nsnd, /* use this for all sound cards */ - &tty_imask /* imask */ -}; -DATA_SET (pnpdevice_set, guspnp); - -static char * -guspnp_probe(u_long csn, u_long vend_id) -{ - if (vend_id == 0x0100561e) { - struct pnp_cinfo d; - read_pnp_parms(&d, 0); - if (d.enable == 0) { - printf("This is a GusPnP, but LDN 0 is disabled\n"); - return NULL ; - } - return "GusPnP" ; - } - return NULL ; -} - -static void -guspnp_attach(u_long csn, u_long vend_id, char *name, - struct isa_device *dev) -{ - struct pnp_cinfo d ; - snddev_info tmp_d ; /* patched copy of the basic snddev_info */ - - u_char tmp; - - read_pnp_parms ( &d , 0 ) ; - - /* d.irq[1] = d.irq[0] ; */ - pnp_write ( 0xf2, 0xff ); /* enable power on the guspnp */ - - write_pnp_parms ( &d , 0 ); - enable_pnp_card(); - - tmp_d = mss_op_desc ; - snddev_last_probed = &tmp_d; - - dev->id_iobase = d.port[2] - 4 ; /* room for 4 mss registers */ - dev->id_drq = d.drq[1] ; /* XXX PLAY dma */ - dev->id_irq = (1 << d.irq[0] ) ; - dev->id_ointr = pcmintr ; - dev->id_flags = DV_F_DUAL_DMA | d.drq[0] ; /* REC dma */ - - tmp_d.io_base = d.port[2] - 4; - tmp_d.alt_base = d.port[0]; /* 0x220 */ - tmp_d.conf_base = d.port[1]; /* gus control block... */ - tmp_d.bd_id = MD_GUSPNP ; - - /* reset */ - gus_write(tmp_d.conf_base, 0x4c /* _URSTI */, 0 );/* Pull reset */ - DELAY(1000 * 30); - /* release reset and enable DAC */ - gus_write(tmp_d.conf_base, 0x4c /* _URSTI */, 3 ); - DELAY(1000 * 30); - /* end of reset */ - - outb( tmp_d.alt_base, 0xC ); /* enable int and dma */ - - /* - * unmute left & right line. Need to go in mode3, unmute, - * and back to mode 2 - */ - tmp = ad_read(&tmp_d, 0x0c); - ad_write(&tmp_d, 0x0c, 0x6c ); /* special value to enter mode 3 */ - ad_write(&tmp_d, 0x19, 0 ); /* unmute left */ - ad_write(&tmp_d, 0x1b, 0 ); /* unmute right */ - ad_write(&tmp_d, 0x0c, tmp ); /* restore old mode */ - - /* send codec interrupts on irq1 and only use that one */ - gus_write(tmp_d.conf_base, 0x5a , 0x4f ); - - /* enable access to hidden regs */ - tmp = gus_read(tmp_d.conf_base, 0x5b /* IVERI */ ); - gus_write(tmp_d.conf_base, 0x5b , tmp | 1 ); - BVDDB(printf("GUS: silicon rev %c\n", 'A' + ( ( tmp & 0xf ) >> 4) );) - - snprintf(tmp_d.name, sizeof(tmp_d.name), "%s", name); - - pcmattach(dev); -} - -#if 0 -int -gus_mem_write(snddev_info *d, int addr, u_char data) -{ - gus_writew(d->conf_base, 0x43 , addr & 0xffff ); - gus_write(d->conf_base, 0x44 , (addr>>16) & 0xff ); - outb(d->conf_base + 7, data); -} - -u_char -gus_mem_read(snddev_info *d, int addr) -{ - gus_writew(d->conf_base, 0x43 , addr & 0xffff ); - gus_write(d->conf_base, 0x44 , (addr>>16) & 0xff ); - return inb(d->conf_base + 7); -} - -void -gus_mem_cfg(snddev_info *d) -{ - int base; - u_char old; - u_char a, b; - - printf("configuring gus memory...\n"); - gus_writew(d->conf_base, 0x52 /* LMCFI */, 1 /* 512K*/); - old = gus_read(d->conf_base, 0x19); - gus_write(d->conf_base, 0x19, old | 1); /* enable enhaced mode */ - for (base = 0; base < 1024; base++) { - a=gus_mem_read(d, base*1024); - a = ~a ; - gus_mem_write(d, base*1024, a); - b=gus_mem_read(d, base*1024); - if ( b != a ) - break ; - } - printf("Have found %d KB ( 0x%x != 0x%x)\n", base, a, b); -} -#endif /* gus mem cfg... */ - -static int -ad1816_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p) -{ - snddev_info *d; - int unit; - int dev; - - dev = minor(i_dev); - unit = dev >> 4; - d = &pcm_info[unit]; - - if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) { - cmd &= 0xff; - if (cmd == SOUND_MIXER_RECSRC) - return ad1816_set_recsrc(d, *(int *) arg); - else - return ad1816_mixer_set(d, cmd, *(int *) arg); - } - switch (cmd) { /* driver specific ioctls other than mixer - * calls */ - /* ad1816 has special features */ - case AIOGCAP: /* get capabilities */ - { - snd_capabilities *p = (snd_capabilities *) arg; - p->rate_min = 4000; - p->rate_max = 55200; - p->bufsize = d->bufsize; - p->formats = d->audio_fmt; - p->mixers = 1; - p->inputs = d->mix_devs; - p->left = p->right = 100; - return 0; - } - default: - { - return ENOSYS; /* fallback to default */ - } - break; - } -} - -static int -ad1816_callback(snddev_info * d, int reason) -{ - int wr, cnt; - - wr = reason & SND_CB_WR; - reason &= SND_CB_REASON_MASK; - - switch (reason) { - case SND_CB_INIT: - ad1816_reinit(d); - reset_dbuf(&(d->dbuf_in), SND_CHAN_RD); - reset_dbuf(&(d->dbuf_out), SND_CHAN_WR); - return 1; - break; - - case SND_CB_START: - cnt = wr ? d->dbuf_out.dl : d->dbuf_in.dl; - - cnt /= 4; - cnt--; - - /* start only if not already running */ - if (wr && !(inb(ad1816_play(d)) & AD1816_ENABLE)) { - /* set dma counter */ - ad1816_write(d, 8, cnt); /* playback count */ - /* int enable */ - ad1816_write(d, 1, ad1816_read(d, 1) | 0x8000); - /* enable playback */ - outb(ad1816_play(d), (inb(ad1816_play(d)) | AD1816_ENABLE)); - /* check if we succeeded */ - if (!(inb(ad1816_play(d)) & AD1816_ENABLE)) { - printf("ad1816: failed to start write (playback) DMA !\n"); - } - } else if (!wr && !(inb(ad1816_capt(d)) & AD1816_ENABLE)) { - /* same for capture */ - ad1816_write(d, 10, cnt); /* capture count */ - ad1816_write(d, 1, ad1816_read(d, 1) | 0x4000); /* int */ - outb(ad1816_capt(d), (inb(ad1816_capt(d)) | AD1816_ENABLE)); /* CEN */ - if (!(inb(ad1816_capt(d)) & AD1816_ENABLE)) { /* check */ - printf("ad1816: failed to start read (capture) DMA !\n"); - } - } - break; - - case SND_CB_STOP: - case SND_CB_ABORT: /* XXX check this... */ - /* we don't test here if it is running... */ - if (wr) { - ad1816_write(d, 1, ad1816_read(d, 1) & ~0x8000); - /* disable int */ - outb(ad1816_play(d), (inb(ad1816_play(d)) & ~AD1816_ENABLE)); - /* disable playback */ - if ((inb(ad1816_play(d)) & AD1816_ENABLE)) { - printf("ad1816: failed to stop write (playback) DMA !\n"); - } - ad1816_write(d, 8, 0); /* reset base counter */ - ad1816_write(d, 9, 0); /* reset cur counter */ - } else { - /* same for capture */ - ad1816_write(d, 1, ad1816_read(d, 1) & ~0x4000); - outb(ad1816_capt(d), (inb(ad1816_capt(d)) & ~AD1816_ENABLE)); - if ((inb(ad1816_capt(d)) & AD1816_ENABLE)) { - printf("ad1816: failed to stop read (capture) DMA !\n"); - } - ad1816_write(d, 10, 0); - ad1816_write(d, 11, 0); - } - break; - } - - return 0; -} - -static void -ad1816_intr(int unit) -{ - snddev_info *d = &pcm_info[unit]; - unsigned char c, served = 0; - - /* get interupt status */ - c = inb(ad1816_int(d)); - - /* check for stray interupts */ - if (c & ~(AD1816_INTRCI | AD1816_INTRPI)) { - printf("ad1816: Stray interrupt 0x%x.\n", c); - c = c & (AD1816_INTRCI | AD1816_INTRPI); - outb(ad1816_int(d), c); /* ack it anyway */ - } - /* check for capture interupt */ - if (d->dbuf_in.dl && (c & AD1816_INTRCI)) { - outb(ad1816_int(d), c & ~AD1816_INTRCI); /* ack it */ - if (inb(ad1816_int(d)) & AD1816_INTRCI) - printf("ad1816: Failed to clear cp int !!!\n"); - dsp_rdintr(d); - served |= AD1816_INTRCI; /* cp served */ - } - /* check for playback interupt */ - if (d->dbuf_out.dl && (c & AD1816_INTRPI)) { - outb(ad1816_int(d), c & ~AD1816_INTRPI); /* ack it */ - if ((inb(ad1816_int(d)) & AD1816_INTRPI) != 0) - printf("ad1816: Failed to clear pb int !!!\n"); - dsp_wrintr(d); - served |= AD1816_INTRPI; /* pb served */ - } - if (served == 0) { - /* this probably means this is not a (working) ad1816 chip, */ - /* or an error in dma handling */ - printf("ad1816: raised an interrupt without reason 0x%x.\n", c); - outb(ad1816_int(d), 0); /* Clear interrupt status anyway */ - } -} - -static int -ad1816_wait_init(snddev_info * d, int x) -{ - int n = 0; /* to shut up the compiler... */ - - for (; x--;) - if (((n = (inb(ad1816_ale(d)) & AD1816_BUSY))) == 0) - DELAY(10); - else - return n; - printf("ad1816_wait_init failed 0x%02x.\n", inb(ad1816_ale(d))); - return n; -} - -static unsigned short -ad1816_read(snddev_info * d, unsigned int reg) -{ - int flags; - u_short x; - - /* we don't want to be blocked here */ - flags = spltty(); - if (ad1816_wait_init(d, 100) == 0) { - printf("ad1816_read: chip timeout before read.\n"); - return 0; - } - outb(ad1816_ale(d), (u_char) 0); - outb(ad1816_ale(d), (u_char) (reg & AD1816_ALEMASK)); - if (ad1816_wait_init(d, 100) == 0) { - printf("ad1816_read: chip timeout during read.\n"); - return 0; - } - x = (inb(ad1816_high(d)) << 8) | inb(ad1816_low(d)); - splx(flags); - return x; -} - -static void -ad1816_write(snddev_info * d, unsigned int reg, unsigned short data) -{ - int flags; - - flags = spltty(); - if (ad1816_wait_init(d, 100) == 0) { - printf("ad1816_write: chip timeout before write.\n"); - return; - } - outb(ad1816_ale(d), (u_char) (reg & AD1816_ALEMASK)); - outb(ad1816_low(d), (u_char) (data & 0x000000ff)); - outb(ad1816_high(d), (u_char) ((data & 0x0000ff00) >> 8)); - splx(flags); -} - -#if 0 /* unused right now..., and untested... */ -static void -ad1816_mute(snddev_info * d) -{ - ad1816_write(d, 14, ad1816_read(d, 14) | 0x8000 | 0x80); -} - -static void -ad1816_unmute(snddev_info * d) -{ - ad1816_write(d, 14, ad1816_read(d, 14) & ~(0x8000 | 0x80)); -} -#endif - -/* only one rec source is possible */ - -static int -ad1816_set_recsrc(snddev_info * d, int mask) -{ - mask &= d->mix_rec_devs; - - switch (mask) { - case SOUND_MASK_LINE: - case SOUND_MASK_LINE3: - ad1816_write(d, 20, (ad1816_read(d, 20) & ~0x7070) | 0x0000); - break; - - case SOUND_MASK_CD: - case SOUND_MASK_LINE1: - ad1816_write(d, 20, (ad1816_read(d, 20) & ~0x7070) | 0x2020); - break; - - case SOUND_MASK_MIC: - default: - ad1816_write(d, 20, (ad1816_read(d, 20) & ~0x7070) | 0x5050); - } - - d->mix_recsrc = mask; - - return 0; /* success */ -} - -#define AD1816_MUTE 31 /* value for mute */ - -static int -ad1816_mixer_set(snddev_info * d, int dev, int value) -{ - u_char left = (value & 0x000000ff); - u_char right = (value & 0x0000ff00) >> 8; - u_short reg = 0; - - if (dev > 31) - return EINVAL; - - if (!(d->mix_devs & (1 << dev))) - return EINVAL; - - if (left > 100) - left = 100; - if (right > 100) - right = 100; - - d->mix_levels[dev] = left | (right << 8); - - /* Scale volumes */ - left = AD1816_MUTE - (AD1816_MUTE * left) / 100; - right = AD1816_MUTE - (AD1816_MUTE * right) / 100; - - reg = (left << 8) | right; - - /* do channel selective muting if volume is zero */ - if (left == AD1816_MUTE) - reg |= 0x8000; - if (right == AD1816_MUTE) - reg |= 0x0080; - - switch (dev) { - case SOUND_MIXER_VOLUME: /* Register 14 master volume */ - ad1816_write(d, 14, reg); - break; - case SOUND_MIXER_CD: /* Register 15 cd */ - case SOUND_MIXER_LINE1: - ad1816_write(d, 15, reg); - break; - case SOUND_MIXER_SYNTH: /* Register 16 synth */ - ad1816_write(d, 16, reg); - break; - case SOUND_MIXER_PCM: /* Register 4 pcm */ - ad1816_write(d, 4, reg); - break; - case SOUND_MIXER_LINE: - case SOUND_MIXER_LINE3: /* Register 18 line in */ - ad1816_write(d, 18, reg); - break; - case SOUND_MIXER_MIC: /* Register 19 mic volume */ - ad1816_write(d, 19, reg & ~0xff); /* mic is mono */ - break; - case SOUND_MIXER_IGAIN: - /* and now to something completely different ... */ - ad1816_write(d, 20, ((ad1816_read(d, 20) & ~0x0f0f) - | (((AD1816_MUTE - left) / 2) << 8) /* four bits of adc gain */ - | ((AD1816_MUTE - right) / 2))); - break; - default: - printf("ad1816_mixer_set(): unknown device.\n"); - break; - } - - return 0; /* success */ -} - -static void -ad1816_mixer_reset(snddev_info * d) -{ - int i; - - d->mix_devs = AD1816_MIXER_DEVICES; - d->mix_rec_devs = AD1816_REC_DEVICES; - - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - if (d->mix_devs & (1 << i)) - ad1816_mixer_set(d, i, default_mixer_levels[i]); - ad1816_set_recsrc(d, SOUND_MASK_MIC); -} - -/* Set the playback and capture rates. */ - -static int -ad1816_speed(snddev_info * d) -{ - RANGE(d->play_speed,4000,55200); - RANGE(d->rec_speed,4000,55200); - - ad1816_write(d, 2, d->play_speed); - ad1816_write(d, 3, d->rec_speed); - - return d->play_speed; -} - -/* - * ad1816_format checks that the format is supported (or defaults to AFMT_U8) - * and sets the chip to the desired format. - */ - -static int -ad1816_format(snddev_info * d) -{ - int oldplay =inb(ad1816_play(d)) & ~AD1816_FORMASK; - int oldrec = inb(ad1816_capt(d)) & ~AD1816_FORMASK; - int play = (d->play_fmt & d->audio_fmt) ? d->play_fmt : AFMT_U8; - int rec = (d->rec_fmt & d->audio_fmt) ? d->rec_fmt : AFMT_U8; - - /* - * check that arg is one of the supported formats in d->format; otherwise - * fallback to AFMT_U8 - */ - - switch (play) { - case AFMT_A_LAW: - outb(ad1816_play(d), oldplay | AD1816_ALAW); - break; - case AFMT_MU_LAW: - outb(ad1816_play(d), oldplay | AD1816_MULAW); - break; - case AFMT_S16_LE: - outb(ad1816_play(d), oldplay | AD1816_S16LE); - break; - case AFMT_S16_BE: - outb(ad1816_play(d), oldplay | AD1816_S16BE); - break; - default: - /* unlikely to happen */ - printf("ad1816: unknown play format. defaulting to U8.\n"); - case AFMT_U8: - outb(ad1816_play(d), oldplay | AD1816_U8); - break; - } - - switch (rec) { - case AFMT_A_LAW: - outb(ad1816_capt(d), oldrec | AD1816_ALAW); - break; - case AFMT_MU_LAW: - outb(ad1816_capt(d), oldrec | AD1816_MULAW); - break; - case AFMT_S16_LE: - outb(ad1816_capt(d), oldrec | AD1816_S16LE); - break; - case AFMT_S16_BE: - outb(ad1816_capt(d), oldrec | AD1816_S16BE); - break; - default: - printf("ad1816: unknown capture format. defaulting to U8.\n"); - case AFMT_U8: - outb(ad1816_capt(d), oldrec | AD1816_U8); - break; - } - - d->play_fmt = play; - d->rec_fmt = rec; - - return (play); -} - -/* - * ad1816_reinit resets codec registers - */ -static void -ad1816_reinit(snddev_info * d) -{ - ad1816_write(d, 8, 0x0000); /* reset base and current counter */ - ad1816_write(d, 9, 0x0000); /* for playback and capture */ - ad1816_write(d, 10, 0x0000); - ad1816_write(d, 11, 0x0000); - - if (d->flags & SND_F_STEREO) { - outb((ad1816_play(d)), AD1816_STEREO); /* set playback to stereo */ - outb((ad1816_capt(d)), AD1816_STEREO); /* set capture to stereo */ - } else { - outb((ad1816_play(d)), 0x00); /* set playback to mono */ - outb((ad1816_capt(d)), 0x00); /* set capture to mono */ - } - - ad1816_format(d); - ad1816_speed(d); - - snd_set_blocksize(d); /* update blocksize if user did not force it */ -} - -#endif /* NPNP > 0 */ -#endif /* NPCM > 0 */ diff --git a/sys/i386/isa/snd/clones.c b/sys/i386/isa/snd/clones.c deleted file mode 100644 index 492793281504..000000000000 --- a/sys/i386/isa/snd/clones.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * sound/clones.c - * - * init code for enabling clone cards to work in sb/mss emulation. - * - * Note -- this code is currently unused! - * - * Copyright by Luigi Rizzo - 1997 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. 2. Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * This file has been written using information from various sources - * in the Voxware 3.5 distribution. - */ - -#include -#if NPCM > 0 - -/* - * Known clones card include: - * - * Trix (emulating MSS) - * MAD16 (emulating MSS) - * OPTi930 -- same as the OPTi931, but no PnP ? - */ - - -#ifdef JAZZ16 - -/* - * Initialization of a Media Vision ProSonic 16 Soundcard. The function - * initializes a ProSonic 16 like PROS.EXE does for DOS. It sets the base - * address, the DMA-channels, interrupts and enables the joystickport. - * - * Also used by Jazz 16 (same card, different name) - * - * written 1994 by Rainer Vranken E-Mail: - * rvranken@polaris.informatik.uni-essen.de - */ - -#ifdef SM_WAVE -/* - * Logitech Soundman Wave detection and initialization by Hannu Savolainen. - * - * There is a microcontroller (8031) in the SM Wave card for MIDI emulation. - * it's located at address MPU_BASE+4. MPU_BASE+7 is a SM Wave specific - * control register for MC reset, SCSI, OPL4 and DSP (future expansion) - * address decoding. Otherwise the SM Wave is just a ordinary MV Jazz16 based - * soundcard. - */ - -static void -smw_putmem(int base, int addr, u_char val) -{ - u_long s; - - s = spltty(); - - outb(base + 1, addr & 0xff); /* Low address bits */ - outb(base + 2, addr >> 8); /* High address bits */ - outb(base, val); /* Data */ - - splx(s); -} - -static u_char -smw_getmem(int base, int addr) -{ - u_long s; - u_char val; - - s = spltty(); - - outb(base + 1, addr & 0xff); /* Low address bits */ - outb(base + 2, addr >> 8); /* High address bits */ - val = inb(base); /* Data */ - - splx(s); - return val; -} - -#ifdef SMW_MIDI0001_INCLUDED -#include -#else -u_char *smw_ucode = NULL; -int smw_ucodeLen = 0; -#endif /* SWM_MIDI0001_INCLUDED */ - -static int -initialize_smw(int mpu_base) -{ - - int i, mp_base = mpu_base + 4; /* Microcontroller base */ - u_char control; - - /* - * Reset the microcontroller so that the RAM can be accessed - */ - - control = inb(mpu_base + 7); - outb(mpu_base + 7, control | 3); /* Set last two bits to 1 (?) */ - outb(mpu_base + 7, (control & 0xfe) | 2); /* xxxxxxx0 resets the mc */ - DELAY(3000); /* Wait at least 1ms */ - - outb(mpu_base + 7, control & 0xfc); /* xxxxxx00 enables RAM */ - - /* - * Detect microcontroller by probing the 8k RAM area - */ - smw_putmem(mp_base, 0, 0x00); - smw_putmem(mp_base, 1, 0xff); - DELAY(10); - - if (smw_getmem(mp_base, 0) != 0x00 || smw_getmem(mp_base, 1) != 0xff) { - printf("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n", - smw_getmem(mp_base, 0), smw_getmem(mp_base, 1)); - return 0; /* No RAM */ - } - /* - * There is RAM so assume it's really a SM Wave - */ - - if (smw_ucodeLen > 0) { - if (smw_ucodeLen != 8192) { - printf("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n"); - return 1; - } - /* - * Download microcode - */ - - for (i = 0; i < 8192; i++) - smw_putmem(mp_base, i, smw_ucode[i]); - - /* - * Verify microcode - */ - - for (i = 0; i < 8192; i++) - if (smw_getmem(mp_base, i) != smw_ucode[i]) { - printf("SM Wave: Microcode verification failed\n"); - return 0; - } - } - control = 0; -#ifdef SMW_SCSI_IRQ - /* - * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt - * is disabled by default. - * - * Btw the Zilog 5380 SCSI controller is located at MPU base + 0x10. - */ - { - static u_char scsi_irq_bits[] = - {0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0}; - - control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6; - } -#endif - -#ifdef SMW_OPL4_ENABLE - /* - * Make the OPL4 chip visible on the PC bus at 0x380. - * - * There is no need to enable this feature since VoxWare doesn't support - * OPL4 yet. Also there is no RAM in SM Wave so enabling OPL4 is - * pretty useless. - */ - control |= 0x10; /* Uses IRQ12 if bit 0x20 == 0 */ - /* control |= 0x20; Uncomment this if you want to use IRQ7 */ -#endif - - outb(mpu_base + 7, control | 0x03); /* xxxxxx11 restarts */ - return 1; -} - -#endif - -/* - * this is only called during the probe. Variables are found in - * sb_probed. - */ -static sbdev_info sb_probed ; -static int -initialize_ProSonic16(snddev_info *d) -{ - int x; - static u_char int_translat[16] = - {0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6}, - dma_translat[8] = - {0, 1, 0, 2, 0, 3, 0, 4}; - - struct address_info *mpu_config = NULL; - - int mpu_base, mpu_irq; - - if (mpu_config != NULL) { /* XXX dead code? */ - mpu_base = mpu_config->io_base; - mpu_irq = mpu_config->irq; - } else { - mpu_base = mpu_irq = 0; - } - - outb(0x201, 0xAF); /* ProSonic/Jazz16 wakeup */ - DELAY(15000); /* wait at least 10 milliseconds */ - outb(0x201, 0x50); - outb(0x201, (sb_probed.io_base & 0x70) | ((mpu_base & 0x30) >> 4)); - - if (sb_reset_dsp(sb_probed.io_base)) { /* OK. We have at least a SB */ - - /* Check the version number of ProSonic (I guess) */ - - if (!sb_cmd(sb_probed.io_base, 0xFA)) - return 1; - if (sb_get_byte(sb_probed.io_base) != 0x12) - return 1; - - if (sb_cmd(sb_probed.io_base, 0xFB) && /* set DMA and irq */ - sb_cmd(sb_probed.io_base, - (dma_translat[JAZZ_DMA16]<<4)|dma_translat[sb_probed.dbuf_out.chan]) && - sb_cmd(sb_probed.io_base, - (int_translat[mpu_irq]<<4)|int_translat[sb_probed.irq])) { - d->bf_flags |= BD_F_JAZZ16 ; - if (mpu_base == 0) - printf("Jazz16: No MPU401 devices configured " - "- MIDI port not initialized\n"); - -#ifdef SM_WAVE - if (mpu_base != 0) - if (initialize_smw(mpu_base)) - d->bf_flags |= BD_F_JAZZ16_2 ; -#endif - /* sb_dsp_disable_midi(); */ - } - return 1; /* There was at least a SB */ - } - return 0; /* No SB or ProSonic16 detected */ -} - -#endif /* ifdef JAZZ16 */ - -#endif /* NPCM */ diff --git a/sys/i386/isa/snd/dmabuf.c b/sys/i386/isa/snd/dmabuf.c deleted file mode 100644 index 66f94ac55267..000000000000 --- a/sys/i386/isa/snd/dmabuf.c +++ /dev/null @@ -1,810 +0,0 @@ -/* - * snd/dmabuf.c - * - * This file implements the new DMA routines for the sound driver. - * AUTO DMA MODE (ISA DMA SIDE). - * - * Copyright by Luigi Rizzo - 1997-99 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include - -#define MIN_CHUNK_SIZE 256 /* for uiomove etc. */ -#define DMA_ALIGN_THRESHOLD 4 -#define DMA_ALIGN_MASK (~ (DMA_ALIGN_THRESHOLD - 1)) - -static void dsp_wr_dmadone(snddev_info *d); -static void dsp_rd_dmadone(snddev_info *d); - -/* - * SOUND OUTPUT - -We use a circular buffer to store samples directed to the DAC. -The buffer is split into two variable-size regions, each identified -by an offset in the buffer (rp,fp) and a length (rl,fl): - - 0 rp,rl fp,fl bufsize - |__________>____________>________| - FREE d READY w FREE - - READY: data written from the process and ready to be sent to the DAC; - FREE: free part of the buffer. - -Both regions can wrap around the end of the buffer. At initialization, -READY is empty, FREE takes all the available space, and dma is -idle. dl contains the length of the current DMA transfer, dl=0 -means that the dma is idle. - -The two boundaries (rp,fp) in the buffers are advanced by DMA [d] -and write() [w] operations. The first portion of the READY region -is used for DMA transfers. The transfer is started at rp and with -chunks of length dl. During DMA operations, dsp_wr_dmaupdate() -updates rp, rl and fl tracking the ISA DMA engine as the transfer -makes progress. -When a new block is written, fp advances and rl,fl are updated -accordingly. - -The code works as follows: the user write routine dsp_write_body() -fills up the READY region with new data (reclaiming space from the -FREE region) and starts the write DMA engine if inactive. When a -DMA transfer is complete, an interrupt causes dsp_wrintr() to be -called which extends the FREE region and possibly starts the next -transfer. - -In some cases, the code tries to track the current status of DMA -operations by calling dsp_wr_dmaupdate() which changes rp, rl and fl. - -The sistem tries to make all DMA transfers use the same size, -play_blocksize or rec_blocksize. The size is either selected by -the user, or computed by the system to correspond to about .25s of -audio. The blocksize must be within a range which is currently: - - min(5ms, 40 bytes) ... 1/2 buffer size. - -When there aren't enough data (write) or space (read), a transfer -is started with a reduced size. - -To reduce problems in case of overruns, the routine which fills up -the buffer should initialize (e.g. by repeating the last value) a -reasonably long area after the last block so that no noise is -produced on overruns. - - * - */ - - -/* - * dsp_wr_dmadone() updates pointers and wakes up any process sleeping - * or waiting on a select(). - * Must be called at spltty(). - */ -static void -dsp_wr_dmadone(snddev_info *d) -{ - snd_dbuf *b = & (d->dbuf_out) ; - - if (d->special_dma) - d->callback(d, SND_CB_WR | SND_CB_DMAUPDATE) ; - else - dsp_wr_dmaupdate(b); - /* - * XXX here it would be more efficient to record if there - * actually is a sleeping process, but this should still work. - */ - wakeup(b); /* wakeup possible sleepers */ - if (b->sel.si_pid && - ( !(d->flags & SND_F_HAS_SIZE) || b->fl >= d->play_blocksize ) ) - selwakeup( & b->sel ); -} - -/* - * dsp_wr_dmaupdate() tracks the status of a (write) dma transfer, - * updating pointers. It must be called at spltty() and the ISA DMA must - * have been started. - * - * NOTE: when we are using auto dma in the device, rl might become - * negative. - */ -void -dsp_wr_dmaupdate(snd_dbuf *b) -{ - int tmp, delta; - - tmp = b->bufsize - isa_dmastatus1(b->chan) ; - tmp &= DMA_ALIGN_MASK; /* align... */ - delta = tmp - b->rp; - if (delta < 0) /* wrapped */ - delta += b->bufsize ; - b->rp = tmp; - b->rl -= delta ; - b->fl += delta ; - b->total += delta ; -} - -/* - * Write interrupt routine. Can be called from other places (e.g. - * to start a paused transfer), but with interrupts disabled. - */ -void -dsp_wrintr(snddev_info *d) -{ - snd_dbuf *b = & (d->dbuf_out) ; - - if (b->dl) { /* dma was active */ - b->int_count++; - dsp_wr_dmadone(d); - } - - DEB(if (b->rl < 0) - printf("dsp_wrintr: dl %d, rp:rl %d:%d, fp:fl %d:%d\n", - b->dl, b->rp, b->rl, b->fp, b->fl)); - /* - * start another dma operation only if have ready data in the buffer, - * there is no pending abort, have a full-duplex device, or have a - * half duplex device and there is no pending op on the other side. - * - * Force transfers to be aligned to a boundary of 4, which is - * needed when doing stereo and 16-bit. We could make this - * adaptive, but why bother for now... - */ - if ( b->rl >= DMA_ALIGN_THRESHOLD && - ! (d->flags & SND_F_ABORTING) && - ( FULL_DUPLEX(d) || ! (d->flags & SND_F_READING) ) ) { - int l = min(b->rl, d->play_blocksize ); /* avoid too large transfer */ - l &= DMA_ALIGN_MASK ; /* realign things */ - - /* - * check if we need to reprogram the DMA on the sound card. - * This happens if the size has changed _and_ the new size - * is smaller, or it matches the blocksize. - */ - if (l != b->dl && (b->dl == 0 || ldl || l == d->play_blocksize) ) { - /* for any reason, size has changed. Stop and restart */ - DEB(printf("wrintr: bsz change from %d to %d, rp %d rl %d\n", - b->dl, l, b->rp, b->rl)); - DEB(printf("wrintr: dl %d -> %d\n", b->dl, l);) - if (b->dl != 0) - d->callback(d, SND_CB_WR | SND_CB_STOP ); - /* - * at high speed, it might well be that the count - * changes in the meantime. So we try to update b->rl - */ - if (d->special_dma) - d->callback(d, SND_CB_WR | SND_CB_DMAUPDATE) ; - else - dsp_wr_dmaupdate(b) ; - l = min(b->rl, d->play_blocksize ); - l &= DMA_ALIGN_MASK ; /* realign things */ - b->dl = l; /* record previous transfer size */ - d->callback(d, SND_CB_WR | SND_CB_START ); - } - } else { - /* cannot start a new dma transfer */ - DEB(printf("cannot start wr-dma flags 0x%08x rp %d rl %d\n", - d->flags, b->rp, b->rl)); - if (b->dl > 0) { /* was active */ - b->dl = 0; - d->callback(d, SND_CB_WR | SND_CB_STOP ); /* stop dma */ - if (d->flags & SND_F_WRITING) - DEB(printf("Race! got wrint while reloading...\n")); - else if (b->rl <= 0) /* XXX added 980110 lr */ - reset_dbuf(b, SND_CHAN_WR); - } - /* - * if switching to read, should start the read dma... - */ - if ( !FULL_DUPLEX(d) && (d->flags & SND_F_READING) ) - dsp_rdintr(d); - } -} - -/* - * user write routine - * - * advance the boundary between READY and FREE, fill the space with - * uiomove(), and possibly start DMA. Do the above until the transfer - * is complete. - * - * To minimize latency in case a pending DMA transfer is about to end, - * we do the transfer in pieces of increasing sizes, extending the - * READY area at every checkpoint. In the (necessary) assumption that - * memory bandwidth is larger than the rate at which the dma consumes - * data, we reduce the latency to something proportional to the length - * of the first piece, while keeping the overhead low and being able - * to feed the DMA with large blocks. - * - * assume d->flags |= SND_F_WRITING ; has been done before - */ - -int -dsp_write_body(snddev_info *d, struct uio *buf) -{ - int n, l, bsz, ret = 0 ; - long s; - snd_dbuf *b = & (d->dbuf_out) ; - - /* - * bsz is the max size for the next transfer. If the dma was idle - * (dl == 0), we want it as large as possible. Otherwise, start with - * a small block to avoid underruns if we are close to the end of - * the previous operation. - */ - bsz = b->dl ? MIN_CHUNK_SIZE : b->bufsize ; - while ( (n = buf->uio_resid) ) { - l = min (n, bsz); /* at most n bytes ... */ - s = spltty(); /* no interrupts here ... */ - if (d->special_dma) - d->callback(d, SND_CB_WR | SND_CB_DMAUPDATE) ; - else - dsp_wr_dmaupdate(b); - l = min( l, b->fl ); /* no more than avail. space */ - DEB(printf("dsp_write_body: prepare %d bytes out of %d\n", l,n)); - /* - * at this point, we assume that if l==0 the dma engine - * must be running. - */ - if (l == 0) { /* no space, must sleep */ - int timeout; - if (d->flags & SND_F_NBIO) { - /* unless of course we are doing non-blocking i/o */ - splx(s); - break; - } - DEB(printf("dsp_write_body: l=0, (fl %d) sleeping\n", b->fl)); - if ( b->fl < n ) - timeout = hz; - else - timeout = 1 ; - ret = tsleep( (caddr_t)b, PRIBIO|PCATCH, "dspwr", timeout); - if (ret == EINTR) - d->flags |= SND_F_ABORTING ; - splx(s); - if (ret == EINTR || ret == ERESTART) - break ; - continue; - } - splx(s); - - /* - * copy data to the buffer, and possibly do format - * conversions (here, from ULAW to U8). - * NOTE: I can use fp here since it is not modified by the - * interrupt routines. - */ - if (b->fp + l > b->bufsize) { - int l1 = b->bufsize - b->fp ; - uiomove(b->buf + b->fp, l1, buf) ; - uiomove(b->buf, l - l1, buf) ; - if (d->flags & SND_F_XLAT8) { - translate_bytes(ulaw_dsp, b->buf + b->fp, l1); - translate_bytes(ulaw_dsp, b->buf , l - l1); - } - } else { - uiomove(b->buf + b->fp, l, buf) ; - if (d->flags & SND_F_XLAT8) - translate_bytes(ulaw_dsp, b->buf + b->fp, l); - } - - s = spltty(); /* no interrupts here ... */ - b->rl += l ; /* this more ready bytes */ - b->fl -= l ; /* this less free bytes */ - b->fp += l ; - if (b->fp >= b->bufsize) /* handle wraps */ - b->fp -= b->bufsize ; - if ( b->dl == 0 ) /* dma was idle, restart it */ - dsp_wrintr(d) ; - splx(s) ; - if (buf->uio_resid == 0 && (b->fp & (b->sample_size - 1)) == 0) { - /* - * If data is correctly aligned, pad the region with - * replicas of the last sample. l0 goes from current to - * the buffer end, l1 is the portion which wraps around. - */ - int l0, l1, i; - - l1 = min(/* b->dl */ d->play_blocksize, b->fl); - l0 = min (l1, b->bufsize - b->fp); - l1 = l1 - l0 ; - - i = b->fp - b->sample_size; - if (i < 0 ) i += b->bufsize ; - if (b->sample_size == 1) { - u_char *p= (u_char *)(b->buf + i), sample = *p; - - for ( ; l0 ; l0--) - *p++ = sample ; - for (p= (u_char *)(b->buf) ; l1 ; l1--) - *p++ = sample ; - } else if (b->sample_size == 2) { - u_short *p= (u_short *)(b->buf + i), sample = *p; - - l1 /= 2 ; - l0 /= 2 ; - for ( ; l0 ; l0--) - *p++ = sample ; - for (p= (u_short *)(b->buf) ; l1 ; l1--) - *p++ = sample ; - } else { /* must be 4 ... */ - u_long *p= (u_long *)(b->buf + i), sample = *p; - - l1 /= 4 ; - l0 /= 4 ; - for ( ; l0 ; l0--) - *p++ = sample ; - for (p= (u_long *)(b->buf) ; l1 ; l1--) - *p++ = sample ; - } - - } - bsz = min(b->bufsize, bsz*2); - } - s = spltty(); /* no interrupts here ... */ - d->flags &= ~SND_F_WRITING ; - if (d->flags & SND_F_ABORTING) { - d->flags &= ~SND_F_ABORTING; - splx(s); - dsp_wrabort(d, 1 /* restart */); - /* XXX return EINTR ? */ - } - splx(s) ; - return ret ; -} - -/* - * SOUND INPUT - * - -The input part is similar to the output one, with a circular buffer -split in two regions, and boundaries advancing because of read() calls -[r] or dma operation [d]. At initialization, as for the write -routine, READY is empty, and FREE takes all the space. - - 0 rp,rl fp,fl bufsize - |__________>____________>________| - FREE r READY d FREE - -Operation is as follows: upon user read (dsp_read_body()) a DMA read -is started if not already active (marked by b->dl > 0), -then as soon as data are available in the READY region they are -transferred to the user buffer, thus advancing the boundary between FREE -and READY. Upon interrupts, caused by a completion of a DMA transfer, -the READY region is extended and possibly a new transfer is started. - -When necessary, dsp_rd_dmaupdate() is called to advance fp (and update -rl,fl accordingly). Upon user reads, rp is advanced and rl,fl are -updated accordingly. - -The rules to choose the size of the new DMA area are similar to -the other case, with a preferred constant transfer size equal to -rec_blocksize, and fallback to smaller sizes if no space is available. - - * - */ - -/* - * dsp_rd_dmadone moves bytes in the input buffer from DMA region to - * READY region. We assume it is called at spltty() and with dl>0 - */ -static void -dsp_rd_dmadone(snddev_info *d) -{ - snd_dbuf *b = & (d->dbuf_in) ; - - if (d->special_dma) - d->callback(d, SND_CB_RD | SND_CB_DMAUPDATE) ; - else - dsp_rd_dmaupdate(b); - wakeup(b) ; /* wakeup possibly sleeping processes */ - if (b->sel.si_pid && - ( !(d->flags & SND_F_HAS_SIZE) || b->rl >= d->rec_blocksize ) ) - selwakeup( & b->sel ); -} - -/* - * The following function tracks the status of a (read) dma transfer, - * and moves the boundary between the READY and the DMA regions. - * It works under the following assumptions: - * - the DMA engine is running; - * - the function is called with interrupts blocked. - */ -void -dsp_rd_dmaupdate(snd_dbuf *b) -{ - int delta, tmp ; - - tmp = b->bufsize - isa_dmastatus1(b->chan) ; - tmp &= DMA_ALIGN_MASK; /* align... */ - delta = tmp - b->fp; - if (delta < 0) /* wrapped */ - delta += b->bufsize ; - b->fp = tmp; - b->fl -= delta ; - b->rl += delta ; - b->total += delta ; -} - -/* - * read interrupt routine. Must be called with interrupts blocked. - */ -void -dsp_rdintr(snddev_info *d) -{ - snd_dbuf *b = & (d->dbuf_in) ; - - if (b->dl) { /* dma was active */ - b->int_count++; - dsp_rd_dmadone(d); - } - - DEB(printf("dsp_rdintr: start dl %d, rp:rl %d:%d, fp:fl %d:%d\n", - b->dl, b->rp, b->rl, b->fp, b->fl)); - /* - * Restart if have enough free space to absorb overruns; - */ - if ( b->fl > 0x200 && - (d->flags & (SND_F_ABORTING|SND_F_CLOSING)) == 0 && - ( FULL_DUPLEX(d) || (d->flags & SND_F_WRITING) == 0 ) ) { - int l = min(b->fl - 0x100, d->rec_blocksize); - l &= DMA_ALIGN_MASK ; /* realign sizes */ - DEB(printf("rdintr: dl %d -> %d\n", b->dl, l);) - if (l != b->dl) { - /* for any reason, size has changed. Stop and restart */ - if (b->dl > 0 ) - d->callback(d, SND_CB_RD | SND_CB_STOP ); - b->dl = l ; - d->callback(d, SND_CB_RD | SND_CB_START ); - } - } else { - if (b->dl > 0) { /* was active */ - b->dl = 0; - d->callback(d, SND_CB_RD | SND_CB_STOP); - } - /* - * if switching to write, start write dma engine - */ - if ( ! FULL_DUPLEX(d) && (d->flags & SND_F_WRITING) ) - dsp_wrintr(d) ; - DEB(printf("cannot start rd-dma rl %d fl %d\n", - b->rl, b->fl)); - } -} - -/* - * body of user-read routine - * - * Start DMA if not active; wait for READY not empty. - * Transfer data from READY region using uiomove(), advance boundary - * between FREE and READY. Repeat until transfer is complete. - * - * To avoid excessive latency in freeing up space for the DMA - * engine, transfers are done in blocks of increasing size, so that - * the latency is proportional to the size of the smallest block, but - * we have a low overhead and are able to feed the dma engine with - * large blocks. - * - * When we enter this routine, we assume that d->flags |= SND_F_READING - * was done before. - * - * NOTE: in the current version, read will not return more than - * blocksize bytes at once (unless more are already available), to - * avoid that requests using very large buffers block for too long. - */ - -int -dsp_read_body(snddev_info *d, struct uio *buf) -{ - int limit, l, n, bsz, ret = 0 ; - long s; - snd_dbuf *b = & (d->dbuf_in) ; - - /* - * "limit" serves to return after at most one blocksize of data - * (unless more are already available). Otherwise, things like - * cat /dev/audio would use a 64K buffer and would start returning - * data after a _very_ long time... - * Note -- some applications depend on reads not returning short - * blocks. But I believe these apps are broken, since interrupted - * system calls might return short reads anyways, and the - * application should better check that. - */ - - if (buf->uio_resid > d->rec_blocksize) - limit = buf->uio_resid - d->rec_blocksize; - else - limit = 0; - bsz = MIN_CHUNK_SIZE ; /* the current transfer (doubles at each step) */ - while ( (n = buf->uio_resid) > limit ) { - DEB(printf("dsp_read_body: start waiting for %d bytes\n", n)); - l = min (n, bsz); - s = spltty(); /* no interrupts here ! */ - if (d->special_dma) - d->callback(d, SND_CB_RD | SND_CB_DMAUPDATE) ; - else - dsp_rd_dmaupdate(b); - l = min( l, b->rl ); /* no more than avail. data */ - if (l == 0) { - int timeout; - /* - * If there is no data ready, then we must sleep (unless - * of course we have doing non-blocking i/o). But also - * consider restarting the DMA engine. - */ - if ( b->dl == 0 ) { /* dma was idle, start it */ - if ( d->flags & SND_F_INIT && d->dbuf_out.dl == 0 ) { - /* want to init and there is no pending DMA activity */ - splx(s); - d->callback(d, SND_CB_INIT); /* this is slow! */ - s = spltty(); - } - dsp_rdintr(d); - } - if (d->flags & SND_F_NBIO) { - splx(s); - break; - } - if (n-limit > b->dl) - timeout = hz; /* we need to wait for an int. */ - else - timeout = 1; /* maybe data will be ready earlier */ - ret = tsleep( (caddr_t)b, PRIBIO | PCATCH , "dsprd", timeout ) ; - if (ret == EINTR) - d->flags |= SND_F_ABORTING ; - splx(s); - if (ret == EINTR || ret == ERESTART) - break ; - continue; - } - splx(s); - - /* - * Do any necessary format conversion, and copy to user space. - * NOTE: I _can_ use rp here because it is not modified by the - * interrupt routines. - */ - if (b->rp + l > b->bufsize) { /* handle wraparounds */ - int l1 = b->bufsize - b->rp ; - if (d->flags & SND_F_XLAT8) { - translate_bytes(dsp_ulaw, b->buf + b->rp, l1); - translate_bytes(dsp_ulaw, b->buf , l - l1); - } - uiomove(b->buf + b->rp, l1, buf) ; - uiomove(b->buf, l - l1, buf) ; - } else { - if (d->flags & SND_F_XLAT8) - translate_bytes(dsp_ulaw, b->buf + b->rp, l); - uiomove(b->buf + b->rp, l, buf) ; - } - - s = spltty(); /* no interrupts here ... */ - b->fl += l ; /* this more free bytes */ - b->rl -= l ; /* this less ready bytes */ - b->rp += l ; /* advance ready pointer */ - if (b->rp >= b->bufsize) /* handle wraps */ - b->rp -= b->bufsize ; - splx(s) ; - bsz = min(b->bufsize, bsz*2); - } - s = spltty(); /* no interrupts here ... */ - d->flags &= ~SND_F_READING ; - if (d->flags & SND_F_ABORTING) { - d->flags &= ~SND_F_ABORTING; /* XXX */ - splx(s); - dsp_rdabort(d, 1 /* restart */); - /* XXX return EINTR ? */ - } - splx(s) ; - return ret ; -} - - -/* - * short routine to initialize a dma buffer descriptor (usually - * located in the XXX_desc structure). The first parameter is - * the buffer size, the second one specifies that a 16-bit dma channel - * is used (hence the buffer must be properly aligned). - */ -void -alloc_dbuf(snd_dbuf *b, int size) -{ - if (size > 0x10000) - panic("max supported size is 64k"); - b->buf = contigmalloc(size, M_DEVBUF, M_NOWAIT, - 0ul, 0xfffffful, 1ul, 0x10000ul); - /* should check that malloc does not fail... */ - b->rp = b->fp = 0 ; - b->dl = b->rl = 0 ; - b->bufsize = b->fl = size ; -} - -/* - * this resets a buffer and starts the isa dma on that channel. - * Must be called when the dma on the card is disabled (e.g. after init). - */ -void -reset_dbuf(snd_dbuf *b, int chan) -{ - DEB(printf("reset dbuf for chan %d\n", b->chan)); - b->rp = b->fp = 0 ; - b->dl = b->rl = 0 ; - b->fl = b->bufsize ; - if (chan == SND_CHAN_NONE) - return ; - if (chan == SND_CHAN_WR) - chan = B_WRITE | B_RAW ; - else - chan = B_READ | B_RAW ; - if (b->chan != 4 && b->chan < 8) /* XXX hack for pci... */ - isa_dmastart( chan , b->buf, b->bufsize, b->chan); -} - -/* - * snd_sync waits until the space in the given channel goes above - * a threshold. chan = 1 : play, 2: capture. The threshold is - * checked against fl or rl respectively. - * Assume that the condition can become true, do not check here... - */ -int -snd_sync(snddev_info *d, int chan, int threshold) -{ - u_long s; - int ret; - snd_dbuf *b; - - b = (chan == 1) ? &(d->dbuf_out ) : &(d->dbuf_in ) ; - - for (;;) { - s=spltty(); - if (d->special_dma) - d->callback(d, (chan==1? SND_CB_WR:SND_CB_RD) | SND_CB_DMAUPDATE); - else { - if ( chan==1 ) - dsp_wr_dmaupdate(b); - else - dsp_rd_dmaupdate(b); - } - if ( (chan == 1 && b->fl <= threshold) || - (chan == 2 && b->rl <= threshold) ) { - ret = tsleep((caddr_t)b, PRIBIO|PCATCH, "sndsyn", 1); - splx(s); - if (ret == ERESTART || ret == EINTR) { - printf("tsleep returns %d\n", ret); - return -1 ; - } - } else - break; - } - splx(s); - return 0 ; -} - -/* - * dsp_wrabort(d) and dsp_rdabort(d) are non-blocking functions - * which abort a pending DMA transfer and flush the buffers. - * They return the number of bytes that has not been transferred. - * The second parameter is used to restart the engine if needed. - */ -int -dsp_wrabort(snddev_info *d, int restart) -{ - long s; - int missing = 0; - snd_dbuf *b = & (d->dbuf_out) ; - - s = spltty(); - if ( b->dl ) { - b->dl = 0 ; - d->flags &= ~ SND_F_WRITING ; - if (d->callback) - d->callback(d, SND_CB_WR | SND_CB_ABORT); - if (!d->special_dma) - isa_dmastop(b->chan) ; - dsp_wr_dmadone(d); - - DEB(printf("dsp_wrabort: stopped, %d bytes left\n", b->rl)); - } - missing = b->rl; - if (!d->special_dma) - isa_dmadone(B_WRITE, b->buf, b->bufsize, b->chan); /*free chan */ - reset_dbuf(b, restart ? SND_CHAN_WR : SND_CHAN_NONE); - splx(s); - return missing; -} - -int -dsp_rdabort(snddev_info *d, int restart) -{ - long s; - int missing = 0; - snd_dbuf *b = & (d->dbuf_in) ; - - s = spltty(); - if ( b->dl ) { - b->dl = 0 ; - d->flags &= ~ SND_F_READING ; - if (d->callback) - d->callback(d, SND_CB_RD | SND_CB_ABORT); - if (!d->special_dma) - isa_dmastop(b->chan) ; - dsp_rd_dmadone(d); - } - missing = b->rl ; - if (!d->special_dma) - isa_dmadone(B_READ, b->buf, b->bufsize, b->chan); - reset_dbuf(b, restart ? SND_CHAN_RD : SND_CHAN_NONE); - splx(s); - return missing; -} - -/* - * this routine tries to flush the dma transfer. It is called - * on a close. The caller must set SND_F_CLOSING, and insure that - * interrupts are enabled. We immediately abort any read DMA - * operation, and then wait for the play buffer to drain. - */ - -int -snd_flush(snddev_info *d) -{ - int ret, count=10; - u_long s; - snd_dbuf *b = &(d->dbuf_out) ; - - DEB(printf("snd_flush d->flags 0x%08x\n", d->flags)); - dsp_rdabort(d, 0 /* no restart */); - /* close write */ - while ( b->dl ) { - /* - * still pending output data. - */ - ret = tsleep( (caddr_t)b, PRIBIO|PCATCH, "dmafl1", hz); - if (d->special_dma) - d->callback(d, SND_CB_WR | SND_CB_DMAUPDATE); - else - dsp_wr_dmaupdate(b); - DEB( printf("snd_sync: now rl : fl %d : %d\n", b->rl, b->fl ) ); - if (ret == EINTR) { - printf("tsleep returns %d\n", ret); - return -1 ; - } - if ( ret && --count == 0) { - printf("timeout flushing dbuf_out, chan %d cnt 0x%x flags 0x%08lx\n", - b->chan, - b->rl, d->flags); - break; - } - } - s = spltty(); /* should not be necessary... */ - d->flags &= ~SND_F_CLOSING ; - dsp_wrabort(d, 0 /* no restart */); - splx(s); - return 0 ; -} - -/* - * end of new code for dma buffer handling - */ diff --git a/sys/i386/isa/snd/mss.h b/sys/i386/isa/snd/mss.h deleted file mode 100644 index 20ceaaf9da0c..000000000000 --- a/sys/i386/isa/snd/mss.h +++ /dev/null @@ -1,304 +0,0 @@ -/* - * file: mss.h - * - * (C) 1997 Luigi Rizzo (luigi@iet.unipi.it) - * - * This file contains information and macro definitions for - * AD1848-compatible devices, used in the MSS/WSS compatible boards. - * - */ - -/* - * - -The codec part of the board is seen as a set of 4 registers mapped -at the base address for the board (default 0x534). Note that some -(early) boards implemented 4 additional registers 4 location before -(usually 0x530) to store configuration information. This is a source -of confusion in that one never knows what address to specify. The -(current) convention is to use the old address (0x530) in the kernel -configuration file and consider MSS registers start four location -ahead. - - * - */ - -/* - * The four visible registers of the MSS : - * - */ - -#define io_Index_Addr(d) ((d)->io_base + 4) -#define IA_BUSY 0x80 /* readonly, set when busy */ -#define IA_MCE 0x40 /* the MCE bit. */ - /* - * the MCE bit must be set whenever the current mode of the - * codec is changed; this in particular is true for the - * Data Format (I8, I28) and Interface Config(I9) registers. - * Only exception are CEN and PEN which can be changed on the fly. - * The DAC output is muted when MCE is set. - */ -#define IA_TRD 0x20 /* Transfer request disable */ - /* - * When TRD is set, DMA transfers cease when the INT bit in - * the MSS status reg is set. Must be cleared for automode - * DMA, set otherwise. - */ -#define IA_AMASK 0x1f /* mask for indirect address */ - -#define io_Indexed_Data(d) ((d)->io_base+1+4) - /* - * data to be transferred to the indirect register addressed - * by index addr. During init and sw. powerdown, cannot be - * written to, and is always read as 0x80 (consistent with the - * busy flag). - */ - -#define io_Status(d) ((d)->io_base+2+4) - -#define IS_CUL 0x80 /* capture upper/lower */ -#define IS_CLR 0x40 /* capture left/right */ -#define IS_CRDY 0x20 /* capture ready for programmed i/o */ -#define IS_SER 0x10 /* sample error (overrun/underrun) */ -#define IS_PUL 0x08 /* playback upper/lower */ -#define IS_PLR 0x04 /* playback left/right */ -#define IS_PRDY 0x02 /* playback ready for programmed i/o */ -#define IS_INT 0x01 /* int status (1 = active) */ - /* - * IS_INT is clreared by any write to the status register. - */ - -#define io_Polled_IO(d) ((d)->io_base+3+4) - /* - * this register is used in case of polled i/o - */ - -/* - * The MSS has a set of 16 (or 32 depending on the model) indirect - * registers accessible through the data port by specifying the - * appropriate address in the address register. - * - * The 16 low registers are uniformly handled in AD1848/CS4248 compatible - * mode (often called MODE1). For the upper 16 registers there are - * some differences among different products, mainly Crystal uses them - * differently from OPTi. - * - */ - -/* - * volume registers - */ - -#define I6_MUTE 0x80 - -/* - * register I9 -- interface configuration. - */ - -#define I9_PEN 0x01 /* playback enable */ -#define I9_CEN 0x02 /* capture enable */ - -/* - * values used in bd_flags - */ -#define BD_F_MCE_BIT 0x0001 -#define BD_F_IRQ_OK 0x0002 -#define BD_F_TMR_RUN 0x0004 - -/* AD1816 register macros */ - -#define ad1816_ale(d) ((d)->io_base+0) /* indirect reg access */ -#define ad1816_int(d) ((d)->io_base+1) /* interupt status */ -#define ad1816_low(d) ((d)->io_base+2) /* indirect low byte */ -#define ad1816_high(d) ((d)->io_base+3) /* indirect high byte */ -/* unused */ -#define ad1816_pioD(d) ((d)->io_base+4) /* PIO debug */ -#define ad1816_pios(d) ((d)->io_base+5) /* PIO status */ -#define ad1816_piod(d) ((d)->io_base+6) /* PIO data */ -/* end of unused */ -/* values for playback/capture config: - bits: 0 enable/disable - 1 pio/dma - 2 stereo/mono - 3 companded/linearPCM - 4-5 format : 00 8bit linear (uncomp) - 00 8bit mulaw (comp) - 01 16bit le (uncomp) - 01 8bit alaw (comp) - 11 16bit be (uncomp) -*/ -#define ad1816_play(d) ((d)->io_base+8) /* playback config */ -#define ad1816_capt(d) ((d)->io_base+9) /* capture config */ - -#define AD1816_BUSY 0x80 /* chip is busy */ -#define AD1816_ALEMASK 0x3F /* mask for indirect adr. */ -/* unusud */ -#define AD1816_INTRSI 0x01 /* sb intr */ -#define AD1816_INTRGI 0x02 /* game intr */ -#define AD1816_INTRRI 0x04 /* ring intr */ -#define AD1816_INTRDI 0x08 /* dsp intr */ -#define AD1816_INTRVI 0x10 /* vol intr */ -#define AD1816_INTRTI 0x20 /* timer intr */ -/* used again */ -#define AD1816_INTRCI 0x40 /* capture intr */ -#define AD1816_INTRPI 0x80 /* playback intr */ -/* PIO stuff is not supplied here */ -/* playback / capture config */ -#define AD1816_ENABLE 0x01 /* enable pl/cp */ -#define AD1816_PIO 0x02 /* use pio */ -#define AD1816_STEREO 0x04 -#define AD1816_COMP 0x08 /* data is companded */ -#define AD1816_U8 0x00 /* 8 bit linear pcm */ -#define AD1816_MULAW 0x08 /* 8 bit mulaw */ -#define AD1816_ALAW 0x18 /* 8 bit alaw */ -#define AD1816_S16LE 0x10 /* 16 bit linear little endian */ -#define AD1816_S16BE 0x30 /* 16 bit linear big endian */ -#define AD1816_FORMASK 0x38 /* format mask */ - -/* - * sound/ad1848_mixer.h - * - * Definitions for the mixer of AD1848 and compatible codecs. - * - * Copyright by Hannu Savolainen 1994 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/* - * The AD1848 codec has generic input lines called Line, Aux1 and Aux2. - * Soundcard manufacturers have connected actual inputs (CD, synth, line, - * etc) to these inputs in different order. Therefore it's difficult - * to assign mixer channels to to these inputs correctly. The following - * contains two alternative mappings. The first one is for GUS MAX and - * the second is just a generic one (line1, line2 and line3). - * (Actually this is not a mapping but rather some kind of interleaving - * solution). - */ - -#define MSS_REC_DEVICES \ - (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD|SOUND_MASK_IMIX) - - -/* - * Table of mixer registers. There is a default table for the - * AD1848/CS423x clones, and one for the OPTI931. As more MSS - * clones come out, there ought to be more tables. - * - * Fields in the table are : polarity, register, offset, bits - * - * The channel numbering used by individual soundcards is not fixed. - * Some cards have assigned different meanings for the AUX1, AUX2 - * and LINE inputs. Some have different features... - * - * Following there is a macro ...MIXER_DEVICES which is a bitmap - * of all non-zero fields in the table. - * MODE1_MIXER_DEVICES is the basic mixer of the 1848 in mode 1 - * registers I0..I15) - * - */ - -mixer_ent mix_devices[32][2] = { -MIX_NONE(SOUND_MIXER_VOLUME), -MIX_NONE(SOUND_MIXER_BASS), -MIX_NONE(SOUND_MIXER_TREBLE), -MIX_ENT(SOUND_MIXER_SYNTH, 2, 1, 0, 5, 3, 1, 0, 5), -MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6), -MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5), -MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1), -MIX_ENT(SOUND_MIXER_CD, 4, 1, 0, 5, 5, 1, 0, 5), -MIX_ENT(SOUND_MIXER_IMIX, 13, 1, 2, 6, 0, 0, 0, 0), -MIX_NONE(SOUND_MIXER_ALTPCM), -MIX_NONE(SOUND_MIXER_RECLEV), -MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4), -MIX_NONE(SOUND_MIXER_OGAIN), -MIX_NONE(SOUND_MIXER_LINE1), -MIX_NONE(SOUND_MIXER_LINE2), -MIX_NONE(SOUND_MIXER_LINE3), -}; - -#define MODE2_MIXER_DEVICES \ - (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | \ - SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | \ - SOUND_MASK_IMIX | SOUND_MASK_IGAIN ) - -#define MODE1_MIXER_DEVICES \ - (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_IMIX | SOUND_MASK_IGAIN ) - - -/* - * entries for the opti931... - */ - -mixer_ent opti931_devices[32][2] = { /* for the opti931 */ -MIX_ENT(SOUND_MIXER_VOLUME, 22, 1, 1, 5, 23, 1, 1, 5), -MIX_NONE(SOUND_MIXER_BASS), -MIX_NONE(SOUND_MIXER_TREBLE), -MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 1, 4, 5, 1, 1, 4), -MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 5, 7, 1, 0, 5), -MIX_NONE(SOUND_MIXER_SPEAKER), -MIX_ENT(SOUND_MIXER_LINE, 18, 1, 1, 4, 19, 1, 1, 4), -MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1), -MIX_ENT(SOUND_MIXER_CD, 2, 1, 1, 4, 3, 1, 1, 4), -MIX_NONE(SOUND_MIXER_IMIX), -MIX_NONE(SOUND_MIXER_ALTPCM), -MIX_NONE(SOUND_MIXER_RECLEV), -MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4), -MIX_NONE(SOUND_MIXER_OGAIN), -MIX_ENT(SOUND_MIXER_LINE1, 16, 1, 1, 4, 17, 1, 1, 4), -MIX_NONE(SOUND_MIXER_LINE2), -MIX_NONE(SOUND_MIXER_LINE3), -}; - -#define OPTI931_MIXER_DEVICES \ - (SOUND_MASK_VOLUME | SOUND_MASK_SYNTH | SOUND_MASK_PCM | \ - SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | \ - SOUND_MASK_IGAIN | SOUND_MASK_LINE1 ) - -#define AD1816_REC_DEVICES \ - (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) - -#define AD1816_MIXER_DEVICES \ - (SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH | \ - SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_IGAIN) - -static u_short default_mixer_levels[SOUND_MIXER_NRDEVICES] = { - 0x5a5a, /* Master Volume */ - 0x3232, /* Bass */ - 0x3232, /* Treble */ - 0x4b4b, /* FM */ - 0x4040, /* PCM */ - 0x4b4b, /* PC Speaker */ - 0x2020, /* Ext Line */ - 0x4040, /* Mic */ - 0x4b4b, /* CD */ - 0x0000, /* Recording monitor */ - 0x4b4b, /* SB PCM */ - 0x4b4b, /* Recording level */ - 0x2525, /* Input gain */ - 0x0000, /* Output gain */ - /* 0x4040, Line1 */ - 0x0000, /* Line1 */ - 0x0000, /* Line2 */ - 0x1515 /* Line3 (usually line in)*/ -}; - diff --git a/sys/i386/isa/snd/sb_dsp.c b/sys/i386/isa/snd/sb_dsp.c deleted file mode 100644 index 7544dae73327..000000000000 --- a/sys/i386/isa/snd/sb_dsp.c +++ /dev/null @@ -1,1366 +0,0 @@ -/* - * sound/sb_dsp.c - * - * driver for the SoundBlaster and clones. - * - * Copyright 1997,1998 Luigi Rizzo. - * - * Derived from files in the Voxware 3.5 distribution, - * Copyright by Hannu Savolainen 1994, under the same copyright - * conditions. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -/* - * use this as a template file for board-specific drivers. - * The next two lines (and the final #endif) are in all drivers: - */ - -#include -#if NPCM > 0 - -/* - * Begin with the board-specific include files... - */ - -#define __SB_MIXER_C__ /* XXX warning... */ -#include - -/* - * then prototypes of functions which go in the snddev_info - * (usually static, unless they are shared by other modules)... - */ - -static int sb_probe(struct isa_device *dev); -static int sb_attach(struct isa_device *dev); - -static d_open_t sb_dsp_open; -static d_close_t sb_dsp_close; -static d_ioctl_t sb_dsp_ioctl; -static irq_proc_t sb_intr; -static snd_callback_t sb_callback; - -/* - * and prototypes for other private functions defined in this module. - */ - -static void sb_dsp_init(snddev_info *d, struct isa_device *dev); -static void sb_mix_init(snddev_info *d); -static int sb_mixer_set(snddev_info *d, int dev, int value); -static int dsp_speed(snddev_info *d); -static void sb_mixer_reset(snddev_info *d); - -u_int sb_get_byte(int io_base); -int ess_write(int io_base, u_char reg, int val); -int ess_read(int io_base, u_char reg); - -/* - * Then put here the descriptors for the various boards supported - * by this module, properly initialized. - */ - -snddev_info sb_op_desc = { - "basic soundblaster", - - SNDCARD_SB, - sb_probe, - sb_attach, - - sb_dsp_open, - sb_dsp_close /* sb_close */, - NULL /* use generic sndread */, - NULL /* use generic sndwrite */, - sb_dsp_ioctl, - sndselect, - - sb_intr, - sb_callback, - - DSP_BUFFSIZE, /* bufsize */ - - AFMT_STEREO | AFMT_U8, /* audio format */ - -} ; - -/* - * Then the file continues with the body of all functions - * directly referenced in the descriptor. - */ - -/* - * the probe routine for the SoundBlaster only consists in - * resetting the dsp and testing if it is there. - * Version detection etc. will be done at attach time. - * - * Remember, ISA probe routines are supposed to return the - * size of io space used. - */ - -static int -sb_probe(struct isa_device *dev) -{ - bzero(&pcm_info[dev->id_unit], sizeof(pcm_info[dev->id_unit]) ); - if (dev->id_iobase == -1) { - dev->id_iobase = 0x220; - BVDDB(printf("sb_probe: no address supplied, try defaults (0x220,0x240)\n");) - if (snd_conflict(dev->id_iobase)) - dev->id_iobase = 0x240; - } - if (snd_conflict(dev->id_iobase)) - return 0 ; - - if (sb_reset_dsp(dev->id_iobase)) - return 16 ; /* the SB uses 16 registers... */ - else - return 0; -} - -static int -sb_attach(struct isa_device *dev) -{ - snddev_info *d = &pcm_info[dev->id_unit] ; - - dev->id_alive = 16 ; /* number of io ports */ - /* should be already set but just in case... */ - sb_dsp_init(d, dev); - return 0 ; -} - -/* - * here are the main routines from the switches. - */ - -/* - * Unlike MSS, the sb only supports a single open (does not mean - * that only a single process is using it, since it can fork - * afterwards, or pass the descriptor to another process). - * - */ -static int -sb_dsp_open(dev_t i_dev, int flags, int mode, struct proc * p) -{ - snddev_info *d; - int unit ; - int dev; - - dev = minor(i_dev); - unit = dev >> 4 ; - d = &pcm_info[unit] ; - - DEB(printf("<%s>%d : open\n", d->name, unit)); - - if (d->flags & SND_F_BUSY) { - DEB(printf("<%s>%d open: device busy\n", d->name, unit)); - return EBUSY ; - } - - d->wsel.si_pid = 0; - d->wsel.si_flags = 0; - - d->rsel.si_pid = 0; - d->rsel.si_flags = 0; - - d->dbuf_out.total = d->dbuf_out.prev_total = 0 ; - d->dbuf_in.total = d->dbuf_in.prev_total = 0 ; - - d->flags = 0 ; - d->bd_flags &= ~BD_F_HISPEED ; - - switch ( dev & 0xf ) { - case SND_DEV_DSP16 : - if ((d->audio_fmt & AFMT_S16_LE) == 0) { - printf("sorry, 16-bit not supported on SB %d.%02d\n", - (d->bd_id >>8) & 0xff, d->bd_id & 0xff); - return ENXIO; - } - d->play_fmt = d->rec_fmt = AFMT_S16_LE ; - break; - case SND_DEV_AUDIO : - d->play_fmt = d->rec_fmt = AFMT_MU_LAW ; - break ; - case SND_DEV_DSP : - d->play_fmt = d->rec_fmt = AFMT_U8 ; - break ; - } - /* - * since the SB is not simmetric, I use the open mode to select - * which channel should be privileged, and disable I/O in the - * other direction. - * In case the board is opened RW, we don't have enough - * information on what to do. Temporarily, privilege the - * playback channel, which is used more often, and set the other - * one to U8. - */ - if ( (flags & FREAD) == 0) /* opened write only */ - d->rec_fmt = 0 ; - else if ( (flags & FWRITE) == 0) /* opened read only */ - d->play_fmt = 0 ; - else /* opened read/write */ - d->rec_fmt = (d->play_fmt == AFMT_S16_LE) ? AFMT_U8 : AFMT_S16_LE ; - - d->flags |= SND_F_BUSY ; - d->play_speed = d->rec_speed = DSP_DEFAULT_SPEED ; - - if (flags & O_NONBLOCK) - d->flags |= SND_F_NBIO ; - - sb_reset_dsp(d->io_base); - if (d->bd_flags & BD_F_ESS) - sb_cmd(d->io_base, 0xc6 ); /* enable extended ESS mode */ - ask_init(d); - - return 0; -} - -static int -sb_dsp_close(dev_t i_dev, int flags, int mode, struct proc * p) -{ - int unit; - int dev; - snddev_info *d; - u_long s; - - dev = minor(i_dev); - unit = dev >> 4 ; - d = &pcm_info[unit] ; - - s = spltty(); - d->flags |= SND_F_CLOSING ; - splx(s); - snd_flush(d); - - sb_cmd(d->io_base, DSP_CMD_SPKOFF ); /* XXX useless ? */ - - d->flags = 0 ; - return 0 ; -} - -static int -sb_dsp_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p) -{ - int unit; - int dev; - snddev_info *d; - - dev = minor(i_dev); - unit = dev >> 4 ; - d = &pcm_info[unit] ; - - /* - * handle mixer calls first. Reads are in the default handler, - * so do not bother about them. - */ - if ( (cmd & MIXER_WRITE(0)) == MIXER_WRITE(0) ) - return sb_mixer_set(d, cmd & 0xff, *(int *)arg) ; - - /* - * for the remaining functions, use the default handler. - * ENOSYS means that the default handler should take care - * of implementing the ioctl. - */ - - return ENOSYS ; -} - -static void -sb_intr(int unit) -{ - snddev_info *d = &pcm_info[unit]; - int reason = 3, c=1, io_base = d->io_base; - - DEB(printf("got sb_intr for unit %d, flags 0x%08lx\n", unit, d->flags)); - - /* - * SB < 4.0 is half duplex and has only 1 bit for int source, - * so we fake it. SB 4.x (SB16) has the int source in a separate - * register. - * The Vibra16X has separate flags for 8 and 16 bit transfers, but - * I have no idea how to tell capture from playback interrupts... - */ -#define PLAIN_SB16(x) ( ( (x) & (BD_F_SB16|BD_F_SB16X) ) == BD_F_SB16) -again: - if (d->bd_flags & BD_F_SB16) { - c = sb_getmixer(io_base, IRQ_STAT); - /* this tells us if the source is 8-bit or 16-bit dma. We - * have to check the io channel to map it to read or write... - */ - reason = 0 ; - if ( c & 1 ) { /* 8-bit dma */ - if (d->play_fmt == AFMT_U8 || d->play_fmt == AFMT_MU_LAW ) - reason |= 1; - if (d->rec_fmt == AFMT_U8 || d->rec_fmt == AFMT_MU_LAW ) - reason |= 2; - } - if ( c & 2 ) { /* 16-bit dma */ - if (d->play_fmt == AFMT_S16_LE) - reason |= 1; - if (d->rec_fmt == AFMT_S16_LE) - reason |= 2; - } - } - /* XXX previous location of ack... */ - DEB(printf("sb_intr, flags 0x%08lx reason %d c 0x%x\n", - d->flags, reason, c)); - if ( reason & 1 ) { /* possibly a write interrupt */ - if ( d->dbuf_out.dl ) - dsp_wrintr(d); - } - if ( reason & 2 ) { - if ( d->dbuf_in.dl ) - dsp_rdintr(d); - } - if ( c & 2 ) - inb(DSP_DATA_AVL16); /* 16-bit int ack */ - if (c & 1) - inb(DSP_DATA_AVAIL); /* 8-bit int ack */ - - /* - * the sb16 might have multiple sources etc. - */ - if ((d->bd_flags & BD_F_SB16) && (c & 3)) - goto again; -} - -/* - * device-specific function called back from the dma module. - * The reason of the callback is the second argument. - * NOTE: during operations, some ioctl can be called to change - * settings (e.g. speed, channels, format), and the default - * ioctl handler will just record the change and set the - * flag SND_F_INIT. The callback routine is in charge of applying - * the changes at the next convenient time (typically, at the - * start of operations). For full duplex devices, in some cases the - * init requires both channels to be idle. - */ -static int -sb_callback(snddev_info *d, int reason) -{ - int rd = reason & SND_CB_RD ; - snd_dbuf *b = (rd) ? & (d->dbuf_in) : & (d->dbuf_out) ; - int l = b->dl ; - - switch (reason & SND_CB_REASON_MASK) { - case SND_CB_INIT : /* called with int enabled and no pending io */ - /* - * set the speed - */ - dsp_speed(d); - /* - * set the desired DMA blocksize (influences select behaviour) - */ - snd_set_blocksize(d); - /* - * since native mulaw is not present, emulate it. - */ - if ( (d->play_fmt & AFMT_MU_LAW) || (d->rec_fmt & AFMT_MU_LAW) ) - d->flags |= SND_F_XLAT8 ; - else - d->flags &= ~SND_F_XLAT8 ; - - /* - * there are too many flavours of SB for my taste... here i try to do - * the proper initialization for each one. - */ - if (PLAIN_SB16(d->bd_flags)) { - - /* the original SB16 (non-PnP, or PnP, or Vibra16C) - * can do full duplex using one 16-bit channel - * and one 8-bit channel. It needs to be programmed to - * use split format though. - * I DON'T do this for the Vibra16X because I have no idea - * of what needs to be done there... - * - * I use the following algorithm: - * 1. check which direction(s) are active; - * 2. check if we should swap dma channels - * 3. check if we can do the swap. - */ - int swap = 1 ; /* default... */ - - if (d->play_fmt == 0) { - /* do whatever the read channel wants */ - if ( d->rec_fmt == AFMT_S16_LE && d->dbuf_in.chan > 4 ) - swap = 0; - if ( d->rec_fmt != AFMT_S16_LE && d->dbuf_in.chan < 4 ) - swap = 0; - } else { - /* privilege the write channel */ - if ( d->play_fmt == AFMT_S16_LE && d->dbuf_out.chan > 4 ) - swap = 0; - if ( d->play_fmt != AFMT_S16_LE && d->dbuf_out.chan < 4 ) - swap = 0; - if ( d->rec_fmt ) { - /* check for possible config errors. - * This cannot happen at open time since even in - * case of opening rw we privilege the play - * channel. - */ - if (d->rec_fmt == d->play_fmt) { - DDB(printf("sorry, read DMA channel unavailable\n")); - } - } - } - DEB(printf("sb16: play_fmt %d, rec_fmt %x, swap %d\n", - d->play_fmt, d->rec_fmt, swap);) - if (swap) { - int c = d->dbuf_in.chan ; - d->dbuf_in.chan = d->dbuf_out.chan; - d->dbuf_out.chan = c ; - } - } - else if (d->bd_flags & BD_F_ESS) { - u_char c; - - DEB(printf("SND_CB_INIT, play_fmt == 0x%x, rec_fmt == 0x%x\n", - (int) d->play_fmt, (int) d->rec_fmt)); - - /* autoinit DMA mode */ - if (d->play_fmt) - ess_write(d->io_base, 0xb8, 0x04); - else - ess_write(d->io_base, 0xb8, 0x0e); - - c = (ess_read(d->io_base, 0xa8) & ~0x03) | 0x01; - if ((d->flags & SND_F_STEREO) == 0) - c++; - ess_write(d->io_base, 0xa8, c); /* select mono/stereo */ - ess_write(d->io_base, 0xb9, 2); /* demand 4 bytes/transfer */ - - switch (d->play_fmt ? d->play_fmt : d->rec_fmt) { - case AFMT_S16_LE: - if (d->flags & SND_F_STEREO) { - /* 16 bit stereo */ - if (d->play_fmt) - ess_write(d->io_base, 0xb6, 0x00); - ess_write(d->io_base, 0xb7, 0x71); - ess_write(d->io_base, 0xb7, 0xbc); - } - else { - /* 16 bit mono */ - if (d->play_fmt) - ess_write(d->io_base, 0xb6, 0x00); - ess_write(d->io_base, 0xb7, 0x71); - ess_write(d->io_base, 0xb7, 0xf4); - } - break; - case AFMT_U8: - if (d->flags & SND_F_STEREO) { - /* 8 bit stereo */ - if (d->play_fmt) - ess_write(d->io_base, 0xb6, 0x80); - ess_write(d->io_base, 0xb7, 0x51); - ess_write(d->io_base, 0xb7, 0x98); - } - else { - /* 8 bit mono */ - if (d->play_fmt) - ess_write(d->io_base, 0xb6, 0x80); - ess_write(d->io_base, 0xb7, 0x51); - ess_write(d->io_base, 0xb7, 0xd0); - } - break; - } - ess_write(d->io_base, 0xb1, - ess_read(d->io_base, 0xb1) | 0x50); - ess_write(d->io_base, 0xb2, - ess_read(d->io_base, 0xb1) | 0x50); - } - reset_dbuf(& (d->dbuf_in), SND_CHAN_RD ); - reset_dbuf(& (d->dbuf_out), SND_CHAN_WR ); - break ; - - case SND_CB_START : /* called with int disabled */ - if (d->bd_flags & BD_F_SB16) { - u_char c, c1 ; - - if (d->bd_flags & BD_F_SB16X) { - /* just a guess: on the Vibra16X, the first - * op started takes the first dma channel, - * the second one takes the next... - * The default is to be ready for play. - */ - DEB(printf("start %s -- now dma %d:%d\n", - rd ? "rd" : "wr", - d->dbuf_out.chan, d->dbuf_in.chan);); - /* swap only if both channels are idle - * play: dl=0, since there is no pause; - * rec: rl=0 - */ - if ( rd && d->dbuf_out.dl == 0 && d->dbuf_in.rl == 0 ) { - /* must swap channels, but also save dl */ - int c = d->dbuf_in.chan ; - int dl = d->dbuf_in.dl ; - d->dbuf_in.chan = d->dbuf_out.chan; - d->dbuf_out.chan = c ; - reset_dbuf(& (d->dbuf_in), SND_CHAN_RD ); - reset_dbuf(& (d->dbuf_out), SND_CHAN_WR ); - d->dbuf_in.dl = dl ; - printf("swapped -- now dma %d:%d\n", - d->dbuf_out.chan, d->dbuf_in.chan); - } - } - - /* - * XXX note: c1 and l should be set basing on d->rec_fmt, - * but there is no choice once a 16 or 8-bit channel - * is assigned. This means that if the application - * tries to use a bad format, the sound will not be nice. - */ - if ( b->chan > 4 - || (rd && d->rec_fmt == AFMT_S16_LE) - || (!rd && d->play_fmt == AFMT_S16_LE) - ) { - c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA16 ; - c1 = DSP_F16_SIGNED ; - l /= 2 ; - } else { - c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA8 ; - c1 = 0 ; - } - c |= (rd) ? DSP_F16_ADC : DSP_F16_DAC ; - if (d->flags & SND_F_STEREO) - c1 |= DSP_F16_STEREO ; - - sb_cmd(d->io_base, c ); - sb_cmd3(d->io_base, c1 , l - 1) ; - } else if (d->bd_flags & BD_F_ESS) { - u_long fmt = rd ? d->rec_fmt : d->play_fmt; - - DEB(printf("SND_CB_START: %s (%d)\n", rd ? "rd" : "wr", l)); - if (fmt == AFMT_S16_LE) - l >>= 1; - l--; - if (!rd) - sb_cmd(d->io_base, DSP_CMD_SPKON); - ess_write(d->io_base, 0xa4, l); - ess_write(d->io_base, 0xa5, l >> 8); - ess_write(d->io_base, 0xb8, - ess_read(d->io_base, 0xb8) | (rd ? 0x0f : 0x05)); - } else { /* SBPro -- stereo not supported */ - u_char c ; - if (!rd) - sb_cmd(d->io_base, DSP_CMD_SPKON); - /* code for the SB2 and SB3, only MONO */ - if (d->bd_flags & BD_F_HISPEED) - c = (rd) ? 0x98 : 0x90 ; - else - c = (rd) ? 0x2c : 0x1c ; - if (d->flags & SND_F_STEREO) - sb_setmixer(d->io_base, 0xe, 2 ); - else - sb_setmixer(d->io_base, 0xe, 0 ); - /* - * some ESS extensions -- they can do 16 bits - */ - if ( (rd && d->rec_fmt == AFMT_S16_LE) || - (!rd && d->play_fmt == AFMT_S16_LE) ) { - c |= 1; - l /= 2 ; - } - sb_cmd3(d->io_base, 0x48 , l - 1) ; - sb_cmd(d->io_base, c ) ; - } - break; - - case SND_CB_ABORT : /* XXX */ - case SND_CB_STOP : - { - int cmd = DSP_CMD_DMAPAUSE_8 ; /* default: halt 8 bit chan */ - DEB(printf("SND_CB_XXX: reason 0x%x\n", reason)); - if ( b->chan > 4 - || (rd && d->rec_fmt == AFMT_S16_LE) - || (!rd && d->play_fmt == AFMT_S16_LE) - ) - cmd = DSP_CMD_DMAPAUSE_16 ; - if (d->bd_flags & BD_F_HISPEED) { - sb_reset_dsp(d->io_base); - if (d->bd_flags & BD_F_ESS) - sb_cmd(d->io_base, 0xc6 ); /* enable extended ESS mode */ - d->flags |= SND_F_INIT ; - } else { - sb_cmd(d->io_base, cmd); /* pause dma. */ - /* - * The above seems to have the undocumented side effect of - * blocking the other side as well. If the other - * channel was active (SB16) I have to re-enable it :( - */ - if ( (rd && d->dbuf_out.dl) || - (!rd && d->dbuf_in.dl) ) - sb_cmd(d->io_base, cmd == DSP_CMD_DMAPAUSE_8 ? - 0xd6 : 0xd4); /* continue other dma */ - } - if (d->bd_flags & BD_F_SB16X) { - /* restore possible swapped channels. - * The default is to be ready for play. - * XXX right now, it kills all input on overflow - */ - if ( rd && d->dbuf_out.dl == 0 ) { - /* must swap channels ? */ - int c = d->dbuf_in.chan ; - d->dbuf_in.chan = d->dbuf_out.chan; - d->dbuf_out.chan = c ; - reset_dbuf(& (d->dbuf_in), SND_CHAN_RD ); - reset_dbuf(& (d->dbuf_out), SND_CHAN_WR ); - printf("restored -- now dma %d:%d\n", - d->dbuf_out.chan, d->dbuf_in.chan); - } - } - } - DEB( sb_cmd(d->io_base, DSP_CMD_SPKOFF) ); /* speaker off */ - break ; - - } - return 0 ; -} - -/* - * The second part of the file contains all functions specific to - * the board and (usually) not exported to other modules. - */ - -int -sb_reset_dsp(int io_base) -{ - int loopc; - - outb(io_base + SBDSP_RST, 3); - DELAY(100); - outb(io_base + SBDSP_RST, 0); - for (loopc = 0; loopc<100 && !(inb(DSP_DATA_AVAIL) & 0x80); loopc++) - DELAY(30); - - if (inb(DSP_READ) != 0xAA) { - DEB(printf("sb_reset_dsp 0x%x failed\n", io_base)); - return 0; /* Sorry */ - } - return 1; -} - -/* - * only used in sb_attach from here. - */ - -static void -sb_dsp_init(snddev_info *d, struct isa_device *dev) -{ - int i, x; - char *fmt = NULL ; - int io_base = dev->id_iobase ; - - d->bd_id = 0 ; - - sb_reset_dsp(io_base); - sb_cmd(io_base, DSP_CMD_GETVER); /* Get version */ - - for (i = 10000; i; i--) { /* perhaps wait longer on a fast machine ? */ - if (inb(DSP_DATA_AVAIL) & 0x80) { /* wait for Data Ready */ - if ( (d->bd_id & 0xff00) == 0) - d->bd_id = inb(DSP_READ) << 8; /* major */ - else { - d->bd_id |= inb(DSP_READ); /* minor */ - break; - } - } else - DELAY(20); - } - - /* - * now do various initializations depending on board id. - */ - - fmt = "SoundBlaster %d.%d" ; /* default */ - - switch ( d->bd_id >> 8 ) { - case 0 : - printf("\n\nFailed to get SB version (%x) - possible I/O conflict\n\n", - inb(DSP_DATA_AVAIL)); - d->bd_id = 0x100; - case 1 : /* old sound blaster has nothing... */ - break ; - - case 2 : - d->dbuf_in.chan = d->dbuf_out.chan ; /* half duplex */ - d->bd_flags |= BD_F_DUP_MIDI ; - - if (d->bd_id == 0x200) - break ; /* no mixer on the 2.0 */ - d->bd_flags &= ~BD_F_MIX_MASK ; - d->bd_flags |= BD_F_MIX_CT1335 ; - - break ; - case 4 : - fmt = "SoundBlaster 16 %d.%d"; - d->audio_fmt |= AFMT_FULLDUPLEX | AFMT_WEIRD | AFMT_S8 | AFMT_S16_LE; - d->bd_flags |= BD_F_SB16; - d->bd_flags &= ~BD_F_MIX_MASK ; - d->bd_flags |= BD_F_MIX_CT1745 ; - - /* soft irq/dma configuration */ - x = -1 ; - if (d->irq == 5) x = 2; - else if (d->irq == 7) x = 4; - else if (d->irq == 9) x = 1; - else if (d->irq == 10) x = 8; - if (x == -1) - printf("<%s>%d: bad irq %d (only 5,7,9,10 allowed)\n", - d->name, dev->id_unit, d->irq); - else - sb_setmixer(io_base, IRQ_NR, x); - if (d->dbuf_out.chan == d->dbuf_in.chan) { - printf("WARNING: sb: misconfigured secondary DMA channel\n"); - } - sb_setmixer(io_base, DMA_NR, (1 << d->dbuf_out.chan) | (1 << d->dbuf_in.chan)); - break ; - - case 3 : - d->dbuf_in.chan = d->dbuf_out.chan ; /* half duplex */ - fmt = "SoundBlaster Pro %d.%d"; - d->bd_flags |= BD_F_DUP_MIDI ; - d->bd_flags &= ~BD_F_MIX_MASK ; - d->bd_flags |= BD_F_MIX_CT1345 ; - if (d->bd_id == 0x301) { - int ess_major = 0, ess_minor = 0; - - /* - * Try to detect ESS chips. - */ - - sb_cmd(io_base, DSP_CMD_GETID); /* Return ident. bytes. */ - - for (i = 1000; i; i--) { - if (inb(DSP_DATA_AVAIL) & 0x80) { /* wait for Data Ready */ - if (ess_major == 0) - ess_major = inb(DSP_READ); - else { - ess_minor = inb(DSP_READ); - break; - } - } else - DELAY(20); - } - - if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) { - /* the ESS488 can be treated as an SBPRO */ - printf("ESS488 (rev %d)\n", ess_minor & 0x0f); - break ; - } - else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) { - int rev = ess_minor & 0xf; - - if (rev >= 8) - printf("ESS1868 (rev %d)\n", rev); - else - printf("ESS688 (rev %d)\n", rev); - d->bd_flags |= BD_F_ESS; - d->audio_fmt |= AFMT_S16_LE; - - /* enable extended ESS mode */ - sb_cmd(d->io_base, 0xc6); - break; - } else { - printf("Unknown card 0x%x 0x%x -- hope it is SBPRO\n", - ess_major, ess_minor); - break ; - } - } - - } - - snprintf(d->name, sizeof(d->name), - fmt, (d->bd_id >> 8) &0xff, d->bd_id & 0xff); - - sb_mix_init(d); -} - -static void -sb_mix_init(snddev_info *d) -{ - switch (d->bd_flags & BD_F_MIX_MASK) { - case BD_F_MIX_CT1345 : /* SB 3.0 has 1345 mixer */ - - d->mix_devs = SBPRO_MIXER_DEVICES ; - d->mix_rec_devs = SBPRO_RECORDING_DEVICES ; - d->mix_recsrc = SOUND_MASK_MIC ; - - sb_setmixer(d->io_base, 0, 1 ); /* reset mixer */ - sb_setmixer(d->io_base, MIC_VOL , 0x6 ); /* mic volume max */ - sb_setmixer(d->io_base, RECORD_SRC , 0x0 ); /* mic source */ - sb_setmixer(d->io_base, FM_VOL , 0x0 ); /* no midi */ - break ; - - case BD_F_MIX_CT1745 : /* SB16 mixer ... */ - - d->mix_devs = SB16_MIXER_DEVICES ; - d->mix_rec_devs = SB16_RECORDING_DEVICES ; - d->mix_recsrc = SOUND_MASK_MIC ; - } - sb_mixer_reset(d); -} - -/* - * Common code for the midi and pcm functions - * - * sb_cmd write a single byte to the CMD port. - * sb_cmd2 write a CMD + 1 byte arg - * sb_cmd3 write a CMD + 2 byte arg - * sb_get_byte returns a single byte from the DSP data port - * - * ess_write is actually sb_cmd2 - * ess_read access ext. regs via sb_cmd(0xc0, reg) followed by sb_get_byte - */ - -int -sb_cmd(int io_base, u_char val) -{ - int i; - - for (i = 0; i < 1000 ; i++) { - if ((inb(io_base + SBDSP_STATUS) & 0x80) == 0) { - outb(io_base + SBDSP_CMD, val); - return 1; - } - if (i > 10) - DELAY (i > 100 ? 1000 : 10 ); - } - - printf("SoundBlaster: DSP Command(0x%02x) timeout. IRQ conflict ?\n", val); - return 0; -} - -int -sb_cmd3(int io_base, u_char cmd, int val) -{ - if (sb_cmd(io_base, cmd)) { - sb_cmd(io_base, val & 0xff ); - sb_cmd(io_base, (val>>8) & 0xff ); - return 1 ; - } else - return 0; -} - -int -sb_cmd2(int io_base, u_char cmd, int val) -{ - if (sb_cmd(io_base, cmd)) { - sb_cmd(io_base, val & 0xff ); - return 1 ; - } else - return 0; -} - -/* - * in the SB, there is a set of indirect "mixer" registers with - * address at offset 4, data at offset 5 - */ -void -sb_setmixer(int io_base, u_int port, u_int value) -{ - u_long flags; - - flags = spltty(); - outb(io_base + SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ - DELAY(10); - outb(io_base + SB_MIX_DATA, (u_char) (value & 0xff)); - DELAY(10); - splx(flags); -} - -int -sb_getmixer(int io_base, u_int port) -{ - int val; - u_long flags; - - flags = spltty(); - outb(io_base + SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ - DELAY(10); - val = inb(io_base + SB_MIX_DATA); - DELAY(10); - splx(flags); - - return val; -} - -u_int -sb_get_byte(int io_base) -{ - int i; - - for (i = 1000; i; i--) - if (inb(DSP_DATA_AVAIL) & 0x80) - return inb(DSP_READ); - else - DELAY(20); - return 0xffff; -} - -int -ess_write(int io_base, u_char reg, int val) -{ - return sb_cmd2(io_base, reg, val); -} - -int -ess_read(int io_base, u_char reg) -{ - if (!sb_cmd(io_base, 0xc0) || !sb_cmd(io_base, reg) ) - return 0xffff ; - return sb_get_byte(io_base); -} - - -/* - * various utility functions for the DSP - */ - -/* - * dsp_speed updates the speed setting from the descriptor. make sure - * it is called at spltty(). - * Besides, it takes care of stereo setting. - */ -static int -dsp_speed(snddev_info *d) -{ - u_char tconst; - u_long flags; - int max_speed = 44100, speed = d->play_speed ; - - /* - * special code for the SB16 - */ - if (d->bd_flags & BD_F_SB16) { - RANGE (speed, 5000, 45000); - d->play_speed = d->rec_speed = speed ; - sb_cmd(d->io_base, 0x41); - sb_cmd(d->io_base, d->play_speed >> 8 ); - sb_cmd(d->io_base, d->play_speed & 0xff ); - sb_cmd(d->io_base, 0x42); - sb_cmd(d->io_base, d->rec_speed >> 8 ); - sb_cmd(d->io_base, d->rec_speed & 0xff ); - return speed ; - } - - /* - * special code for the ESS ... - */ - if (d->bd_flags & BD_F_ESS) { - int t; - RANGE (speed, 5000, 49000); - if (speed > 22000) { - t = (795500 + speed / 2) / speed; - speed = (795500 + t / 2) / t ; - t = (256 - t ) | 0x80 ; - } else { - t = (397700 + speed / 2) / speed; - speed = (397700 + t / 2) / t ; - t = 128 - t ; - } - ess_write(d->io_base, 0xa1, t); /* set time constant */ - d->play_speed = d->rec_speed = speed ; - speed = (speed * 9 ) / 20 ; - t = 256-7160000/(speed*82); - ess_write(d->io_base,0xa2,t); - return speed ; - } - - /* - * This is code for the SB3.x and lower. - * Only some models can do stereo, and only if not - * simultaneously using midi. - * At the moment we do not support either... - */ -#if 0 - d->flags &= ~SND_F_STEREO; -#endif - - /* - * here enforce speed limitations. - */ - if (d->bd_id <= 0x200) - max_speed = 22050; /* max 22050 on SB 1.X */ - - /* - * SB models earlier than SB Pro have low limit for the - * input rate. Note that this is only for input, but since - * we do not support separate values for rec & play.... - */ - if (d->bd_id <= 0x200) - max_speed = 13000; - else if (d->bd_id < 0x300) - max_speed = 15000; - - RANGE(speed, 4000, max_speed); - - if (d->flags & SND_F_STEREO) /* really unused right now... */ - speed *= 2; - - /* - * Now the speed should be valid. Compute the value to be - * programmed into the board. - */ - - if (speed > 22050) { /* High speed mode on 2.01/3.xx */ - int tmp; - - tconst = (u_char) ((65536 - ((256000000 + speed / 2) / speed)) >> 8) ; - d->bd_flags |= BD_F_HISPEED ; - - flags = spltty(); - sb_cmd2(d->io_base, 0x40, tconst); /* set time constant */ - splx(flags); - - tmp = 65536 - (tconst << 8); - speed = (256000000 + tmp / 2) / tmp; - } else { - int tmp; - - d->bd_flags &= ~BD_F_HISPEED ; - tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; - - flags = spltty(); - sb_cmd2(d->io_base, 0x40, tconst); /* set time constant */ - splx(flags); - - tmp = 256 - tconst; - speed = (1000000 + tmp / 2) / tmp; - } - - if (d->flags & SND_F_STEREO) /* really unused right now... */ - speed /= 2; - - d->play_speed = d->rec_speed = speed; - return speed; -} - -/* - * mixer support, originally in sb_mixer.c - */ - -static void -sb_set_recsrc(snddev_info *d, int mask) -{ - u_char recdev ; - - mask &= d->mix_rec_devs; - switch (d->bd_flags & BD_F_MIX_MASK) { - case BD_F_MIX_CT1345 : - if (mask == SOUND_MASK_LINE) - recdev = 6 ; - else if (mask == SOUND_MASK_CD) - recdev = 2 ; - else { /* default: mic */ - mask = SOUND_MASK_MIC ; - recdev = 0 ; - } - sb_setmixer(d->io_base, RECORD_SRC, - recdev | (sb_getmixer(d->io_base, RECORD_SRC) & ~7 )); - break ; - case BD_F_MIX_CT1745 : /* sb16 */ - if (mask == 0) - mask = SOUND_MASK_MIC ; /* XXX For compatibility. Bug ? */ - recdev = 0 ; - if (mask & SOUND_MASK_MIC) - recdev |= 1 ; - if (mask & SOUND_MASK_CD) - recdev |= 6 ; /* l+r cd */ - if (mask & SOUND_MASK_LINE) - recdev |= 0x18 ; /* l+r line */ - if (mask & SOUND_MASK_SYNTH) - recdev |= 0x60 ; /* l+r midi */ - sb_setmixer(d->io_base, SB16_IMASK_L, recdev); - sb_setmixer(d->io_base, SB16_IMASK_R, recdev); - /* - * since the same volume controls apply to the input and - * output sections, the best approach to have a consistent - * behaviour among cards would be to disable the output path - * on devices which are used to record. - * However, since users like to have feedback, we only disable - * the mike -- permanently. - */ - sb_setmixer(d->io_base, SB16_OMASK, 0x1f & ~1); - break ; - } - d->mix_recsrc = mask; -} - -static void -sb_mixer_reset(snddev_info *d) -{ - int i; - - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - sb_mixer_set(d, i, levels[i]); - if (d->bd_flags & BD_F_SB16) { - sb_setmixer(d->io_base, 0x3c, 0x1f); /* make all output active */ - sb_setmixer(d->io_base, 0x3d, 0); /* make all inputs-l off */ - sb_setmixer(d->io_base, 0x3e, 0); /* make all inputs-r off */ - } - sb_set_recsrc(d, SOUND_MASK_MIC); -} - -static int -sb_mixer_set(snddev_info *d, int dev, int value) -{ - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; - int regoffs; - u_char val; - mixer_tab *iomap; - -#ifdef JAZZ16 - if (d->bd_flags & BD_F_JAZZ16 && d->bd_flags & BD_F_JAZZ16_2) - return smw_mixer_set(dev, value); -#endif - - if (dev == SOUND_MIXER_RECSRC) { - sb_set_recsrc(d, value); - return 0 ; - } - if (left > 100) - left = 100; - if (right > 100) - right = 100; - - if (dev > 31) - return EINVAL ; - - if (!(d->mix_devs & (1 << dev))) /* Not supported */ - return EINVAL; - - switch ( d->bd_flags & BD_F_MIX_MASK ) { - default: - /* mixer unknown, fail... */ - return EINVAL ;/* XXX change this */ - case BD_F_MIX_CT1345 : - iomap = &sbpro_mix ; - break; - case BD_F_MIX_CT1745 : - iomap = &sb16_mix ; - break; - /* XXX how about the SG NX Pro, iomap = sgnxpro_mix */ - } - regoffs = (*iomap)[dev][LEFT_CHN].regno; - if (regoffs == 0) - return EINVAL; - - val = sb_getmixer(d->io_base, regoffs); - - change_bits(iomap, &val, dev, LEFT_CHN, left); - - d->mix_levels[dev] = left | (left << 8); - - if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) { /* Change register */ - sb_setmixer(d->io_base, regoffs, val); /* Save the old one */ - regoffs = (*iomap)[dev][RIGHT_CHN].regno; - - if (regoffs == 0) - return 0 ; /* Just left channel present */ - - val = sb_getmixer(d->io_base, regoffs); /* Read the new one */ - } - change_bits(iomap, &val, dev, RIGHT_CHN, right); - - sb_setmixer(d->io_base, regoffs, val); - - d->mix_levels[dev] = left | (right << 8); - return 0 ; /* ok */ -} - -/* - * now support for some PnP boards. - */ - -#if NPNP > 0 -static char *ess1868_probe(u_long csn, u_long vend_id); -static void ess1868_attach(u_long csn, u_long vend_id, char *name, - struct isa_device *dev); - -static struct pnp_device ess1868 = { - "ESS1868", - ess1868_probe, - ess1868_attach, - &nsnd, /* use this for all sound cards */ - &tty_imask /* imask */ -}; -DATA_SET (pnpdevice_set, ess1868); - -static char * -ess1868_probe(u_long csn, u_long vend_id) -{ - /* - * pnp X 1 os enable drq0 3 irq0 12 port0 0x240 - */ - if (vend_id == 0x68187316) { - struct pnp_cinfo d ; - read_pnp_parms ( &d , 1 ) ; - if (d.enable == 0) { - printf("This is an ESS1868, but LDN 1 is disabled\n"); - return NULL; - } - return "ESS1868" ; - } - return NULL ; -} - -static void -ess1868_attach(u_long csn, u_long vend_id, char *name, - struct isa_device *dev) -{ - struct pnp_cinfo d ; - snddev_info tmp_d ; /* patched copy of the basic snddev_info */ - - tmp_d = sb_op_desc; - snddev_last_probed = &tmp_d; - -#if 0 - read_pnp_parms ( &d , 3 ); /* disable LDN 3 */ - d.port[0] = 0 ; - d.enable = 0 ; - write_pnp_parms ( &d , 3 ); - - read_pnp_parms ( &d , 2 ); /* disable LDN 2 */ - d.port[0] = 0 ; - d.enable = 0 ; - write_pnp_parms ( &d , 2 ); - read_pnp_parms ( &d , 0 ); /* read config base */ - tmp_d.conf_base = d.port[0]; - write_pnp_parms ( &d , 0 ); -#endif - - read_pnp_parms ( &d , 1 ) ; - dev->id_iobase = d.port[0]; - d.port[1] = 0 ; - d.port[2] = 0 ; - write_pnp_parms ( &d , 1 ); - enable_pnp_card(); - - dev->id_drq = d.drq[0] ; /* primary dma */ - dev->id_irq = (1 << d.irq[0] ) ; - dev->id_intr = (inthand2_t *)pcmintr ; - dev->id_flags = 0 /* DV_F_DUAL_DMA | (d.drq[1] ) */; - -#if 0 - snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */ -#endif - pcmattach(dev); -} - -/* - * A driver for some SB16pnp and compatibles... - * - * Avance Asound 100 -- 0x01009305 - * Avance Logic ALS100+ -- 0x10019305 - * Avance Logic ASound Gold ALS120 -- 0x20019305 - * xxx -- 0x2b008c0e - * - */ - -static char *sb16pnp_probe(u_long csn, u_long vend_id); -static void sb16pnp_attach(u_long csn, u_long vend_id, char *name, - struct isa_device *dev); - -static struct pnp_device sb16pnp = { - "SB16pnp", - sb16pnp_probe, - sb16pnp_attach, - &nsnd, /* use this for all sound cards */ - &tty_imask /* imask */ -}; -DATA_SET (pnpdevice_set, sb16pnp); - -static char * -sb16pnp_probe(u_long csn, u_long vend_id) -{ - char *s = NULL ; - - /* - * The SB16/AWExx cards seem to differ in the fourth byte of - * the vendor id, so I have just masked it for the time being... - * Reported values are: - * SB16 Value PnP: 0x2b008c0e - * SB AWExx PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e - * Vibra16X: 0xf0008c0e - */ - if (vend_id == 0xf0008c0e) - s = "Vibra16X" ; - else if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) ) - s = "SB16 PnP"; - else if (vend_id == 0x01009305) - s = "Avance Asound 100" ; - else if (vend_id == 0x10019305) - s = "Avance Logic 100+" ; /* Vibra16X-class */ - else if (vend_id == 0x20019305) - s = "Avance Logic ALS120" ; /* Vibra16X-class */ - if (s) { - struct pnp_cinfo d; - read_pnp_parms(&d, 0); - if (d.enable == 0) { - printf("This is a %s, but LDN 0 is disabled\n", s); - return NULL ; - } - return s ; - } - return NULL ; -} - -static void -sb16pnp_attach(u_long csn, u_long vend_id, char *name, - struct isa_device *dev) -{ - struct pnp_cinfo d ; - snddev_info tmp_d ; /* patched copy of the basic snddev_info */ - - tmp_d = sb_op_desc; - snddev_last_probed = &tmp_d; - - read_pnp_parms ( &d , 0 ) ; - d.port[1] = 0 ; /* only the first address is used */ - dev->id_iobase = d.port[0]; - tmp_d.synth_base = d.port[2]; - write_pnp_parms ( &d , 0 ); - enable_pnp_card(); - - dev->id_drq = d.drq[0] ; /* primary dma */ - dev->id_irq = (1 << d.irq[0] ) ; - dev->id_intr = (inthand2_t *)pcmintr ; - dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ; - - pcm_info[dev->id_unit] = tmp_d; /* pcm_info[] will be reinitialized after */ - snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */ - - if (vend_id == 0x10019305 || vend_id == 0xf0008c0e - || vend_id == 0x20019305) { - /* - * XXX please add here the vend_id for other vibra16X cards... - * And remember, must change tmp_d, not - */ - tmp_d.bd_flags |= BD_F_SB16X ; - } - pcmattach(dev); -} -#endif /* NPNP */ - -#endif diff --git a/sys/i386/isa/snd/sbcard.h b/sys/i386/isa/snd/sbcard.h deleted file mode 100644 index b05b3659a87a..000000000000 --- a/sys/i386/isa/snd/sbcard.h +++ /dev/null @@ -1,405 +0,0 @@ -/* - * file: sbcard.h - */ - -typedef struct _sbdev_info { - -} sbdev_info ; - -extern int sbc_major, sbc_minor ; -/* - * sound blaster registers - */ - -#define SBDSP_RST 0x6 -#define DSP_READ (io_base + 0xA) -#define DSP_WRITE (io_base + 0xC) -#define SBDSP_CMD 0xC -#define SBDSP_STATUS 0xC -#define DSP_DATA_AVAIL (io_base + 0xE) -#define DSP_DATA_AVL16 (io_base + 0xF) - -#define SB_MIX_ADDR 0x4 -#define SB_MIX_DATA 0x5 -#if 0 -#define OPL3_LEFT (io_base + 0x0) -#define OPL3_RIGHT (io_base + 0x2) -#define OPL3_BOTH (io_base + 0x8) -#endif - -/* - * DSP Commands. There are many, and in many cases they are used explicitly - */ - -/* these are not used except for programmed I/O (not in this driver) */ -#define DSP_DAC8 0x10 /* direct DAC output */ -#define DSP_ADC8 0x20 /* direct ADC input */ - -/* these should be used in the SB 1.0 */ -#define DSP_CMD_DAC8 0x14 /* single cycle 8-bit dma out */ -#define DSP_CMD_ADC8 0x24 /* single cycle 8-bit dma in */ - -/* these should be used in the SB 2.0 and 2.01 */ -#define DSP_CMD_DAC8_AUTO 0x1c /* auto 8-bit dma out */ -#define DSP_CMD_ADC8_AUTO 0x2c /* auto 8-bit dma out */ - -#define DSP_CMD_HSSIZE 0x48 /* high speed dma count */ -#define DSP_CMD_HSDAC_AUTO 0x90 /* high speed dac, auto */ -#define DSP_CMD_HSADC_AUTO 0x98 /* high speed adc, auto */ - -/* SBPro commands. Some cards (JAZZ, SMW) also support 16 bits */ - - /* prepare for dma input */ -#define DSP_CMD_DMAMODE(stereo, bit16) (0xA0 | (stereo ? 8:0) | (bit16 ? 4:0)) - -#define DSP_CMD_DAC2 0x16 /* 2-bit adpcm dma out (cont) */ -#define DSP_CMD_DAC2S 0x17 /* 2-bit adpcm dma out (start) */ - -#define DSP_CMD_DAC2S_AUTO 0x1f /* auto 2-bit adpcm dma out (start) */ - - -/* SB16 commands */ -#define DSP_CMD_O16 0xb0 -#define DSP_CMD_I16 0xb8 -#define DSP_CMD_O8 0xc0 -#define DSP_CMD_I8 0xc8 - -#define DSP_MODE_U8MONO 0x00 -#define DSP_MODE_U8STEREO 0x20 -#define DSP_MODE_S16MONO 0x10 -#define DSP_MODE_S16STEREO 0x30 - -#define DSP_CMD_SPKON 0xD1 -#define DSP_CMD_SPKOFF 0xD3 -#define DSP_CMD_SPKR(on) (0xD1 | (on ? 0:2)) - -#define DSP_CMD_DMAPAUSE_8 0xD0 -#define DSP_CMD_DMAPAUSE_16 0xD5 -#define DSP_CMD_DMAEXIT_8 0xDA -#define DSP_CMD_DMAEXIT_16 0xD9 -#define DSP_CMD_TCONST 0x40 /* set time constant */ -#define DSP_CMD_HSDAC 0x91 /* high speed dac */ -#define DSP_CMD_HSADC 0x99 /* high speed adc */ - -#define DSP_CMD_GETVER 0xE1 -#define DSP_CMD_GETID 0xE7 /* return id bytes */ - - -#define DSP_CMD_OUT16 0x41 /* send parms for dma out on sb16 */ -#define DSP_CMD_IN16 0x42 /* send parms for dma in on sb16 */ -#if 0 /*** unknown ***/ -#define DSP_CMD_FA 0xFA /* get version from prosonic*/ -#define DSP_CMD_FB 0xFB /* set irq/dma for prosonic*/ -#endif - -/* - * in fact, for the SB16, dma commands are as follows: - * - * cmd, mode, len_low, len_high. - * - * cmd is a combination of DSP_DMA16 or DSP_DMA8 and - */ - -#define DSP_DMA16 0xb0 -#define DSP_DMA8 0xc0 -# define DSP_F16_DAC 0x00 -# define DSP_F16_ADC 0x08 -# define DSP_F16_AUTO 0x04 -# define DSP_F16_FIFO_ON 0x02 - -/* - * mode is a combination of the following: - */ -#define DSP_F16_STEREO 0x20 -#define DSP_F16_SIGNED 0x10 - -#define IMODE_NONE 0 -#define IMODE_OUTPUT PCM_ENABLE_OUTPUT -#define IMODE_INPUT PCM_ENABLE_INPUT -#define IMODE_INIT 3 -#define IMODE_MIDI 4 - -#define NORMAL_MIDI 0 -#define UART_MIDI 1 - -/* - * values used for bd_flags in SoundBlaster driver - */ -#define BD_F_HISPEED 0x0001 /* doing high speed ... */ - -#define BD_F_JAZZ16 0x0002 /* jazz16 detected */ -#define BD_F_JAZZ16_2 0x0004 /* jazz16 type 2 */ - -#define BD_F_DUP_MIDI 0x0008 /* duplex midi */ - -#define BD_F_MIX_MASK 0x0070 /* up to 8 mixers (I know of 3) */ -#define BD_F_MIX_CT1335 0x0010 /* CT1335 */ -#define BD_F_MIX_CT1345 0x0020 /* CT1345 */ -#define BD_F_MIX_CT1745 0x0030 /* CT1745 */ - -#define BD_F_SB16 0x0100 /* this is a SB16 */ -#define BD_F_SB16X 0x0200 /* this is a vibra16X or clone */ -#define BD_F_MIDIBUSY 0x0400 /* midi busy */ -#define BD_F_ESS 0x0800 /* this is an ESS chip */ -/* - * on some SB16 cards, at times I swap DMA channels. Remember this - * so that they can be restored later. - */ -#define BD_F_SWAPPED 0x1000 /* have swapped DMA channels */ - - -/* - * sound/sb_mixer.h - * - * Definitions for the SB Pro and SB16 mixers - * - * Copyright by Hannu Savolainen 1993 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Modified: Hunyue Yau Jan 6 1994 Added defines for the Sound Galaxy NX Pro - * mixer. - * - */ - -#define SBPRO_RECORDING_DEVICES \ - (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) - -/* Same as SB Pro, unless I find otherwise */ -#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES - -#define SBPRO_MIXER_DEVICES \ - (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_VOLUME) - -/* - * SG NX Pro has treble and bass settings on the mixer. The 'speaker' channel - * is the COVOX/DisneySoundSource emulation volume control on the mixer. It - * does NOT control speaker volume. Should have own mask eventually? - */ -#define SGNXPRO_MIXER_DEVICES \ - (SBPRO_MIXER_DEVICES | SOUND_MASK_BASS | \ - SOUND_MASK_TREBLE | SOUND_MASK_SPEAKER ) - -#define SB16_RECORDING_DEVICES \ - (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) - -#define SB16_MIXER_DEVICES \ - (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | \ - SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | \ - SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \ - SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE) - -/* - * Mixer registers - * - * NOTE! RECORD_SRC == IN_FILTER - */ - -/* - * Mixer registers of SB Pro - */ -#define VOC_VOL 0x04 -#define MIC_VOL 0x0A -#define MIC_MIX 0x0A -#define RECORD_SRC 0x0C -#define IN_FILTER 0x0C -#define OUT_FILTER 0x0E -#define MASTER_VOL 0x22 -#define FM_VOL 0x26 -#define CD_VOL 0x28 -#define LINE_VOL 0x2E -#define IRQ_NR 0x80 -#define DMA_NR 0x81 -#define IRQ_STAT 0x82 - -/* - * Additional registers on the SG NX Pro - */ -#define COVOX_VOL 0x42 -#define TREBLE_LVL 0x44 -#define BASS_LVL 0x46 - -#define FREQ_HI (1 << 3)/* Use High-frequency ANFI filters */ -#define FREQ_LOW 0 /* Use Low-frequency ANFI filters */ -#define FILT_ON 0 /* Yes, 0 to turn it on, 1 for off */ -#define FILT_OFF (1 << 5) - -#define MONO_DAC 0x00 -#define STEREO_DAC 0x02 - -/* - * Mixer registers of SB16 - */ -#define SB16_IMASK_L 0x3d -#define SB16_IMASK_R 0x3e -#define SB16_OMASK 0x3c - - -#ifndef __SB_MIXER_C__ -mixer_tab sbpro_mix; -mixer_tab sb16_mix; -#ifdef __SGNXPRO__ -mixer_tab sgnxpro_mix; -#endif -static u_char sb16_recmasks_L[SOUND_MIXER_NRDEVICES]; -static u_char sb16_recmasks_R[SOUND_MIXER_NRDEVICES]; -#else /* __SB_MIXER_C__ defined */ -mixer_tab sbpro_mix = { - PMIX_ENT(SOUND_MIXER_VOLUME, 0x22, 4, 4, 0x22, 0, 4), - PMIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_SYNTH, 0x26, 4, 4, 0x26, 0, 4), - PMIX_ENT(SOUND_MIXER_PCM, 0x04, 4, 4, 0x04, 0, 4), - PMIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_LINE, 0x2e, 4, 4, 0x2e, 0, 4), - PMIX_ENT(SOUND_MIXER_MIC, 0x0a, 0, 3, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_CD, 0x28, 4, 4, 0x28, 0, 4), - PMIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0) -}; - -#ifdef __SGNXPRO__ -mixer_tab sgnxpro_mix = { - PMIX_ENT(SOUND_MIXER_VOLUME, 0x22, 4, 4, 0x22, 0, 4), - PMIX_ENT(SOUND_MIXER_BASS, 0x46, 0, 3, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_TREBLE, 0x44, 0, 3, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_SYNTH, 0x26, 4, 4, 0x26, 0, 4), - PMIX_ENT(SOUND_MIXER_PCM, 0x04, 4, 4, 0x04, 0, 4), - PMIX_ENT(SOUND_MIXER_SPEAKER, 0x42, 0, 3, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_LINE, 0x2e, 4, 4, 0x2e, 0, 4), - PMIX_ENT(SOUND_MIXER_MIC, 0x0a, 0, 3, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_CD, 0x28, 4, 4, 0x28, 0, 4), - PMIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0) -}; -#endif - -mixer_tab sb16_mix = { - PMIX_ENT(SOUND_MIXER_VOLUME, 0x30, 3, 5, 0x31, 3, 5), - PMIX_ENT(SOUND_MIXER_BASS, 0x46, 4, 4, 0x47, 4, 4), - PMIX_ENT(SOUND_MIXER_TREBLE, 0x44, 4, 4, 0x45, 4, 4), - PMIX_ENT(SOUND_MIXER_SYNTH, 0x34, 3, 5, 0x35, 3, 5), - PMIX_ENT(SOUND_MIXER_PCM, 0x32, 3, 5, 0x33, 3, 5), - PMIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 6, 2, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_LINE, 0x38, 3, 5, 0x39, 3, 5), - PMIX_ENT(SOUND_MIXER_MIC, 0x3a, 3, 5, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_CD, 0x36, 3, 5, 0x37, 3, 5), - PMIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), - PMIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 6, 2, 0x40, 6, 2), /* Obsol,Use IGAIN*/ - PMIX_ENT(SOUND_MIXER_IGAIN, 0x3f, 6, 2, 0x40, 6, 2), - PMIX_ENT(SOUND_MIXER_OGAIN, 0x41, 6, 2, 0x42, 6, 2) -}; - -#ifdef SM_GAMES /* Master volume is lower and PCM & FM - * volumes higher than with SB Pro. This - * improves the sound quality */ - -static u_short levels[SOUND_MIXER_NRDEVICES] = -{ - 0x2020, /* Master Volume */ - 0x4b4b, /* Bass */ - 0x4b4b, /* Treble */ - 0x6464, /* FM */ - 0x6464, /* PCM */ - 0x4b4b, /* PC Speaker */ - 0x4b4b, /* Ext Line */ - 0x0000, /* Mic */ - 0x4b4b, /* CD */ - 0x4b4b, /* Recording monitor */ - 0x4b4b, /* SB PCM */ - 0x4b4b, /* Recording level */ - 0x4b4b, /* Input gain */ -0x4b4b}; /* Output gain */ - -#else /* If the user selected just plain SB Pro */ - -static u_short levels[SOUND_MIXER_NRDEVICES] = -{ - 0x5a5a, /* Master Volume */ - 0x4b4b, /* Bass */ - 0x4b4b, /* Treble */ - 0x4b4b, /* FM */ - 0x4b4b, /* PCM */ - 0x4b4b, /* PC Speaker */ - 0x4b4b, /* Ext Line */ - 0x1010, /* Mic */ - 0x4b4b, /* CD */ - 0x4b4b, /* Recording monitor */ - 0x4b4b, /* SB PCM */ - 0x4b4b, /* Recording level */ - 0x4b4b, /* Input gain */ -0x4b4b}; /* Output gain */ -#endif /* SM_GAMES */ - -#if 0 -static u_char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] = -{ - 0x00, /* SOUND_MIXER_VOLUME */ - 0x00, /* SOUND_MIXER_BASS */ - 0x00, /* SOUND_MIXER_TREBLE */ - 0x40, /* SOUND_MIXER_SYNTH */ - 0x00, /* SOUND_MIXER_PCM */ - 0x00, /* SOUND_MIXER_SPEAKER */ - 0x10, /* SOUND_MIXER_LINE */ - 0x01, /* SOUND_MIXER_MIC */ - 0x04, /* SOUND_MIXER_CD */ - 0x00, /* SOUND_MIXER_IMIX */ - 0x00, /* SOUND_MIXER_ALTPCM */ - 0x00, /* SOUND_MIXER_RECLEV */ - 0x00, /* SOUND_MIXER_IGAIN */ - 0x00 /* SOUND_MIXER_OGAIN */ -}; - -static u_char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] = -{ - 0x00, /* SOUND_MIXER_VOLUME */ - 0x00, /* SOUND_MIXER_BASS */ - 0x00, /* SOUND_MIXER_TREBLE */ - 0x20, /* SOUND_MIXER_SYNTH */ - 0x00, /* SOUND_MIXER_PCM */ - 0x00, /* SOUND_MIXER_SPEAKER */ - 0x08, /* SOUND_MIXER_LINE */ - 0x01, /* SOUND_MIXER_MIC */ - 0x02, /* SOUND_MIXER_CD */ - 0x00, /* SOUND_MIXER_IMIX */ - 0x00, /* SOUND_MIXER_ALTPCM */ - 0x00, /* SOUND_MIXER_RECLEV */ - 0x00, /* SOUND_MIXER_IGAIN */ - 0x00 /* SOUND_MIXER_OGAIN */ -}; -#endif - -/* - * Recording sources (SB Pro) - */ -#endif /* __SB_MIXER_C__ */ - -#define SRC_MIC 1 /* Select Microphone recording source */ -#define SRC_CD 3 /* Select CD recording source */ -#define SRC_LINE 7 /* Use Line-in for recording source */ - - diff --git a/sys/i386/isa/snd/sound.c b/sys/i386/isa/snd/sound.c deleted file mode 100644 index bf980fd5b825..000000000000 --- a/sys/i386/isa/snd/sound.c +++ /dev/null @@ -1,1496 +0,0 @@ -/* - * snd/sound.c - * - * Main sound driver for FreeBSD. This file provides the main - * entry points for probe/attach and all i/o demultiplexing, including - * default routines for generic devices. - * - * (C) 1997 Luigi Rizzo (luigi@iet.unipi.it) - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS - * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * For each card type a template "snddev_info" structure contains - * all the relevant parameters, both for configuration and runtime. - * - * In this file we build tables of pointers to the descriptors for - * the various supported cards. The generic probe routine scans - * the table(s) looking for a matching entry, then invokes the - * board-specific probe routine. If successful, a pointer to the - * correct snddev_info is stored in snddev_last_probed, for subsequent - * use in the attach routine. The generic attach routine copies - * the template to a permanent descriptor (pcm_info[unit] and - * friends), initializes all generic parameters, and calls the - * board-specific attach routine. - * - * On device calls, the generic routines do the checks on unit and - * device parameters, then call the board-specific routines if - * available, or try to perform the task using the default code. - * - * $FreeBSD$ - * - */ - -#include - - -#if NPCM > 0 /* from "pcm.h" via disgusting #include in snd/sound.h */ - -extern struct isa_driver pcmdriver ; -#define SNDSTAT_BUF_SIZE 4000 -static char status_buf[SNDSTAT_BUF_SIZE] ; -static int status_len = 0 ; -static void init_status(snddev_info *d); - -static d_open_t sndopen; -static d_close_t sndclose; -static d_ioctl_t sndioctl; -static d_read_t sndread; -static d_write_t sndwrite; -static d_mmap_t sndmmap; - -#define CDEV_MAJOR 30 -static struct cdevsw snd_cdevsw = { - /* open */ sndopen, - /* close */ sndclose, - /* read */ sndread, - /* write */ sndwrite, - /* ioctl */ sndioctl, - /* poll */ sndselect, - /* mmap */ sndmmap, - /* strategy */ nostrategy, - /* name */ "snd", - /* maj */ CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ 0, - /* bmaj */ -1 -}; - -/* - * descriptors for active devices. - * - */ -snddev_info pcm_info[NPCM_MAX] ; -snddev_info midi_info[NPCM_MAX] ; -snddev_info synth_info[NPCM_MAX] ; - -u_long nsnd = NPCM ; /* total number of sound devices */ - -/* - * Hooks for APM support, but code not operational yet. - */ - -#include "apm.h" -#include -#if NAPM > 0 - -static int -sound_suspend(void *arg) -{ - /* - * I think i can safely do nothing here and - * reserve all the work for wakeup time - */ - printf("Called APM sound suspend hook for unit %d\n", (int)arg); - return 0 ; -} - -static int -sound_resume(void *arg) -{ - snddev_info *d = NULL ; - - d = &pcm_info[(int)arg] ; - /* - * reinitialize card registers. - * Flush buffers and reinitialize DMA channels. - * If a write was pending, pretend it is done - * (and issue any wakeup we need). - * If a read is pending, restart it. - */ - if (d->bd_id == MD_YM0020) { - DDB(printf("setting up yamaha registers\n")); - outb(0x370, 6 /* dma config */ ) ; - if (FULL_DUPLEX(d)) - outb(0x371, 0xa9 ); /* use both dma chans */ - else - outb(0x371, 0x8b ); /* use low dma chan */ - } - printf("Called APM sound resume hook for unit %d\n", (int)arg); - return 0 ; -} - -static void -init_sound_apm(int unit) -{ - struct apmhook *ap; - - ap = malloc(sizeof *ap, M_DEVBUF, M_NOWAIT); - bzero(ap, sizeof *ap); - - ap->ah_fun = sound_resume; - ap->ah_arg = (void *)unit; - ap->ah_name = "pcm resume handler"; - ap->ah_order = APM_MID_ORDER; - apm_hook_establish(APM_HOOK_RESUME, ap); - - ap = malloc(sizeof *ap, M_DEVBUF, M_NOWAIT); - bzero(ap, sizeof *ap); - - ap->ah_fun = sound_suspend; - ap->ah_arg = (void *)unit; - ap->ah_name = "pcm suspend handler"; - ap->ah_order = APM_MID_ORDER; - apm_hook_establish(APM_HOOK_SUSPEND, ap); -} -#endif /* NAPM */ - -/* - * the probe routine can only return an int to the upper layer. Hence, - * it leaves the pointer to the last successfully - * probed device descriptor in snddev_last_probed - */ -snddev_info *snddev_last_probed = NULL ; - -static snddev_info * -generic_snd_probe(struct isa_device * dev, snddev_info **p[], char *s); - -/* - * here are the lists of known cards. Similar cards (e.g. all - * sb clones, all mss clones, ... are in the same array. - * All lists of devices of the same type (eg. all pcm, all midi...) - * are in the same array. - * Each probe for a device type gets the pointer to the main array - * and then scans the sublists. - * - * XXX should use DATA_SET to create a linker set for sb_devs and other - * such structures. - */ - -extern snddev_info sb_op_desc; -extern snddev_info mss_op_desc; - -static snddev_info *sb_devs[] = { /* all SB clones */ - &sb_op_desc, - NULL, -} ; - -static snddev_info *mss_devs[] = { /* all MSS clones */ - &mss_op_desc, - NULL, -} ; - -static snddev_info **pcm_devslist[] = { /* all pcm devices */ - mss_devs, - sb_devs, - NULL -} ; - - -int -pcmprobe(struct isa_device * dev) -{ - bzero(&pcm_info[dev->id_unit], sizeof(pcm_info[dev->id_unit]) ); - return generic_snd_probe(dev, pcm_devslist, "pcm") ? 1 : 0 ; -} - -static snddev_info **midi_devslist[] = {/* all midi devices */ - NULL -} ; - -int -midiprobe(struct isa_device * dev) -{ - bzero(&midi_info[dev->id_unit], sizeof(midi_info[dev->id_unit]) ); - return 0 ; - return generic_snd_probe(dev, midi_devslist, "midi") ? 1 : 0 ; -} - -int -synthprobe(struct isa_device * dev) -{ - bzero(&synth_info[dev->id_unit], sizeof(synth_info[dev->id_unit]) ); - return 0 ; -} - -/* - * this is the ISA part of the generic attach routine - */ - -int -pcmattach(struct isa_device * dev) -{ - snddev_info *d = NULL ; - int stat = 0; - - dev->id_ointr = pcmintr; - - if ( (dev->id_unit >= NPCM_MAX) || /* too many devs */ - (snddev_last_probed == NULL) || /* last probe failed */ - (snddev_last_probed->attach==NULL) ) /* no attach routine */ - return 0 ; /* fail */ - - /* - * default initialization: copy generic parameters for the routine, - * initialize from the isa_device structure, and allocate memory. - * If everything succeeds, then call the attach routine for - * further initialization. - */ - pcm_info[dev->id_unit] = *snddev_last_probed ; - d = &pcm_info[dev->id_unit] ; - - d->io_base = dev->id_iobase ; - d->irq = ffs(dev->id_irq) - 1 ; - d->dbuf_out.chan = dev->id_drq ; - if (dev->id_flags != -1 && dev->id_flags & DV_F_DUAL_DMA && - (dev->id_flags & DV_F_DRQ_MASK) != 4 ) /* enable dma2 */ - d->dbuf_in.chan = dev->id_flags & DV_F_DRQ_MASK ; - else - d->dbuf_in.chan = d->dbuf_out.chan ; -#if 1 /* does this cause trouble with PnP cards ? */ - if (d->bd_id == 0) - d->bd_id = (dev->id_flags & DV_F_DEV_MASK) >> DV_F_DEV_SHIFT ; -#endif - d->status_ptr = 0; - - /* - * Allocates memory and initializes the dma structs properly. We - * use independent buffers for each channel. For the time being, - * this is done independently of the dma setting. In future - * revisions, if we see that we have a single dma, we might decide - * to use a single buffer to save memory. - */ - alloc_dbuf( &(d->dbuf_out), d->bufsize ); - alloc_dbuf( &(d->dbuf_in), d->bufsize ); - - isa_dma_acquire(d->dbuf_out.chan); - if (FULL_DUPLEX(d)) - isa_dma_acquire(d->dbuf_in.chan); - - - /* - * should try and find a suitable value for id_id, otherwise - * the interrupt is not registered and dispatched properly. - * This is important for PnP devices, where "dev" is built on - * the fly and many field are not initialized. - */ - if (dev->id_driver == NULL) { - dev->id_driver = &pcmdriver ; - dev->id_id = isa_compat_nextid(); - } - - /* - * call the generic part of the attach - */ - pcminit(d, dev->id_unit); - /* - * and finally, call the device attach routine - * XXX I should probably use d->attach(dev) - */ - stat = snddev_last_probed->attach(dev); -#if 0 - /* - * XXX hooks for synt support. Try probe and attach... - */ - if (d->synth_base && opl3_probe(dev) ) { - opl3_attach(dev); - } -#endif - snddev_last_probed = NULL ; - - return stat ; -} - -/* - * This is the generic init routine - */ -int -pcminit(snddev_info *d, int unit) -{ - cdevsw_add(&snd_cdevsw); - - /* - * initialize standard parameters for the device. This can be - * overridden by device-specific configurations but better do - * here the generic things. - */ - - d->magic = MAGIC(unit); /* debugging... */ - d->play_speed = d->rec_speed = 8000 ; - d->play_blocksize = d->rec_blocksize = 2048 ; - d->play_fmt = d->rec_fmt = AFMT_MU_LAW ; - -#ifndef GID_GAMES -#define GID_SND UID_ROOT -#else -#define GID_SND GID_GAMES /* i am not really sure this is a good one. */ -#endif -#define UID_SND UID_ROOT -#define PERM_SND 0660 - /* - * Make links to first successfully probed unit. - * Attempts by later devices to make these links will fail. - */ - make_dev(&snd_cdevsw, (unit << 4) | SND_DEV_DSP, - UID_SND, GID_SND, PERM_SND, "dsp%r", unit); - make_dev(&snd_cdevsw, (unit << 4) | SND_DEV_DSP16, - UID_SND, GID_SND, PERM_SND, "dspW%r", unit); - make_dev(&snd_cdevsw, (unit << 4) | SND_DEV_AUDIO, - UID_SND, GID_SND, PERM_SND, "audio%r", unit); - make_dev(&snd_cdevsw, (unit << 4) | SND_DEV_CTL, - UID_SND, GID_SND, PERM_SND, "mixer%r", unit); - make_dev(&snd_cdevsw, (unit << 4) | SND_DEV_STATUS, - UID_SND, GID_SND, PERM_SND, "sndstat%r", unit); - -#if NAPM > 0 - init_sound_apm(unit); -#endif - return 0 ; -} - -int midiattach(struct isa_device * dev) { return 0 ; } -int synthattach(struct isa_device * dev) { return 0 ; } - -struct isa_driver pcmdriver = { pcmprobe, pcmattach, "pcm" } ; - -struct isa_driver mididriver = { midiprobe, midiattach, "midi" } ; -struct isa_driver synthdriver = { synthprobe, synthattach, "synth" } ; - -void -pcmintr(int unit) -{ - DEB(printf("__/\\/ pcmintr -- unit %d\n", unit)); - pcm_info[unit].interrupts++; - if (pcm_info[unit].isr) - pcm_info[unit].isr(unit); -#if 0 /* these do not exist at the moment. */ - if (midi_info[unit].isr) - midi_info[unit].isr(unit); - if (synth_info[unit].isr) - synth_info[unit].isr(unit); -#endif -} - -static snddev_info * -generic_snd_probe(struct isa_device * dev, snddev_info **p[], char *s) -{ - snddev_info **q ; - struct isa_device saved_dev ; - - snddev_last_probed = NULL ; - - saved_dev = *dev ; /* the probe routine might alter parameters */ - - /* - * XXX todo: should try to match flags with device type. - */ - for ( ; p[0] != NULL ; p++ ) - for ( q = *p ; q[0] ; q++ ) - if (q[0]->probe && q[0]->probe(dev)) - return (snddev_last_probed = q[0]) ; - else - *dev = saved_dev ; - - return NULL ; -} - - -/* - * a small utility function which, given a device number, returns - * a pointer to the associated snddev_info struct, and sets the unit - * number. - */ -static snddev_info * -get_snddev_info(dev_t i_dev, int *unit) -{ - int u; - snddev_info *d = NULL ; - int dev; - - dev = minor(i_dev); - u = dev >> 4 ; - if (unit) - *unit = u ; - - if (u >= NPCM_MAX || - ( pcm_info[u].io_base == 0 && (dev & 0x0f) != SND_DEV_STATUS)) { - int i; - for (i = 0 ; i < NPCM_MAX ; i++) - if (pcm_info[i].io_base) - break ; - if (i != NPCM_MAX) - printf("pcm%d: unit not configured, perhaps you want pcm%d ?\n", - u, i); - else - printf("no pcm units configured\b"); - return NULL ; - } - switch(dev & 0x0f) { - case SND_DEV_CTL : /* /dev/mixer handled by pcm */ - case SND_DEV_STATUS : /* /dev/sndstat handled by pcm */ - case SND_DEV_SNDPROC : /* /dev/sndproc handled by pcm */ - case SND_DEV_DSP : - case SND_DEV_DSP16 : - case SND_DEV_AUDIO : - case SND_DEV_SEQ : /* XXX when enabled... */ - d = & pcm_info[u] ; - break ; - case SND_DEV_SEQ2 : - case SND_DEV_MIDIN: - default: - printf("unsupported subdevice %d\n", dev & 0xf); - return NULL ; - } - return d ; -} - -/* - * here are the switches for the main functions. The switches do - * all necessary checks on the device number to make sure - * that the device is configured. They also provide some default - * functionalities so that device-specific drivers have to deal - * only with special cases. - */ - -static int -sndopen(dev_t i_dev, int flags, int mode, struct proc * p) -{ - int dev, unit ; - snddev_info *d; - - dev = minor(i_dev); - d = get_snddev_info(i_dev, &unit); - - DEB(printf("open snd%d subdev %d flags 0x%08x mode 0x%08x\n", - unit, dev & 0xf, flags, mode)); - - if (d == NULL) - return (ENXIO) ; - - switch(dev & 0x0f) { - case SND_DEV_SEQ: /* sequencer. Hack... */ -#if 0 /* XXX hook for opl3 support */ - if (d->synth_base) - return opl3_open(i_dev, flags, mode, p); - else -#endif - return ENXIO ; - - case SND_DEV_CTL : /* mixer ... */ - return 0 ; /* always succeed */ - - case SND_DEV_STATUS : /* implemented right here */ - init_status(&pcm_info[unit]); - d->status_ptr = 0 ; - return 0 ; - - default: - if (d->open == NULL) { - printf("open: unit %d not configured, perhaps you want unit %d ?\n", - unit, unit+1 ); - return (ENXIO) ; - } else - return d->open(i_dev, flags, mode, p); - } - return ENXIO ; -} - -static int -sndclose(dev_t i_dev, int flags, int mode, struct proc * p) -{ - int dev, unit ; - snddev_info *d; - - dev = minor(i_dev); - d = get_snddev_info(i_dev, &unit); - - DEB(printf("close snd%d subdev %d\n", unit, dev & 0xf)); - - if (d == NULL) - return (ENXIO) ; - - switch(dev & 0xf) { /* only those for which close makes sense */ - case SND_DEV_SEQ: -#if 0 /* XXX hook for opl3 support */ - if (d->synth_base) - return opl3_close(i_dev, flags, mode, p); - else -#endif - return ENXIO ; - - case SND_DEV_AUDIO : - case SND_DEV_DSP : - case SND_DEV_DSP16 : - if (d->close) - return d->close(i_dev, flags, mode, p); - } - return 0 ; -} - -static int -sndread(dev_t i_dev, struct uio * buf, int flag) -{ - int ret, dev, unit; - snddev_info *d ; - u_long s; - - dev = minor(i_dev); - - d = get_snddev_info(i_dev, &unit); - DEB(printf("read snd%d subdev %d flag 0x%08x\n", unit, dev & 0xf, flag)); - - if (d == NULL) - return ENXIO ; - - if ( (dev & 0x0f) == SND_DEV_STATUS ) { - int l, c; - u_char *p; - - l = buf->uio_resid; - s=spltty(); - c = status_len - d->status_ptr ; - if (c < 0) /* should not happen! */ - c = 0 ; - if (c < l) - l = c ; - p = status_buf + d->status_ptr ; - d->status_ptr += l ; - splx(s); - return uiomove(p, l, buf) ; - } - - /* - * XXX read from the ad1816 with a single DMA channel is unsupported. - * This is really not the place for machine-dependent functions, - * a proper device routine will be supplied in the future - luigi - */ - if ((d->bd_id == MD_AD1816) && (!(FULL_DUPLEX(d)))) - return EIO; - - if (d->read) /* device-specific read */ - return d->read(i_dev, buf, flag); - - /* - * the generic read routine. device-specific stuff should only - * be in the dma-handling procedures. - */ - s = spltty(); - if ( d->flags & SND_F_READING ) { - /* another reader is in, deny request */ - splx(s); - DDB(printf("read denied, another reader is in\n")); - /* - * sleep for a while to avoid killing the machine. - */ - tsleep( (void *)s, PZERO, "sndar", hz ) ; - return EBUSY ; - } - if ( ! FULL_DUPLEX(d) ) { /* half duplex */ - if ( d->flags & SND_F_WRITING ) { - /* another writer is in, deny request */ - splx(s); - DDB(printf("read denied, half duplex and a writer is in\n")); - tsleep( (void *)s, PZERO, "sndaw", hz ) ; - return EBUSY ; - } - while ( d->dbuf_out.dl ) { - /* - * we have a pending dma operation, post a read request - * and wait for the write to complete. - */ - d->flags |= SND_F_READING ; - DEB(printf("sndread: sleeping waiting for write to end\n")); - ret = tsleep( (caddr_t)&(d->dbuf_out), - PRIBIO | PCATCH , "sndrdw", hz ) ; - if (ret == ERESTART || ret == EINTR) { - d->flags &= ~SND_F_READING ; - splx(s); - return EINTR ; - } - } - } - d->flags |= SND_F_READING ; - splx(s); - - return dsp_read_body(d, buf); -} - -static int -sndwrite(dev_t i_dev, struct uio * buf, int flag) -{ - int ret, dev, unit; - snddev_info *d; - u_long s; - - dev = minor(i_dev); - d = get_snddev_info(i_dev, &unit); - - DEB(printf("write snd%d subdev %d flag 0x%08x\n", unit, dev & 0xf, flag)); - - if (d == NULL) - return (ENXIO) ; - - switch( dev & 0x0f) { /* only writeable devices */ - case SND_DEV_MIDIN: /* XXX is this writable ? */ - case SND_DEV_SEQ : - case SND_DEV_SEQ2 : - case SND_DEV_DSP : - case SND_DEV_DSP16 : - case SND_DEV_AUDIO : - break ; - default: - return EPERM ; /* for non-writeable devices ; */ - } - if (d->write) - return d->write(i_dev, buf, flag); - - /* - * Otherwise, use the generic write routine. device-specific - * stuff should only be in the dma-handling procedures. - */ - - s = spltty(); - if ( d->flags & SND_F_WRITING ) { - /* another writer is in, deny request */ - splx(s); - DDB(printf("write denied, another writer is in\n")); - tsleep( (void *)s, PZERO , "sndaw", hz ) ; - return EBUSY ; - } - if ( ! FULL_DUPLEX(d) ) { /* half duplex */ - if ( d->flags & SND_F_READING ) { - /* another reader is in, deny request */ - splx(s); - DDB(printf("write denied, half duplex and a reader is in\n")); - tsleep( (void *)s, PZERO, "sndar", hz ) ; - return EBUSY ; - } - while ( d->dbuf_in.dl ) { - /* - * we have a pending read dma. Post a write request - * and wait for the read to complete (in fact I could - * abort the read dma... - */ - d->flags |= SND_F_WRITING ; - DEB(printf("sndwrite: sleeping waiting for read to end\n")); - ret = tsleep( (caddr_t)&(d->dbuf_out), - PRIBIO | PCATCH , "sndwr", hz ) ; - if (ret == ERESTART || ret == EINTR) { - d->flags &= ~SND_F_WRITING ; - splx(s); - return EINTR ; - } - } - } - d->flags |= SND_F_WRITING ; - splx(s); - - return dsp_write_body(d, buf); -} - -/* - * generic sound ioctl. Functions of the default driver can be - * overridden by the device-specific ioctl call. - * If a device-specific call returns ENOSYS (Function not implemented), - * the default driver is called. Otherwise, the returned value - * is passed up. - * - * The default handler, for many parameters, sets the value in the - * descriptor, sets SND_F_INIT, and calls the callback function with - * reason INIT. If successful, the callback returns 1 and the caller - * can update the parameter. - */ - -static int -sndioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p) -{ - int ret = ENOSYS, dev, unit ; - snddev_info *d; - u_long s; - - dev = minor(i_dev); - d = get_snddev_info(i_dev, &unit); - - if (d == NULL) - return (ENXIO) ; - - if ( (dev & 0x0f) == SND_DEV_SEQ ) { - /* sequencer. Hack... */ -#if 0 - if (d->synth_base) - return opl3_ioctl(i_dev, cmd, arg, mode, p) ; - else -#endif - return ENXIO ; - } - if (d->ioctl) - ret = d->ioctl(i_dev, cmd, arg, mode, p); - if (ret != ENOSYS) - return ret ; - - /* - * pass control to the default ioctl handler. Set ret to 0 now. - */ - ret = 0 ; - - /* - * The linux ioctl interface for the sound driver has a thousand - * different calls, and it is unpractical to put the names in - * the switch(). So we have some tests before for common routines, - * such as the ones related to the mixer. But we really ought - * to redesign the interface! - * - * Reading from the mixer just requires to look at the cached - * copy in d->mix_levels[dev], so this routine should cover - * practically all needs for mixer reading. - */ - if ( (cmd & MIXER_READ(0)) == MIXER_READ(0) && (cmd & 0xff) < 32 ) { - int dev = cmd & 0x1f ; - if ( d->mix_devs & (1<mix_levels[dev]; - return 0 ; - } else - return EINVAL ; - } - - /* - * all routines are called with int. blocked. Make sure that - * ints are re-enabled when calling slow or blocking functions! - */ - s = spltty(); - switch(cmd) { - - /* - * we start with the new ioctl interface. - */ - case AIONWRITE : /* how many bytes can write ? */ - if (d->dbuf_out.dl) { - if (d->special_dma) - d->callback(d, SND_CB_WR | SND_CB_DMAUPDATE) ; - else - dsp_wr_dmaupdate(&(d->dbuf_out)); - } - *(int *)arg = d->dbuf_out.fl; - break; - - case AIOSSIZE : /* set the current blocksize */ - { - struct snd_size *p = (struct snd_size *)arg; - if (p->play_size <= 1 && p->rec_size <= 1) { /* means no blocks */ - d->flags &= ~SND_F_HAS_SIZE ; - } else { - RANGE (p->play_size, 40, d->dbuf_out.bufsize /4); - d->play_blocksize = p->play_size & ~3 ; - RANGE (p->rec_size, 40, d->dbuf_in.bufsize /4); - d->rec_blocksize = p->rec_size & ~3 ; - d->flags |= SND_F_HAS_SIZE ; - } - } - splx(s); - ask_init(d); - /* FALLTHROUGH */ - case AIOGSIZE : /* get the current blocksize */ - { - struct snd_size *p = (struct snd_size *)arg; - p->play_size = d->play_blocksize ; - p->rec_size = d->rec_blocksize ; - } - break ; - - case AIOSFMT : - { - snd_chan_param *p = (snd_chan_param *)arg; - d->play_speed = p->play_rate; - d->rec_speed = p->play_rate; /* XXX one speed allowed */ - if (p->play_format & AFMT_STEREO) - d->flags |= SND_F_STEREO ; - else - d->flags &= ~SND_F_STEREO ; - d->play_fmt = p->play_format & ~AFMT_STEREO ; - d->rec_fmt = p->rec_format & ~AFMT_STEREO ; - } - splx(s); - if (!ask_init(d)) - break ; /* could not reinit */ - /* FALLTHROUGH */ - - case AIOGFMT : - { - snd_chan_param *p = (snd_chan_param *)arg; - p->play_rate = d->play_speed; - p->rec_rate = d->rec_speed; - p->play_format = d->play_fmt; - p->rec_format = d->rec_fmt; - if (d->flags & SND_F_STEREO) { - p->play_format |= AFMT_STEREO ; - p->rec_format |= AFMT_STEREO ; - } - } - break; - - case AIOGCAP : /* get capabilities */ - /* this should really be implemented by the driver */ - { - snd_capabilities *p = (snd_capabilities *)arg; - p->rate_min = 5000; - p->rate_max = 48000; /* default */ - p->bufsize = d->bufsize; - p->formats = d->audio_fmt; /* default */ - p->mixers = 1 ; /* default: one mixer */ - p->inputs = d->mix_devs ; - p->left = p->right = 255 ; - } - break ; - - case AIOSTOP: - if (*(int *)arg == AIOSYNC_PLAY) /* play */ - *(int *)arg = dsp_wrabort(d, 1 /* restart */); - else if (*(int *)arg == AIOSYNC_CAPTURE) - *(int *)arg = dsp_rdabort(d, 1 /* restart */); - else { - splx(s); - printf("AIOSTOP: bad channel 0x%x\n", *(int *)arg); - *(int *)arg = 0 ; - } - break ; - - case AIOSYNC: - printf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n", - ((snd_sync_parm *)arg)->chan, - ((snd_sync_parm *)arg)->pos); - break; - /* - * here follow the standard ioctls (filio.h etc.) - */ - case FIONREAD : /* get # bytes to read */ - if ( d->dbuf_in.dl ) { - if (d->special_dma) - d->callback(d, SND_CB_RD | SND_CB_DMAUPDATE) ; - else - dsp_rd_dmaupdate(&(d->dbuf_in)); - } - *(int *)arg = d->dbuf_in.rl; - break; - - case FIOASYNC: /*set/clear async i/o */ - DEB( printf("FIOASYNC\n") ; ) - break; - - case SNDCTL_DSP_NONBLOCK : - case FIONBIO : /* set/clear non-blocking i/o */ - if ( *(int *)arg == 0 ) - d->flags &= ~SND_F_NBIO ; - else - d->flags |= SND_F_NBIO ; - break ; - - /* - * Finally, here is the linux-compatible ioctl interface - */ -#define THE_REAL_SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int) - case THE_REAL_SNDCTL_DSP_GETBLKSIZE: - case SNDCTL_DSP_GETBLKSIZE: - *(int *) arg = d->play_blocksize ; - break ; - - case SNDCTL_DSP_SETBLKSIZE : - { - int t = *(int *)arg; - if (t <= 1) { /* means no blocks */ - d->flags &= ~SND_F_HAS_SIZE ; - } else { - RANGE (t, 40, d->dbuf_out.bufsize /4); - d->play_blocksize = - d->rec_blocksize = t & ~3 ; /* align to multiple of 4 */ - d->flags |= SND_F_HAS_SIZE ; - } - } - splx(s); - ask_init(d); - break ; - case SNDCTL_DSP_RESET: - DEB(printf("dsp reset\n")); - dsp_wrabort(d, 1 /* restart */); - dsp_rdabort(d, 1 /* restart */); - break ; - - case SNDCTL_DSP_SYNC: - DEB(printf("dsp sync\n")); - splx(s); - snd_sync(d, 1, d->dbuf_out.bufsize - 4); /* DMA does not start with <4 bytes */ - break ; - - case SNDCTL_DSP_SPEED: - d->play_speed = d->rec_speed = *(int *)arg ; - splx(s); - if (ask_init(d)) - *(int *)arg = d->play_speed ; - break ; - - case SNDCTL_DSP_STEREO: - if ( *(int *)arg == 0 ) - d->flags &= ~SND_F_STEREO ; /* mono */ - else if ( *(int *)arg == 1 ) - d->flags |= SND_F_STEREO ; /* stereo */ - else { - printf("dsp stereo: %d is invalid, assuming 1\n", *(int *)arg ); - d->flags |= SND_F_STEREO ; /* stereo */ - } - splx(s); - if (ask_init(d)) - *(int *)arg = (d->flags & SND_F_STEREO) ? 1 : 0 ; - break ; - - case SOUND_PCM_WRITE_CHANNELS: - if ( *(int *)arg == 1) - d->flags &= ~SND_F_STEREO ; /* mono */ - else if ( *(int *)arg == 2) - d->flags |= SND_F_STEREO ; /* stereo */ - else { - ret = EINVAL ; - break ; - } - splx(s); - if (ask_init(d)) - *(int *)arg = (d->flags & SND_F_STEREO) ? 2 : 1 ; - break ; - - case SOUND_PCM_READ_RATE: - *(int *)arg = d->play_speed; - break ; - - case SOUND_PCM_READ_CHANNELS: - *(int *)arg = (d->flags & SND_F_STEREO) ? 2 : 1; - break ; - - case SNDCTL_DSP_GETFMTS: /* returns a mask of supported fmts */ - *(int *)arg = (int)d->audio_fmt ; - break ; - - case SNDCTL_DSP_SETFMT: /* sets _one_ format */ - /* - * when some card (SB16) is opened RDONLY or WRONLY, - * only one of the fields is set, the other becomes 0. - * This makes it possible to select DMA channels at runtime. - */ - if (d->play_fmt) - d->play_fmt = *(int *)arg ; - if (d->rec_fmt) - d->rec_fmt = *(int *)arg ; - splx(s); - if (ask_init(d)) - *(int *)arg = d->play_fmt ; - break ; - - case SNDCTL_DSP_SUBDIVIDE: - /* XXX watch out, this is RW! */ - DEB(printf("SNDCTL_DSP_SUBDIVIDE yet unimplemented\n");) - break; - - case SNDCTL_DSP_SETFRAGMENT: - /* XXX watch out, this is RW! */ - DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg)); - { - int bytes, count; - bytes = *(int *)arg & 0xffff ; - count = ( *(int *)arg >> 16) & 0xffff ; - if (bytes > 15) - bytes = 15 ; - bytes = 1 << bytes ; - if (bytes <= 1) { /* means no blocks */ - d->flags &= ~SND_F_HAS_SIZE ; - } else { - RANGE (bytes, 40, d->dbuf_out.bufsize /4); - d->play_blocksize = - d->rec_blocksize = bytes & ~3 ; /* align to multiple of 4 */ - d->flags |= SND_F_HAS_SIZE ; - } - splx(s); - ask_init(d); -#if 0 - /* XXX todo: set the buffer size to the # of fragments */ - count = d->dbuf_in.bufsize / d->play_blocksize ; - bytes = ffs(d->play_blocksize) - 1; - /* - * don't change arg, since it's fake anyways and some - * programs might fail if we do. - */ - *(int *)arg = (count << 16) | bytes ; -#endif - } - break ; - - case SNDCTL_DSP_GETISPACE: - /* return space available in the input queue */ - { - audio_buf_info *a = (audio_buf_info *)arg; - snd_dbuf *b = &(d->dbuf_in); - if (b->dl) { - if (d->special_dma) - d->callback(d, SND_CB_RD | SND_CB_DMAUPDATE) ; - else - dsp_rd_dmaupdate( b ); - } - a->bytes = d->dbuf_in.fl ; - a->fragments = 1 ; - a->fragstotal = b->bufsize / d->rec_blocksize ; - a->fragsize = d->rec_blocksize ; - } - break ; - - case SNDCTL_DSP_GETOSPACE: - /* return space available in the output queue */ - { - audio_buf_info *a = (audio_buf_info *)arg; - snd_dbuf *b = &(d->dbuf_out); - if (b->dl) { - if (d->special_dma) - d->callback(d, SND_CB_WR | SND_CB_DMAUPDATE) ; - else - dsp_wr_dmaupdate( b ); - } - a->bytes = d->dbuf_out.fl ; - a->fragments = 1 ; - a->fragstotal = b->bufsize / d->play_blocksize ; - a->fragsize = d->play_blocksize ; - } - break ; - - case SNDCTL_DSP_GETIPTR: - { - count_info *a = (count_info *)arg; - snd_dbuf *b = &(d->dbuf_in); - if (b->dl) { - if (d->special_dma) - d->callback(d, SND_CB_RD | SND_CB_DMAUPDATE) ; - else - dsp_rd_dmaupdate( b ); - } - a->bytes = b->total; - a->blocks = (b->total - b->prev_total + - d->rec_blocksize -1 ) / d->rec_blocksize ; - a->ptr = b->fp ; /* XXX not sure... */ - b->prev_total = b->total ; - } - break; - - case SNDCTL_DSP_GETOPTR: - { - count_info *a = (count_info *)arg; - snd_dbuf *b = &(d->dbuf_out); - if (b->dl) { - if (d->special_dma) - d->callback(d, SND_CB_WR | SND_CB_DMAUPDATE) ; - else - dsp_wr_dmaupdate( b ); - } - a->bytes = b->total; - a->blocks = (b->total - b->prev_total - /* +d->play_blocksize -1*/ ) / d->play_blocksize ; - a->ptr = b->rp ; /* XXX not sure... */ - b->prev_total = b->total ; - } - break; - - case SNDCTL_DSP_GETCAPS : - *(int *) arg = 0x0 ; /* revision */ - if (FULL_DUPLEX(d)) - *(int *) arg |= DSP_CAP_DUPLEX ; - *(int *) arg |= DSP_CAP_REALTIME ; - break ; - - case SOUND_PCM_READ_BITS: - if (d->play_fmt == AFMT_S16_LE) - *(int *) arg = 16 ; - else - *(int *) arg = 8 ; - break ; - - /* - * mixer calls - */ - - case SOUND_MIXER_READ_DEVMASK : - case SOUND_MIXER_READ_CAPS : - case SOUND_MIXER_READ_STEREODEVS : - *(int *)arg = d->mix_devs; - break ; - - case SOUND_MIXER_READ_RECMASK : - *(int *)arg = d->mix_rec_devs; - break ; - - case SOUND_MIXER_READ_RECSRC : - *(int *)arg = d->mix_recsrc ; - break; - - default: - DEB(printf("default ioctl snd%d subdev %d fn 0x%08x fail\n", - unit, dev & 0xf, cmd)); - ret = EINVAL; - break ; - } - splx(s); - return ret ; -} - -/* - * we use the name 'select', but the new "poll" interface this is - * really sndpoll. Second arg for poll is not "rw" but "events" - */ -int -sndselect(dev_t i_dev, int rw, struct proc * p) -{ - int dev, unit, c = 1 /* default: success */ ; - snddev_info *d ; - u_long flags; - - dev = minor(i_dev); - d = get_snddev_info(i_dev, &unit); - DEB(printf("sndselect dev 0x%04x rw 0x%08x\n",i_dev, rw)); - if (d == NULL ) /* should not happen! */ - return (ENXIO) ; - if (d->select == NULL) - return ( (rw & (POLLIN|POLLOUT|POLLRDNORM|POLLWRNORM)) | POLLHUP); - else if (d->select != sndselect ) - return d->select(i_dev, rw, p); - else { - /* handle it here with the generic code */ - /* - * if the user selected a block size, then we want to use the - * device as a block device, and select will return ready when - * we have a full block. - * In all other cases, select will return when 1 byte is ready. - */ - int lim = 1; - - int revents = 0 ; - if (rw & (POLLOUT | POLLWRNORM) ) { - if ( d->flags & SND_F_HAS_SIZE ) - lim = d->play_blocksize ; - /* XXX fix the test here for half duplex devices */ - if (1 /* write is compatible with current mode */) { - flags = spltty(); - if (d->dbuf_out.dl) { - if (d->special_dma) - d->callback(d, SND_CB_WR | SND_CB_DMAUPDATE) ; - else - dsp_wr_dmaupdate(&(d->dbuf_out)); - } - c = d->dbuf_out.fl ; - if (c < lim) /* no space available */ - selrecord(p, & (d->wsel)); - else - revents |= rw & (POLLOUT | POLLWRNORM); - splx(flags); - } - } - if (rw & (POLLIN | POLLRDNORM)) { - if ( d->flags & SND_F_HAS_SIZE ) - lim = d->rec_blocksize ; - /* XXX fix the test here */ - if (1 /* read is compatible with current mode */) { - flags = spltty(); - if ( d->dbuf_in.dl == 0 ) /* dma idle, restart it */ - dsp_rdintr(d); - else { - if (d->special_dma) - d->callback(d, SND_CB_RD | SND_CB_DMAUPDATE) ; - else - dsp_rd_dmaupdate(&(d->dbuf_in)); - } - c = d->dbuf_in.rl ; - if (c < lim) /* no data available */ - selrecord(p, & (d->rsel)); - else - revents |= rw & (POLLIN | POLLRDNORM); - splx(flags); - } - DEB(printf("sndselect on read: %d >= %d flags 0x%08x\n", - c, lim, d->flags)); - return c < lim ? 0 : 1 ; - } - return revents; - } - return ENXIO ; /* notreached */ -} - -/* - * The mmap interface allows access to the play and read buffer, - * plus the device descriptor. - * The various blocks are accessible at the following offsets: - * - * 0x00000000 ( 0 ) : write buffer ; - * 0x01000000 (16 MB) : read buffer ; - * 0x02000000 (32 MB) : device descriptor (dangerous!) - * - * WARNING: the mmap routines assume memory areas are aligned. This - * is true (probably) for the dma buffers, but likely false for the - * device descriptor. As a consequence, we do not know where it is - * located in the requested area. - */ -#include -#include -#include -#include -#include -#include - -static int -sndmmap(dev_t dev, vm_offset_t offset, int nprot) -{ - snddev_info *d = get_snddev_info(dev, NULL); - - DEB(printf("sndmmap d 0x%p dev 0x%04x ofs 0x%08x nprot 0x%08x\n", - d, dev, offset, nprot)); - - if (d == NULL || nprot & PROT_EXEC) - return -1 ; /* forbidden */ - - if (offset >= d->dbuf_out.bufsize && (nprot & PROT_WRITE) ) - return -1 ; /* can only write to the first block */ - - if (offset < d->dbuf_out.bufsize) - return i386_btop(vtophys(d->dbuf_out.buf + offset)); - offset -= 1 << 24; - if ( (offset >= 0) && (offset < d->dbuf_in.bufsize)) - return i386_btop(vtophys(d->dbuf_in.buf + offset)); - offset -= 1 << 24; - if ( (offset >= 0) && (offset < 0x2000)) { - return i386_btop(vtophys( ((int)d & ~0xfff) + offset)); - } - return -1 ; -} - - -/* - * ask_init sets the init flag in the device descriptor, and - * possibly calls the appropriate callback routine, returning 1 - * if the callback was successful. This enables ioctls handler for - * rw parameters to read back the updated value. - * Since the init callback can be slow, ask_init() should be called - * with interrupts enabled. - */ - -int -ask_init(snddev_info *d) -{ - u_long s; - - if ( d->callback == NULL ) - return 0 ; - s = spltty(); - if ( d->flags & SND_F_PENDING_IO || - d->dbuf_out.dl || d->dbuf_in.dl ) { - /* cannot do it now, record the request and return */ - d->flags |= SND_F_INIT ; - splx(s); - return 0 ; - } else { - splx(s); - d->callback(d, SND_CB_INIT ); - return 1; - } -} - -/* - * these are the functions for the soundstat device. We copy parameters - * from the device info structure to static variables, and from there - * back to the structure when done. - */ - -static void -init_status(snddev_info *d) -{ - /* - * Write the status information to the status_buf and update - * status_len. There is a limit of SNDSTAT_BUF_SIZE bytes for the data. - */ - - int i; - - if (status_len != 0) /* only do init once */ - return ; - snprintf(status_buf, sizeof(status_buf), - "FreeBSD Audio Driver (981002) " __DATE__ " " __TIME__ "\n" - "Installed devices:\n"); - - for (i = 0; i < NPCM_MAX; i++) { - if (pcm_info[i].open) - snprintf(status_buf + strlen(status_buf), - sizeof(status_buf) - strlen(status_buf), - "pcm%d: <%s> at 0x%x irq %d dma %d:%d\n", - i, pcm_info[i].name, pcm_info[i].io_base, - pcm_info[i].irq, - pcm_info[i].dbuf_out.chan, pcm_info[i].dbuf_in.chan); - if (midi_info[i].open) - snprintf(status_buf + strlen(status_buf), - sizeof(status_buf) - strlen(status_buf), - "midi%d: <%s> at 0x%x irq %d dma %d:%d\n", - i, midi_info[i].name, midi_info[i].io_base, - midi_info[i].irq, - midi_info[i].dbuf_out.chan, midi_info[i].dbuf_in.chan); - if (pcm_info[i].synth_base) { - char *s = "???"; - switch (pcm_info[i].synth_type) { - case 2 : s = "OPL2"; break; - case 3 : s = "OPL3"; break; - case 4 : s = "OPL4"; break; - } - - snprintf(status_buf + strlen(status_buf), - sizeof(status_buf) - strlen(status_buf), - "sequencer%d: <%s> at 0x%x (not functional)\n", - i, s, pcm_info[i].synth_base); - } - } - status_len = strlen(status_buf) ; -} - -/* - * finally, some "libraries" - */ - -/* - * isa_dmastatus1() is a wrapper for isa_dmastatus(), which - * might return -1 or -2 in some cases (errors). Since for the - * user code it is more comfortable not to check for these cases, - * negative values are mapped back to 0 (which is reasonable). - */ - -int -isa_dmastatus1(int channel) -{ - int r = isa_dmastatus(channel); - if (r<0) r = 0; - return r; -} - -/* - * snd_conflict scans already-attached boards to see if - * the current address is conflicting with one of the already - * assigned ones. Returns 1 if a conflict is detected. - */ -int -snd_conflict(int io_base) -{ - int i; - for (i=0; i< NPCM_MAX ; i++) { - if ( (io_base == pcm_info[i].io_base ) || - (io_base == pcm_info[i].alt_base ) || - (io_base == pcm_info[i].conf_base) || - (io_base == pcm_info[i].mix_base ) || - (io_base == pcm_info[i].midi_base) || - (io_base == pcm_info[i].synth_base) ) { - BVDDB(printf("device at 0x%x already attached as unit %d\n", - io_base, i);) - return 1 ; - } - } - return 0; -} - -void -snd_set_blocksize(snddev_info *d) -{ - int tmp ; - /* - * compute the sample size, and possibly - * set the blocksize so as to guarantee approx 1/4s - * between callbacks. - */ - tmp = 1 ; - if (d->flags & SND_F_STEREO) tmp += tmp; - if (d->play_fmt & (AFMT_S16_LE|AFMT_U16_LE)) tmp += tmp; - d->dbuf_out.sample_size = tmp ; - tmp = tmp * d->play_speed; - if ( (d->flags & SND_F_HAS_SIZE) == 0) { - d->play_blocksize = (tmp / 4) & ~3; /* 0.25s, aligned to 4 */ - RANGE (d->play_blocksize, 1024, (d->bufsize / 4) & ~3); - } - - tmp = 1 ; - if (d->flags & SND_F_STEREO) tmp += tmp; - if (d->rec_fmt & (AFMT_S16_LE|AFMT_U16_LE)) tmp += tmp; - tmp = tmp * d->rec_speed; - d->dbuf_in.sample_size = tmp ; - if ( (d->flags & SND_F_HAS_SIZE) == 0) { - d->rec_blocksize = (tmp / 4) & ~3; /* 0.25s, aligned to 4 */ - RANGE (d->rec_blocksize, 1024, (d->bufsize / 4) & ~3); - } -} - -/* - * The various mixers use a variety of bitmasks etc. The Voxware - * driver had a very nice technique to describe a mixer and interface - * to it. A table defines, for each channel, which register, bits, - * offset, polarity to use. This procedure creates the new value - * using the table and the old value. - */ - -void -change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval) -{ - u_char mask; - int shift; - - DEB(printf("ch_bits dev %d ch %d val %d old 0x%02x " - "r %d p %d bit %d off %d\n", - dev, chn, newval, *regval, - (*t)[dev][chn].regno, (*t)[dev][chn].polarity, - (*t)[dev][chn].nbits, (*t)[dev][chn].bitoffs ) ); - - if ( (*t)[dev][chn].polarity == 1) /* reverse */ - newval = 100 - newval ; - - mask = (1 << (*t)[dev][chn].nbits) - 1; - newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ - shift = (*t)[dev][chn].bitoffs /*- (*t)[dev][LEFT_CHN].nbits + 1*/; - - *regval &= ~(mask << shift); /* Filter out the previous value */ - *regval |= (newval & mask) << shift; /* Set the new value */ -} - - -/* - * code for translating between U8 and ULAW. Needed to support - * /dev/audio on the SoundBlaster. Actually, we would also need - * ulaw -> 16 bits (for the soundblaster as well, when used in - * full-duplex) - */ - -void -translate_bytes (u_char *table, u_char *buff, int n) -{ - u_long i; - - if (n <= 0) - return; - - for (i = 0; i < n; ++i) - buff[i] = table[buff[i]]; -} - -#endif /* NPCM > 0 */ diff --git a/sys/i386/isa/snd/sound.h b/sys/i386/isa/snd/sound.h deleted file mode 100644 index 5d5db4d837b7..000000000000 --- a/sys/i386/isa/snd/sound.h +++ /dev/null @@ -1,528 +0,0 @@ -/* - * sound.h - * - * include file for kernel sources, sound driver. - * - * Copyright by Hannu Savolainen 1995 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#ifdef KERNEL -#include "pcm.h" -#else -#define NPCM 1 -#endif -#if NPCM > 0 - -/* - * first, include kernel header files. - */ - -#ifndef _OS_H_ -#define _OS_H_ - -#ifdef KERNEL -#include -#include -#include - -#include -#include -#include -#include -#include - -#include /* for DATA_SET */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for DELAY */ - -/* - * the following assumes that FreeBSD 3.X uses poll(2) instead of select(2). - * This change dates to late 1997. - */ -#include -#define d_select_t d_poll_t - -#else -struct isa_device { int dummy ; } ; -#define d_open_t void -#define d_close_t void -#define d_read_t void -#define d_write_t void -#define d_ioctl_t void -#define d_select_t void -#endif /* KERNEL */ -typedef void (irq_proc_t) (int irq); - -#endif /* _OS_H_ */ - -/* - * descriptor of a dma buffer. See dmabuf.c for documentation. - * (rp,rl) and (fp,fl) identify the READY and FREE regions of the - * buffer. dl contains the length used for dma transfer, dl>0 also - * means that the channel is busy and there is a DMA transfer in progress. - */ - -typedef struct _snd_dbuf { - char *buf; - int bufsize ; - volatile int rp, fp; /* pointers to the ready and free area */ - volatile int dl; /* transfer size */ - volatile int rl, fl; /* lenght of ready and free areas. */ - int int_count; - int chan; /* dma channel */ - int sample_size ; /* 1, 2, 4 */ - struct selinfo sel; - u_long total; /* total bytes processed */ - u_long prev_total; /* copy of the above when GETxPTR called */ -} snd_dbuf ; - -/* - * descriptor of audio operations ... - * - */ -typedef struct _snddev_info snddev_info ; -typedef int (snd_callback_t)(snddev_info *d, int reason); - -struct _snddev_info { - - /* - * the first part of the descriptor is filled up from a - * template. - */ - char name[64]; - - int type ; - - int (*probe)(struct isa_device * dev); - int (*attach)(struct isa_device * dev) ; - d_open_t *open ; - d_close_t *close ; - d_read_t *read ; - d_write_t *write ; - d_ioctl_t *ioctl ; - d_select_t *select ; - irq_proc_t *isr ; - snd_callback_t *callback; - - int bufsize; /* space used for buffers */ - - u_long audio_fmt ; /* supported audio formats */ - - - /* - * combinations of the following flags are used as second argument in - * the callback from the dma module to the device-specific routines. - */ - -#define SND_CB_RD 0x100 /* read callback */ -#define SND_CB_WR 0x200 /* write callback */ -#define SND_CB_REASON_MASK 0xff -#define SND_CB_START 0x01 /* start dma op */ -#define SND_CB_STOP 0x03 /* stop dma op */ -#define SND_CB_ABORT 0x04 /* abort dma op */ -#define SND_CB_INIT 0x05 /* init board parameters */ - - /* - * callback extensions - */ -#define SND_CB_DMADONE 0x10 -#define SND_CB_DMAUPDATE 0x11 -#define SND_CB_DMASTOP 0x12 - - /* init can only be called with int enabled and - * no pending DMA activity. - */ - - /* - * whereas from here, parameters are set at runtime. - * io_base == 0 means that the board is not configured. - */ - - int io_base ; /* primary I/O address for the board */ - int alt_base ; /* some codecs are accessible as SB+MSS... */ - int conf_base ; /* and the opti931 also has a config space */ - int mix_base ; /* base for the mixer... */ - int midi_base ; /* base for the midi */ - - int irq ; - int bd_id ; /* used to hold board-id info, eg. sb version, - * mss codec type, etc. etc. - */ - - snd_dbuf dbuf_out, dbuf_in; - - int status_ptr; /* used to implement sndstat */ - - /* - * these parameters describe the operation of the board. - * Generic things like busy flag, speed, etc are here. - */ - - volatile u_long flags ; /* 32 bits, used for various purposes. */ - - /* - * we have separate flags for read and write, although in some - * cases this is probably not necessary (e.g. because we cannot - * know how many processes are using the device, we cannot - * distinguish if open, close, abort are for a write or for a - * read). - */ - - /* - * the following flag is used by open-close routines - * to mark the status of the device. - */ -#define SND_F_BUSY 0x0001 /* has been opened */ - /* - * Only the last close for a device will propagate to the driver. - * Unfortunately, voxware uses 3 different minor numbers - * (dsp, dsp16 and audio) to access the same unit. So, if - * we want to support multiple opens and still keep track of - * what is happening, we also need a separate flag for each minor - * number. These are below... - */ -#define SND_F_BUSY_AUDIO 0x10000000 -#define SND_F_BUSY_DSP 0x20000000 -#define SND_F_BUSY_DSP16 0x40000000 -#define SND_F_BUSY_ANY 0x70000000 -#define SND_F_BUSY_SYNTH 0x80000000 - /* - * the next two are used to allow only one pending operation of - * each type. - */ -#define SND_F_READING 0x0004 /* have a pending read */ -#define SND_F_WRITING 0x0008 /* have a pending write */ - /* - * these mark pending DMA operations. When you have pending dma ops, - * you might get interrupts, so some manipulations of the - * descriptors must be done with interrupts blocked. - */ -#if 0 -#define SND_F_RD_DMA 0x0010 /* read-dma active */ -#define SND_F_WR_DMA 0x0020 /* write-dma active */ - -#define SND_F_PENDING_IN (SND_F_READING | SND_F_RD_DMA) -#define SND_F_PENDING_OUT (SND_F_WRITING | SND_F_WR_DMA) -#endif -#define SND_F_PENDING_IO (SND_F_READING | SND_F_WRITING) - - /* - * flag used to mark a pending close. - */ -#define SND_F_CLOSING 0x0040 /* a pending close */ - - /* - * if user has not set block size, then make it adaptive - * (0.25s, or the perhaps last read/write ?) - */ -#define SND_F_HAS_SIZE 0x0080 /* user set block size */ - /* - * assorted flags related to operating mode. - */ -#define SND_F_STEREO 0x0100 /* doing stereo */ -#define SND_F_NBIO 0x0200 /* do non-blocking i/o */ - - /* - * the user requested ulaw, but the board does not support it - * natively, so a (software) format conversion is necessary. - * The kernel is not really the place to do this, but since - * many applications expect to use /dev/audio , we do it for - * portability. - */ -#define SND_F_XLAT8 0x0400 /* u-law <--> 8-bit unsigned */ -#define SND_F_XLAT16 0x0800 /* u-law <--> 16-bit signed */ - - /* - * these flags mark a pending abort on a r/w operation. - */ -#define SND_F_ABORTING 0x1000 /* a pending abort */ - - /* - * this is used to mark that board initialization is needed, e.g. - * because of a change in sampling rate, format, etc. -- It will - * be done at the next convenient time. - */ -#define SND_F_INIT 0x4000 /* changed parameters. need init */ - - u_long bd_flags; /* board-specific flags */ - int play_speed, rec_speed; - - int play_blocksize, rec_blocksize; /* blocksize for io and dma ops */ - u_long play_fmt, rec_fmt ; /* current audio format */ - - /* - * mixer parameters - */ - u_long mix_devs; /* existing devices for mixer */ - u_long mix_rec_devs; /* possible recording sources */ - u_long mix_recsrc; /* current recording source(s) */ - u_short mix_levels[32]; - -#define wsel dbuf_out.sel -#define rsel dbuf_in.sel - u_long interrupts; /* counter of interrupts */ - u_long magic; -#define MAGIC(unit) ( 0xa4d10de0 + unit ) - int synth_base ; /* base for the synth */ - int synth_type ; /* type of synth */ - void *device_data ; /* just in case it is needed...*/ - int special_dma ; - /* when this is set, dsp_wr_dmaupdate etc. - * are processed using callback extensions. - */ -} ; - -/* - * then ioctls and other stuff - */ - -#define NPCM_MAX 8 /* Number of supported devices */ - -/* - * values used in bd_id for the mss boards - */ -#define MD_AD1848 0x91 -#define MD_AD1845 0x92 -#define MD_AD1816 0x93 -#define MD_CS4248 0xA1 -#define MD_CS4231 0xA2 -#define MD_CS4231A 0xA3 -#define MD_CS4232 0xA4 -#define MD_CS4232A 0xA5 -#define MD_CS4236 0xA6 -#define MD_CS4237 0xA7 -#define MD_OPTI931 0xB1 -#define MD_GUSPNP 0xB8 -#define MD_YM0020 0xC1 -#define MD_VIVO 0xD1 - -/* - * TODO: add some card classes rather than specific types. - */ -#include -/* - * many variables should be reduced to a range. Here define a macro - */ - -#define RANGE(var, low, high) (var) = \ - ((var)<(low)?(low) : (var)>(high)?(high) : (var)) - -/* - * finally, all default parameters - */ -#define DSP_BUFFSIZE (65536 - 256) /* XXX */ -/* - * the last 256 bytes are room for buggy soundcard to overflow. - */ - -#ifdef KERNEL -#include "pnp.h" -#if NPNP > 0 -#include /* XXX pnp support */ -#endif -#endif /* KERNEL */ - -/* - * Minor numbers for the sound driver. - * - * Unfortunately Creative called the codec chip of SB as a DSP. For this - * reason the /dev/dsp is reserved for digitized audio use. There is a - * device for true DSP processors but it will be called something else. - * In v3.0 it's /dev/sndproc but this could be a temporary solution. - */ - - -#define SND_DEV_CTL 0 /* Control port /dev/mixer */ -#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM - synthesizer and MIDI output) */ -#define SND_DEV_MIDIN 2 /* Raw midi access */ -#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ -#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ -#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ -#define SND_DEV_STATUS 6 /* /dev/sndstat */ - /* #7 not in use now. Was in 2.4. Free for use after v3.0. */ -#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ -#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ -#define SND_DEV_PSS SND_DEV_SNDPROC - -#define DSP_DEFAULT_SPEED 8000 - -#define ON 1 -#define OFF 0 - - -#define SYNTH_MAX_VOICES 32 - -struct voice_alloc_info { - int max_voice; - int used_voices; - int ptr; /* For device specific use */ - u_short map[SYNTH_MAX_VOICES]; /* (ch << 8) | (note+1) */ - int timestamp; - int alloc_times[SYNTH_MAX_VOICES]; -}; - -struct channel_info { - int pgm_num; - int bender_value; - u_char controllers[128]; -}; - -/* - * mixer description structure and macros - */ - -struct mixer_def { - u_int regno:7; - u_int polarity:1; /* 1 means reversed */ - u_int bitoffs:4; - u_int nbits:4; -}; -typedef struct mixer_def mixer_ent; -typedef struct mixer_def mixer_tab[32][2]; - -#ifdef KERNEL - -#define FULL_DUPLEX(d) (d->dbuf_out.chan != d->dbuf_in.chan) -#define MIX_ENT(name, reg_l, pol_l, pos_l, len_l, reg_r, pol_r, pos_r, len_r) \ - {{reg_l, pol_l, pos_l, len_l}, {reg_r, pol_r, pos_r, len_r}} -#define PMIX_ENT(name, reg_l, pos_l, len_l, reg_r, pos_r, len_r) \ - {{reg_l, 0, pos_l, len_l}, {reg_r, 0, pos_r, len_r}} - -#define MIX_NONE(name) MIX_ENT(name, 0,0,0,0, 0,0,0,0) - -/* - * some macros for debugging purposes - * DDB/DEB to enable/disable debugging stuff - * BVDDB to enable debugging when bootverbose - */ -#define DDB(x) x /* XXX */ -#define BVDDB(x) if (bootverbose) x - -#ifndef DEB -#define DEB(x) -#endif - -extern snddev_info pcm_info[NPCM_MAX] ; -extern snddev_info midi_info[NPCM_MAX] ; -extern snddev_info synth_info[NPCM_MAX] ; - -extern u_long nsnd ; -extern snddev_info *snddev_last_probed; - -int pcmprobe(struct isa_device * dev); -int midiprobe(struct isa_device * dev); -int synthprobe(struct isa_device * dev); -int pcmattach(struct isa_device * dev); -int pcminit(snddev_info *d, int unit); -int midiattach(struct isa_device * dev); -int synthattach(struct isa_device * dev); - -ointhand2_t pcmintr; - -/* - * DMA buffer calls - */ - -void dsp_wrintr(snddev_info *d); -void dsp_rdintr(snddev_info *d); -int dsp_write_body(snddev_info *d, struct uio *buf); -int dsp_read_body(snddev_info *d, struct uio *buf); -void alloc_dbuf(snd_dbuf *d, int size); - -int snd_flush(snddev_info *d); - -/* the following parameters are used in snd_sync and reset_dbuf - * to decide whether or not to restart a channel - */ -#define SND_CHAN_NONE 0x0 -#define SND_CHAN_WR 0x1 -#define SND_CHAN_RD 0x2 - -void reset_dbuf(snd_dbuf *b, int chan); -int snd_sync(snddev_info *d, int chan, int threshold); -int dsp_wrabort(snddev_info *d, int restart); -int dsp_rdabort(snddev_info *d, int restart); -void dsp_wr_dmaupdate(snd_dbuf *b); -void dsp_rd_dmaupdate(snd_dbuf *b); - -d_select_t sndselect; - -/* - * library functions (in sound.c) - */ - -int ask_init(snddev_info *d); -void translate_bytes(u_char *table, u_char *buff, int n); -void change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval); -int snd_conflict(int io_base); -void snd_set_blocksize(snddev_info *d); -int isa_dmastatus1(int channel); -/* - * routines in ad1848.c and sb_dsp.c which others might use - */ -int mss_detect (struct isa_device *dev); -int sb_cmd (int io_base, u_char cmd); -int sb_cmd2 (int io_base, u_char cmd, int val); -int sb_cmd3 (int io_base, u_char cmd, int val); -int sb_reset_dsp (int io_base); -void sb_setmixer (int io_base, u_int port, u_int value); -int sb_getmixer (int io_base, u_int port); - -#endif /* KERNEL */ - -/* - * usage of flags in device config entry (config file) - */ - -#define DV_F_DRQ_MASK 0x00000007 /* mask for secondary drq */ -#define DV_F_DUAL_DMA 0x00000010 /* set to use secondary dma channel */ -#define DV_F_DEV_MASK 0x0000ff00 /* force device type/class */ -#define DV_F_DEV_SHIFT 8 /* force device type/class */ - -/* - * some flags are used in a device-specific manner, so that values can - * be used multiple times. - */ - -#define DV_F_TRUE_MSS 0x00010000 /* mss _with_ base regs */ - /* almost all modern cards do not have this set of registers, - * so it is better to make this the default behaviour - */ - -/* - * the following flags are for PnP cards only and are undocumented - */ -#define DV_PNP_SBCODEC 0x1 - -#endif diff --git a/sys/i386/isa/snd/ulaw.h b/sys/i386/isa/snd/ulaw.h deleted file mode 100644 index 4b9916f3063e..000000000000 --- a/sys/i386/isa/snd/ulaw.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * on entry: ulaw, on exit: unsigned 8 bit. - */ -static unsigned char ulaw_dsp[] = { - 3, 7, 11, 15, 19, 23, 27, 31, - 35, 39, 43, 47, 51, 55, 59, 63, - 66, 68, 70, 72, 74, 76, 78, 80, - 82, 84, 86, 88, 90, 92, 94, 96, - 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, - 113, 114, 114, 115, 115, 116, 116, 117, - 117, 118, 118, 119, 119, 120, 120, 121, - 121, 121, 122, 122, 122, 122, 123, 123, - 123, 123, 124, 124, 124, 124, 125, 125, - 125, 125, 125, 125, 126, 126, 126, 126, - 126, 126, 126, 126, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 253, 249, 245, 241, 237, 233, 229, 225, - 221, 217, 213, 209, 205, 201, 197, 193, - 190, 188, 186, 184, 182, 180, 178, 176, - 174, 172, 170, 168, 166, 164, 162, 160, - 158, 157, 156, 155, 154, 153, 152, 151, - 150, 149, 148, 147, 146, 145, 144, 143, - 143, 142, 142, 141, 141, 140, 140, 139, - 139, 138, 138, 137, 137, 136, 136, 135, - 135, 135, 134, 134, 134, 134, 133, 133, - 133, 133, 132, 132, 132, 132, 131, 131, - 131, 131, 131, 131, 130, 130, 130, 130, - 130, 130, 130, 130, 129, 129, 129, 129, - 129, 129, 129, 129, 129, 129, 129, 129, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, -}; - -#ifndef DSP_ULAW_NOT_WANTED -static unsigned char dsp_ulaw[] = { - 0, 0, 0, 0, 0, 1, 1, 1, - 1, 2, 2, 2, 2, 3, 3, 3, - 3, 4, 4, 4, 4, 5, 5, 5, - 5, 6, 6, 6, 6, 7, 7, 7, - 7, 8, 8, 8, 8, 9, 9, 9, - 9, 10, 10, 10, 10, 11, 11, 11, - 11, 12, 12, 12, 12, 13, 13, 13, - 13, 14, 14, 14, 14, 15, 15, 15, - 15, 16, 16, 17, 17, 18, 18, 19, - 19, 20, 20, 21, 21, 22, 22, 23, - 23, 24, 24, 25, 25, 26, 26, 27, - 27, 28, 28, 29, 29, 30, 30, 31, - 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, - 47, 49, 51, 53, 55, 57, 59, 61, - 63, 66, 70, 74, 78, 84, 92, 104, - 254, 231, 219, 211, 205, 201, 197, 193, - 190, 188, 186, 184, 182, 180, 178, 176, - 175, 174, 173, 172, 171, 170, 169, 168, - 167, 166, 165, 164, 163, 162, 161, 160, - 159, 159, 158, 158, 157, 157, 156, 156, - 155, 155, 154, 154, 153, 153, 152, 152, - 151, 151, 150, 150, 149, 149, 148, 148, - 147, 147, 146, 146, 145, 145, 144, 144, - 143, 143, 143, 143, 142, 142, 142, 142, - 141, 141, 141, 141, 140, 140, 140, 140, - 139, 139, 139, 139, 138, 138, 138, 138, - 137, 137, 137, 137, 136, 136, 136, 136, - 135, 135, 135, 135, 134, 134, 134, 134, - 133, 133, 133, 133, 132, 132, 132, 132, - 131, 131, 131, 131, 130, 130, 130, 130, - 129, 129, 129, 129, 128, 128, 128, 128, -}; -#endif /* !DSP_ULAW_NOT_WANTED */