📄 cs4281.c
字号:
if (axes[jst] == 0xFFFF) axes[jst] = -1; return 0;}#else#define snd_cs4281_gameport_cooked_read NULL#endifstatic int snd_cs4281_gameport_open(struct gameport *gameport, int mode){ switch (mode) {#ifdef COOKED_MODE case GAMEPORT_MODE_COOKED: return 0;#endif case GAMEPORT_MODE_RAW: return 0; default: return -1; } return 0;}static int __devinit snd_cs4281_create_gameport(struct cs4281 *chip){ struct gameport *gp; chip->gameport = gp = gameport_allocate_port(); if (!gp) { printk(KERN_ERR "cs4281: cannot allocate memory for gameport\n"); return -ENOMEM; } gameport_set_name(gp, "CS4281 Gameport"); gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci)); gameport_set_dev_parent(gp, &chip->pci->dev); gp->open = snd_cs4281_gameport_open; gp->read = snd_cs4281_gameport_read; gp->trigger = snd_cs4281_gameport_trigger; gp->cooked_read = snd_cs4281_gameport_cooked_read; gameport_set_port_data(gp, chip); snd_cs4281_pokeBA0(chip, BA0_JSIO, 0xFF); // ? snd_cs4281_pokeBA0(chip, BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW); gameport_register_port(gp); return 0;}static void snd_cs4281_free_gameport(struct cs4281 *chip){ if (chip->gameport) { gameport_unregister_port(chip->gameport); chip->gameport = NULL; }}#elsestatic inline int snd_cs4281_create_gameport(struct cs4281 *chip) { return -ENOSYS; }static inline void snd_cs4281_free_gameport(struct cs4281 *chip) { }#endif /* CONFIG_GAMEPORT || (MODULE && CONFIG_GAMEPORT_MODULE) */static int snd_cs4281_free(struct cs4281 *chip){ snd_cs4281_free_gameport(chip); if (chip->irq >= 0) synchronize_irq(chip->irq); /* Mask interrupts */ snd_cs4281_pokeBA0(chip, BA0_HIMR, 0x7fffffff); /* Stop the DLL Clock logic. */ snd_cs4281_pokeBA0(chip, BA0_CLKCR1, 0); /* Sound System Power Management - Turn Everything OFF */ snd_cs4281_pokeBA0(chip, BA0_SSPM, 0); /* PCI interface - D3 state */ pci_set_power_state(chip->pci, 3); if (chip->irq >= 0) free_irq(chip->irq, chip); if (chip->ba0) iounmap(chip->ba0); if (chip->ba1) iounmap(chip->ba1); pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); return 0;}static int snd_cs4281_dev_free(struct snd_device *device){ struct cs4281 *chip = device->device_data; return snd_cs4281_free(chip);}static int snd_cs4281_chip_init(struct cs4281 *chip); /* defined below */static int __devinit snd_cs4281_create(struct snd_card *card, struct pci_dev *pci, struct cs4281 ** rchip, int dual_codec){ struct cs4281 *chip; unsigned int tmp; int err; static struct snd_device_ops ops = { .dev_free = snd_cs4281_dev_free, }; *rchip = NULL; if ((err = pci_enable_device(pci)) < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; } spin_lock_init(&chip->reg_lock); chip->card = card; chip->pci = pci; chip->irq = -1; pci_set_master(pci); if (dual_codec < 0 || dual_codec > 3) { snd_printk(KERN_ERR "invalid dual_codec option %d\n", dual_codec); dual_codec = 0; } chip->dual_codec = dual_codec; if ((err = pci_request_regions(pci, "CS4281")) < 0) { kfree(chip); pci_disable_device(pci); return err; } chip->ba0_addr = pci_resource_start(pci, 0); chip->ba1_addr = pci_resource_start(pci, 1); chip->ba0 = ioremap_nocache(chip->ba0_addr, pci_resource_len(pci, 0)); chip->ba1 = ioremap_nocache(chip->ba1_addr, pci_resource_len(pci, 1)); if (!chip->ba0 || !chip->ba1) { snd_cs4281_free(chip); return -ENOMEM; } if (request_irq(pci->irq, snd_cs4281_interrupt, IRQF_SHARED, "CS4281", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_cs4281_free(chip); return -ENOMEM; } chip->irq = pci->irq; tmp = snd_cs4281_chip_init(chip); if (tmp) { snd_cs4281_free(chip); return tmp; } if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_cs4281_free(chip); return err; } snd_cs4281_proc_init(chip); snd_card_set_dev(card, &pci->dev); *rchip = chip; return 0;}static int snd_cs4281_chip_init(struct cs4281 *chip){ unsigned int tmp; unsigned long end_time; int retry_count = 2; /* Having EPPMC.FPDN=1 prevent proper chip initialisation */ tmp = snd_cs4281_peekBA0(chip, BA0_EPPMC); if (tmp & BA0_EPPMC_FPDN) snd_cs4281_pokeBA0(chip, BA0_EPPMC, tmp & ~BA0_EPPMC_FPDN); __retry: tmp = snd_cs4281_peekBA0(chip, BA0_CFLR); if (tmp != BA0_CFLR_DEFAULT) { snd_cs4281_pokeBA0(chip, BA0_CFLR, BA0_CFLR_DEFAULT); tmp = snd_cs4281_peekBA0(chip, BA0_CFLR); if (tmp != BA0_CFLR_DEFAULT) { snd_printk(KERN_ERR "CFLR setup failed (0x%x)\n", tmp); return -EIO; } } /* Set the 'Configuration Write Protect' register * to 4281h. Allows vendor-defined configuration * space between 0e4h and 0ffh to be written. */ snd_cs4281_pokeBA0(chip, BA0_CWPR, 0x4281); if ((tmp = snd_cs4281_peekBA0(chip, BA0_SERC1)) != (BA0_SERC1_SO1EN | BA0_SERC1_AC97)) { snd_printk(KERN_ERR "SERC1 AC'97 check failed (0x%x)\n", tmp); return -EIO; } if ((tmp = snd_cs4281_peekBA0(chip, BA0_SERC2)) != (BA0_SERC2_SI1EN | BA0_SERC2_AC97)) { snd_printk(KERN_ERR "SERC2 AC'97 check failed (0x%x)\n", tmp); return -EIO; } /* Sound System Power Management */ snd_cs4281_pokeBA0(chip, BA0_SSPM, BA0_SSPM_MIXEN | BA0_SSPM_CSRCEN | BA0_SSPM_PSRCEN | BA0_SSPM_JSEN | BA0_SSPM_ACLEN | BA0_SSPM_FMEN); /* Serial Port Power Management */ /* Blast the clock control register to zero so that the * PLL starts out in a known state, and blast the master serial * port control register to zero so that the serial ports also * start out in a known state. */ snd_cs4281_pokeBA0(chip, BA0_CLKCR1, 0); snd_cs4281_pokeBA0(chip, BA0_SERMC, 0); /* Make ESYN go to zero to turn off * the Sync pulse on the AC97 link. */ snd_cs4281_pokeBA0(chip, BA0_ACCTL, 0); udelay(50); /* Drive the ARST# pin low for a minimum of 1uS (as defined in the AC97 * spec) and then drive it high. This is done for non AC97 modes since * there might be logic external to the CS4281 that uses the ARST# line * for a reset. */ snd_cs4281_pokeBA0(chip, BA0_SPMC, 0); udelay(50); snd_cs4281_pokeBA0(chip, BA0_SPMC, BA0_SPMC_RSTN); msleep(50); if (chip->dual_codec) snd_cs4281_pokeBA0(chip, BA0_SPMC, BA0_SPMC_RSTN | BA0_SPMC_ASDI2E); /* * Set the serial port timing configuration. */ snd_cs4281_pokeBA0(chip, BA0_SERMC, (chip->dual_codec ? BA0_SERMC_TCID(chip->dual_codec) : BA0_SERMC_TCID(1)) | BA0_SERMC_PTC_AC97 | BA0_SERMC_MSPE); /* * Start the DLL Clock logic. */ snd_cs4281_pokeBA0(chip, BA0_CLKCR1, BA0_CLKCR1_DLLP); msleep(50); snd_cs4281_pokeBA0(chip, BA0_CLKCR1, BA0_CLKCR1_SWCE | BA0_CLKCR1_DLLP); /* * Wait for the DLL ready signal from the clock logic. */ end_time = jiffies + HZ; do { /* * Read the AC97 status register to see if we've seen a CODEC * signal from the AC97 codec. */ if (snd_cs4281_peekBA0(chip, BA0_CLKCR1) & BA0_CLKCR1_DLLRDY) goto __ok0; schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); snd_printk(KERN_ERR "DLLRDY not seen\n"); return -EIO; __ok0: /* * The first thing we do here is to enable sync generation. As soon * as we start receiving bit clock, we'll start producing the SYNC * signal. */ snd_cs4281_pokeBA0(chip, BA0_ACCTL, BA0_ACCTL_ESYN); /* * Wait for the codec ready signal from the AC97 codec. */ end_time = jiffies + HZ; do { /* * Read the AC97 status register to see if we've seen a CODEC * signal from the AC97 codec. */ if (snd_cs4281_peekBA0(chip, BA0_ACSTS) & BA0_ACSTS_CRDY) goto __ok1; schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); snd_printk(KERN_ERR "never read codec ready from AC'97 (0x%x)\n", snd_cs4281_peekBA0(chip, BA0_ACSTS)); return -EIO; __ok1: if (chip->dual_codec) { end_time = jiffies + HZ; do { if (snd_cs4281_peekBA0(chip, BA0_ACSTS2) & BA0_ACSTS_CRDY) goto __codec2_ok; schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); snd_printk(KERN_INFO "secondary codec doesn't respond. disable it...\n"); chip->dual_codec = 0; __codec2_ok: ; } /* * Assert the valid frame signal so that we can start sending commands * to the AC97 codec. */ snd_cs4281_pokeBA0(chip, BA0_ACCTL, BA0_ACCTL_VFRM | BA0_ACCTL_ESYN); /* * Wait until we've sampled input slots 3 and 4 as valid, meaning that * the codec is pumping ADC data across the AC-link. */ end_time = jiffies + HZ; do { /* * Read the input slot valid register and see if input slots 3 * 4 are valid yet. */ if ((snd_cs4281_peekBA0(chip, BA0_ACISV) & (BA0_ACISV_SLV(3) | BA0_ACISV_SLV(4))) == (BA0_ACISV_SLV(3) | BA0_ACISV_SLV(4))) goto __ok2; schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); if (--retry_count > 0) goto __retry; snd_printk(KERN_ERR "never read ISV3 and ISV4 from AC'97\n"); return -EIO; __ok2: /* * Now, assert valid frame and the slot 3 and 4 valid bits. This will * commense the transfer of digital audio data to the AC97 codec. */ snd_cs4281_pokeBA0(chip, BA0_ACOSV, BA0_ACOSV_SLV(3) | BA0_ACOSV_SLV(4)); /* * Initialize DMA structures */ for (tmp = 0; tmp < 4; tmp++) { struct cs4281_dma *dma = &chip->dma[tmp]; dma->regDBA = BA0_DBA0 + (tmp * 0x10); dma->regDCA = BA0_DCA0 + (tmp * 0x10); dma->regDBC = BA0_DBC0 + (tmp * 0x10); dma->regDCC = BA0_DCC0 + (tmp * 0x10); dma->regDMR = BA0_DMR0 + (tmp * 8); dma->regDCR = BA0_DCR0 + (tmp * 8); dma->regHDSR = BA0_HDSR0 + (tmp * 4); dma->regFCR = BA0_FCR0 + (tmp * 4); dma->regFSIC = BA0_FSIC0 + (tmp * 4); dma->fifo_offset = tmp * CS4281_FIFO_SIZE; snd_cs4281_pokeBA0(chip, dma->regFCR, BA0_FCR_LS(31) | BA0_FCR_RS(31) | BA0_FCR_SZ(CS4281_FIFO_SIZE) | BA0_FCR_OF(dma->fifo_offset)); } chip->src_left_play_slot = 0; /* AC'97 left PCM playback (3) */ chip->src_right_play_slot = 1; /* AC'97 right PCM playback (4) */ chip->src_left_rec_slot = 10; /* AC'97 left PCM record (3) */ chip->src_right_rec_slot = 11; /* AC'97 right PCM record (4) */ /* Activate wave playback FIFO for FM playback */ chip->dma[0].valFCR = BA0_FCR_FEN | BA0_FCR_LS(0) | BA0_FCR_RS(1) | BA0_FCR_SZ(CS4281_FIFO_SIZE) | BA0_FCR_OF(chip->dma[0].fifo_offset); snd_cs4281_pokeBA0(chip, chip->dma[0].regFCR, chip->dma[0].valFCR); snd_cs4281_pokeBA0(chip, BA0_SRCSA, (chip->src_left_play_slot << 0) | (chip->src_right_play_slot << 8) | (chip->src_left_rec_slot << 16) | (chip->src_right_rec_slot << 24)); /* Initialize digital volume */ snd_cs4281_pokeBA0(chip, BA0_PPLVC, 0); snd_cs4281_pokeBA0(chip, BA0_PPRVC, 0); /* Enable IRQs */ snd_cs4281_pokeBA0(chip, BA0_HICR, BA0_HICR_EOI); /* Unmask interrupts */ snd_cs4281_pokeBA0(chip, BA0_HIMR, 0x7fffffff & ~( BA0_HISR_MIDI | BA0_HISR_DMAI | BA0_HISR_DMA(0) | BA0_HISR_DMA(1) | BA0_HISR_DMA(2) | BA0_HISR_DMA(3))); synchronize_irq(chip->irq); return 0;}/* * MIDI section */static void snd_cs4281_midi_reset(struct cs4281 *chip){ snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr | BA0_MIDCR_MRST); udelay(100); snd_cs4281_pokeBA0(chip, BA0_MIDCR, chip->midcr);}static int snd_cs4281_midi_input_open(struct snd_rawmidi_substream *substream){ struct cs4281 *chip = substream->rmidi->private_data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -