📄 ca0106_main.c
字号:
ca0106_t *chip; ca0106_details_t *c; int err; int ch; static snd_device_ops_t ops = { .dev_free = snd_ca0106_dev_free, }; *rchip = NULL; if ((err = pci_enable_device(pci)) < 0) return err; if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { printk(KERN_ERR "error to set 32bit mask DMA\n"); pci_disable_device(pci); return -ENXIO; } chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; } chip->card = card; chip->pci = pci; chip->irq = -1; spin_lock_init(&chip->emu_lock); chip->port = pci_resource_start(pci, 0); if ((chip->res_port = request_region(chip->port, 0x20, "snd_ca0106")) == NULL) { snd_ca0106_free(chip); printk(KERN_ERR "cannot allocate the port\n"); return -EBUSY; } if (request_irq(pci->irq, snd_ca0106_interrupt, SA_INTERRUPT|SA_SHIRQ, "snd_ca0106", (void *)chip)) { snd_ca0106_free(chip); printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; } chip->irq = pci->irq; /* This stores the periods table. */ if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &chip->buffer) < 0) { snd_ca0106_free(chip); return -ENOMEM; } pci_set_master(pci); /* read revision & serial */ pci_read_config_byte(pci, PCI_REVISION_ID, (char *)&chip->revision); pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);#if 1 printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model, chip->revision, chip->serial);#endif strcpy(card->driver, "CA0106"); strcpy(card->shortname, "CA0106"); for (c=ca0106_chip_details; c->serial; c++) { if (c->serial == chip->serial) break; } chip->details = c; sprintf(card->longname, "%s at 0x%lx irq %i", c->name, chip->port, chip->irq); outl(0, chip->port + INTE); /* * Init to 0x02109204 : * Clock accuracy = 0 (1000ppm) * Sample Rate = 2 (48kHz) * Audio Channel = 1 (Left of 2) * Source Number = 0 (Unspecified) * Generation Status = 1 (Original for Cat Code 12) * Cat Code = 12 (Digital Signal Mixer) * Mode = 0 (Mode 0) * Emphasis = 0 (None) * CP = 1 (Copyright unasserted) * AN = 0 (Audio data) * P = 0 (Consumer) */ snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); /* Only SPCS1 has been tested */ snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); /* Write 0x8000 to AC97_REC_GAIN to mute it. */ outb(AC97_REC_GAIN, chip->port + AC97ADDRESS); outw(0x8000, chip->port + AC97DATA);#if 0 snd_ca0106_ptr_write(chip, SPCS0, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x42, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x43, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x44, 0, 0x2108006);#endif //snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */ /* Analog or Digital output */ snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ chip->spdif_enable = 0; /* Set digital SPDIF output off */ chip->capture_source = 3; /* Set CAPTURE_SOURCE */ //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ //snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); /* goes to 0x40c80000 when doing SPDIF IN/OUT */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); /* (Mute) CAPTURE feedback into PLAYBACK volume. Only lower 16 bits matter. */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); /* SPDIF IN Volume */ snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING1, 0, 0x32765410); snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING2, 0, 0x76767676); snd_ca0106_ptr_write(chip, CAPTURE_ROUTING1, 0, 0x32765410); snd_ca0106_ptr_write(chip, CAPTURE_ROUTING2, 0, 0x76767676); for(ch = 0; ch < 4; ch++) { snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); /* Only high 16 bits matter */ snd_ca0106_ptr_write(chip, CAPTURE_VOLUME2, ch, 0x30303030); //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); /* Mute */ //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); /* Mute */ snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */ snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */ } snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */ chip->capture_source = 3; /* Set CAPTURE_SOURCE */ if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ outl(0x0, chip->port+GPIO); //outl(0x00f0e000, chip->port+GPIO); /* Analog */ outl(0x005f5301, chip->port+GPIO); /* Analog */ } else { outl(0x0, chip->port+GPIO); outl(0x005f03a3, chip->port+GPIO); /* Analog */ //outl(0x005f02a2, chip->port+GPIO); /* SPDIF */ } snd_ca0106_intr_enable(chip, 0x105); /* Win2000 uses 0x1e0 */ //outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); //outl(0x00001409, chip->port+HCFG); /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ //outl(0x00000009, chip->port+HCFG); outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ } if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_ca0106_free(chip); return err; } *rchip = chip; return 0;}static void ca0106_midi_interrupt_enable(ca_midi_t *midi, int intr){ snd_ca0106_intr_enable((ca0106_t *)(midi->dev_id), intr);}static void ca0106_midi_interrupt_disable(ca_midi_t *midi, int intr){ snd_ca0106_intr_disable((ca0106_t *)(midi->dev_id), intr);}static unsigned char ca0106_midi_read(ca_midi_t *midi, int idx){ return (unsigned char)snd_ca0106_ptr_read((ca0106_t *)(midi->dev_id), midi->port + idx, 0);}static void ca0106_midi_write(ca_midi_t *midi, int data, int idx){ snd_ca0106_ptr_write((ca0106_t *)(midi->dev_id), midi->port + idx, 0, data);}static snd_card_t *ca0106_dev_id_card(void *dev_id){ return ((ca0106_t *)dev_id)->card;}static int ca0106_dev_id_port(void *dev_id){ return ((ca0106_t *)dev_id)->port;}static int __devinit snd_ca0106_midi(ca0106_t *chip, unsigned int channel){ ca_midi_t *midi; char *name; int err; if(channel==CA0106_MIDI_CHAN_B) { name = "CA0106 MPU-401 (UART) B"; midi = &chip->midi2; midi->tx_enable = INTE_MIDI_TX_B; midi->rx_enable = INTE_MIDI_RX_B; midi->ipr_tx = IPR_MIDI_TX_B; midi->ipr_rx = IPR_MIDI_RX_B; midi->port = MIDI_UART_B_DATA; } else { name = "CA0106 MPU-401 (UART)"; midi = &chip->midi; midi->tx_enable = INTE_MIDI_TX_A; midi->rx_enable = INTE_MIDI_TX_B; midi->ipr_tx = IPR_MIDI_TX_A; midi->ipr_rx = IPR_MIDI_RX_A; midi->port = MIDI_UART_A_DATA; } midi->reset = CA0106_MPU401_RESET; midi->enter_uart = CA0106_MPU401_ENTER_UART; midi->ack = CA0106_MPU401_ACK; midi->input_avail = CA0106_MIDI_INPUT_AVAIL; midi->output_ready = CA0106_MIDI_OUTPUT_READY; midi->channel = channel; midi->interrupt_enable = ca0106_midi_interrupt_enable; midi->interrupt_disable = ca0106_midi_interrupt_disable; midi->read = ca0106_midi_read; midi->write = ca0106_midi_write; midi->get_dev_id_card = ca0106_dev_id_card; midi->get_dev_id_port = ca0106_dev_id_port; midi->dev_id = chip; if ((err = ca_midi_init(chip, midi, 0, name)) < 0) return err; return 0;}static int __devinit snd_ca0106_probe(struct pci_dev *pci, const struct pci_device_id *pci_id){ static int dev; snd_card_t *card; ca0106_t *chip; int err; if (dev >= SNDRV_CARDS) return -ENODEV; if (!enable[dev]) { dev++; return -ENOENT; } card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); if (card == NULL) return -ENOMEM; if ((err = snd_ca0106_create(card, pci, &chip)) < 0) { snd_card_free(card); return err; } if ((err = snd_ca0106_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); return err; } if ((err = snd_ca0106_pcm(chip, 1, NULL)) < 0) { snd_card_free(card); return err; } if ((err = snd_ca0106_pcm(chip, 2, NULL)) < 0) { snd_card_free(card); return err; } if ((err = snd_ca0106_pcm(chip, 3, NULL)) < 0) { snd_card_free(card); return err; } if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ if ((err = snd_ca0106_ac97(chip)) < 0) { snd_card_free(card); return err; } } if ((err = snd_ca0106_mixer(chip)) < 0) { snd_card_free(card); return err; } snd_printdd("ca0106: probe for MIDI channel A ..."); if ((err = snd_ca0106_midi(chip,CA0106_MIDI_CHAN_A)) < 0) { snd_card_free(card); snd_printdd(" failed, err=0x%x\n",err); return err; } snd_printdd(" done.\n"); snd_ca0106_proc_init(chip); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; } pci_set_drvdata(pci, card); dev++; return 0;}static void __devexit snd_ca0106_remove(struct pci_dev *pci){ snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL);}// PCI IDsstatic struct pci_device_id snd_ca0106_ids[] = { { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Audigy LS or Live 24bit */ { 0, }};MODULE_DEVICE_TABLE(pci, snd_ca0106_ids);// pci_driver definitionstatic struct pci_driver driver = { .name = "CA0106", .id_table = snd_ca0106_ids, .probe = snd_ca0106_probe, .remove = __devexit_p(snd_ca0106_remove),};// initialization of the modulestatic int __init alsa_card_ca0106_init(void){ int err; if ((err = pci_register_driver(&driver)) > 0) return err; return 0;}// clean up the modulestatic void __exit alsa_card_ca0106_exit(void){ pci_unregister_driver(&driver);}module_init(alsa_card_ca0106_init)module_exit(alsa_card_ca0106_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -