1*175859bfSDavid Dillow /* 2*175859bfSDavid Dillow * Driver for SiS7019 Audio Accelerator 3*175859bfSDavid Dillow * 4*175859bfSDavid Dillow * Copyright (C) 2004-2007, David Dillow 5*175859bfSDavid Dillow * Written by David Dillow <dave@thedillows.org> 6*175859bfSDavid Dillow * Inspired by the Trident 4D-WaveDX/NX driver. 7*175859bfSDavid Dillow * 8*175859bfSDavid Dillow * All rights reserved. 9*175859bfSDavid Dillow * 10*175859bfSDavid Dillow * This program is free software; you can redistribute it and/or modify 11*175859bfSDavid Dillow * it under the terms of the GNU General Public License as published by 12*175859bfSDavid Dillow * the Free Software Foundation, version 2. 13*175859bfSDavid Dillow * 14*175859bfSDavid Dillow * This program is distributed in the hope that it will be useful, 15*175859bfSDavid Dillow * but WITHOUT ANY WARRANTY; without even the implied warranty of 16*175859bfSDavid Dillow * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17*175859bfSDavid Dillow * GNU General Public License for more details. 18*175859bfSDavid Dillow * 19*175859bfSDavid Dillow * You should have received a copy of the GNU General Public License 20*175859bfSDavid Dillow * along with this program; if not, write to the Free Software 21*175859bfSDavid Dillow * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22*175859bfSDavid Dillow */ 23*175859bfSDavid Dillow 24*175859bfSDavid Dillow #include <sound/driver.h> 25*175859bfSDavid Dillow #include <linux/init.h> 26*175859bfSDavid Dillow #include <linux/pci.h> 27*175859bfSDavid Dillow #include <linux/time.h> 28*175859bfSDavid Dillow #include <linux/moduleparam.h> 29*175859bfSDavid Dillow #include <linux/interrupt.h> 30*175859bfSDavid Dillow #include <linux/delay.h> 31*175859bfSDavid Dillow #include <sound/core.h> 32*175859bfSDavid Dillow #include <sound/ac97_codec.h> 33*175859bfSDavid Dillow #include <sound/initval.h> 34*175859bfSDavid Dillow #include "sis7019.h" 35*175859bfSDavid Dillow 36*175859bfSDavid Dillow MODULE_AUTHOR("David Dillow <dave@thedillows.org>"); 37*175859bfSDavid Dillow MODULE_DESCRIPTION("SiS7019"); 38*175859bfSDavid Dillow MODULE_LICENSE("GPL"); 39*175859bfSDavid Dillow MODULE_SUPPORTED_DEVICE("{{SiS,SiS7019 Audio Accelerator}}"); 40*175859bfSDavid Dillow 41*175859bfSDavid Dillow static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ 42*175859bfSDavid Dillow static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ 43*175859bfSDavid Dillow static int enable = 1; 44*175859bfSDavid Dillow 45*175859bfSDavid Dillow module_param(index, int, 0444); 46*175859bfSDavid Dillow MODULE_PARM_DESC(index, "Index value for SiS7019 Audio Accelerator."); 47*175859bfSDavid Dillow module_param(id, charp, 0444); 48*175859bfSDavid Dillow MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator."); 49*175859bfSDavid Dillow module_param(enable, bool, 0444); 50*175859bfSDavid Dillow MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator."); 51*175859bfSDavid Dillow 52*175859bfSDavid Dillow static struct pci_device_id snd_sis7019_ids[] = { 53*175859bfSDavid Dillow { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) }, 54*175859bfSDavid Dillow { 0, } 55*175859bfSDavid Dillow }; 56*175859bfSDavid Dillow 57*175859bfSDavid Dillow MODULE_DEVICE_TABLE(pci, snd_sis7019_ids); 58*175859bfSDavid Dillow 59*175859bfSDavid Dillow /* There are three timing modes for the voices. 60*175859bfSDavid Dillow * 61*175859bfSDavid Dillow * For both playback and capture, when the buffer is one or two periods long, 62*175859bfSDavid Dillow * we use the hardware's built-in Mid-Loop Interrupt and End-Loop Interrupt 63*175859bfSDavid Dillow * to let us know when the periods have ended. 64*175859bfSDavid Dillow * 65*175859bfSDavid Dillow * When performing playback with more than two periods per buffer, we set 66*175859bfSDavid Dillow * the "Stop Sample Offset" and tell the hardware to interrupt us when we 67*175859bfSDavid Dillow * reach it. We then update the offset and continue on until we are 68*175859bfSDavid Dillow * interrupted for the next period. 69*175859bfSDavid Dillow * 70*175859bfSDavid Dillow * Capture channels do not have a SSO, so we allocate a playback channel to 71*175859bfSDavid Dillow * use as a timer for the capture periods. We use the SSO on the playback 72*175859bfSDavid Dillow * channel to clock out virtual periods, and adjust the virtual period length 73*175859bfSDavid Dillow * to maintain synchronization. This algorithm came from the Trident driver. 74*175859bfSDavid Dillow * 75*175859bfSDavid Dillow * FIXME: It'd be nice to make use of some of the synth features in the 76*175859bfSDavid Dillow * hardware, but a woeful lack of documentation is a significant roadblock. 77*175859bfSDavid Dillow */ 78*175859bfSDavid Dillow struct voice { 79*175859bfSDavid Dillow u16 flags; 80*175859bfSDavid Dillow #define VOICE_IN_USE 1 81*175859bfSDavid Dillow #define VOICE_CAPTURE 2 82*175859bfSDavid Dillow #define VOICE_SSO_TIMING 4 83*175859bfSDavid Dillow #define VOICE_SYNC_TIMING 8 84*175859bfSDavid Dillow u16 sync_cso; 85*175859bfSDavid Dillow u16 period_size; 86*175859bfSDavid Dillow u16 buffer_size; 87*175859bfSDavid Dillow u16 sync_period_size; 88*175859bfSDavid Dillow u16 sync_buffer_size; 89*175859bfSDavid Dillow u32 sso; 90*175859bfSDavid Dillow u32 vperiod; 91*175859bfSDavid Dillow struct snd_pcm_substream *substream; 92*175859bfSDavid Dillow struct voice *timing; 93*175859bfSDavid Dillow void __iomem *ctrl_base; 94*175859bfSDavid Dillow void __iomem *wave_base; 95*175859bfSDavid Dillow void __iomem *sync_base; 96*175859bfSDavid Dillow int num; 97*175859bfSDavid Dillow }; 98*175859bfSDavid Dillow 99*175859bfSDavid Dillow /* We need four pages to store our wave parameters during a suspend. If 100*175859bfSDavid Dillow * we're not doing power management, we still need to allocate a page 101*175859bfSDavid Dillow * for the silence buffer. 102*175859bfSDavid Dillow */ 103*175859bfSDavid Dillow #ifdef CONFIG_PM 104*175859bfSDavid Dillow #define SIS_SUSPEND_PAGES 4 105*175859bfSDavid Dillow #else 106*175859bfSDavid Dillow #define SIS_SUSPEND_PAGES 1 107*175859bfSDavid Dillow #endif 108*175859bfSDavid Dillow 109*175859bfSDavid Dillow struct sis7019 { 110*175859bfSDavid Dillow unsigned long ioport; 111*175859bfSDavid Dillow void __iomem *ioaddr; 112*175859bfSDavid Dillow int irq; 113*175859bfSDavid Dillow int codecs_present; 114*175859bfSDavid Dillow 115*175859bfSDavid Dillow struct pci_dev *pci; 116*175859bfSDavid Dillow struct snd_pcm *pcm; 117*175859bfSDavid Dillow struct snd_card *card; 118*175859bfSDavid Dillow struct snd_ac97 *ac97[3]; 119*175859bfSDavid Dillow 120*175859bfSDavid Dillow /* Protect against more than one thread hitting the AC97 121*175859bfSDavid Dillow * registers (in a more polite manner than pounding the hardware 122*175859bfSDavid Dillow * semaphore) 123*175859bfSDavid Dillow */ 124*175859bfSDavid Dillow struct mutex ac97_mutex; 125*175859bfSDavid Dillow 126*175859bfSDavid Dillow /* voice_lock protects allocation/freeing of the voice descriptions 127*175859bfSDavid Dillow */ 128*175859bfSDavid Dillow spinlock_t voice_lock; 129*175859bfSDavid Dillow 130*175859bfSDavid Dillow struct voice voices[64]; 131*175859bfSDavid Dillow struct voice capture_voice; 132*175859bfSDavid Dillow 133*175859bfSDavid Dillow /* Allocate pages to store the internal wave state during 134*175859bfSDavid Dillow * suspends. When we're operating, this can be used as a silence 135*175859bfSDavid Dillow * buffer for a timing channel. 136*175859bfSDavid Dillow */ 137*175859bfSDavid Dillow void *suspend_state[SIS_SUSPEND_PAGES]; 138*175859bfSDavid Dillow 139*175859bfSDavid Dillow int silence_users; 140*175859bfSDavid Dillow dma_addr_t silence_dma_addr; 141*175859bfSDavid Dillow }; 142*175859bfSDavid Dillow 143*175859bfSDavid Dillow #define SIS_PRIMARY_CODEC_PRESENT 0x0001 144*175859bfSDavid Dillow #define SIS_SECONDARY_CODEC_PRESENT 0x0002 145*175859bfSDavid Dillow #define SIS_TERTIARY_CODEC_PRESENT 0x0004 146*175859bfSDavid Dillow 147*175859bfSDavid Dillow /* The HW offset parameters (Loop End, Stop Sample, End Sample) have a 148*175859bfSDavid Dillow * documented range of 8-0xfff8 samples. Given that they are 0-based, 149*175859bfSDavid Dillow * that places our period/buffer range at 9-0xfff9 samples. That makes the 150*175859bfSDavid Dillow * max buffer size 0xfff9 samples * 2 channels * 2 bytes per sample, and 151*175859bfSDavid Dillow * max samples / min samples gives us the max periods in a buffer. 152*175859bfSDavid Dillow * 153*175859bfSDavid Dillow * We'll add a constraint upon open that limits the period and buffer sample 154*175859bfSDavid Dillow * size to values that are legal for the hardware. 155*175859bfSDavid Dillow */ 156*175859bfSDavid Dillow static struct snd_pcm_hardware sis_playback_hw_info = { 157*175859bfSDavid Dillow .info = (SNDRV_PCM_INFO_MMAP | 158*175859bfSDavid Dillow SNDRV_PCM_INFO_MMAP_VALID | 159*175859bfSDavid Dillow SNDRV_PCM_INFO_INTERLEAVED | 160*175859bfSDavid Dillow SNDRV_PCM_INFO_BLOCK_TRANSFER | 161*175859bfSDavid Dillow SNDRV_PCM_INFO_SYNC_START | 162*175859bfSDavid Dillow SNDRV_PCM_INFO_RESUME), 163*175859bfSDavid Dillow .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | 164*175859bfSDavid Dillow SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE), 165*175859bfSDavid Dillow .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS, 166*175859bfSDavid Dillow .rate_min = 4000, 167*175859bfSDavid Dillow .rate_max = 48000, 168*175859bfSDavid Dillow .channels_min = 1, 169*175859bfSDavid Dillow .channels_max = 2, 170*175859bfSDavid Dillow .buffer_bytes_max = (0xfff9 * 4), 171*175859bfSDavid Dillow .period_bytes_min = 9, 172*175859bfSDavid Dillow .period_bytes_max = (0xfff9 * 4), 173*175859bfSDavid Dillow .periods_min = 1, 174*175859bfSDavid Dillow .periods_max = (0xfff9 / 9), 175*175859bfSDavid Dillow }; 176*175859bfSDavid Dillow 177*175859bfSDavid Dillow static struct snd_pcm_hardware sis_capture_hw_info = { 178*175859bfSDavid Dillow .info = (SNDRV_PCM_INFO_MMAP | 179*175859bfSDavid Dillow SNDRV_PCM_INFO_MMAP_VALID | 180*175859bfSDavid Dillow SNDRV_PCM_INFO_INTERLEAVED | 181*175859bfSDavid Dillow SNDRV_PCM_INFO_BLOCK_TRANSFER | 182*175859bfSDavid Dillow SNDRV_PCM_INFO_SYNC_START | 183*175859bfSDavid Dillow SNDRV_PCM_INFO_RESUME), 184*175859bfSDavid Dillow .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | 185*175859bfSDavid Dillow SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE), 186*175859bfSDavid Dillow .rates = SNDRV_PCM_RATE_48000, 187*175859bfSDavid Dillow .rate_min = 4000, 188*175859bfSDavid Dillow .rate_max = 48000, 189*175859bfSDavid Dillow .channels_min = 1, 190*175859bfSDavid Dillow .channels_max = 2, 191*175859bfSDavid Dillow .buffer_bytes_max = (0xfff9 * 4), 192*175859bfSDavid Dillow .period_bytes_min = 9, 193*175859bfSDavid Dillow .period_bytes_max = (0xfff9 * 4), 194*175859bfSDavid Dillow .periods_min = 1, 195*175859bfSDavid Dillow .periods_max = (0xfff9 / 9), 196*175859bfSDavid Dillow }; 197*175859bfSDavid Dillow 198*175859bfSDavid Dillow static void sis_update_sso(struct voice *voice, u16 period) 199*175859bfSDavid Dillow { 200*175859bfSDavid Dillow void __iomem *base = voice->ctrl_base; 201*175859bfSDavid Dillow 202*175859bfSDavid Dillow voice->sso += period; 203*175859bfSDavid Dillow if (voice->sso >= voice->buffer_size) 204*175859bfSDavid Dillow voice->sso -= voice->buffer_size; 205*175859bfSDavid Dillow 206*175859bfSDavid Dillow /* Enforce the documented hardware minimum offset */ 207*175859bfSDavid Dillow if (voice->sso < 8) 208*175859bfSDavid Dillow voice->sso = 8; 209*175859bfSDavid Dillow 210*175859bfSDavid Dillow /* The SSO is in the upper 16 bits of the register. */ 211*175859bfSDavid Dillow writew(voice->sso & 0xffff, base + SIS_PLAY_DMA_SSO_ESO + 2); 212*175859bfSDavid Dillow } 213*175859bfSDavid Dillow 214*175859bfSDavid Dillow static void sis_update_voice(struct voice *voice) 215*175859bfSDavid Dillow { 216*175859bfSDavid Dillow if (voice->flags & VOICE_SSO_TIMING) { 217*175859bfSDavid Dillow sis_update_sso(voice, voice->period_size); 218*175859bfSDavid Dillow } else if (voice->flags & VOICE_SYNC_TIMING) { 219*175859bfSDavid Dillow int sync; 220*175859bfSDavid Dillow 221*175859bfSDavid Dillow /* If we've not hit the end of the virtual period, update 222*175859bfSDavid Dillow * our records and keep going. 223*175859bfSDavid Dillow */ 224*175859bfSDavid Dillow if (voice->vperiod > voice->period_size) { 225*175859bfSDavid Dillow voice->vperiod -= voice->period_size; 226*175859bfSDavid Dillow if (voice->vperiod < voice->period_size) 227*175859bfSDavid Dillow sis_update_sso(voice, voice->vperiod); 228*175859bfSDavid Dillow else 229*175859bfSDavid Dillow sis_update_sso(voice, voice->period_size); 230*175859bfSDavid Dillow return; 231*175859bfSDavid Dillow } 232*175859bfSDavid Dillow 233*175859bfSDavid Dillow /* Calculate our relative offset between the target and 234*175859bfSDavid Dillow * the actual CSO value. Since we're operating in a loop, 235*175859bfSDavid Dillow * if the value is more than half way around, we can 236*175859bfSDavid Dillow * consider ourselves wrapped. 237*175859bfSDavid Dillow */ 238*175859bfSDavid Dillow sync = voice->sync_cso; 239*175859bfSDavid Dillow sync -= readw(voice->sync_base + SIS_CAPTURE_DMA_FORMAT_CSO); 240*175859bfSDavid Dillow if (sync > (voice->sync_buffer_size / 2)) 241*175859bfSDavid Dillow sync -= voice->sync_buffer_size; 242*175859bfSDavid Dillow 243*175859bfSDavid Dillow /* If sync is positive, then we interrupted too early, and 244*175859bfSDavid Dillow * we'll need to come back in a few samples and try again. 245*175859bfSDavid Dillow * There's a minimum wait, as it takes some time for the DMA 246*175859bfSDavid Dillow * engine to startup, etc... 247*175859bfSDavid Dillow */ 248*175859bfSDavid Dillow if (sync > 0) { 249*175859bfSDavid Dillow if (sync < 16) 250*175859bfSDavid Dillow sync = 16; 251*175859bfSDavid Dillow sis_update_sso(voice, sync); 252*175859bfSDavid Dillow return; 253*175859bfSDavid Dillow } 254*175859bfSDavid Dillow 255*175859bfSDavid Dillow /* Ok, we interrupted right on time, or (hopefully) just 256*175859bfSDavid Dillow * a bit late. We'll adjst our next waiting period based 257*175859bfSDavid Dillow * on how close we got. 258*175859bfSDavid Dillow * 259*175859bfSDavid Dillow * We need to stay just behind the actual channel to ensure 260*175859bfSDavid Dillow * it really is past a period when we get our interrupt -- 261*175859bfSDavid Dillow * otherwise we'll fall into the early code above and have 262*175859bfSDavid Dillow * a minimum wait time, which makes us quite late here, 263*175859bfSDavid Dillow * eating into the user's time to refresh the buffer, esp. 264*175859bfSDavid Dillow * if using small periods. 265*175859bfSDavid Dillow * 266*175859bfSDavid Dillow * If we're less than 9 samples behind, we're on target. 267*175859bfSDavid Dillow */ 268*175859bfSDavid Dillow if (sync > -9) 269*175859bfSDavid Dillow voice->vperiod = voice->sync_period_size + 1; 270*175859bfSDavid Dillow else 271*175859bfSDavid Dillow voice->vperiod = voice->sync_period_size - 4; 272*175859bfSDavid Dillow 273*175859bfSDavid Dillow if (voice->vperiod < voice->buffer_size) { 274*175859bfSDavid Dillow sis_update_sso(voice, voice->vperiod); 275*175859bfSDavid Dillow voice->vperiod = 0; 276*175859bfSDavid Dillow } else 277*175859bfSDavid Dillow sis_update_sso(voice, voice->period_size); 278*175859bfSDavid Dillow 279*175859bfSDavid Dillow sync = voice->sync_cso + voice->sync_period_size; 280*175859bfSDavid Dillow if (sync >= voice->sync_buffer_size) 281*175859bfSDavid Dillow sync -= voice->sync_buffer_size; 282*175859bfSDavid Dillow voice->sync_cso = sync; 283*175859bfSDavid Dillow } 284*175859bfSDavid Dillow 285*175859bfSDavid Dillow snd_pcm_period_elapsed(voice->substream); 286*175859bfSDavid Dillow } 287*175859bfSDavid Dillow 288*175859bfSDavid Dillow static void sis_voice_irq(u32 status, struct voice *voice) 289*175859bfSDavid Dillow { 290*175859bfSDavid Dillow int bit; 291*175859bfSDavid Dillow 292*175859bfSDavid Dillow while (status) { 293*175859bfSDavid Dillow bit = __ffs(status); 294*175859bfSDavid Dillow status >>= bit + 1; 295*175859bfSDavid Dillow voice += bit; 296*175859bfSDavid Dillow sis_update_voice(voice); 297*175859bfSDavid Dillow voice++; 298*175859bfSDavid Dillow } 299*175859bfSDavid Dillow } 300*175859bfSDavid Dillow 301*175859bfSDavid Dillow static irqreturn_t sis_interrupt(int irq, void *dev) 302*175859bfSDavid Dillow { 303*175859bfSDavid Dillow struct sis7019 *sis = dev; 304*175859bfSDavid Dillow unsigned long io = sis->ioport; 305*175859bfSDavid Dillow struct voice *voice; 306*175859bfSDavid Dillow u32 intr, status; 307*175859bfSDavid Dillow 308*175859bfSDavid Dillow /* We only use the DMA interrupts, and we don't enable any other 309*175859bfSDavid Dillow * source of interrupts. But, it is possible to see an interupt 310*175859bfSDavid Dillow * status that didn't actually interrupt us, so eliminate anything 311*175859bfSDavid Dillow * we're not expecting to avoid falsely claiming an IRQ, and an 312*175859bfSDavid Dillow * ensuing endless loop. 313*175859bfSDavid Dillow */ 314*175859bfSDavid Dillow intr = inl(io + SIS_GISR); 315*175859bfSDavid Dillow intr &= SIS_GISR_AUDIO_PLAY_DMA_IRQ_STATUS | 316*175859bfSDavid Dillow SIS_GISR_AUDIO_RECORD_DMA_IRQ_STATUS; 317*175859bfSDavid Dillow if (!intr) 318*175859bfSDavid Dillow return IRQ_NONE; 319*175859bfSDavid Dillow 320*175859bfSDavid Dillow do { 321*175859bfSDavid Dillow status = inl(io + SIS_PISR_A); 322*175859bfSDavid Dillow if (status) { 323*175859bfSDavid Dillow sis_voice_irq(status, sis->voices); 324*175859bfSDavid Dillow outl(status, io + SIS_PISR_A); 325*175859bfSDavid Dillow } 326*175859bfSDavid Dillow 327*175859bfSDavid Dillow status = inl(io + SIS_PISR_B); 328*175859bfSDavid Dillow if (status) { 329*175859bfSDavid Dillow sis_voice_irq(status, &sis->voices[32]); 330*175859bfSDavid Dillow outl(status, io + SIS_PISR_B); 331*175859bfSDavid Dillow } 332*175859bfSDavid Dillow 333*175859bfSDavid Dillow status = inl(io + SIS_RISR); 334*175859bfSDavid Dillow if (status) { 335*175859bfSDavid Dillow voice = &sis->capture_voice; 336*175859bfSDavid Dillow if (!voice->timing) 337*175859bfSDavid Dillow snd_pcm_period_elapsed(voice->substream); 338*175859bfSDavid Dillow 339*175859bfSDavid Dillow outl(status, io + SIS_RISR); 340*175859bfSDavid Dillow } 341*175859bfSDavid Dillow 342*175859bfSDavid Dillow outl(intr, io + SIS_GISR); 343*175859bfSDavid Dillow intr = inl(io + SIS_GISR); 344*175859bfSDavid Dillow intr &= SIS_GISR_AUDIO_PLAY_DMA_IRQ_STATUS | 345*175859bfSDavid Dillow SIS_GISR_AUDIO_RECORD_DMA_IRQ_STATUS; 346*175859bfSDavid Dillow } while (intr); 347*175859bfSDavid Dillow 348*175859bfSDavid Dillow return IRQ_HANDLED; 349*175859bfSDavid Dillow } 350*175859bfSDavid Dillow 351*175859bfSDavid Dillow static u32 sis_rate_to_delta(unsigned int rate) 352*175859bfSDavid Dillow { 353*175859bfSDavid Dillow u32 delta; 354*175859bfSDavid Dillow 355*175859bfSDavid Dillow /* This was copied from the trident driver, but it seems its gotten 356*175859bfSDavid Dillow * around a bit... nevertheless, it works well. 357*175859bfSDavid Dillow * 358*175859bfSDavid Dillow * We special case 44100 and 8000 since rounding with the equation 359*175859bfSDavid Dillow * does not give us an accurate enough value. For 11025 and 22050 360*175859bfSDavid Dillow * the equation gives us the best answer. All other frequencies will 361*175859bfSDavid Dillow * also use the equation. JDW 362*175859bfSDavid Dillow */ 363*175859bfSDavid Dillow if (rate == 44100) 364*175859bfSDavid Dillow delta = 0xeb3; 365*175859bfSDavid Dillow else if (rate == 8000) 366*175859bfSDavid Dillow delta = 0x2ab; 367*175859bfSDavid Dillow else if (rate == 48000) 368*175859bfSDavid Dillow delta = 0x1000; 369*175859bfSDavid Dillow else 370*175859bfSDavid Dillow delta = (((rate << 12) + 24000) / 48000) & 0x0000ffff; 371*175859bfSDavid Dillow return delta; 372*175859bfSDavid Dillow } 373*175859bfSDavid Dillow 374*175859bfSDavid Dillow static void __sis_map_silence(struct sis7019 *sis) 375*175859bfSDavid Dillow { 376*175859bfSDavid Dillow /* Helper function: must hold sis->voice_lock on entry */ 377*175859bfSDavid Dillow if (!sis->silence_users) 378*175859bfSDavid Dillow sis->silence_dma_addr = pci_map_single(sis->pci, 379*175859bfSDavid Dillow sis->suspend_state[0], 380*175859bfSDavid Dillow 4096, PCI_DMA_TODEVICE); 381*175859bfSDavid Dillow sis->silence_users++; 382*175859bfSDavid Dillow } 383*175859bfSDavid Dillow 384*175859bfSDavid Dillow static void __sis_unmap_silence(struct sis7019 *sis) 385*175859bfSDavid Dillow { 386*175859bfSDavid Dillow /* Helper function: must hold sis->voice_lock on entry */ 387*175859bfSDavid Dillow sis->silence_users--; 388*175859bfSDavid Dillow if (!sis->silence_users) 389*175859bfSDavid Dillow pci_unmap_single(sis->pci, sis->silence_dma_addr, 4096, 390*175859bfSDavid Dillow PCI_DMA_TODEVICE); 391*175859bfSDavid Dillow } 392*175859bfSDavid Dillow 393*175859bfSDavid Dillow static void sis_free_voice(struct sis7019 *sis, struct voice *voice) 394*175859bfSDavid Dillow { 395*175859bfSDavid Dillow unsigned long flags; 396*175859bfSDavid Dillow 397*175859bfSDavid Dillow spin_lock_irqsave(&sis->voice_lock, flags); 398*175859bfSDavid Dillow if (voice->timing) { 399*175859bfSDavid Dillow __sis_unmap_silence(sis); 400*175859bfSDavid Dillow voice->timing->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING | 401*175859bfSDavid Dillow VOICE_SYNC_TIMING); 402*175859bfSDavid Dillow voice->timing = NULL; 403*175859bfSDavid Dillow } 404*175859bfSDavid Dillow voice->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING | VOICE_SYNC_TIMING); 405*175859bfSDavid Dillow spin_unlock_irqrestore(&sis->voice_lock, flags); 406*175859bfSDavid Dillow } 407*175859bfSDavid Dillow 408*175859bfSDavid Dillow static struct voice *__sis_alloc_playback_voice(struct sis7019 *sis) 409*175859bfSDavid Dillow { 410*175859bfSDavid Dillow /* Must hold the voice_lock on entry */ 411*175859bfSDavid Dillow struct voice *voice; 412*175859bfSDavid Dillow int i; 413*175859bfSDavid Dillow 414*175859bfSDavid Dillow for (i = 0; i < 64; i++) { 415*175859bfSDavid Dillow voice = &sis->voices[i]; 416*175859bfSDavid Dillow if (voice->flags & VOICE_IN_USE) 417*175859bfSDavid Dillow continue; 418*175859bfSDavid Dillow voice->flags |= VOICE_IN_USE; 419*175859bfSDavid Dillow goto found_one; 420*175859bfSDavid Dillow } 421*175859bfSDavid Dillow voice = NULL; 422*175859bfSDavid Dillow 423*175859bfSDavid Dillow found_one: 424*175859bfSDavid Dillow return voice; 425*175859bfSDavid Dillow } 426*175859bfSDavid Dillow 427*175859bfSDavid Dillow static struct voice *sis_alloc_playback_voice(struct sis7019 *sis) 428*175859bfSDavid Dillow { 429*175859bfSDavid Dillow struct voice *voice; 430*175859bfSDavid Dillow unsigned long flags; 431*175859bfSDavid Dillow 432*175859bfSDavid Dillow spin_lock_irqsave(&sis->voice_lock, flags); 433*175859bfSDavid Dillow voice = __sis_alloc_playback_voice(sis); 434*175859bfSDavid Dillow spin_unlock_irqrestore(&sis->voice_lock, flags); 435*175859bfSDavid Dillow 436*175859bfSDavid Dillow return voice; 437*175859bfSDavid Dillow } 438*175859bfSDavid Dillow 439*175859bfSDavid Dillow static int sis_alloc_timing_voice(struct snd_pcm_substream *substream, 440*175859bfSDavid Dillow struct snd_pcm_hw_params *hw_params) 441*175859bfSDavid Dillow { 442*175859bfSDavid Dillow struct sis7019 *sis = snd_pcm_substream_chip(substream); 443*175859bfSDavid Dillow struct snd_pcm_runtime *runtime = substream->runtime; 444*175859bfSDavid Dillow struct voice *voice = runtime->private_data; 445*175859bfSDavid Dillow unsigned int period_size, buffer_size; 446*175859bfSDavid Dillow unsigned long flags; 447*175859bfSDavid Dillow int needed; 448*175859bfSDavid Dillow 449*175859bfSDavid Dillow /* If there are one or two periods per buffer, we don't need a 450*175859bfSDavid Dillow * timing voice, as we can use the capture channel's interrupts 451*175859bfSDavid Dillow * to clock out the periods. 452*175859bfSDavid Dillow */ 453*175859bfSDavid Dillow period_size = params_period_size(hw_params); 454*175859bfSDavid Dillow buffer_size = params_buffer_size(hw_params); 455*175859bfSDavid Dillow needed = (period_size != buffer_size && 456*175859bfSDavid Dillow period_size != (buffer_size / 2)); 457*175859bfSDavid Dillow 458*175859bfSDavid Dillow if (needed && !voice->timing) { 459*175859bfSDavid Dillow spin_lock_irqsave(&sis->voice_lock, flags); 460*175859bfSDavid Dillow voice->timing = __sis_alloc_playback_voice(sis); 461*175859bfSDavid Dillow if (voice->timing) 462*175859bfSDavid Dillow __sis_map_silence(sis); 463*175859bfSDavid Dillow spin_unlock_irqrestore(&sis->voice_lock, flags); 464*175859bfSDavid Dillow if (!voice->timing) 465*175859bfSDavid Dillow return -ENOMEM; 466*175859bfSDavid Dillow voice->timing->substream = substream; 467*175859bfSDavid Dillow } else if (!needed && voice->timing) { 468*175859bfSDavid Dillow sis_free_voice(sis, voice); 469*175859bfSDavid Dillow voice->timing = NULL; 470*175859bfSDavid Dillow } 471*175859bfSDavid Dillow 472*175859bfSDavid Dillow return 0; 473*175859bfSDavid Dillow } 474*175859bfSDavid Dillow 475*175859bfSDavid Dillow static int sis_playback_open(struct snd_pcm_substream *substream) 476*175859bfSDavid Dillow { 477*175859bfSDavid Dillow struct sis7019 *sis = snd_pcm_substream_chip(substream); 478*175859bfSDavid Dillow struct snd_pcm_runtime *runtime = substream->runtime; 479*175859bfSDavid Dillow struct voice *voice; 480*175859bfSDavid Dillow 481*175859bfSDavid Dillow voice = sis_alloc_playback_voice(sis); 482*175859bfSDavid Dillow if (!voice) 483*175859bfSDavid Dillow return -EAGAIN; 484*175859bfSDavid Dillow 485*175859bfSDavid Dillow voice->substream = substream; 486*175859bfSDavid Dillow runtime->private_data = voice; 487*175859bfSDavid Dillow runtime->hw = sis_playback_hw_info; 488*175859bfSDavid Dillow snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 489*175859bfSDavid Dillow 9, 0xfff9); 490*175859bfSDavid Dillow snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 491*175859bfSDavid Dillow 9, 0xfff9); 492*175859bfSDavid Dillow snd_pcm_set_sync(substream); 493*175859bfSDavid Dillow return 0; 494*175859bfSDavid Dillow } 495*175859bfSDavid Dillow 496*175859bfSDavid Dillow static int sis_substream_close(struct snd_pcm_substream *substream) 497*175859bfSDavid Dillow { 498*175859bfSDavid Dillow struct sis7019 *sis = snd_pcm_substream_chip(substream); 499*175859bfSDavid Dillow struct snd_pcm_runtime *runtime = substream->runtime; 500*175859bfSDavid Dillow struct voice *voice = runtime->private_data; 501*175859bfSDavid Dillow 502*175859bfSDavid Dillow sis_free_voice(sis, voice); 503*175859bfSDavid Dillow return 0; 504*175859bfSDavid Dillow } 505*175859bfSDavid Dillow 506*175859bfSDavid Dillow static int sis_playback_hw_params(struct snd_pcm_substream *substream, 507*175859bfSDavid Dillow struct snd_pcm_hw_params *hw_params) 508*175859bfSDavid Dillow { 509*175859bfSDavid Dillow return snd_pcm_lib_malloc_pages(substream, 510*175859bfSDavid Dillow params_buffer_bytes(hw_params)); 511*175859bfSDavid Dillow } 512*175859bfSDavid Dillow 513*175859bfSDavid Dillow static int sis_hw_free(struct snd_pcm_substream *substream) 514*175859bfSDavid Dillow { 515*175859bfSDavid Dillow return snd_pcm_lib_free_pages(substream); 516*175859bfSDavid Dillow } 517*175859bfSDavid Dillow 518*175859bfSDavid Dillow static int sis_pcm_playback_prepare(struct snd_pcm_substream *substream) 519*175859bfSDavid Dillow { 520*175859bfSDavid Dillow struct snd_pcm_runtime *runtime = substream->runtime; 521*175859bfSDavid Dillow struct voice *voice = runtime->private_data; 522*175859bfSDavid Dillow void __iomem *ctrl_base = voice->ctrl_base; 523*175859bfSDavid Dillow void __iomem *wave_base = voice->wave_base; 524*175859bfSDavid Dillow u32 format, dma_addr, control, sso_eso, delta, reg; 525*175859bfSDavid Dillow u16 leo; 526*175859bfSDavid Dillow 527*175859bfSDavid Dillow /* We rely on the PCM core to ensure that the parameters for this 528*175859bfSDavid Dillow * substream do not change on us while we're programming the HW. 529*175859bfSDavid Dillow */ 530*175859bfSDavid Dillow format = 0; 531*175859bfSDavid Dillow if (snd_pcm_format_width(runtime->format) == 8) 532*175859bfSDavid Dillow format |= SIS_PLAY_DMA_FORMAT_8BIT; 533*175859bfSDavid Dillow if (!snd_pcm_format_signed(runtime->format)) 534*175859bfSDavid Dillow format |= SIS_PLAY_DMA_FORMAT_UNSIGNED; 535*175859bfSDavid Dillow if (runtime->channels == 1) 536*175859bfSDavid Dillow format |= SIS_PLAY_DMA_FORMAT_MONO; 537*175859bfSDavid Dillow 538*175859bfSDavid Dillow /* The baseline setup is for a single period per buffer, and 539*175859bfSDavid Dillow * we add bells and whistles as needed from there. 540*175859bfSDavid Dillow */ 541*175859bfSDavid Dillow dma_addr = runtime->dma_addr; 542*175859bfSDavid Dillow leo = runtime->buffer_size - 1; 543*175859bfSDavid Dillow control = leo | SIS_PLAY_DMA_LOOP | SIS_PLAY_DMA_INTR_AT_LEO; 544*175859bfSDavid Dillow sso_eso = leo; 545*175859bfSDavid Dillow 546*175859bfSDavid Dillow if (runtime->period_size == (runtime->buffer_size / 2)) { 547*175859bfSDavid Dillow control |= SIS_PLAY_DMA_INTR_AT_MLP; 548*175859bfSDavid Dillow } else if (runtime->period_size != runtime->buffer_size) { 549*175859bfSDavid Dillow voice->flags |= VOICE_SSO_TIMING; 550*175859bfSDavid Dillow voice->sso = runtime->period_size - 1; 551*175859bfSDavid Dillow voice->period_size = runtime->period_size; 552*175859bfSDavid Dillow voice->buffer_size = runtime->buffer_size; 553*175859bfSDavid Dillow 554*175859bfSDavid Dillow control &= ~SIS_PLAY_DMA_INTR_AT_LEO; 555*175859bfSDavid Dillow control |= SIS_PLAY_DMA_INTR_AT_SSO; 556*175859bfSDavid Dillow sso_eso |= (runtime->period_size - 1) << 16; 557*175859bfSDavid Dillow } 558*175859bfSDavid Dillow 559*175859bfSDavid Dillow delta = sis_rate_to_delta(runtime->rate); 560*175859bfSDavid Dillow 561*175859bfSDavid Dillow /* Ok, we're ready to go, set up the channel. 562*175859bfSDavid Dillow */ 563*175859bfSDavid Dillow writel(format, ctrl_base + SIS_PLAY_DMA_FORMAT_CSO); 564*175859bfSDavid Dillow writel(dma_addr, ctrl_base + SIS_PLAY_DMA_BASE); 565*175859bfSDavid Dillow writel(control, ctrl_base + SIS_PLAY_DMA_CONTROL); 566*175859bfSDavid Dillow writel(sso_eso, ctrl_base + SIS_PLAY_DMA_SSO_ESO); 567*175859bfSDavid Dillow 568*175859bfSDavid Dillow for (reg = 0; reg < SIS_WAVE_SIZE; reg += 4) 569*175859bfSDavid Dillow writel(0, wave_base + reg); 570*175859bfSDavid Dillow 571*175859bfSDavid Dillow writel(SIS_WAVE_GENERAL_WAVE_VOLUME, wave_base + SIS_WAVE_GENERAL); 572*175859bfSDavid Dillow writel(delta << 16, wave_base + SIS_WAVE_GENERAL_ARTICULATION); 573*175859bfSDavid Dillow writel(SIS_WAVE_CHANNEL_CONTROL_FIRST_SAMPLE | 574*175859bfSDavid Dillow SIS_WAVE_CHANNEL_CONTROL_AMP_ENABLE | 575*175859bfSDavid Dillow SIS_WAVE_CHANNEL_CONTROL_INTERPOLATE_ENABLE, 576*175859bfSDavid Dillow wave_base + SIS_WAVE_CHANNEL_CONTROL); 577*175859bfSDavid Dillow 578*175859bfSDavid Dillow /* Force PCI writes to post. */ 579*175859bfSDavid Dillow readl(ctrl_base); 580*175859bfSDavid Dillow 581*175859bfSDavid Dillow return 0; 582*175859bfSDavid Dillow } 583*175859bfSDavid Dillow 584*175859bfSDavid Dillow static int sis_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 585*175859bfSDavid Dillow { 586*175859bfSDavid Dillow struct sis7019 *sis = snd_pcm_substream_chip(substream); 587*175859bfSDavid Dillow unsigned long io = sis->ioport; 588*175859bfSDavid Dillow struct snd_pcm_substream *s; 589*175859bfSDavid Dillow struct voice *voice; 590*175859bfSDavid Dillow void *chip; 591*175859bfSDavid Dillow int starting; 592*175859bfSDavid Dillow u32 record = 0; 593*175859bfSDavid Dillow u32 play[2] = { 0, 0 }; 594*175859bfSDavid Dillow 595*175859bfSDavid Dillow /* No locks needed, as the PCM core will hold the locks on the 596*175859bfSDavid Dillow * substreams, and the HW will only start/stop the indicated voices 597*175859bfSDavid Dillow * without changing the state of the others. 598*175859bfSDavid Dillow */ 599*175859bfSDavid Dillow switch (cmd) { 600*175859bfSDavid Dillow case SNDRV_PCM_TRIGGER_START: 601*175859bfSDavid Dillow case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 602*175859bfSDavid Dillow case SNDRV_PCM_TRIGGER_RESUME: 603*175859bfSDavid Dillow starting = 1; 604*175859bfSDavid Dillow break; 605*175859bfSDavid Dillow case SNDRV_PCM_TRIGGER_STOP: 606*175859bfSDavid Dillow case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 607*175859bfSDavid Dillow case SNDRV_PCM_TRIGGER_SUSPEND: 608*175859bfSDavid Dillow starting = 0; 609*175859bfSDavid Dillow break; 610*175859bfSDavid Dillow default: 611*175859bfSDavid Dillow return -EINVAL; 612*175859bfSDavid Dillow } 613*175859bfSDavid Dillow 614*175859bfSDavid Dillow snd_pcm_group_for_each_entry(s, substream) { 615*175859bfSDavid Dillow /* Make sure it is for us... */ 616*175859bfSDavid Dillow chip = snd_pcm_substream_chip(s); 617*175859bfSDavid Dillow if (chip != sis) 618*175859bfSDavid Dillow continue; 619*175859bfSDavid Dillow 620*175859bfSDavid Dillow voice = s->runtime->private_data; 621*175859bfSDavid Dillow if (voice->flags & VOICE_CAPTURE) { 622*175859bfSDavid Dillow record |= 1 << voice->num; 623*175859bfSDavid Dillow voice = voice->timing; 624*175859bfSDavid Dillow } 625*175859bfSDavid Dillow 626*175859bfSDavid Dillow /* voice could be NULL if this a recording stream, and it 627*175859bfSDavid Dillow * doesn't have an external timing channel. 628*175859bfSDavid Dillow */ 629*175859bfSDavid Dillow if (voice) 630*175859bfSDavid Dillow play[voice->num / 32] |= 1 << (voice->num & 0x1f); 631*175859bfSDavid Dillow 632*175859bfSDavid Dillow snd_pcm_trigger_done(s, substream); 633*175859bfSDavid Dillow } 634*175859bfSDavid Dillow 635*175859bfSDavid Dillow if (starting) { 636*175859bfSDavid Dillow if (record) 637*175859bfSDavid Dillow outl(record, io + SIS_RECORD_START_REG); 638*175859bfSDavid Dillow if (play[0]) 639*175859bfSDavid Dillow outl(play[0], io + SIS_PLAY_START_A_REG); 640*175859bfSDavid Dillow if (play[1]) 641*175859bfSDavid Dillow outl(play[1], io + SIS_PLAY_START_B_REG); 642*175859bfSDavid Dillow } else { 643*175859bfSDavid Dillow if (record) 644*175859bfSDavid Dillow outl(record, io + SIS_RECORD_STOP_REG); 645*175859bfSDavid Dillow if (play[0]) 646*175859bfSDavid Dillow outl(play[0], io + SIS_PLAY_STOP_A_REG); 647*175859bfSDavid Dillow if (play[1]) 648*175859bfSDavid Dillow outl(play[1], io + SIS_PLAY_STOP_B_REG); 649*175859bfSDavid Dillow } 650*175859bfSDavid Dillow return 0; 651*175859bfSDavid Dillow } 652*175859bfSDavid Dillow 653*175859bfSDavid Dillow static snd_pcm_uframes_t sis_pcm_pointer(struct snd_pcm_substream *substream) 654*175859bfSDavid Dillow { 655*175859bfSDavid Dillow struct snd_pcm_runtime *runtime = substream->runtime; 656*175859bfSDavid Dillow struct voice *voice = runtime->private_data; 657*175859bfSDavid Dillow u32 cso; 658*175859bfSDavid Dillow 659*175859bfSDavid Dillow cso = readl(voice->ctrl_base + SIS_PLAY_DMA_FORMAT_CSO); 660*175859bfSDavid Dillow cso &= 0xffff; 661*175859bfSDavid Dillow return cso; 662*175859bfSDavid Dillow } 663*175859bfSDavid Dillow 664*175859bfSDavid Dillow static int sis_capture_open(struct snd_pcm_substream *substream) 665*175859bfSDavid Dillow { 666*175859bfSDavid Dillow struct sis7019 *sis = snd_pcm_substream_chip(substream); 667*175859bfSDavid Dillow struct snd_pcm_runtime *runtime = substream->runtime; 668*175859bfSDavid Dillow struct voice *voice = &sis->capture_voice; 669*175859bfSDavid Dillow unsigned long flags; 670*175859bfSDavid Dillow 671*175859bfSDavid Dillow /* FIXME: The driver only supports recording from one channel 672*175859bfSDavid Dillow * at the moment, but it could support more. 673*175859bfSDavid Dillow */ 674*175859bfSDavid Dillow spin_lock_irqsave(&sis->voice_lock, flags); 675*175859bfSDavid Dillow if (voice->flags & VOICE_IN_USE) 676*175859bfSDavid Dillow voice = NULL; 677*175859bfSDavid Dillow else 678*175859bfSDavid Dillow voice->flags |= VOICE_IN_USE; 679*175859bfSDavid Dillow spin_unlock_irqrestore(&sis->voice_lock, flags); 680*175859bfSDavid Dillow 681*175859bfSDavid Dillow if (!voice) 682*175859bfSDavid Dillow return -EAGAIN; 683*175859bfSDavid Dillow 684*175859bfSDavid Dillow voice->substream = substream; 685*175859bfSDavid Dillow runtime->private_data = voice; 686*175859bfSDavid Dillow runtime->hw = sis_capture_hw_info; 687*175859bfSDavid Dillow runtime->hw.rates = sis->ac97[0]->rates[AC97_RATES_ADC]; 688*175859bfSDavid Dillow snd_pcm_limit_hw_rates(runtime); 689*175859bfSDavid Dillow snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 690*175859bfSDavid Dillow 9, 0xfff9); 691*175859bfSDavid Dillow snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 692*175859bfSDavid Dillow 9, 0xfff9); 693*175859bfSDavid Dillow snd_pcm_set_sync(substream); 694*175859bfSDavid Dillow return 0; 695*175859bfSDavid Dillow } 696*175859bfSDavid Dillow 697*175859bfSDavid Dillow static int sis_capture_hw_params(struct snd_pcm_substream *substream, 698*175859bfSDavid Dillow struct snd_pcm_hw_params *hw_params) 699*175859bfSDavid Dillow { 700*175859bfSDavid Dillow struct sis7019 *sis = snd_pcm_substream_chip(substream); 701*175859bfSDavid Dillow int rc; 702*175859bfSDavid Dillow 703*175859bfSDavid Dillow rc = snd_ac97_set_rate(sis->ac97[0], AC97_PCM_LR_ADC_RATE, 704*175859bfSDavid Dillow params_rate(hw_params)); 705*175859bfSDavid Dillow if (rc) 706*175859bfSDavid Dillow goto out; 707*175859bfSDavid Dillow 708*175859bfSDavid Dillow rc = snd_pcm_lib_malloc_pages(substream, 709*175859bfSDavid Dillow params_buffer_bytes(hw_params)); 710*175859bfSDavid Dillow if (rc < 0) 711*175859bfSDavid Dillow goto out; 712*175859bfSDavid Dillow 713*175859bfSDavid Dillow rc = sis_alloc_timing_voice(substream, hw_params); 714*175859bfSDavid Dillow 715*175859bfSDavid Dillow out: 716*175859bfSDavid Dillow return rc; 717*175859bfSDavid Dillow } 718*175859bfSDavid Dillow 719*175859bfSDavid Dillow static void sis_prepare_timing_voice(struct voice *voice, 720*175859bfSDavid Dillow struct snd_pcm_substream *substream) 721*175859bfSDavid Dillow { 722*175859bfSDavid Dillow struct sis7019 *sis = snd_pcm_substream_chip(substream); 723*175859bfSDavid Dillow struct snd_pcm_runtime *runtime = substream->runtime; 724*175859bfSDavid Dillow struct voice *timing = voice->timing; 725*175859bfSDavid Dillow void __iomem *play_base = timing->ctrl_base; 726*175859bfSDavid Dillow void __iomem *wave_base = timing->wave_base; 727*175859bfSDavid Dillow u16 buffer_size, period_size; 728*175859bfSDavid Dillow u32 format, control, sso_eso, delta; 729*175859bfSDavid Dillow u32 vperiod, sso, reg; 730*175859bfSDavid Dillow 731*175859bfSDavid Dillow /* Set our initial buffer and period as large as we can given a 732*175859bfSDavid Dillow * single page of silence. 733*175859bfSDavid Dillow */ 734*175859bfSDavid Dillow buffer_size = 4096 / runtime->channels; 735*175859bfSDavid Dillow buffer_size /= snd_pcm_format_size(runtime->format, 1); 736*175859bfSDavid Dillow period_size = buffer_size; 737*175859bfSDavid Dillow 738*175859bfSDavid Dillow /* Initially, we want to interrupt just a bit behind the end of 739*175859bfSDavid Dillow * the period we're clocking out. 10 samples seems to give a good 740*175859bfSDavid Dillow * delay. 741*175859bfSDavid Dillow * 742*175859bfSDavid Dillow * We want to spread our interrupts throughout the virtual period, 743*175859bfSDavid Dillow * so that we don't end up with two interrupts back to back at the 744*175859bfSDavid Dillow * end -- this helps minimize the effects of any jitter. Adjust our 745*175859bfSDavid Dillow * clocking period size so that the last period is at least a fourth 746*175859bfSDavid Dillow * of a full period. 747*175859bfSDavid Dillow * 748*175859bfSDavid Dillow * This is all moot if we don't need to use virtual periods. 749*175859bfSDavid Dillow */ 750*175859bfSDavid Dillow vperiod = runtime->period_size + 10; 751*175859bfSDavid Dillow if (vperiod > period_size) { 752*175859bfSDavid Dillow u16 tail = vperiod % period_size; 753*175859bfSDavid Dillow u16 quarter_period = period_size / 4; 754*175859bfSDavid Dillow 755*175859bfSDavid Dillow if (tail && tail < quarter_period) { 756*175859bfSDavid Dillow u16 loops = vperiod / period_size; 757*175859bfSDavid Dillow 758*175859bfSDavid Dillow tail = quarter_period - tail; 759*175859bfSDavid Dillow tail += loops - 1; 760*175859bfSDavid Dillow tail /= loops; 761*175859bfSDavid Dillow period_size -= tail; 762*175859bfSDavid Dillow } 763*175859bfSDavid Dillow 764*175859bfSDavid Dillow sso = period_size - 1; 765*175859bfSDavid Dillow } else { 766*175859bfSDavid Dillow /* The initial period will fit inside the buffer, so we 767*175859bfSDavid Dillow * don't need to use virtual periods -- disable them. 768*175859bfSDavid Dillow */ 769*175859bfSDavid Dillow period_size = runtime->period_size; 770*175859bfSDavid Dillow sso = vperiod - 1; 771*175859bfSDavid Dillow vperiod = 0; 772*175859bfSDavid Dillow } 773*175859bfSDavid Dillow 774*175859bfSDavid Dillow /* The interrupt handler implements the timing syncronization, so 775*175859bfSDavid Dillow * setup its state. 776*175859bfSDavid Dillow */ 777*175859bfSDavid Dillow timing->flags |= VOICE_SYNC_TIMING; 778*175859bfSDavid Dillow timing->sync_base = voice->ctrl_base; 779*175859bfSDavid Dillow timing->sync_cso = runtime->period_size - 1; 780*175859bfSDavid Dillow timing->sync_period_size = runtime->period_size; 781*175859bfSDavid Dillow timing->sync_buffer_size = runtime->buffer_size; 782*175859bfSDavid Dillow timing->period_size = period_size; 783*175859bfSDavid Dillow timing->buffer_size = buffer_size; 784*175859bfSDavid Dillow timing->sso = sso; 785*175859bfSDavid Dillow timing->vperiod = vperiod; 786*175859bfSDavid Dillow 787*175859bfSDavid Dillow /* Using unsigned samples with the all-zero silence buffer 788*175859bfSDavid Dillow * forces the output to the lower rail, killing playback. 789*175859bfSDavid Dillow * So ignore unsigned vs signed -- it doesn't change the timing. 790*175859bfSDavid Dillow */ 791*175859bfSDavid Dillow format = 0; 792*175859bfSDavid Dillow if (snd_pcm_format_width(runtime->format) == 8) 793*175859bfSDavid Dillow format = SIS_CAPTURE_DMA_FORMAT_8BIT; 794*175859bfSDavid Dillow if (runtime->channels == 1) 795*175859bfSDavid Dillow format |= SIS_CAPTURE_DMA_FORMAT_MONO; 796*175859bfSDavid Dillow 797*175859bfSDavid Dillow control = timing->buffer_size - 1; 798*175859bfSDavid Dillow control |= SIS_PLAY_DMA_LOOP | SIS_PLAY_DMA_INTR_AT_SSO; 799*175859bfSDavid Dillow sso_eso = timing->buffer_size - 1; 800*175859bfSDavid Dillow sso_eso |= timing->sso << 16; 801*175859bfSDavid Dillow 802*175859bfSDavid Dillow delta = sis_rate_to_delta(runtime->rate); 803*175859bfSDavid Dillow 804*175859bfSDavid Dillow /* We've done the math, now configure the channel. 805*175859bfSDavid Dillow */ 806*175859bfSDavid Dillow writel(format, play_base + SIS_PLAY_DMA_FORMAT_CSO); 807*175859bfSDavid Dillow writel(sis->silence_dma_addr, play_base + SIS_PLAY_DMA_BASE); 808*175859bfSDavid Dillow writel(control, play_base + SIS_PLAY_DMA_CONTROL); 809*175859bfSDavid Dillow writel(sso_eso, play_base + SIS_PLAY_DMA_SSO_ESO); 810*175859bfSDavid Dillow 811*175859bfSDavid Dillow for (reg = 0; reg < SIS_WAVE_SIZE; reg += 4) 812*175859bfSDavid Dillow writel(0, wave_base + reg); 813*175859bfSDavid Dillow 814*175859bfSDavid Dillow writel(SIS_WAVE_GENERAL_WAVE_VOLUME, wave_base + SIS_WAVE_GENERAL); 815*175859bfSDavid Dillow writel(delta << 16, wave_base + SIS_WAVE_GENERAL_ARTICULATION); 816*175859bfSDavid Dillow writel(SIS_WAVE_CHANNEL_CONTROL_FIRST_SAMPLE | 817*175859bfSDavid Dillow SIS_WAVE_CHANNEL_CONTROL_AMP_ENABLE | 818*175859bfSDavid Dillow SIS_WAVE_CHANNEL_CONTROL_INTERPOLATE_ENABLE, 819*175859bfSDavid Dillow wave_base + SIS_WAVE_CHANNEL_CONTROL); 820*175859bfSDavid Dillow } 821*175859bfSDavid Dillow 822*175859bfSDavid Dillow static int sis_pcm_capture_prepare(struct snd_pcm_substream *substream) 823*175859bfSDavid Dillow { 824*175859bfSDavid Dillow struct snd_pcm_runtime *runtime = substream->runtime; 825*175859bfSDavid Dillow struct voice *voice = runtime->private_data; 826*175859bfSDavid Dillow void __iomem *rec_base = voice->ctrl_base; 827*175859bfSDavid Dillow u32 format, dma_addr, control; 828*175859bfSDavid Dillow u16 leo; 829*175859bfSDavid Dillow 830*175859bfSDavid Dillow /* We rely on the PCM core to ensure that the parameters for this 831*175859bfSDavid Dillow * substream do not change on us while we're programming the HW. 832*175859bfSDavid Dillow */ 833*175859bfSDavid Dillow format = 0; 834*175859bfSDavid Dillow if (snd_pcm_format_width(runtime->format) == 8) 835*175859bfSDavid Dillow format = SIS_CAPTURE_DMA_FORMAT_8BIT; 836*175859bfSDavid Dillow if (!snd_pcm_format_signed(runtime->format)) 837*175859bfSDavid Dillow format |= SIS_CAPTURE_DMA_FORMAT_UNSIGNED; 838*175859bfSDavid Dillow if (runtime->channels == 1) 839*175859bfSDavid Dillow format |= SIS_CAPTURE_DMA_FORMAT_MONO; 840*175859bfSDavid Dillow 841*175859bfSDavid Dillow dma_addr = runtime->dma_addr; 842*175859bfSDavid Dillow leo = runtime->buffer_size - 1; 843*175859bfSDavid Dillow control = leo | SIS_CAPTURE_DMA_LOOP; 844*175859bfSDavid Dillow 845*175859bfSDavid Dillow /* If we've got more than two periods per buffer, then we have 846*175859bfSDavid Dillow * use a timing voice to clock out the periods. Otherwise, we can 847*175859bfSDavid Dillow * use the capture channel's interrupts. 848*175859bfSDavid Dillow */ 849*175859bfSDavid Dillow if (voice->timing) { 850*175859bfSDavid Dillow sis_prepare_timing_voice(voice, substream); 851*175859bfSDavid Dillow } else { 852*175859bfSDavid Dillow control |= SIS_CAPTURE_DMA_INTR_AT_LEO; 853*175859bfSDavid Dillow if (runtime->period_size != runtime->buffer_size) 854*175859bfSDavid Dillow control |= SIS_CAPTURE_DMA_INTR_AT_MLP; 855*175859bfSDavid Dillow } 856*175859bfSDavid Dillow 857*175859bfSDavid Dillow writel(format, rec_base + SIS_CAPTURE_DMA_FORMAT_CSO); 858*175859bfSDavid Dillow writel(dma_addr, rec_base + SIS_CAPTURE_DMA_BASE); 859*175859bfSDavid Dillow writel(control, rec_base + SIS_CAPTURE_DMA_CONTROL); 860*175859bfSDavid Dillow 861*175859bfSDavid Dillow /* Force the writes to post. */ 862*175859bfSDavid Dillow readl(rec_base); 863*175859bfSDavid Dillow 864*175859bfSDavid Dillow return 0; 865*175859bfSDavid Dillow } 866*175859bfSDavid Dillow 867*175859bfSDavid Dillow static struct snd_pcm_ops sis_playback_ops = { 868*175859bfSDavid Dillow .open = sis_playback_open, 869*175859bfSDavid Dillow .close = sis_substream_close, 870*175859bfSDavid Dillow .ioctl = snd_pcm_lib_ioctl, 871*175859bfSDavid Dillow .hw_params = sis_playback_hw_params, 872*175859bfSDavid Dillow .hw_free = sis_hw_free, 873*175859bfSDavid Dillow .prepare = sis_pcm_playback_prepare, 874*175859bfSDavid Dillow .trigger = sis_pcm_trigger, 875*175859bfSDavid Dillow .pointer = sis_pcm_pointer, 876*175859bfSDavid Dillow }; 877*175859bfSDavid Dillow 878*175859bfSDavid Dillow static struct snd_pcm_ops sis_capture_ops = { 879*175859bfSDavid Dillow .open = sis_capture_open, 880*175859bfSDavid Dillow .close = sis_substream_close, 881*175859bfSDavid Dillow .ioctl = snd_pcm_lib_ioctl, 882*175859bfSDavid Dillow .hw_params = sis_capture_hw_params, 883*175859bfSDavid Dillow .hw_free = sis_hw_free, 884*175859bfSDavid Dillow .prepare = sis_pcm_capture_prepare, 885*175859bfSDavid Dillow .trigger = sis_pcm_trigger, 886*175859bfSDavid Dillow .pointer = sis_pcm_pointer, 887*175859bfSDavid Dillow }; 888*175859bfSDavid Dillow 889*175859bfSDavid Dillow static int __devinit sis_pcm_create(struct sis7019 *sis) 890*175859bfSDavid Dillow { 891*175859bfSDavid Dillow struct snd_pcm *pcm; 892*175859bfSDavid Dillow int rc; 893*175859bfSDavid Dillow 894*175859bfSDavid Dillow /* We have 64 voices, and the driver currently records from 895*175859bfSDavid Dillow * only one channel, though that could change in the future. 896*175859bfSDavid Dillow */ 897*175859bfSDavid Dillow rc = snd_pcm_new(sis->card, "SiS7019", 0, 64, 1, &pcm); 898*175859bfSDavid Dillow if (rc) 899*175859bfSDavid Dillow return rc; 900*175859bfSDavid Dillow 901*175859bfSDavid Dillow pcm->private_data = sis; 902*175859bfSDavid Dillow strcpy(pcm->name, "SiS7019"); 903*175859bfSDavid Dillow sis->pcm = pcm; 904*175859bfSDavid Dillow 905*175859bfSDavid Dillow snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &sis_playback_ops); 906*175859bfSDavid Dillow snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &sis_capture_ops); 907*175859bfSDavid Dillow 908*175859bfSDavid Dillow /* Try to preallocate some memory, but it's not the end of the 909*175859bfSDavid Dillow * world if this fails. 910*175859bfSDavid Dillow */ 911*175859bfSDavid Dillow snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, 912*175859bfSDavid Dillow snd_dma_pci_data(sis->pci), 64*1024, 128*1024); 913*175859bfSDavid Dillow 914*175859bfSDavid Dillow return 0; 915*175859bfSDavid Dillow } 916*175859bfSDavid Dillow 917*175859bfSDavid Dillow static unsigned short sis_ac97_rw(struct sis7019 *sis, int codec, u32 cmd) 918*175859bfSDavid Dillow { 919*175859bfSDavid Dillow unsigned long io = sis->ioport; 920*175859bfSDavid Dillow unsigned short val = 0xffff; 921*175859bfSDavid Dillow u16 status; 922*175859bfSDavid Dillow u16 rdy; 923*175859bfSDavid Dillow int count; 924*175859bfSDavid Dillow const static u16 codec_ready[3] = { 925*175859bfSDavid Dillow SIS_AC97_STATUS_CODEC_READY, 926*175859bfSDavid Dillow SIS_AC97_STATUS_CODEC2_READY, 927*175859bfSDavid Dillow SIS_AC97_STATUS_CODEC3_READY, 928*175859bfSDavid Dillow }; 929*175859bfSDavid Dillow 930*175859bfSDavid Dillow rdy = codec_ready[codec]; 931*175859bfSDavid Dillow 932*175859bfSDavid Dillow 933*175859bfSDavid Dillow /* Get the AC97 semaphore -- software first, so we don't spin 934*175859bfSDavid Dillow * pounding out IO reads on the hardware semaphore... 935*175859bfSDavid Dillow */ 936*175859bfSDavid Dillow mutex_lock(&sis->ac97_mutex); 937*175859bfSDavid Dillow 938*175859bfSDavid Dillow count = 0xffff; 939*175859bfSDavid Dillow while ((inw(io + SIS_AC97_SEMA) & SIS_AC97_SEMA_BUSY) && --count) 940*175859bfSDavid Dillow udelay(1); 941*175859bfSDavid Dillow 942*175859bfSDavid Dillow if (!count) 943*175859bfSDavid Dillow goto timeout; 944*175859bfSDavid Dillow 945*175859bfSDavid Dillow /* ... and wait for any outstanding commands to complete ... 946*175859bfSDavid Dillow */ 947*175859bfSDavid Dillow count = 0xffff; 948*175859bfSDavid Dillow do { 949*175859bfSDavid Dillow status = inw(io + SIS_AC97_STATUS); 950*175859bfSDavid Dillow if ((status & rdy) && !(status & SIS_AC97_STATUS_BUSY)) 951*175859bfSDavid Dillow break; 952*175859bfSDavid Dillow 953*175859bfSDavid Dillow udelay(1); 954*175859bfSDavid Dillow } while (--count); 955*175859bfSDavid Dillow 956*175859bfSDavid Dillow if (!count) 957*175859bfSDavid Dillow goto timeout_sema; 958*175859bfSDavid Dillow 959*175859bfSDavid Dillow /* ... before sending our command and waiting for it to finish ... 960*175859bfSDavid Dillow */ 961*175859bfSDavid Dillow outl(cmd, io + SIS_AC97_CMD); 962*175859bfSDavid Dillow udelay(10); 963*175859bfSDavid Dillow 964*175859bfSDavid Dillow count = 0xffff; 965*175859bfSDavid Dillow while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) 966*175859bfSDavid Dillow udelay(1); 967*175859bfSDavid Dillow 968*175859bfSDavid Dillow /* ... and reading the results (if any). 969*175859bfSDavid Dillow */ 970*175859bfSDavid Dillow val = inl(io + SIS_AC97_CMD) >> 16; 971*175859bfSDavid Dillow 972*175859bfSDavid Dillow timeout_sema: 973*175859bfSDavid Dillow outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA); 974*175859bfSDavid Dillow timeout: 975*175859bfSDavid Dillow mutex_unlock(&sis->ac97_mutex); 976*175859bfSDavid Dillow 977*175859bfSDavid Dillow if (!count) { 978*175859bfSDavid Dillow printk(KERN_ERR "sis7019: ac97 codec %d timeout cmd 0x%08x\n", 979*175859bfSDavid Dillow codec, cmd); 980*175859bfSDavid Dillow } 981*175859bfSDavid Dillow 982*175859bfSDavid Dillow return val; 983*175859bfSDavid Dillow } 984*175859bfSDavid Dillow 985*175859bfSDavid Dillow static void sis_ac97_write(struct snd_ac97 *ac97, unsigned short reg, 986*175859bfSDavid Dillow unsigned short val) 987*175859bfSDavid Dillow { 988*175859bfSDavid Dillow const static u32 cmd[3] = { 989*175859bfSDavid Dillow SIS_AC97_CMD_CODEC_WRITE, 990*175859bfSDavid Dillow SIS_AC97_CMD_CODEC2_WRITE, 991*175859bfSDavid Dillow SIS_AC97_CMD_CODEC3_WRITE, 992*175859bfSDavid Dillow }; 993*175859bfSDavid Dillow sis_ac97_rw(ac97->private_data, ac97->num, 994*175859bfSDavid Dillow (val << 16) | (reg << 8) | cmd[ac97->num]); 995*175859bfSDavid Dillow } 996*175859bfSDavid Dillow 997*175859bfSDavid Dillow static unsigned short sis_ac97_read(struct snd_ac97 *ac97, unsigned short reg) 998*175859bfSDavid Dillow { 999*175859bfSDavid Dillow const static u32 cmd[3] = { 1000*175859bfSDavid Dillow SIS_AC97_CMD_CODEC_READ, 1001*175859bfSDavid Dillow SIS_AC97_CMD_CODEC2_READ, 1002*175859bfSDavid Dillow SIS_AC97_CMD_CODEC3_READ, 1003*175859bfSDavid Dillow }; 1004*175859bfSDavid Dillow return sis_ac97_rw(ac97->private_data, ac97->num, 1005*175859bfSDavid Dillow (reg << 8) | cmd[ac97->num]); 1006*175859bfSDavid Dillow } 1007*175859bfSDavid Dillow 1008*175859bfSDavid Dillow static int __devinit sis_mixer_create(struct sis7019 *sis) 1009*175859bfSDavid Dillow { 1010*175859bfSDavid Dillow struct snd_ac97_bus *bus; 1011*175859bfSDavid Dillow struct snd_ac97_template ac97; 1012*175859bfSDavid Dillow static struct snd_ac97_bus_ops ops = { 1013*175859bfSDavid Dillow .write = sis_ac97_write, 1014*175859bfSDavid Dillow .read = sis_ac97_read, 1015*175859bfSDavid Dillow }; 1016*175859bfSDavid Dillow int rc; 1017*175859bfSDavid Dillow 1018*175859bfSDavid Dillow memset(&ac97, 0, sizeof(ac97)); 1019*175859bfSDavid Dillow ac97.private_data = sis; 1020*175859bfSDavid Dillow 1021*175859bfSDavid Dillow rc = snd_ac97_bus(sis->card, 0, &ops, NULL, &bus); 1022*175859bfSDavid Dillow if (!rc && sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) 1023*175859bfSDavid Dillow rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[0]); 1024*175859bfSDavid Dillow ac97.num = 1; 1025*175859bfSDavid Dillow if (!rc && (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT)) 1026*175859bfSDavid Dillow rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[1]); 1027*175859bfSDavid Dillow ac97.num = 2; 1028*175859bfSDavid Dillow if (!rc && (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT)) 1029*175859bfSDavid Dillow rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[2]); 1030*175859bfSDavid Dillow 1031*175859bfSDavid Dillow /* If we return an error here, then snd_card_free() should 1032*175859bfSDavid Dillow * free up any ac97 codecs that got created, as well as the bus. 1033*175859bfSDavid Dillow */ 1034*175859bfSDavid Dillow return rc; 1035*175859bfSDavid Dillow } 1036*175859bfSDavid Dillow 1037*175859bfSDavid Dillow static void sis_free_suspend(struct sis7019 *sis) 1038*175859bfSDavid Dillow { 1039*175859bfSDavid Dillow int i; 1040*175859bfSDavid Dillow 1041*175859bfSDavid Dillow for (i = 0; i < SIS_SUSPEND_PAGES; i++) 1042*175859bfSDavid Dillow kfree(sis->suspend_state[i]); 1043*175859bfSDavid Dillow } 1044*175859bfSDavid Dillow 1045*175859bfSDavid Dillow static int sis_chip_free(struct sis7019 *sis) 1046*175859bfSDavid Dillow { 1047*175859bfSDavid Dillow /* Reset the chip, and disable all interrputs. 1048*175859bfSDavid Dillow */ 1049*175859bfSDavid Dillow outl(SIS_GCR_SOFTWARE_RESET, sis->ioport + SIS_GCR); 1050*175859bfSDavid Dillow udelay(10); 1051*175859bfSDavid Dillow outl(0, sis->ioport + SIS_GCR); 1052*175859bfSDavid Dillow outl(0, sis->ioport + SIS_GIER); 1053*175859bfSDavid Dillow 1054*175859bfSDavid Dillow /* Now, free everything we allocated. 1055*175859bfSDavid Dillow */ 1056*175859bfSDavid Dillow if (sis->irq >= 0) 1057*175859bfSDavid Dillow free_irq(sis->irq, sis); 1058*175859bfSDavid Dillow 1059*175859bfSDavid Dillow if (sis->ioaddr) 1060*175859bfSDavid Dillow iounmap(sis->ioaddr); 1061*175859bfSDavid Dillow 1062*175859bfSDavid Dillow pci_release_regions(sis->pci); 1063*175859bfSDavid Dillow pci_disable_device(sis->pci); 1064*175859bfSDavid Dillow 1065*175859bfSDavid Dillow sis_free_suspend(sis); 1066*175859bfSDavid Dillow return 0; 1067*175859bfSDavid Dillow } 1068*175859bfSDavid Dillow 1069*175859bfSDavid Dillow static int sis_dev_free(struct snd_device *dev) 1070*175859bfSDavid Dillow { 1071*175859bfSDavid Dillow struct sis7019 *sis = dev->device_data; 1072*175859bfSDavid Dillow return sis_chip_free(sis); 1073*175859bfSDavid Dillow } 1074*175859bfSDavid Dillow 1075*175859bfSDavid Dillow static int sis_chip_init(struct sis7019 *sis) 1076*175859bfSDavid Dillow { 1077*175859bfSDavid Dillow unsigned long io = sis->ioport; 1078*175859bfSDavid Dillow void __iomem *ioaddr = sis->ioaddr; 1079*175859bfSDavid Dillow u16 status; 1080*175859bfSDavid Dillow int count; 1081*175859bfSDavid Dillow int i; 1082*175859bfSDavid Dillow 1083*175859bfSDavid Dillow /* Reset the audio controller 1084*175859bfSDavid Dillow */ 1085*175859bfSDavid Dillow outl(SIS_GCR_SOFTWARE_RESET, io + SIS_GCR); 1086*175859bfSDavid Dillow udelay(10); 1087*175859bfSDavid Dillow outl(0, io + SIS_GCR); 1088*175859bfSDavid Dillow 1089*175859bfSDavid Dillow /* Get the AC-link semaphore, and reset the codecs 1090*175859bfSDavid Dillow */ 1091*175859bfSDavid Dillow count = 0xffff; 1092*175859bfSDavid Dillow while ((inw(io + SIS_AC97_SEMA) & SIS_AC97_SEMA_BUSY) && --count) 1093*175859bfSDavid Dillow udelay(1); 1094*175859bfSDavid Dillow 1095*175859bfSDavid Dillow if (!count) 1096*175859bfSDavid Dillow return -EIO; 1097*175859bfSDavid Dillow 1098*175859bfSDavid Dillow outl(SIS_AC97_CMD_CODEC_COLD_RESET, io + SIS_AC97_CMD); 1099*175859bfSDavid Dillow udelay(10); 1100*175859bfSDavid Dillow 1101*175859bfSDavid Dillow count = 0xffff; 1102*175859bfSDavid Dillow while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) 1103*175859bfSDavid Dillow udelay(1); 1104*175859bfSDavid Dillow 1105*175859bfSDavid Dillow /* Now that we've finished the reset, find out what's attached. 1106*175859bfSDavid Dillow */ 1107*175859bfSDavid Dillow status = inl(io + SIS_AC97_STATUS); 1108*175859bfSDavid Dillow if (status & SIS_AC97_STATUS_CODEC_READY) 1109*175859bfSDavid Dillow sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT; 1110*175859bfSDavid Dillow if (status & SIS_AC97_STATUS_CODEC2_READY) 1111*175859bfSDavid Dillow sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT; 1112*175859bfSDavid Dillow if (status & SIS_AC97_STATUS_CODEC3_READY) 1113*175859bfSDavid Dillow sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT; 1114*175859bfSDavid Dillow 1115*175859bfSDavid Dillow /* All done, let go of the semaphore, and check for errors 1116*175859bfSDavid Dillow */ 1117*175859bfSDavid Dillow outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA); 1118*175859bfSDavid Dillow if (!sis->codecs_present || !count) 1119*175859bfSDavid Dillow return -EIO; 1120*175859bfSDavid Dillow 1121*175859bfSDavid Dillow /* Let the hardware know that the audio driver is alive, 1122*175859bfSDavid Dillow * and enable PCM slots on the AC-link for L/R playback (3 & 4) and 1123*175859bfSDavid Dillow * record channels. We're going to want to use Variable Rate Audio 1124*175859bfSDavid Dillow * for recording, to avoid needlessly resampling from 48kHZ. 1125*175859bfSDavid Dillow */ 1126*175859bfSDavid Dillow outl(SIS_AC97_CONF_AUDIO_ALIVE, io + SIS_AC97_CONF); 1127*175859bfSDavid Dillow outl(SIS_AC97_CONF_AUDIO_ALIVE | SIS_AC97_CONF_PCM_LR_ENABLE | 1128*175859bfSDavid Dillow SIS_AC97_CONF_PCM_CAP_MIC_ENABLE | 1129*175859bfSDavid Dillow SIS_AC97_CONF_PCM_CAP_LR_ENABLE | 1130*175859bfSDavid Dillow SIS_AC97_CONF_CODEC_VRA_ENABLE, io + SIS_AC97_CONF); 1131*175859bfSDavid Dillow 1132*175859bfSDavid Dillow /* All AC97 PCM slots should be sourced from sub-mixer 0. 1133*175859bfSDavid Dillow */ 1134*175859bfSDavid Dillow outl(0, io + SIS_AC97_PSR); 1135*175859bfSDavid Dillow 1136*175859bfSDavid Dillow /* There is only one valid DMA setup for a PCI environment. 1137*175859bfSDavid Dillow */ 1138*175859bfSDavid Dillow outl(SIS_DMA_CSR_PCI_SETTINGS, io + SIS_DMA_CSR); 1139*175859bfSDavid Dillow 1140*175859bfSDavid Dillow /* Reset the syncronization groups for all of the channels 1141*175859bfSDavid Dillow * to be asyncronous. If we start doing SPDIF or 5.1 sound, etc. 1142*175859bfSDavid Dillow * we'll need to change how we handle these. Until then, we just 1143*175859bfSDavid Dillow * assign sub-mixer 0 to all playback channels, and avoid any 1144*175859bfSDavid Dillow * attenuation on the audio. 1145*175859bfSDavid Dillow */ 1146*175859bfSDavid Dillow outl(0, io + SIS_PLAY_SYNC_GROUP_A); 1147*175859bfSDavid Dillow outl(0, io + SIS_PLAY_SYNC_GROUP_B); 1148*175859bfSDavid Dillow outl(0, io + SIS_PLAY_SYNC_GROUP_C); 1149*175859bfSDavid Dillow outl(0, io + SIS_PLAY_SYNC_GROUP_D); 1150*175859bfSDavid Dillow outl(0, io + SIS_MIXER_SYNC_GROUP); 1151*175859bfSDavid Dillow 1152*175859bfSDavid Dillow for (i = 0; i < 64; i++) { 1153*175859bfSDavid Dillow writel(i, SIS_MIXER_START_ADDR(ioaddr, i)); 1154*175859bfSDavid Dillow writel(SIS_MIXER_RIGHT_NO_ATTEN | SIS_MIXER_LEFT_NO_ATTEN | 1155*175859bfSDavid Dillow SIS_MIXER_DEST_0, SIS_MIXER_ADDR(ioaddr, i)); 1156*175859bfSDavid Dillow } 1157*175859bfSDavid Dillow 1158*175859bfSDavid Dillow /* Don't attenuate any audio set for the wave amplifier. 1159*175859bfSDavid Dillow * 1160*175859bfSDavid Dillow * FIXME: Maximum attenuation is set for the music amp, which will 1161*175859bfSDavid Dillow * need to change if we start using the synth engine. 1162*175859bfSDavid Dillow */ 1163*175859bfSDavid Dillow outl(0xffff0000, io + SIS_WEVCR); 1164*175859bfSDavid Dillow 1165*175859bfSDavid Dillow /* Ensure that the wave engine is in normal operating mode. 1166*175859bfSDavid Dillow */ 1167*175859bfSDavid Dillow outl(0, io + SIS_WECCR); 1168*175859bfSDavid Dillow 1169*175859bfSDavid Dillow /* Go ahead and enable the DMA interrupts. They won't go live 1170*175859bfSDavid Dillow * until we start a channel. 1171*175859bfSDavid Dillow */ 1172*175859bfSDavid Dillow outl(SIS_GIER_AUDIO_PLAY_DMA_IRQ_ENABLE | 1173*175859bfSDavid Dillow SIS_GIER_AUDIO_RECORD_DMA_IRQ_ENABLE, io + SIS_GIER); 1174*175859bfSDavid Dillow 1175*175859bfSDavid Dillow return 0; 1176*175859bfSDavid Dillow } 1177*175859bfSDavid Dillow 1178*175859bfSDavid Dillow #ifdef CONFIG_PM 1179*175859bfSDavid Dillow static int sis_suspend(struct pci_dev *pci, pm_message_t state) 1180*175859bfSDavid Dillow { 1181*175859bfSDavid Dillow struct snd_card *card = pci_get_drvdata(pci); 1182*175859bfSDavid Dillow struct sis7019 *sis = card->private_data; 1183*175859bfSDavid Dillow void __iomem *ioaddr = sis->ioaddr; 1184*175859bfSDavid Dillow int i; 1185*175859bfSDavid Dillow 1186*175859bfSDavid Dillow snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 1187*175859bfSDavid Dillow snd_pcm_suspend_all(sis->pcm); 1188*175859bfSDavid Dillow if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) 1189*175859bfSDavid Dillow snd_ac97_suspend(sis->ac97[0]); 1190*175859bfSDavid Dillow if (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT) 1191*175859bfSDavid Dillow snd_ac97_suspend(sis->ac97[1]); 1192*175859bfSDavid Dillow if (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT) 1193*175859bfSDavid Dillow snd_ac97_suspend(sis->ac97[2]); 1194*175859bfSDavid Dillow 1195*175859bfSDavid Dillow /* snd_pcm_suspend_all() stopped all channels, so we're quiescent. 1196*175859bfSDavid Dillow */ 1197*175859bfSDavid Dillow if (sis->irq >= 0) { 1198*175859bfSDavid Dillow synchronize_irq(sis->irq); 1199*175859bfSDavid Dillow free_irq(sis->irq, sis); 1200*175859bfSDavid Dillow sis->irq = -1; 1201*175859bfSDavid Dillow } 1202*175859bfSDavid Dillow 1203*175859bfSDavid Dillow /* Save the internal state away 1204*175859bfSDavid Dillow */ 1205*175859bfSDavid Dillow for (i = 0; i < 4; i++) { 1206*175859bfSDavid Dillow memcpy_fromio(sis->suspend_state[i], ioaddr, 4096); 1207*175859bfSDavid Dillow ioaddr += 4096; 1208*175859bfSDavid Dillow } 1209*175859bfSDavid Dillow 1210*175859bfSDavid Dillow pci_disable_device(pci); 1211*175859bfSDavid Dillow pci_save_state(pci); 1212*175859bfSDavid Dillow pci_set_power_state(pci, pci_choose_state(pci, state)); 1213*175859bfSDavid Dillow return 0; 1214*175859bfSDavid Dillow } 1215*175859bfSDavid Dillow 1216*175859bfSDavid Dillow static int sis_resume(struct pci_dev *pci) 1217*175859bfSDavid Dillow { 1218*175859bfSDavid Dillow struct snd_card *card = pci_get_drvdata(pci); 1219*175859bfSDavid Dillow struct sis7019 *sis = card->private_data; 1220*175859bfSDavid Dillow void __iomem *ioaddr = sis->ioaddr; 1221*175859bfSDavid Dillow int i; 1222*175859bfSDavid Dillow 1223*175859bfSDavid Dillow pci_set_power_state(pci, PCI_D0); 1224*175859bfSDavid Dillow pci_restore_state(pci); 1225*175859bfSDavid Dillow 1226*175859bfSDavid Dillow if (pci_enable_device(pci) < 0) { 1227*175859bfSDavid Dillow printk(KERN_ERR "sis7019: unable to re-enable device\n"); 1228*175859bfSDavid Dillow goto error; 1229*175859bfSDavid Dillow } 1230*175859bfSDavid Dillow 1231*175859bfSDavid Dillow if (sis_chip_init(sis)) { 1232*175859bfSDavid Dillow printk(KERN_ERR "sis7019: unable to re-init controller\n"); 1233*175859bfSDavid Dillow goto error; 1234*175859bfSDavid Dillow } 1235*175859bfSDavid Dillow 1236*175859bfSDavid Dillow if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED, 1237*175859bfSDavid Dillow card->shortname, sis)) { 1238*175859bfSDavid Dillow printk(KERN_ERR "sis7019: unable to regain IRQ %d\n", pci->irq); 1239*175859bfSDavid Dillow goto error; 1240*175859bfSDavid Dillow } 1241*175859bfSDavid Dillow 1242*175859bfSDavid Dillow /* Restore saved state, then clear out the page we use for the 1243*175859bfSDavid Dillow * silence buffer. 1244*175859bfSDavid Dillow */ 1245*175859bfSDavid Dillow for (i = 0; i < 4; i++) { 1246*175859bfSDavid Dillow memcpy_toio(ioaddr, sis->suspend_state[i], 4096); 1247*175859bfSDavid Dillow ioaddr += 4096; 1248*175859bfSDavid Dillow } 1249*175859bfSDavid Dillow 1250*175859bfSDavid Dillow memset(sis->suspend_state[0], 0, 4096); 1251*175859bfSDavid Dillow 1252*175859bfSDavid Dillow sis->irq = pci->irq; 1253*175859bfSDavid Dillow pci_set_master(pci); 1254*175859bfSDavid Dillow 1255*175859bfSDavid Dillow if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) 1256*175859bfSDavid Dillow snd_ac97_resume(sis->ac97[0]); 1257*175859bfSDavid Dillow if (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT) 1258*175859bfSDavid Dillow snd_ac97_resume(sis->ac97[1]); 1259*175859bfSDavid Dillow if (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT) 1260*175859bfSDavid Dillow snd_ac97_resume(sis->ac97[2]); 1261*175859bfSDavid Dillow 1262*175859bfSDavid Dillow snd_power_change_state(card, SNDRV_CTL_POWER_D0); 1263*175859bfSDavid Dillow return 0; 1264*175859bfSDavid Dillow 1265*175859bfSDavid Dillow error: 1266*175859bfSDavid Dillow snd_card_disconnect(card); 1267*175859bfSDavid Dillow return -EIO; 1268*175859bfSDavid Dillow } 1269*175859bfSDavid Dillow #endif /* CONFIG_PM */ 1270*175859bfSDavid Dillow 1271*175859bfSDavid Dillow static int sis_alloc_suspend(struct sis7019 *sis) 1272*175859bfSDavid Dillow { 1273*175859bfSDavid Dillow int i; 1274*175859bfSDavid Dillow 1275*175859bfSDavid Dillow /* We need 16K to store the internal wave engine state during a 1276*175859bfSDavid Dillow * suspend, but we don't need it to be contiguous, so play nice 1277*175859bfSDavid Dillow * with the memory system. We'll also use this area for a silence 1278*175859bfSDavid Dillow * buffer. 1279*175859bfSDavid Dillow */ 1280*175859bfSDavid Dillow for (i = 0; i < SIS_SUSPEND_PAGES; i++) { 1281*175859bfSDavid Dillow sis->suspend_state[i] = kmalloc(4096, GFP_KERNEL); 1282*175859bfSDavid Dillow if (!sis->suspend_state[i]) 1283*175859bfSDavid Dillow return -ENOMEM; 1284*175859bfSDavid Dillow } 1285*175859bfSDavid Dillow memset(sis->suspend_state[0], 0, 4096); 1286*175859bfSDavid Dillow 1287*175859bfSDavid Dillow return 0; 1288*175859bfSDavid Dillow } 1289*175859bfSDavid Dillow 1290*175859bfSDavid Dillow static int __devinit sis_chip_create(struct snd_card *card, 1291*175859bfSDavid Dillow struct pci_dev *pci) 1292*175859bfSDavid Dillow { 1293*175859bfSDavid Dillow struct sis7019 *sis = card->private_data; 1294*175859bfSDavid Dillow struct voice *voice; 1295*175859bfSDavid Dillow static struct snd_device_ops ops = { 1296*175859bfSDavid Dillow .dev_free = sis_dev_free, 1297*175859bfSDavid Dillow }; 1298*175859bfSDavid Dillow int rc; 1299*175859bfSDavid Dillow int i; 1300*175859bfSDavid Dillow 1301*175859bfSDavid Dillow rc = pci_enable_device(pci); 1302*175859bfSDavid Dillow if (rc) 1303*175859bfSDavid Dillow goto error_out; 1304*175859bfSDavid Dillow 1305*175859bfSDavid Dillow if (pci_set_dma_mask(pci, DMA_30BIT_MASK) < 0) { 1306*175859bfSDavid Dillow printk(KERN_ERR "sis7019: architecture does not support " 1307*175859bfSDavid Dillow "30-bit PCI busmaster DMA"); 1308*175859bfSDavid Dillow goto error_out_enabled; 1309*175859bfSDavid Dillow } 1310*175859bfSDavid Dillow 1311*175859bfSDavid Dillow memset(sis, 0, sizeof(*sis)); 1312*175859bfSDavid Dillow mutex_init(&sis->ac97_mutex); 1313*175859bfSDavid Dillow spin_lock_init(&sis->voice_lock); 1314*175859bfSDavid Dillow sis->card = card; 1315*175859bfSDavid Dillow sis->pci = pci; 1316*175859bfSDavid Dillow sis->irq = -1; 1317*175859bfSDavid Dillow sis->ioport = pci_resource_start(pci, 0); 1318*175859bfSDavid Dillow 1319*175859bfSDavid Dillow rc = pci_request_regions(pci, "SiS7019"); 1320*175859bfSDavid Dillow if (rc) { 1321*175859bfSDavid Dillow printk(KERN_ERR "sis7019: unable request regions\n"); 1322*175859bfSDavid Dillow goto error_out_enabled; 1323*175859bfSDavid Dillow } 1324*175859bfSDavid Dillow 1325*175859bfSDavid Dillow rc = -EIO; 1326*175859bfSDavid Dillow sis->ioaddr = ioremap_nocache(pci_resource_start(pci, 1), 0x4000); 1327*175859bfSDavid Dillow if (!sis->ioaddr) { 1328*175859bfSDavid Dillow printk(KERN_ERR "sis7019: unable to remap MMIO, aborting\n"); 1329*175859bfSDavid Dillow goto error_out_cleanup; 1330*175859bfSDavid Dillow } 1331*175859bfSDavid Dillow 1332*175859bfSDavid Dillow rc = sis_alloc_suspend(sis); 1333*175859bfSDavid Dillow if (rc < 0) { 1334*175859bfSDavid Dillow printk(KERN_ERR "sis7019: unable to allocate state storage\n"); 1335*175859bfSDavid Dillow goto error_out_cleanup; 1336*175859bfSDavid Dillow } 1337*175859bfSDavid Dillow 1338*175859bfSDavid Dillow rc = sis_chip_init(sis); 1339*175859bfSDavid Dillow if (rc) 1340*175859bfSDavid Dillow goto error_out_cleanup; 1341*175859bfSDavid Dillow 1342*175859bfSDavid Dillow if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED, 1343*175859bfSDavid Dillow card->shortname, sis)) { 1344*175859bfSDavid Dillow printk(KERN_ERR "unable to allocate irq %d\n", sis->irq); 1345*175859bfSDavid Dillow goto error_out_cleanup; 1346*175859bfSDavid Dillow } 1347*175859bfSDavid Dillow 1348*175859bfSDavid Dillow sis->irq = pci->irq; 1349*175859bfSDavid Dillow pci_set_master(pci); 1350*175859bfSDavid Dillow 1351*175859bfSDavid Dillow for (i = 0; i < 64; i++) { 1352*175859bfSDavid Dillow voice = &sis->voices[i]; 1353*175859bfSDavid Dillow voice->num = i; 1354*175859bfSDavid Dillow voice->ctrl_base = SIS_PLAY_DMA_ADDR(sis->ioaddr, i); 1355*175859bfSDavid Dillow voice->wave_base = SIS_WAVE_ADDR(sis->ioaddr, i); 1356*175859bfSDavid Dillow } 1357*175859bfSDavid Dillow 1358*175859bfSDavid Dillow voice = &sis->capture_voice; 1359*175859bfSDavid Dillow voice->flags = VOICE_CAPTURE; 1360*175859bfSDavid Dillow voice->num = SIS_CAPTURE_CHAN_AC97_PCM_IN; 1361*175859bfSDavid Dillow voice->ctrl_base = SIS_CAPTURE_DMA_ADDR(sis->ioaddr, voice->num); 1362*175859bfSDavid Dillow 1363*175859bfSDavid Dillow rc = snd_device_new(card, SNDRV_DEV_LOWLEVEL, sis, &ops); 1364*175859bfSDavid Dillow if (rc) 1365*175859bfSDavid Dillow goto error_out_cleanup; 1366*175859bfSDavid Dillow 1367*175859bfSDavid Dillow snd_card_set_dev(card, &pci->dev); 1368*175859bfSDavid Dillow 1369*175859bfSDavid Dillow return 0; 1370*175859bfSDavid Dillow 1371*175859bfSDavid Dillow error_out_cleanup: 1372*175859bfSDavid Dillow sis_chip_free(sis); 1373*175859bfSDavid Dillow 1374*175859bfSDavid Dillow error_out_enabled: 1375*175859bfSDavid Dillow pci_disable_device(pci); 1376*175859bfSDavid Dillow 1377*175859bfSDavid Dillow error_out: 1378*175859bfSDavid Dillow return rc; 1379*175859bfSDavid Dillow } 1380*175859bfSDavid Dillow 1381*175859bfSDavid Dillow static int __devinit snd_sis7019_probe(struct pci_dev *pci, 1382*175859bfSDavid Dillow const struct pci_device_id *pci_id) 1383*175859bfSDavid Dillow { 1384*175859bfSDavid Dillow struct snd_card *card; 1385*175859bfSDavid Dillow struct sis7019 *sis; 1386*175859bfSDavid Dillow int rc; 1387*175859bfSDavid Dillow 1388*175859bfSDavid Dillow rc = -ENOENT; 1389*175859bfSDavid Dillow if (!enable) 1390*175859bfSDavid Dillow goto error_out; 1391*175859bfSDavid Dillow 1392*175859bfSDavid Dillow rc = -ENOMEM; 1393*175859bfSDavid Dillow card = snd_card_new(index, id, THIS_MODULE, sizeof(*sis)); 1394*175859bfSDavid Dillow if (!card) 1395*175859bfSDavid Dillow goto error_out; 1396*175859bfSDavid Dillow 1397*175859bfSDavid Dillow strcpy(card->driver, "SiS7019"); 1398*175859bfSDavid Dillow strcpy(card->shortname, "SiS7019"); 1399*175859bfSDavid Dillow rc = sis_chip_create(card, pci); 1400*175859bfSDavid Dillow if (rc) 1401*175859bfSDavid Dillow goto card_error_out; 1402*175859bfSDavid Dillow 1403*175859bfSDavid Dillow sis = card->private_data; 1404*175859bfSDavid Dillow 1405*175859bfSDavid Dillow rc = sis_mixer_create(sis); 1406*175859bfSDavid Dillow if (rc) 1407*175859bfSDavid Dillow goto card_error_out; 1408*175859bfSDavid Dillow 1409*175859bfSDavid Dillow rc = sis_pcm_create(sis); 1410*175859bfSDavid Dillow if (rc) 1411*175859bfSDavid Dillow goto card_error_out; 1412*175859bfSDavid Dillow 1413*175859bfSDavid Dillow snprintf(card->longname, sizeof(card->longname), 1414*175859bfSDavid Dillow "%s Audio Accelerator with %s at 0x%lx, irq %d", 1415*175859bfSDavid Dillow card->shortname, snd_ac97_get_short_name(sis->ac97[0]), 1416*175859bfSDavid Dillow sis->ioport, sis->irq); 1417*175859bfSDavid Dillow 1418*175859bfSDavid Dillow rc = snd_card_register(card); 1419*175859bfSDavid Dillow if (rc) 1420*175859bfSDavid Dillow goto card_error_out; 1421*175859bfSDavid Dillow 1422*175859bfSDavid Dillow pci_set_drvdata(pci, card); 1423*175859bfSDavid Dillow return 0; 1424*175859bfSDavid Dillow 1425*175859bfSDavid Dillow card_error_out: 1426*175859bfSDavid Dillow snd_card_free(card); 1427*175859bfSDavid Dillow 1428*175859bfSDavid Dillow error_out: 1429*175859bfSDavid Dillow return rc; 1430*175859bfSDavid Dillow } 1431*175859bfSDavid Dillow 1432*175859bfSDavid Dillow static void __devexit snd_sis7019_remove(struct pci_dev *pci) 1433*175859bfSDavid Dillow { 1434*175859bfSDavid Dillow snd_card_free(pci_get_drvdata(pci)); 1435*175859bfSDavid Dillow pci_set_drvdata(pci, NULL); 1436*175859bfSDavid Dillow } 1437*175859bfSDavid Dillow 1438*175859bfSDavid Dillow static struct pci_driver sis7019_driver = { 1439*175859bfSDavid Dillow .name = "SiS7019", 1440*175859bfSDavid Dillow .id_table = snd_sis7019_ids, 1441*175859bfSDavid Dillow .probe = snd_sis7019_probe, 1442*175859bfSDavid Dillow .remove = __devexit_p(snd_sis7019_remove), 1443*175859bfSDavid Dillow 1444*175859bfSDavid Dillow #ifdef CONFIG_PM 1445*175859bfSDavid Dillow .suspend = sis_suspend, 1446*175859bfSDavid Dillow .resume = sis_resume, 1447*175859bfSDavid Dillow #endif 1448*175859bfSDavid Dillow }; 1449*175859bfSDavid Dillow 1450*175859bfSDavid Dillow static int __init sis7019_init(void) 1451*175859bfSDavid Dillow { 1452*175859bfSDavid Dillow return pci_register_driver(&sis7019_driver); 1453*175859bfSDavid Dillow } 1454*175859bfSDavid Dillow 1455*175859bfSDavid Dillow static void __exit sis7019_exit(void) 1456*175859bfSDavid Dillow { 1457*175859bfSDavid Dillow pci_unregister_driver(&sis7019_driver); 1458*175859bfSDavid Dillow } 1459*175859bfSDavid Dillow 1460*175859bfSDavid Dillow module_init(sis7019_init); 1461*175859bfSDavid Dillow module_exit(sis7019_exit); 1462