1*9b4ffa48SJaya Kumar /* 2*9b4ffa48SJaya Kumar * Driver for audio on multifunction CS5535 companion device 3*9b4ffa48SJaya Kumar * Copyright (C) Jaya Kumar 4*9b4ffa48SJaya Kumar * 5*9b4ffa48SJaya Kumar * Based on Jaroslav Kysela and Takashi Iwai's examples. 6*9b4ffa48SJaya Kumar * This work was sponsored by CIS(M) Sdn Bhd. 7*9b4ffa48SJaya Kumar * 8*9b4ffa48SJaya Kumar * This program is free software; you can redistribute it and/or modify 9*9b4ffa48SJaya Kumar * it under the terms of the GNU General Public License as published by 10*9b4ffa48SJaya Kumar * the Free Software Foundation; either version 2 of the License, or 11*9b4ffa48SJaya Kumar * (at your option) any later version. 12*9b4ffa48SJaya Kumar * 13*9b4ffa48SJaya Kumar * This program is distributed in the hope that it will be useful, 14*9b4ffa48SJaya Kumar * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*9b4ffa48SJaya Kumar * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*9b4ffa48SJaya Kumar * GNU General Public License for more details. 17*9b4ffa48SJaya Kumar * 18*9b4ffa48SJaya Kumar * You should have received a copy of the GNU General Public License 19*9b4ffa48SJaya Kumar * along with this program; if not, write to the Free Software 20*9b4ffa48SJaya Kumar * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21*9b4ffa48SJaya Kumar * 22*9b4ffa48SJaya Kumar */ 23*9b4ffa48SJaya Kumar 24*9b4ffa48SJaya Kumar #include <linux/delay.h> 25*9b4ffa48SJaya Kumar #include <linux/interrupt.h> 26*9b4ffa48SJaya Kumar #include <linux/init.h> 27*9b4ffa48SJaya Kumar #include <linux/pci.h> 28*9b4ffa48SJaya Kumar #include <linux/slab.h> 29*9b4ffa48SJaya Kumar #include <linux/moduleparam.h> 30*9b4ffa48SJaya Kumar #include <asm/io.h> 31*9b4ffa48SJaya Kumar #include <sound/driver.h> 32*9b4ffa48SJaya Kumar #include <sound/core.h> 33*9b4ffa48SJaya Kumar #include <sound/control.h> 34*9b4ffa48SJaya Kumar #include <sound/pcm.h> 35*9b4ffa48SJaya Kumar #include <sound/rawmidi.h> 36*9b4ffa48SJaya Kumar #include <sound/ac97_codec.h> 37*9b4ffa48SJaya Kumar #include <sound/initval.h> 38*9b4ffa48SJaya Kumar #include <sound/asoundef.h> 39*9b4ffa48SJaya Kumar #include "cs5535audio.h" 40*9b4ffa48SJaya Kumar 41*9b4ffa48SJaya Kumar #define DRIVER_NAME "cs5535audio" 42*9b4ffa48SJaya Kumar 43*9b4ffa48SJaya Kumar 44*9b4ffa48SJaya Kumar static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 45*9b4ffa48SJaya Kumar static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; 46*9b4ffa48SJaya Kumar static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; 47*9b4ffa48SJaya Kumar 48*9b4ffa48SJaya Kumar static struct pci_device_id snd_cs5535audio_ids[] = { 49*9b4ffa48SJaya Kumar { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO, PCI_ANY_ID, 50*9b4ffa48SJaya Kumar PCI_ANY_ID, 0, 0, 0, }, 51*9b4ffa48SJaya Kumar {} 52*9b4ffa48SJaya Kumar }; 53*9b4ffa48SJaya Kumar 54*9b4ffa48SJaya Kumar MODULE_DEVICE_TABLE(pci, snd_cs5535audio_ids); 55*9b4ffa48SJaya Kumar 56*9b4ffa48SJaya Kumar static void wait_till_cmd_acked(cs5535audio_t *cs5535au, unsigned long timeout) 57*9b4ffa48SJaya Kumar { 58*9b4ffa48SJaya Kumar unsigned long tmp; 59*9b4ffa48SJaya Kumar do { 60*9b4ffa48SJaya Kumar tmp = cs_readl(cs5535au, ACC_CODEC_CNTL); 61*9b4ffa48SJaya Kumar if (!(tmp & CMD_NEW)) 62*9b4ffa48SJaya Kumar break; 63*9b4ffa48SJaya Kumar msleep(10); 64*9b4ffa48SJaya Kumar } while (--timeout); 65*9b4ffa48SJaya Kumar if (!timeout) 66*9b4ffa48SJaya Kumar snd_printk(KERN_ERR "Failure writing to cs5535 codec\n"); 67*9b4ffa48SJaya Kumar } 68*9b4ffa48SJaya Kumar 69*9b4ffa48SJaya Kumar static unsigned short snd_cs5535audio_codec_read(cs5535audio_t *cs5535au, 70*9b4ffa48SJaya Kumar unsigned short reg) 71*9b4ffa48SJaya Kumar { 72*9b4ffa48SJaya Kumar unsigned long regdata; 73*9b4ffa48SJaya Kumar unsigned long timeout; 74*9b4ffa48SJaya Kumar unsigned long val; 75*9b4ffa48SJaya Kumar 76*9b4ffa48SJaya Kumar regdata = ((unsigned long) reg) << 24; 77*9b4ffa48SJaya Kumar regdata |= ACC_CODEC_CNTL_RD_CMD; 78*9b4ffa48SJaya Kumar regdata |= CMD_NEW; 79*9b4ffa48SJaya Kumar 80*9b4ffa48SJaya Kumar cs_writel(cs5535au, ACC_CODEC_CNTL, regdata); 81*9b4ffa48SJaya Kumar wait_till_cmd_acked(cs5535au, 500); 82*9b4ffa48SJaya Kumar 83*9b4ffa48SJaya Kumar timeout = 50; 84*9b4ffa48SJaya Kumar do { 85*9b4ffa48SJaya Kumar val = cs_readl(cs5535au, ACC_CODEC_STATUS); 86*9b4ffa48SJaya Kumar if ( (val & STS_NEW) && 87*9b4ffa48SJaya Kumar ((unsigned long) reg == ((0xFF000000 & val)>>24)) ) 88*9b4ffa48SJaya Kumar break; 89*9b4ffa48SJaya Kumar msleep(10); 90*9b4ffa48SJaya Kumar } while (--timeout); 91*9b4ffa48SJaya Kumar if (!timeout) 92*9b4ffa48SJaya Kumar snd_printk(KERN_ERR "Failure reading cs5535 codec\n"); 93*9b4ffa48SJaya Kumar 94*9b4ffa48SJaya Kumar return ((unsigned short) val); 95*9b4ffa48SJaya Kumar } 96*9b4ffa48SJaya Kumar 97*9b4ffa48SJaya Kumar static void snd_cs5535audio_codec_write(cs5535audio_t *cs5535au, 98*9b4ffa48SJaya Kumar unsigned short reg, unsigned short val) 99*9b4ffa48SJaya Kumar { 100*9b4ffa48SJaya Kumar unsigned long regdata; 101*9b4ffa48SJaya Kumar 102*9b4ffa48SJaya Kumar regdata = ((unsigned long) reg) << 24; 103*9b4ffa48SJaya Kumar regdata |= (unsigned long) val; 104*9b4ffa48SJaya Kumar regdata &= CMD_MASK; 105*9b4ffa48SJaya Kumar regdata |= CMD_NEW; 106*9b4ffa48SJaya Kumar regdata &= ACC_CODEC_CNTL_WR_CMD; 107*9b4ffa48SJaya Kumar 108*9b4ffa48SJaya Kumar cs_writel(cs5535au, ACC_CODEC_CNTL, regdata); 109*9b4ffa48SJaya Kumar wait_till_cmd_acked(cs5535au, 50); 110*9b4ffa48SJaya Kumar } 111*9b4ffa48SJaya Kumar 112*9b4ffa48SJaya Kumar static void snd_cs5535audio_ac97_codec_write(ac97_t *ac97, 113*9b4ffa48SJaya Kumar unsigned short reg, unsigned short val) 114*9b4ffa48SJaya Kumar { 115*9b4ffa48SJaya Kumar cs5535audio_t *cs5535au = ac97->private_data; 116*9b4ffa48SJaya Kumar snd_cs5535audio_codec_write(cs5535au, reg, val); 117*9b4ffa48SJaya Kumar } 118*9b4ffa48SJaya Kumar 119*9b4ffa48SJaya Kumar static unsigned short snd_cs5535audio_ac97_codec_read(ac97_t *ac97, 120*9b4ffa48SJaya Kumar unsigned short reg) 121*9b4ffa48SJaya Kumar { 122*9b4ffa48SJaya Kumar cs5535audio_t *cs5535au = ac97->private_data; 123*9b4ffa48SJaya Kumar return snd_cs5535audio_codec_read(cs5535au, reg); 124*9b4ffa48SJaya Kumar } 125*9b4ffa48SJaya Kumar 126*9b4ffa48SJaya Kumar static void snd_cs5535audio_mixer_free_ac97(ac97_t *ac97) 127*9b4ffa48SJaya Kumar { 128*9b4ffa48SJaya Kumar cs5535audio_t *cs5535audio = ac97->private_data; 129*9b4ffa48SJaya Kumar cs5535audio->ac97 = NULL; 130*9b4ffa48SJaya Kumar } 131*9b4ffa48SJaya Kumar 132*9b4ffa48SJaya Kumar static int snd_cs5535audio_mixer(cs5535audio_t *cs5535au) 133*9b4ffa48SJaya Kumar { 134*9b4ffa48SJaya Kumar snd_card_t *card = cs5535au->card; 135*9b4ffa48SJaya Kumar ac97_bus_t *pbus; 136*9b4ffa48SJaya Kumar ac97_template_t ac97; 137*9b4ffa48SJaya Kumar int err; 138*9b4ffa48SJaya Kumar static ac97_bus_ops_t ops = { 139*9b4ffa48SJaya Kumar .write = snd_cs5535audio_ac97_codec_write, 140*9b4ffa48SJaya Kumar .read = snd_cs5535audio_ac97_codec_read, 141*9b4ffa48SJaya Kumar }; 142*9b4ffa48SJaya Kumar 143*9b4ffa48SJaya Kumar if ((err = snd_ac97_bus(card, 0, &ops, NULL, &pbus)) < 0) 144*9b4ffa48SJaya Kumar return err; 145*9b4ffa48SJaya Kumar 146*9b4ffa48SJaya Kumar memset(&ac97, 0, sizeof(ac97)); 147*9b4ffa48SJaya Kumar ac97.scaps = AC97_SCAP_AUDIO|AC97_SCAP_SKIP_MODEM; 148*9b4ffa48SJaya Kumar ac97.private_data = cs5535au; 149*9b4ffa48SJaya Kumar ac97.pci = cs5535au->pci; 150*9b4ffa48SJaya Kumar ac97.private_free = snd_cs5535audio_mixer_free_ac97; 151*9b4ffa48SJaya Kumar 152*9b4ffa48SJaya Kumar if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) { 153*9b4ffa48SJaya Kumar snd_printk("mixer failed\n"); 154*9b4ffa48SJaya Kumar return err; 155*9b4ffa48SJaya Kumar } 156*9b4ffa48SJaya Kumar 157*9b4ffa48SJaya Kumar return 0; 158*9b4ffa48SJaya Kumar } 159*9b4ffa48SJaya Kumar 160*9b4ffa48SJaya Kumar static void process_bm0_irq(cs5535audio_t *cs5535au) 161*9b4ffa48SJaya Kumar { 162*9b4ffa48SJaya Kumar u8 bm_stat; 163*9b4ffa48SJaya Kumar spin_lock(&cs5535au->reg_lock); 164*9b4ffa48SJaya Kumar bm_stat = cs_readb(cs5535au, ACC_BM0_STATUS); 165*9b4ffa48SJaya Kumar spin_unlock(&cs5535au->reg_lock); 166*9b4ffa48SJaya Kumar if (bm_stat & EOP) { 167*9b4ffa48SJaya Kumar cs5535audio_dma_t *dma; 168*9b4ffa48SJaya Kumar dma = cs5535au->playback_substream->runtime->private_data; 169*9b4ffa48SJaya Kumar snd_pcm_period_elapsed(cs5535au->playback_substream); 170*9b4ffa48SJaya Kumar } else { 171*9b4ffa48SJaya Kumar snd_printk(KERN_ERR "unexpected bm0 irq src, bm_stat=%x\n", 172*9b4ffa48SJaya Kumar bm_stat); 173*9b4ffa48SJaya Kumar } 174*9b4ffa48SJaya Kumar } 175*9b4ffa48SJaya Kumar 176*9b4ffa48SJaya Kumar static void process_bm1_irq(cs5535audio_t *cs5535au) 177*9b4ffa48SJaya Kumar { 178*9b4ffa48SJaya Kumar u8 bm_stat; 179*9b4ffa48SJaya Kumar spin_lock(&cs5535au->reg_lock); 180*9b4ffa48SJaya Kumar bm_stat = cs_readb(cs5535au, ACC_BM1_STATUS); 181*9b4ffa48SJaya Kumar spin_unlock(&cs5535au->reg_lock); 182*9b4ffa48SJaya Kumar if (bm_stat & EOP) { 183*9b4ffa48SJaya Kumar cs5535audio_dma_t *dma; 184*9b4ffa48SJaya Kumar dma = cs5535au->capture_substream->runtime->private_data; 185*9b4ffa48SJaya Kumar snd_pcm_period_elapsed(cs5535au->capture_substream); 186*9b4ffa48SJaya Kumar } 187*9b4ffa48SJaya Kumar } 188*9b4ffa48SJaya Kumar 189*9b4ffa48SJaya Kumar static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id, 190*9b4ffa48SJaya Kumar struct pt_regs *regs) 191*9b4ffa48SJaya Kumar { 192*9b4ffa48SJaya Kumar u16 acc_irq_stat; 193*9b4ffa48SJaya Kumar u8 bm_stat; 194*9b4ffa48SJaya Kumar unsigned char count; 195*9b4ffa48SJaya Kumar cs5535audio_t *cs5535au = dev_id; 196*9b4ffa48SJaya Kumar 197*9b4ffa48SJaya Kumar if (cs5535au == NULL) 198*9b4ffa48SJaya Kumar return IRQ_NONE; 199*9b4ffa48SJaya Kumar 200*9b4ffa48SJaya Kumar acc_irq_stat = cs_readw(cs5535au, ACC_IRQ_STATUS); 201*9b4ffa48SJaya Kumar 202*9b4ffa48SJaya Kumar if (!acc_irq_stat) 203*9b4ffa48SJaya Kumar return IRQ_NONE; 204*9b4ffa48SJaya Kumar for (count=0; count < 10; count++) { 205*9b4ffa48SJaya Kumar if (acc_irq_stat & (1<<count)) { 206*9b4ffa48SJaya Kumar switch (count) { 207*9b4ffa48SJaya Kumar case IRQ_STS: 208*9b4ffa48SJaya Kumar cs_readl(cs5535au, ACC_GPIO_STATUS); 209*9b4ffa48SJaya Kumar break; 210*9b4ffa48SJaya Kumar case WU_IRQ_STS: 211*9b4ffa48SJaya Kumar cs_readl(cs5535au, ACC_GPIO_STATUS); 212*9b4ffa48SJaya Kumar break; 213*9b4ffa48SJaya Kumar case BM0_IRQ_STS: 214*9b4ffa48SJaya Kumar process_bm0_irq(cs5535au); 215*9b4ffa48SJaya Kumar break; 216*9b4ffa48SJaya Kumar case BM1_IRQ_STS: 217*9b4ffa48SJaya Kumar process_bm1_irq(cs5535au); 218*9b4ffa48SJaya Kumar break; 219*9b4ffa48SJaya Kumar case BM2_IRQ_STS: 220*9b4ffa48SJaya Kumar bm_stat = cs_readb(cs5535au, ACC_BM2_STATUS); 221*9b4ffa48SJaya Kumar break; 222*9b4ffa48SJaya Kumar case BM3_IRQ_STS: 223*9b4ffa48SJaya Kumar bm_stat = cs_readb(cs5535au, ACC_BM3_STATUS); 224*9b4ffa48SJaya Kumar break; 225*9b4ffa48SJaya Kumar case BM4_IRQ_STS: 226*9b4ffa48SJaya Kumar bm_stat = cs_readb(cs5535au, ACC_BM4_STATUS); 227*9b4ffa48SJaya Kumar break; 228*9b4ffa48SJaya Kumar case BM5_IRQ_STS: 229*9b4ffa48SJaya Kumar bm_stat = cs_readb(cs5535au, ACC_BM5_STATUS); 230*9b4ffa48SJaya Kumar break; 231*9b4ffa48SJaya Kumar case BM6_IRQ_STS: 232*9b4ffa48SJaya Kumar bm_stat = cs_readb(cs5535au, ACC_BM6_STATUS); 233*9b4ffa48SJaya Kumar break; 234*9b4ffa48SJaya Kumar case BM7_IRQ_STS: 235*9b4ffa48SJaya Kumar bm_stat = cs_readb(cs5535au, ACC_BM7_STATUS); 236*9b4ffa48SJaya Kumar break; 237*9b4ffa48SJaya Kumar default: 238*9b4ffa48SJaya Kumar snd_printk(KERN_ERR "Unexpected irq src\n"); 239*9b4ffa48SJaya Kumar break; 240*9b4ffa48SJaya Kumar } 241*9b4ffa48SJaya Kumar } 242*9b4ffa48SJaya Kumar } 243*9b4ffa48SJaya Kumar return IRQ_HANDLED; 244*9b4ffa48SJaya Kumar } 245*9b4ffa48SJaya Kumar 246*9b4ffa48SJaya Kumar static int snd_cs5535audio_free(cs5535audio_t *cs5535au) 247*9b4ffa48SJaya Kumar { 248*9b4ffa48SJaya Kumar synchronize_irq(cs5535au->irq); 249*9b4ffa48SJaya Kumar pci_set_power_state(cs5535au->pci, 3); 250*9b4ffa48SJaya Kumar 251*9b4ffa48SJaya Kumar if (cs5535au->irq >= 0) 252*9b4ffa48SJaya Kumar free_irq(cs5535au->irq, cs5535au); 253*9b4ffa48SJaya Kumar 254*9b4ffa48SJaya Kumar pci_release_regions(cs5535au->pci); 255*9b4ffa48SJaya Kumar pci_disable_device(cs5535au->pci); 256*9b4ffa48SJaya Kumar kfree(cs5535au); 257*9b4ffa48SJaya Kumar return 0; 258*9b4ffa48SJaya Kumar } 259*9b4ffa48SJaya Kumar 260*9b4ffa48SJaya Kumar static int snd_cs5535audio_dev_free(snd_device_t *device) 261*9b4ffa48SJaya Kumar { 262*9b4ffa48SJaya Kumar cs5535audio_t *cs5535au = device->device_data; 263*9b4ffa48SJaya Kumar return snd_cs5535audio_free(cs5535au); 264*9b4ffa48SJaya Kumar } 265*9b4ffa48SJaya Kumar 266*9b4ffa48SJaya Kumar static int __devinit snd_cs5535audio_create(snd_card_t *card, 267*9b4ffa48SJaya Kumar struct pci_dev *pci, 268*9b4ffa48SJaya Kumar cs5535audio_t **rcs5535au) 269*9b4ffa48SJaya Kumar { 270*9b4ffa48SJaya Kumar cs5535audio_t *cs5535au; 271*9b4ffa48SJaya Kumar 272*9b4ffa48SJaya Kumar int err; 273*9b4ffa48SJaya Kumar static snd_device_ops_t ops = { 274*9b4ffa48SJaya Kumar .dev_free = snd_cs5535audio_dev_free, 275*9b4ffa48SJaya Kumar }; 276*9b4ffa48SJaya Kumar 277*9b4ffa48SJaya Kumar *rcs5535au = NULL; 278*9b4ffa48SJaya Kumar if ((err = pci_enable_device(pci)) < 0) 279*9b4ffa48SJaya Kumar return err; 280*9b4ffa48SJaya Kumar 281*9b4ffa48SJaya Kumar if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || 282*9b4ffa48SJaya Kumar pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { 283*9b4ffa48SJaya Kumar printk(KERN_WARNING "unable to get 32bit dma\n"); 284*9b4ffa48SJaya Kumar err = -ENXIO; 285*9b4ffa48SJaya Kumar goto pcifail; 286*9b4ffa48SJaya Kumar } 287*9b4ffa48SJaya Kumar 288*9b4ffa48SJaya Kumar cs5535au = kzalloc(sizeof(*cs5535au), GFP_KERNEL); 289*9b4ffa48SJaya Kumar if (cs5535au == NULL) { 290*9b4ffa48SJaya Kumar err = -ENOMEM; 291*9b4ffa48SJaya Kumar goto pcifail; 292*9b4ffa48SJaya Kumar } 293*9b4ffa48SJaya Kumar 294*9b4ffa48SJaya Kumar spin_lock_init(&cs5535au->reg_lock); 295*9b4ffa48SJaya Kumar cs5535au->card = card; 296*9b4ffa48SJaya Kumar cs5535au->pci = pci; 297*9b4ffa48SJaya Kumar cs5535au->irq = -1; 298*9b4ffa48SJaya Kumar 299*9b4ffa48SJaya Kumar if ((err = pci_request_regions(pci, "CS5535 Audio")) < 0) { 300*9b4ffa48SJaya Kumar kfree(cs5535au); 301*9b4ffa48SJaya Kumar goto pcifail; 302*9b4ffa48SJaya Kumar } 303*9b4ffa48SJaya Kumar 304*9b4ffa48SJaya Kumar cs5535au->port = pci_resource_start(pci, 0); 305*9b4ffa48SJaya Kumar 306*9b4ffa48SJaya Kumar if (request_irq(pci->irq, snd_cs5535audio_interrupt, 307*9b4ffa48SJaya Kumar SA_INTERRUPT|SA_SHIRQ, "CS5535 Audio", cs5535au)) { 308*9b4ffa48SJaya Kumar snd_printk("unable to grab IRQ %d\n", pci->irq); 309*9b4ffa48SJaya Kumar err = -EBUSY; 310*9b4ffa48SJaya Kumar goto sndfail; 311*9b4ffa48SJaya Kumar } 312*9b4ffa48SJaya Kumar 313*9b4ffa48SJaya Kumar cs5535au->irq = pci->irq; 314*9b4ffa48SJaya Kumar pci_set_master(pci); 315*9b4ffa48SJaya Kumar 316*9b4ffa48SJaya Kumar if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, 317*9b4ffa48SJaya Kumar cs5535au, &ops)) < 0) 318*9b4ffa48SJaya Kumar goto sndfail; 319*9b4ffa48SJaya Kumar 320*9b4ffa48SJaya Kumar snd_card_set_dev(card, &pci->dev); 321*9b4ffa48SJaya Kumar 322*9b4ffa48SJaya Kumar *rcs5535au = cs5535au; 323*9b4ffa48SJaya Kumar return 0; 324*9b4ffa48SJaya Kumar 325*9b4ffa48SJaya Kumar sndfail: /* leave the device alive, just kill the snd */ 326*9b4ffa48SJaya Kumar snd_cs5535audio_free(cs5535au); 327*9b4ffa48SJaya Kumar return err; 328*9b4ffa48SJaya Kumar 329*9b4ffa48SJaya Kumar pcifail: 330*9b4ffa48SJaya Kumar pci_disable_device(pci); 331*9b4ffa48SJaya Kumar return err; 332*9b4ffa48SJaya Kumar } 333*9b4ffa48SJaya Kumar 334*9b4ffa48SJaya Kumar static int __devinit snd_cs5535audio_probe(struct pci_dev *pci, 335*9b4ffa48SJaya Kumar const struct pci_device_id *pci_id) 336*9b4ffa48SJaya Kumar { 337*9b4ffa48SJaya Kumar static int dev; 338*9b4ffa48SJaya Kumar snd_card_t *card; 339*9b4ffa48SJaya Kumar cs5535audio_t *cs5535au; 340*9b4ffa48SJaya Kumar int err; 341*9b4ffa48SJaya Kumar 342*9b4ffa48SJaya Kumar if (dev >= SNDRV_CARDS) 343*9b4ffa48SJaya Kumar return -ENODEV; 344*9b4ffa48SJaya Kumar if (!enable[dev]) { 345*9b4ffa48SJaya Kumar dev++; 346*9b4ffa48SJaya Kumar return -ENOENT; 347*9b4ffa48SJaya Kumar } 348*9b4ffa48SJaya Kumar 349*9b4ffa48SJaya Kumar card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); 350*9b4ffa48SJaya Kumar if (card == NULL) 351*9b4ffa48SJaya Kumar return -ENOMEM; 352*9b4ffa48SJaya Kumar 353*9b4ffa48SJaya Kumar if ((err = snd_cs5535audio_create(card, pci, &cs5535au)) < 0) 354*9b4ffa48SJaya Kumar goto probefail_out; 355*9b4ffa48SJaya Kumar 356*9b4ffa48SJaya Kumar if ((err = snd_cs5535audio_mixer(cs5535au)) < 0) 357*9b4ffa48SJaya Kumar goto probefail_out; 358*9b4ffa48SJaya Kumar 359*9b4ffa48SJaya Kumar if ((err = snd_cs5535audio_pcm(cs5535au)) < 0) 360*9b4ffa48SJaya Kumar goto probefail_out; 361*9b4ffa48SJaya Kumar 362*9b4ffa48SJaya Kumar strcpy(card->driver, DRIVER_NAME); 363*9b4ffa48SJaya Kumar 364*9b4ffa48SJaya Kumar strcpy(card->shortname, "CS5535 Audio"); 365*9b4ffa48SJaya Kumar sprintf(card->longname, "%s %s at 0x%lx, irq %i", 366*9b4ffa48SJaya Kumar card->shortname, card->driver, 367*9b4ffa48SJaya Kumar cs5535au->port, cs5535au->irq); 368*9b4ffa48SJaya Kumar 369*9b4ffa48SJaya Kumar if ((err = snd_card_register(card)) < 0) 370*9b4ffa48SJaya Kumar goto probefail_out; 371*9b4ffa48SJaya Kumar 372*9b4ffa48SJaya Kumar pci_set_drvdata(pci, card); 373*9b4ffa48SJaya Kumar dev++; 374*9b4ffa48SJaya Kumar return 0; 375*9b4ffa48SJaya Kumar 376*9b4ffa48SJaya Kumar probefail_out: 377*9b4ffa48SJaya Kumar snd_card_free(card); 378*9b4ffa48SJaya Kumar return err; 379*9b4ffa48SJaya Kumar } 380*9b4ffa48SJaya Kumar 381*9b4ffa48SJaya Kumar static void __devexit snd_cs5535audio_remove(struct pci_dev *pci) 382*9b4ffa48SJaya Kumar { 383*9b4ffa48SJaya Kumar snd_card_free(pci_get_drvdata(pci)); 384*9b4ffa48SJaya Kumar pci_set_drvdata(pci, NULL); 385*9b4ffa48SJaya Kumar } 386*9b4ffa48SJaya Kumar 387*9b4ffa48SJaya Kumar static struct pci_driver driver = { 388*9b4ffa48SJaya Kumar .name = DRIVER_NAME, 389*9b4ffa48SJaya Kumar .id_table = snd_cs5535audio_ids, 390*9b4ffa48SJaya Kumar .probe = snd_cs5535audio_probe, 391*9b4ffa48SJaya Kumar .remove = __devexit_p(snd_cs5535audio_remove), 392*9b4ffa48SJaya Kumar }; 393*9b4ffa48SJaya Kumar 394*9b4ffa48SJaya Kumar static int __init alsa_card_cs5535audio_init(void) 395*9b4ffa48SJaya Kumar { 396*9b4ffa48SJaya Kumar return pci_module_init(&driver); 397*9b4ffa48SJaya Kumar } 398*9b4ffa48SJaya Kumar 399*9b4ffa48SJaya Kumar static void __exit alsa_card_cs5535audio_exit(void) 400*9b4ffa48SJaya Kumar { 401*9b4ffa48SJaya Kumar pci_unregister_driver(&driver); 402*9b4ffa48SJaya Kumar } 403*9b4ffa48SJaya Kumar 404*9b4ffa48SJaya Kumar module_init(alsa_card_cs5535audio_init) 405*9b4ffa48SJaya Kumar module_exit(alsa_card_cs5535audio_exit) 406*9b4ffa48SJaya Kumar 407*9b4ffa48SJaya Kumar MODULE_AUTHOR("Jaya Kumar"); 408*9b4ffa48SJaya Kumar MODULE_LICENSE("GPL"); 409*9b4ffa48SJaya Kumar MODULE_DESCRIPTION("CS5535 Audio"); 410*9b4ffa48SJaya Kumar MODULE_SUPPORTED_DEVICE("CS5535 Audio"); 411