aboutsummaryrefslogtreecommitdiff
path: root/sound/oss/ali5455.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/oss/ali5455.c')
-rw-r--r--sound/oss/ali5455.c3735
1 files changed, 0 insertions, 3735 deletions
diff --git a/sound/oss/ali5455.c b/sound/oss/ali5455.c
deleted file mode 100644
index 70dcd703a66..00000000000
--- a/sound/oss/ali5455.c
+++ /dev/null
@@ -1,3735 +0,0 @@
-/*
- * ALI ali5455 and friends ICH driver for Linux
- * LEI HU <Lei_Hu@ali.com.tw>
- *
- * Built from:
- * drivers/sound/i810_audio
- *
- * The ALi 5455 is similar but not quite identical to the Intel ICH
- * series of controllers. Its easier to keep the driver separated from
- * the i810 driver.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * ALi 5455 theory of operation
- *
- * The chipset provides three DMA channels that talk to an AC97
- * CODEC (AC97 is a digital/analog mixer standard). At its simplest
- * you get 48Khz audio with basic volume and mixer controls. At the
- * best you get rate adaption in the codec. We set the card up so
- * that we never take completion interrupts but instead keep the card
- * chasing its tail around a ring buffer. This is needed for mmap
- * mode audio and happens to work rather well for non-mmap modes too.
- *
- * The board has one output channel for PCM audio (supported) and
- * a stereo line in and mono microphone input. Again these are normally
- * locked to 48Khz only. Right now recording is not finished.
- *
- * There is no midi support, no synth support. Use timidity. To get
- * esd working you need to use esd -r 48000 as it won't probe 48KHz
- * by default. mpg123 can't handle 48Khz only audio so use xmms.
- *
- * If you need to force a specific rate set the clocking= option
- *
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/ac97_codec.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-
-#ifndef PCI_DEVICE_ID_ALI_5455
-#define PCI_DEVICE_ID_ALI_5455 0x5455
-#endif
-
-#ifndef PCI_VENDOR_ID_ALI
-#define PCI_VENDOR_ID_ALI 0x10b9
-#endif
-
-static int strict_clocking = 0;
-static unsigned int clocking = 0;
-static unsigned int codec_pcmout_share_spdif_locked = 0;
-static unsigned int codec_independent_spdif_locked = 0;
-static unsigned int controller_pcmout_share_spdif_locked = 0;
-static unsigned int controller_independent_spdif_locked = 0;
-static unsigned int globel = 0;
-
-#define ADC_RUNNING 1
-#define DAC_RUNNING 2
-#define CODEC_SPDIFOUT_RUNNING 8
-#define CONTROLLER_SPDIFOUT_RUNNING 4
-
-#define SPDIF_ENABLE_OUTPUT 4 /* bits 0,1 are PCM */
-
-#define ALI5455_FMT_16BIT 1
-#define ALI5455_FMT_STEREO 2
-#define ALI5455_FMT_MASK 3
-
-#define SPDIF_ON 0x0004
-#define SURR_ON 0x0010
-#define CENTER_LFE_ON 0x0020
-#define VOL_MUTED 0x8000
-
-
-#define ALI_SPDIF_OUT_CH_STATUS 0xbf
-/* the 810's array of pointers to data buffers */
-
-struct sg_item {
-#define BUSADDR_MASK 0xFFFFFFFE
- u32 busaddr;
-#define CON_IOC 0x80000000 /* interrupt on completion */
-#define CON_BUFPAD 0x40000000 /* pad underrun with last sample, else 0 */
-#define CON_BUFLEN_MASK 0x0000ffff /* buffer length in samples */
- u32 control;
-};
-
-/* an instance of the ali channel */
-#define SG_LEN 32
-struct ali_channel {
- /* these sg guys should probably be allocated
- separately as nocache. Must be 8 byte aligned */
- struct sg_item sg[SG_LEN]; /* 32*8 */
- u32 offset; /* 4 */
- u32 port; /* 4 */
- u32 used;
- u32 num;
-};
-
-/*
- * we have 3 separate dma engines. pcm in, pcm out, and mic.
- * each dma engine has controlling registers. These goofy
- * names are from the datasheet, but make it easy to write
- * code while leafing through it.
- */
-
-#define ENUM_ENGINE(PRE,DIG) \
-enum { \
- PRE##_BDBAR = 0x##DIG##0, /* Buffer Descriptor list Base Address */ \
- PRE##_CIV = 0x##DIG##4, /* Current Index Value */ \
- PRE##_LVI = 0x##DIG##5, /* Last Valid Index */ \
- PRE##_SR = 0x##DIG##6, /* Status Register */ \
- PRE##_PICB = 0x##DIG##8, /* Position In Current Buffer */ \
- PRE##_CR = 0x##DIG##b /* Control Register */ \
-}
-
-ENUM_ENGINE(OFF, 0); /* Offsets */
-ENUM_ENGINE(PI, 4); /* PCM In */
-ENUM_ENGINE(PO, 5); /* PCM Out */
-ENUM_ENGINE(MC, 6); /* Mic In */
-ENUM_ENGINE(CODECSPDIFOUT, 7); /* CODEC SPDIF OUT */
-ENUM_ENGINE(CONTROLLERSPDIFIN, A); /* CONTROLLER SPDIF In */
-ENUM_ENGINE(CONTROLLERSPDIFOUT, B); /* CONTROLLER SPDIF OUT */
-
-
-enum {
- ALI_SCR = 0x00, /* System Control Register */
- ALI_SSR = 0x04, /* System Status Register */
- ALI_DMACR = 0x08, /* DMA Control Register */
- ALI_FIFOCR1 = 0x0c, /* FIFO Control Register 1 */
- ALI_INTERFACECR = 0x10, /* Interface Control Register */
- ALI_INTERRUPTCR = 0x14, /* Interrupt control Register */
- ALI_INTERRUPTSR = 0x18, /* Interrupt Status Register */
- ALI_FIFOCR2 = 0x1c, /* FIFO Control Register 2 */
- ALI_CPR = 0x20, /* Command Port Register */
- ALI_SPR = 0x24, /* Status Port Register */
- ALI_FIFOCR3 = 0x2c, /* FIFO Control Register 3 */
- ALI_TTSR = 0x30, /* Transmit Tag Slot Register */
- ALI_RTSR = 0x34, /* Receive Tag Slot Register */
- ALI_CSPSR = 0x38, /* Command/Status Port Status Register */
- ALI_CAS = 0x3c, /* Codec Write Semaphore Register */
- ALI_SPDIFCSR = 0xf8, /* spdif channel status register */
- ALI_SPDIFICS = 0xfc /* spdif interface control/status */
-};
-
-// x-status register(x:pcm in ,pcm out, mic in,)
-/* interrupts for a dma engine */
-#define DMA_INT_FIFO (1<<4) /* fifo under/over flow */
-#define DMA_INT_COMPLETE (1<<3) /* buffer read/write complete and ioc set */
-#define DMA_INT_LVI (1<<2) /* last valid done */
-#define DMA_INT_CELV (1<<1) /* last valid is current */
-#define DMA_INT_DCH (1) /* DMA Controller Halted (happens on LVI interrupts) */ //not eqult intel
-#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
-
-/* interrupts for the whole chip */// by interrupt status register finish
-
-#define INT_SPDIFOUT (1<<23) /* controller spdif out INTERRUPT */
-#define INT_SPDIFIN (1<<22)
-#define INT_CODECSPDIFOUT (1<<19)
-#define INT_MICIN (1<<18)
-#define INT_PCMOUT (1<<17)
-#define INT_PCMIN (1<<16)
-#define INT_CPRAIS (1<<7)
-#define INT_SPRAIS (1<<5)
-#define INT_GPIO (1<<1)
-#define INT_MASK (INT_SPDIFOUT|INT_CODECSPDIFOUT|INT_MICIN|INT_PCMOUT|INT_PCMIN)
-
-#define DRIVER_VERSION "0.02ac"
-
-/* magic numbers to protect our data structures */
-#define ALI5455_CARD_MAGIC 0x5072696E /* "Prin" */
-#define ALI5455_STATE_MAGIC 0x63657373 /* "cess" */
-#define ALI5455_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */
-#define NR_HW_CH 5 //I think 5 channel
-
-/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97 2
-
-/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */
-/* stream at a minimum for this card to be happy */
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */
-/* values are one less than might be expected */
-static const unsigned sample_shift[] = { -1, 0, 0, 1 };
-
-#define ALI5455
-static char *card_names[] = {
- "ALI 5455"
-};
-
-static struct pci_device_id ali_pci_tbl[] = {
- {PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5455,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI5455},
- {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, ali_pci_tbl);
-
-#ifdef CONFIG_PM
-#define PM_SUSPENDED(card) (card->pm_suspended)
-#else
-#define PM_SUSPENDED(card) (0)
-#endif
-
-/* "software" or virtual channel, an instance of opened /dev/dsp */
-struct ali_state {
- unsigned int magic;
- struct ali_card *card; /* Card info */
-
- /* single open lock mechanism, only used for recording */
- struct mutex open_mutex;
- wait_queue_head_t open_wait;
-
- /* file mode */
- mode_t open_mode;
-
- /* virtual channel number */
- int virt;
-
-#ifdef CONFIG_PM
- unsigned int pm_saved_dac_rate, pm_saved_adc_rate;
-#endif
- struct dmabuf {
- /* wave sample stuff */
- unsigned int rate;
- unsigned char fmt, enable, trigger;
-
- /* hardware channel */
- struct ali_channel *read_channel;
- struct ali_channel *write_channel;
- struct ali_channel *codec_spdifout_channel;
- struct ali_channel *controller_spdifout_channel;
-
- /* OSS buffer management stuff */
- void *rawbuf;
- dma_addr_t dma_handle;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
-
- /* our buffer acts like a circular ring */
- unsigned hwptr; /* where dma last started, updated by update_ptr */
- unsigned swptr; /* where driver last clear/filled, updated by read/write */
- int count; /* bytes to be consumed or been generated by dma machine */
- unsigned total_bytes; /* total bytes dmaed by hardware */
-
- unsigned error; /* number of over/underruns */
- wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */
-
- /* redundant, but makes calculations easier */
- /* what the hardware uses */
- unsigned dmasize;
- unsigned fragsize;
- unsigned fragsamples;
-
- /* what we tell the user to expect */
- unsigned userfrags;
- unsigned userfragsize;
-
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned update_flag;
- unsigned ossfragsize;
- unsigned ossmaxfrags;
- unsigned subdivision;
- } dmabuf;
-};
-
-
-struct ali_card {
- struct ali_channel channel[5];
- unsigned int magic;
-
- /* We keep ali5455 cards in a linked list */
- struct ali_card *next;
-
- /* The ali has a certain amount of cross channel interaction
- so we use a single per card lock */
- spinlock_t lock;
- spinlock_t ac97_lock;
-
- /* PCI device stuff */
- struct pci_dev *pci_dev;
- u16 pci_id;
-#ifdef CONFIG_PM
- u16 pm_suspended;
- int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97];
-#endif
- /* soundcore stuff */
- int dev_audio;
-
- /* structures for abstraction of hardware facilities, codecs, banks and channels */
- struct ac97_codec *ac97_codec[NR_AC97];
- struct ali_state *states[NR_HW_CH];
-
- u16 ac97_features;
- u16 ac97_status;
- u16 channels;
-
- /* hardware resources */
- unsigned long iobase;
-
- u32 irq;
-
- /* Function support */
- struct ali_channel *(*alloc_pcm_channel) (struct ali_card *);
- struct ali_channel *(*alloc_rec_pcm_channel) (struct ali_card *);
- struct ali_channel *(*alloc_rec_mic_channel) (struct ali_card *);
- struct ali_channel *(*alloc_codec_spdifout_channel) (struct ali_card *);
- struct ali_channel *(*alloc_controller_spdifout_channel) (struct ali_card *);
- void (*free_pcm_channel) (struct ali_card *, int chan);
-
- /* We have a *very* long init time possibly, so use this to block */
- /* attempts to open our devices before we are ready (stops oops'es) */
- int initializing;
-};
-
-
-static struct ali_card *devs = NULL;
-
-static int ali_open_mixdev(struct inode *inode, struct file *file);
-static int ali_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg);
-static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
-
-static struct ali_channel *ali_alloc_pcm_channel(struct ali_card *card)
-{
- if (card->channel[1].used == 1)
- return NULL;
- card->channel[1].used = 1;
- return &card->channel[1];
-}
-
-static struct ali_channel *ali_alloc_rec_pcm_channel(struct ali_card *card)
-{
- if (card->channel[0].used == 1)
- return NULL;
- card->channel[0].used = 1;
- return &card->channel[0];
-}
-
-static struct ali_channel *ali_alloc_rec_mic_channel(struct ali_card *card)
-{
- if (card->channel[2].used == 1)
- return NULL;
- card->channel[2].used = 1;
- return &card->channel[2];
-}
-
-static struct ali_channel *ali_alloc_codec_spdifout_channel(struct ali_card *card)
-{
- if (card->channel[3].used == 1)
- return NULL;
- card->channel[3].used = 1;
- return &card->channel[3];
-}
-
-static struct ali_channel *ali_alloc_controller_spdifout_channel(struct ali_card *card)
-{
- if (card->channel[4].used == 1)
- return NULL;
- card->channel[4].used = 1;
- return &card->channel[4];
-}
-static void ali_free_pcm_channel(struct ali_card *card, int channel)
-{
- card->channel[channel].used = 0;
-}
-
-
-//add support codec spdif out
-static int ali_valid_spdif_rate(struct ac97_codec *codec, int rate)
-{
- unsigned long id = 0L;
-
- id = (ali_ac97_get(codec, AC97_VENDOR_ID1) << 16);
- id |= ali_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff;
- switch (id) {
- case 0x41445361: /* AD1886 */
- if (rate == 48000) {
- return 1;
- }
- break;
- case 0x414c4720: /* ALC650 */
- if (rate == 48000) {
- return 1;
- }
- break;
- default: /* all other codecs, until we know otherwiae */
- if (rate == 48000 || rate == 44100 || rate == 32000) {
- return 1;
- }
- break;
- }
- return (0);
-}
-
-/* ali_set_spdif_output
- *
- * Configure the S/PDIF output transmitter. When we turn on
- * S/PDIF, we turn off the analog output. This may not be
- * the right thing to do.
- *
- * Assumptions:
- * The DSP sample rate must already be set to a supported
- * S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort.
- */
-static void ali_set_spdif_output(struct ali_state *state, int slots,
- int rate)
-{
- int vol;
- int aud_reg;
- struct ac97_codec *codec = state->card->ac97_codec[0];
-
- if (!(state->card->ac97_features & 4)) {
- state->card->ac97_status &= ~SPDIF_ON;
- } else {
- if (slots == -1) { /* Turn off S/PDIF */
- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
-
- /* If the volume wasn't muted before we turned on S/PDIF, unmute it */
- if (!(state->card->ac97_status & VOL_MUTED)) {
- aud_reg = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
- ali_ac97_set(codec, AC97_MASTER_VOL_STEREO,
- (aud_reg & ~VOL_MUTED));
- }
- state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
- return;
- }
-
- vol = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
- state->card->ac97_status = vol & VOL_MUTED;
-
- /* Set S/PDIF transmitter sample rate */
- aud_reg = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
- switch (rate) {
- case 32000:
- aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K;
- break;
- case 44100:
- aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K;
- break;
- case 48000:
- aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K;
- break;
- default:
- /* turn off S/PDIF */
- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
- state->card->ac97_status &= ~SPDIF_ON;
- return;
- }
-
- ali_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg);
-
- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
- aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_SPDIF;
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
-
- aud_reg = ali_ac97_get(codec, AC97_POWER_CONTROL);
- aud_reg |= 0x0002;
- ali_ac97_set(codec, AC97_POWER_CONTROL, aud_reg);
- udelay(1);
-
- state->card->ac97_status |= SPDIF_ON;
-
- /* Check to make sure the configuration is valid */
- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
- if (!(aud_reg & 0x0400)) {
- /* turn off S/PDIF */
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
- state->card->ac97_status &= ~SPDIF_ON;
- return;
- }
- if (codec_independent_spdif_locked > 0) {
- aud_reg = ali_ac97_get(codec, 0x6a);
- ali_ac97_set(codec, 0x6a, (aud_reg & 0xefff));
- }
- /* Mute the analog output */
- /* Should this only mute the PCM volume??? */
- }
-}
-
-/* ali_set_dac_channels
- *
- * Configure the codec's multi-channel DACs
- *
- * The logic is backwards. Setting the bit to 1 turns off the DAC.
- *
- * What about the ICH? We currently configure it using the
- * SNDCTL_DSP_CHANNELS ioctl. If we're turnning on the DAC,
- * does that imply that we want the ICH set to support
- * these channels?
- *
- * TODO:
- * vailidate that the codec really supports these DACs
- * before turning them on.
- */
-static void ali_set_dac_channels(struct ali_state *state, int channel)
-{
- int aud_reg;
- struct ac97_codec *codec = state->card->ac97_codec[0];
-
- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
- aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;
- state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON);
-
- switch (channel) {
- case 2: /* always enabled */
- break;
- case 4:
- aud_reg &= ~AC97_EA_PRJ;
- state->card->ac97_status |= SURR_ON;
- break;
- case 6:
- aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK);
- state->card->ac97_status |= SURR_ON | CENTER_LFE_ON;
- break;
- default:
- break;
- }
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
-
-}
-
-/* set playback sample rate */
-static unsigned int ali_set_dac_rate(struct ali_state *state,
- unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- u32 new_rate;
- struct ac97_codec *codec = state->card->ac97_codec[0];
-
- if (!(state->card->ac97_features & 0x0001)) {
- dmabuf->rate = clocking;
- return clocking;
- }
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- dmabuf->rate = rate;
-
- /*
- * Adjust for misclocked crap
- */
-
- rate = (rate * clocking) / 48000;
-
- if (strict_clocking && rate < 8000) {
- rate = 8000;
- dmabuf->rate = (rate * 48000) / clocking;
- }
-
- new_rate = ac97_set_dac_rate(codec, rate);
- if (new_rate != rate) {
- dmabuf->rate = (new_rate * 48000) / clocking;
- }
- rate = new_rate;
- return dmabuf->rate;
-}
-
-/* set recording sample rate */
-static unsigned int ali_set_adc_rate(struct ali_state *state,
- unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- u32 new_rate;
- struct ac97_codec *codec = state->card->ac97_codec[0];
-
- if (!(state->card->ac97_features & 0x0001)) {
- dmabuf->rate = clocking;
- return clocking;
- }
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- dmabuf->rate = rate;
-
- /*
- * Adjust for misclocked crap
- */
-
- rate = (rate * clocking) / 48000;
- if (strict_clocking && rate < 8000) {
- rate = 8000;
- dmabuf->rate = (rate * 48000) / clocking;
- }
-
- new_rate = ac97_set_adc_rate(codec, rate);
-
- if (new_rate != rate) {
- dmabuf->rate = (new_rate * 48000) / clocking;
- rate = new_rate;
- }
- return dmabuf->rate;
-}
-
-/* set codec independent spdifout sample rate */
-static unsigned int ali_set_codecspdifout_rate(struct ali_state *state,
- unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
-
- if (!(state->card->ac97_features & 0x0001)) {
- dmabuf->rate = clocking;
- return clocking;
- }
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- dmabuf->rate = rate;
-
- return dmabuf->rate;
-}
-
-/* set controller independent spdif out function sample rate */
-static void ali_set_spdifout_rate(struct ali_state *state,
- unsigned int rate)
-{
- unsigned char ch_st_sel;
- unsigned short status_rate;
-
- switch (rate) {
- case 44100:
- status_rate = 0;
- break;
- case 32000:
- status_rate = 0x300;
- break;
- case 48000:
- default:
- status_rate = 0x200;
- break;
- }
-
- ch_st_sel = inb(state->card->iobase + ALI_SPDIFICS) & ALI_SPDIF_OUT_CH_STATUS; //select spdif_out
-
- ch_st_sel |= 0x80; //select right
- outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS));
- outb(status_rate | 0x20, (state->card->iobase + ALI_SPDIFCSR + 2));
-
- ch_st_sel &= (~0x80); //select left
- outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS));
- outw(status_rate | 0x10, (state->card->iobase + ALI_SPDIFCSR + 2));
-}
-
-/* get current playback/recording dma buffer pointer (byte offset from LBA),
- called with spinlock held! */
-
-static inline unsigned ali_get_dma_addr(struct ali_state *state, int rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned int civ, offset, port, port_picb;
- unsigned int data;
-
- if (!dmabuf->enable)
- return 0;
-
- if (rec == 1)
- port = state->card->iobase + dmabuf->read_channel->port;
- else if (rec == 2)
- port = state->card->iobase + dmabuf->codec_spdifout_channel->port;
- else if (rec == 3)
- port = state->card->iobase + dmabuf->controller_spdifout_channel->port;
- else
- port = state->card->iobase + dmabuf->write_channel->port;
-
- port_picb = port + OFF_PICB;
-
- do {
- civ = inb(port + OFF_CIV) & 31;
- offset = inw(port_picb);
- /* Must have a delay here! */
- if (offset == 0)
- udelay(1);
-
- /* Reread both registers and make sure that that total
- * offset from the first reading to the second is 0.
- * There is an issue with SiS hardware where it will count
- * picb down to 0, then update civ to the next value,
- * then set the new picb to fragsize bytes. We can catch
- * it between the civ update and the picb update, making
- * it look as though we are 1 fragsize ahead of where we
- * are. The next to we get the address though, it will
- * be back in thdelay is more than long enough
- * that we won't have to worry about the chip still being
- * out of sync with reality ;-)
- */
- } while (civ != (inb(port + OFF_CIV) & 31) || offset != inw(port_picb));
-
- data = ((civ + 1) * dmabuf->fragsize - (2 * offset)) % dmabuf->dmasize;
- if (inw(port_picb) == 0)
- data -= 2048;
-
- return data;
-}
-
-/* Stop recording (lock held) */
-static inline void __stop_adc(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct ali_card *card = state->card;
-
- dmabuf->enable &= ~ADC_RUNNING;
-
- outl((1 << 18) | (1 << 16), card->iobase + ALI_DMACR);
- udelay(1);
-
- outb(0, card->iobase + PI_CR);
- while (inb(card->iobase + PI_CR) != 0);
-
- // now clear any latent interrupt bits (like the halt bit)
- outb(inb(card->iobase + PI_SR) | 0x001e, card->iobase + PI_SR);
- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMIN, card->iobase + ALI_INTERRUPTSR);
-}
-
-static void stop_adc(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- __stop_adc(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_adc(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
-
- if (dmabuf->count < dmabuf->dmasize && dmabuf->ready
- && !dmabuf->enable && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
- dmabuf->enable |= ADC_RUNNING;
- outb((1 << 4) | (1 << 2), state->card->iobase + PI_CR);
- if (state->card->channel[0].used == 1)
- outl(1, state->card->iobase + ALI_DMACR); // DMA CONTROL REGISTRER
- udelay(100);
- if (state->card->channel[2].used == 1)
- outl((1 << 2), state->card->iobase + ALI_DMACR); //DMA CONTROL REGISTER
- udelay(100);
- }
-}
-
-static void start_adc(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- __start_adc(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* stop playback (lock held) */
-static inline void __stop_dac(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct ali_card *card = state->card;
-
- dmabuf->enable &= ~DAC_RUNNING;
- outl(0x00020000, card->iobase + 0x08);
- outb(0, card->iobase + PO_CR);
- while (inb(card->iobase + PO_CR) != 0)
- cpu_relax();
-
- outb(inb(card->iobase + PO_SR) | 0x001e, card->iobase + PO_SR);
-
- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMOUT, card->iobase + ALI_INTERRUPTSR);
-}
-
-static void stop_dac(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- __stop_dac(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_dac(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
- (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
- dmabuf->enable |= DAC_RUNNING;
- outb((1 << 4) | (1 << 2), state->card->iobase + PO_CR);
- outl((1 << 1), state->card->iobase + 0x08); //dma control register
- }
-}
-
-static void start_dac(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- __start_dac(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* stop codec and controller spdif out (lock held) */
-static inline void __stop_spdifout(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct ali_card *card = state->card;
-
- if (codec_independent_spdif_locked > 0) {
- dmabuf->enable &= ~CODEC_SPDIFOUT_RUNNING;
- outl((1 << 19), card->iobase + 0x08);
- outb(0, card->iobase + CODECSPDIFOUT_CR);
-
- while (inb(card->iobase + CODECSPDIFOUT_CR) != 0)
- cpu_relax();
-
- outb(inb(card->iobase + CODECSPDIFOUT_SR) | 0x001e, card->iobase + CODECSPDIFOUT_SR);
- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_CODECSPDIFOUT, card->iobase + ALI_INTERRUPTSR);
- } else {
- if (controller_independent_spdif_locked > 0) {
- dmabuf->enable &= ~CONTROLLER_SPDIFOUT_RUNNING;
- outl((1 << 23), card->iobase + 0x08);
- outb(0, card->iobase + CONTROLLERSPDIFOUT_CR);
- while (inb(card->iobase + CONTROLLERSPDIFOUT_CR) != 0)
- cpu_relax();
- outb(inb(card->iobase + CONTROLLERSPDIFOUT_SR) | 0x001e, card->iobase + CONTROLLERSPDIFOUT_SR);
- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_SPDIFOUT, card->iobase + ALI_INTERRUPTSR);
- }
- }
-}
-
-static void stop_spdifout(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- __stop_spdifout(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_spdifout(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
- (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
- if (codec_independent_spdif_locked > 0) {
- dmabuf->enable |= CODEC_SPDIFOUT_RUNNING;
- outb((1 << 4) | (1 << 2), state->card->iobase + CODECSPDIFOUT_CR);
- outl((1 << 3), state->card->iobase + 0x08); //dma control register
- } else {
- if (controller_independent_spdif_locked > 0) {
- dmabuf->enable |= CONTROLLER_SPDIFOUT_RUNNING;
- outb((1 << 4) | (1 << 2), state->card->iobase + CONTROLLERSPDIFOUT_CR);
- outl((1 << 7), state->card->iobase + 0x08); //dma control register
- }
- }
- }
-}
-
-static void start_spdifout(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- __start_spdifout(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-/* allocate DMA buffer, playback , recording,spdif out buffer should be allocated separately */
-static int alloc_dmabuf(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- void *rawbuf = NULL;
- int order, size;
- struct page *page, *pend;
-
- /* If we don't have any oss frag params, then use our default ones */
- if (dmabuf->ossmaxfrags == 0)
- dmabuf->ossmaxfrags = 4;
- if (dmabuf->ossfragsize == 0)
- dmabuf->ossfragsize = (PAGE_SIZE << DMABUF_DEFAULTORDER) / dmabuf->ossmaxfrags;
- size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
-
- if (dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size)
- return 0;
- /* alloc enough to satisfy the oss params */
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
- if ((PAGE_SIZE << order) > size)
- continue;
- if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
- PAGE_SIZE << order,
- &dmabuf->dma_handle)))
- break;
- }
- if (!rawbuf)
- return -ENOMEM;
-
- dmabuf->ready = dmabuf->mapped = 0;
- dmabuf->rawbuf = rawbuf;
- dmabuf->buforder = order;
-
- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
- pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
- for (page = virt_to_page(rawbuf); page <= pend; page++)
- SetPageReserved(page);
- return 0;
-}
-
-/* free DMA buffer */
-static void dealloc_dmabuf(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct page *page, *pend;
-
- if (dmabuf->rawbuf) {
- /* undo marking the pages as reserved */
- pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
- for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
- ClearPageReserved(page);
- pci_free_consistent(state->card->pci_dev,
- PAGE_SIZE << dmabuf->buforder,
- dmabuf->rawbuf, dmabuf->dma_handle);
- }
- dmabuf->rawbuf = NULL;
- dmabuf->mapped = dmabuf->ready = 0;
-}
-
-static int prog_dmabuf(struct ali_state *state, unsigned rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct ali_channel *c = NULL;
- struct sg_item *sg;
- unsigned long flags;
- int ret;
- unsigned fragint;
- int i;
-
- spin_lock_irqsave(&state->card->lock, flags);
- if (dmabuf->enable & DAC_RUNNING)
- __stop_dac(state);
- if (dmabuf->enable & ADC_RUNNING)
- __stop_adc(state);
- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- __stop_spdifout(state);
- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- __stop_spdifout(state);
-
- dmabuf->total_bytes = 0;
- dmabuf->count = dmabuf->error = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- /* allocate DMA buffer, let alloc_dmabuf determine if we are already
- * allocated well enough or if we should replace the current buffer
- * (assuming one is already allocated, if it isn't, then allocate it).
- */
- if ((ret = alloc_dmabuf(state)))
- return ret;
-
- /* FIXME: figure out all this OSS fragment stuff */
- /* I did, it now does what it should according to the OSS API. DL */
- /* We may not have realloced our dmabuf, but the fragment size to
- * fragment number ratio may have changed, so go ahead and reprogram
- * things
- */
-
- dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder;
- dmabuf->numfrag = SG_LEN;
- dmabuf->fragsize = dmabuf->dmasize / dmabuf->numfrag;
- dmabuf->fragsamples = dmabuf->fragsize >> 1;
- dmabuf->userfragsize = dmabuf->ossfragsize;
- dmabuf->userfrags = dmabuf->dmasize / dmabuf->ossfragsize;
-
- memset(dmabuf->rawbuf, 0, dmabuf->dmasize);
-
- if (dmabuf->ossmaxfrags == 4) {
- fragint = 8;
- dmabuf->fragshift = 2;
- } else if (dmabuf->ossmaxfrags == 8) {
- fragint = 4;
- dmabuf->fragshift = 3;
- } else if (dmabuf->ossmaxfrags == 16) {
- fragint = 2;
- dmabuf->fragshift = 4;
- } else {
- fragint = 1;
- dmabuf->fragshift = 5;
- }
- /*
- * Now set up the ring
- */
-
- if (rec == 1)
- c = dmabuf->read_channel;
- else if (rec == 2)
- c = dmabuf->codec_spdifout_channel;
- else if (rec == 3)
- c = dmabuf->controller_spdifout_channel;
- else if (rec == 0)
- c = dmabuf->write_channel;
- if (c != NULL) {
- sg = &c->sg[0];
- /*
- * Load up 32 sg entries and take an interrupt at half
- * way (we might want more interrupts later..)
- */
- for (i = 0; i < dmabuf->numfrag; i++) {
- sg->busaddr =
- virt_to_bus(dmabuf->rawbuf +
- dmabuf->fragsize * i);
- // the card will always be doing 16bit stereo
- sg->control = dmabuf->fragsamples;
- sg->control |= CON_BUFPAD; //I modify
- // set us up to get IOC interrupts as often as needed to
- // satisfy numfrag requirements, no more
- if (((i + 1) % fragint) == 0) {
- sg->control |= CON_IOC;
- }
- sg++;
- }
- spin_lock_irqsave(&state->card->lock, flags);
- outb(2, state->card->iobase + c->port + OFF_CR); /* reset DMA machine */
- outl(virt_to_bus(&c->sg[0]), state->card->iobase + c->port + OFF_BDBAR);
- outb(0, state->card->iobase + c->port + OFF_CIV);
- outb(0, state->card->iobase + c->port + OFF_LVI);
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- /* set the ready flag for the dma buffer */
- dmabuf->ready = 1;
- return 0;
-}
-
-static void __ali_update_lvi(struct ali_state *state, int rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- int x, port;
- port = state->card->iobase;
- if (rec == 1)
- port += dmabuf->read_channel->port;
- else if (rec == 2)
- port += dmabuf->codec_spdifout_channel->port;
- else if (rec == 3)
- port += dmabuf->controller_spdifout_channel->port;
- else if (rec == 0)
- port += dmabuf->write_channel->port;
- /* if we are currently stopped, then our CIV is actually set to our
- * *last* sg segment and we are ready to wrap to the next. However,
- * if we set our LVI to the last sg segment, then it won't wrap to
- * the next sg segment, it won't even get a start. So, instead, when
- * we are stopped, we set both the LVI value and also we increment
- * the CIV value to the next sg segment to be played so that when
- * we call start_{dac,adc}, things will operate properly
- */
- if (!dmabuf->enable && dmabuf->ready) {
- if (rec && dmabuf->count < dmabuf->dmasize && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
- outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
- __start_adc(state);
- while (! (inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
- cpu_relax();
- } else if (!rec && dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
- outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
- __start_dac(state);
- while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
- cpu_relax();
- } else if (rec &a