📄 emu10k1x.c
字号:
static inline void mpu401_write(emu10k1x_t *emu, emu10k1x_midi_t *mpu, int data, int idx){ snd_emu10k1x_ptr_write(emu, mpu->port + idx, 0, data);}#define mpu401_write_data(emu, mpu, data) mpu401_write(emu, mpu, data, 0)#define mpu401_write_cmd(emu, mpu, data) mpu401_write(emu, mpu, data, 1)#define mpu401_read_data(emu, mpu) mpu401_read(emu, mpu, 0)#define mpu401_read_stat(emu, mpu) mpu401_read(emu, mpu, 1)#define mpu401_input_avail(emu,mpu) (!(mpu401_read_stat(emu,mpu) & 0x80))#define mpu401_output_ready(emu,mpu) (!(mpu401_read_stat(emu,mpu) & 0x40))#define MPU401_RESET 0xff#define MPU401_ENTER_UART 0x3f#define MPU401_ACK 0xfestatic void mpu401_clear_rx(emu10k1x_t *emu, emu10k1x_midi_t *mpu){ int timeout = 100000; for (; timeout > 0 && mpu401_input_avail(emu, mpu); timeout--) mpu401_read_data(emu, mpu);#ifdef CONFIG_SND_DEBUG if (timeout <= 0) snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", mpu401_read_stat(emu, mpu));#endif}/* */static void do_emu10k1x_midi_interrupt(emu10k1x_t *emu, emu10k1x_midi_t *midi, unsigned int status){ unsigned char byte; if (midi->rmidi == NULL) { snd_emu10k1x_intr_disable(emu, midi->tx_enable | midi->rx_enable); return; } spin_lock(&midi->input_lock); if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) { if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) { mpu401_clear_rx(emu, midi); } else { byte = mpu401_read_data(emu, midi); if (midi->substream_input) snd_rawmidi_receive(midi->substream_input, &byte, 1); } } spin_unlock(&midi->input_lock); spin_lock(&midi->output_lock); if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) { if (midi->substream_output && snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) { mpu401_write_data(emu, midi, byte); } else { snd_emu10k1x_intr_disable(emu, midi->tx_enable); } } spin_unlock(&midi->output_lock);}static void snd_emu10k1x_midi_interrupt(emu10k1x_t *emu, unsigned int status){ do_emu10k1x_midi_interrupt(emu, &emu->midi, status);}static void snd_emu10k1x_midi_cmd(emu10k1x_t * emu, emu10k1x_midi_t *midi, unsigned char cmd, int ack){ unsigned long flags; int timeout, ok; spin_lock_irqsave(&midi->input_lock, flags); mpu401_write_data(emu, midi, 0x00); /* mpu401_clear_rx(emu, midi); */ mpu401_write_cmd(emu, midi, cmd); if (ack) { ok = 0; timeout = 10000; while (!ok && timeout-- > 0) { if (mpu401_input_avail(emu, midi)) { if (mpu401_read_data(emu, midi) == MPU401_ACK) ok = 1; } } if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK) ok = 1; } else { ok = 1; } spin_unlock_irqrestore(&midi->input_lock, flags); if (!ok) snd_printk(KERN_ERR "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n", cmd, emu->port, mpu401_read_stat(emu, midi), mpu401_read_data(emu, midi));}static int snd_emu10k1x_midi_input_open(snd_rawmidi_substream_t * substream){ emu10k1x_t *emu; emu10k1x_midi_t *midi = (emu10k1x_midi_t *)substream->rmidi->private_data; unsigned long flags; emu = midi->emu; snd_assert(emu, return -ENXIO); spin_lock_irqsave(&midi->open_lock, flags); midi->midi_mode |= EMU10K1X_MIDI_MODE_INPUT; midi->substream_input = substream; if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT)) { spin_unlock_irqrestore(&midi->open_lock, flags); snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 1); snd_emu10k1x_midi_cmd(emu, midi, MPU401_ENTER_UART, 1); } else { spin_unlock_irqrestore(&midi->open_lock, flags); } return 0;}static int snd_emu10k1x_midi_output_open(snd_rawmidi_substream_t * substream){ emu10k1x_t *emu; emu10k1x_midi_t *midi = (emu10k1x_midi_t *)substream->rmidi->private_data; unsigned long flags; emu = midi->emu; snd_assert(emu, return -ENXIO); spin_lock_irqsave(&midi->open_lock, flags); midi->midi_mode |= EMU10K1X_MIDI_MODE_OUTPUT; midi->substream_output = substream; if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) { spin_unlock_irqrestore(&midi->open_lock, flags); snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 1); snd_emu10k1x_midi_cmd(emu, midi, MPU401_ENTER_UART, 1); } else { spin_unlock_irqrestore(&midi->open_lock, flags); } return 0;}static int snd_emu10k1x_midi_input_close(snd_rawmidi_substream_t * substream){ emu10k1x_t *emu; emu10k1x_midi_t *midi = (emu10k1x_midi_t *)substream->rmidi->private_data; unsigned long flags; emu = midi->emu; snd_assert(emu, return -ENXIO); spin_lock_irqsave(&midi->open_lock, flags); snd_emu10k1x_intr_disable(emu, midi->rx_enable); midi->midi_mode &= ~EMU10K1X_MIDI_MODE_INPUT; midi->substream_input = NULL; if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT)) { spin_unlock_irqrestore(&midi->open_lock, flags); snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 0); } else { spin_unlock_irqrestore(&midi->open_lock, flags); } return 0;}static int snd_emu10k1x_midi_output_close(snd_rawmidi_substream_t * substream){ emu10k1x_t *emu; emu10k1x_midi_t *midi = (emu10k1x_midi_t *)substream->rmidi->private_data; unsigned long flags; emu = midi->emu; snd_assert(emu, return -ENXIO); spin_lock_irqsave(&midi->open_lock, flags); snd_emu10k1x_intr_disable(emu, midi->tx_enable); midi->midi_mode &= ~EMU10K1X_MIDI_MODE_OUTPUT; midi->substream_output = NULL; if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) { spin_unlock_irqrestore(&midi->open_lock, flags); snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 0); } else { spin_unlock_irqrestore(&midi->open_lock, flags); } return 0;}static void snd_emu10k1x_midi_input_trigger(snd_rawmidi_substream_t * substream, int up){ emu10k1x_t *emu; emu10k1x_midi_t *midi = (emu10k1x_midi_t *)substream->rmidi->private_data; emu = midi->emu; snd_assert(emu, return); if (up) snd_emu10k1x_intr_enable(emu, midi->rx_enable); else snd_emu10k1x_intr_disable(emu, midi->rx_enable);}static void snd_emu10k1x_midi_output_trigger(snd_rawmidi_substream_t * substream, int up){ emu10k1x_t *emu; emu10k1x_midi_t *midi = (emu10k1x_midi_t *)substream->rmidi->private_data; unsigned long flags; emu = midi->emu; snd_assert(emu, return); if (up) { int max = 4; unsigned char byte; /* try to send some amount of bytes here before interrupts */ spin_lock_irqsave(&midi->output_lock, flags); while (max > 0) { if (mpu401_output_ready(emu, midi)) { if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT) || snd_rawmidi_transmit(substream, &byte, 1) != 1) { /* no more data */ spin_unlock_irqrestore(&midi->output_lock, flags); return; } mpu401_write_data(emu, midi, byte); max--; } else { break; } } spin_unlock_irqrestore(&midi->output_lock, flags); snd_emu10k1x_intr_enable(emu, midi->tx_enable); } else { snd_emu10k1x_intr_disable(emu, midi->tx_enable); }}/* */static snd_rawmidi_ops_t snd_emu10k1x_midi_output ={ .open = snd_emu10k1x_midi_output_open, .close = snd_emu10k1x_midi_output_close, .trigger = snd_emu10k1x_midi_output_trigger,};static snd_rawmidi_ops_t snd_emu10k1x_midi_input ={ .open = snd_emu10k1x_midi_input_open, .close = snd_emu10k1x_midi_input_close, .trigger = snd_emu10k1x_midi_input_trigger,};static void snd_emu10k1x_midi_free(snd_rawmidi_t *rmidi){ emu10k1x_midi_t *midi = (emu10k1x_midi_t *)rmidi->private_data; midi->interrupt = NULL; midi->rmidi = NULL;}static int __devinit emu10k1x_midi_init(emu10k1x_t *emu, emu10k1x_midi_t *midi, int device, char *name){ snd_rawmidi_t *rmidi; int err; if ((err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi)) < 0) return err; midi->emu = emu; spin_lock_init(&midi->open_lock); spin_lock_init(&midi->input_lock); spin_lock_init(&midi->output_lock); strcpy(rmidi->name, name); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_emu10k1x_midi_output); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_emu10k1x_midi_input); rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = midi; rmidi->private_free = snd_emu10k1x_midi_free; midi->rmidi = rmidi; return 0;}static int __devinit snd_emu10k1x_midi(emu10k1x_t *emu){ emu10k1x_midi_t *midi = &emu->midi; int err; if ((err = emu10k1x_midi_init(emu, midi, 0, "EMU10K1X MPU-401 (UART)")) < 0) return err; midi->tx_enable = INTE_MIDITXENABLE; midi->rx_enable = INTE_MIDIRXENABLE; midi->port = MUDATA; midi->ipr_tx = IPR_MIDITRANSBUFEMPTY; midi->ipr_rx = IPR_MIDIRECVBUFEMPTY; midi->interrupt = snd_emu10k1x_midi_interrupt; return 0;}static int __devinit snd_emu10k1x_probe(struct pci_dev *pci, const struct pci_device_id *pci_id){ static int dev; snd_card_t *card; emu10k1x_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_emu10k1x_create(card, pci, &chip)) < 0) { snd_card_free(card); return err; } if ((err = snd_emu10k1x_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); return err; } if ((err = snd_emu10k1x_pcm(chip, 1, NULL)) < 0) { snd_card_free(card); return err; } if ((err = snd_emu10k1x_pcm(chip, 2, NULL)) < 0) { snd_card_free(card); return err; } if ((err = snd_emu10k1x_ac97(chip)) < 0) { snd_card_free(card); return err; } if ((err = snd_emu10k1x_mixer(chip)) < 0) { snd_card_free(card); return err; } if ((err = snd_emu10k1x_midi(chip)) < 0) { snd_card_free(card); return err; } snd_emu10k1x_proc_init(chip); strcpy(card->driver, "EMU10K1X"); strcpy(card->shortname, "Dell Sound Blaster Live!"); sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->port, chip->irq); 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_emu10k1x_remove(struct pci_dev *pci){ snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL);}// PCI IDsstatic struct pci_device_id snd_emu10k1x_ids[] = { { 0x1102, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Dell OEM version (EMU10K1) */ { 0, }};MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids);// pci_driver definitionstatic struct pci_driver driver = { .name = "EMU10K1X", .id_table = snd_emu10k1x_ids, .probe = snd_emu10k1x_probe, .remove = __devexit_p(snd_emu10k1x_remove),};// initialization of the modulestatic int __init alsa_card_emu10k1x_init(void){ int err; if ((err = pci_register_driver(&driver)) > 0) return err; return 0;}// clean up the modulestatic void __exit alsa_card_emu10k1x_exit(void){ pci_unregister_driver(&driver);}module_init(alsa_card_emu10k1x_init)module_exit(alsa_card_emu10k1x_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -