📄 main.c
字号:
/* ********************************************************************** * main.c - Creative EMU10K1 audio driver * Copyright 1999, 2000 Creative Labs, Inc. * ********************************************************************** * * Date Author Summary of changes * ---- ------ ------------------ * October 20, 1999 Bertrand Lee base code release * November 2, 1999 Alan Cox cleaned up stuff * ********************************************************************** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, * USA. * ********************************************************************** * * Supported devices: * /dev/dsp: Standard /dev/dsp device, OSS-compatible * /dev/dsp1: Routes to rear speakers only * /dev/mixer: Standard /dev/mixer device, OSS-compatible * /dev/midi: Raw MIDI UART device, mostly OSS-compatible * /dev/sequencer: Sequencer Interface (requires sound.o) * * Revision history: * 0.1 beta Initial release * 0.2 Lowered initial mixer vol. Improved on stuttering wave playback. Added MIDI UART support. * 0.3 Fixed mixer routing bug, added APS, joystick support. * 0.4 Added rear-channel, SPDIF support. * 0.5 Source cleanup, SMP fixes, multiopen support, 64 bit arch fixes, * moved bh's to tasklets, moved to the new PCI driver initialization style. * 0.6 Make use of pci_alloc_consistent, improve compatibility layer for 2.2 kernels, * code reorganization and cleanup. * 0.7 Support for the Emu-APS. Bug fixes for voice cache setup, mmaped sound + poll(). * Support for setting external TRAM size. * 0.8 Make use of the kernel ac97 interface. Support for a dsp patch manager. * 0.9 Re-enables rear speakers volume controls * 0.10 Initializes rear speaker volume. * Dynamic patch storage allocation. * New private ioctls to change control gpr values. * Enable volume control interrupts. * By default enable dsp routes to digital out. * 0.11 Fixed fx / 4 problem. * 0.12 Implemented mmaped for recording. * Fixed bug: not unreserving mmaped buffer pages. * IRQ handler cleanup. * 0.13 Fixed problem with dsp1 * Simplified dsp patch writing (inside the driver) * Fixed several bugs found by the Stanford tools * 0.14 New control gpr to oss mixer mapping feature (Chris Purnell) * Added AC3 Passthrough Support (Juha Yrjola) * Added Support for 5.1 cards (digital out and the third analog out) * 0.15 Added Sequencer Support (Daniel Mack) * Support for multichannel pcm playback (Eduard Hasenleithner) * 0.16 Mixer improvements, added old treble/bass support (Daniel Bertrand) * Small code format cleanup. * Deadlock bug fix for emu10k1_volxxx_irqhandler(). * 0.17 Fix for mixer SOUND_MIXER_INFO ioctl. * Fix for HIGHMEM machines (emu10k1 can only do 31 bit bus master) * midi poll initial implementation. * Small mixer fixes/cleanups. * Improved support for 5.1 cards. * 0.18 Fix for possible leak in pci_alloc_consistent() * Cleaned up poll() functions (audio and midi). Don't start input. * Restrict DMA pages used to 512Mib range. * New AC97_BOOST mixer ioctl. * 0.19a Added Support for Audigy Cards * Real fix for kernel with highmem support (cast dma_handle to u32). * Fix recording buffering parameters calculation. * Use unsigned long for variables in bit ops. * 0.20a Fixed recording startup * Fixed timer rate setting (it's a 16-bit register) * 0.21 Converted code to use pci_name() instead of accessing slot_name * directly (Eugene Teo) *********************************************************************//* These are only included once per module */#include <linux/module.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/proc_fs.h>#include "hwaccess.h"#include "8010.h"#include "efxmgr.h"#include "cardwo.h"#include "cardwi.h"#include "cardmo.h"#include "cardmi.h"#include "recmgr.h"#include "ecard.h"#ifdef EMU10K1_SEQUENCER#define MIDI_SYNTH_NAME "EMU10K1 MIDI"#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT #include "../sound_config.h"#include "../midi_synth.h"/* this should be in dev_table.h */#define SNDCARD_EMU10K1 46#endif /* the emu10k1 _seems_ to only supports 29 bit (512MiB) bit bus master */#define EMU10K1_DMA_MASK 0x1fffffff /* DMA buffer mask for pci_alloc_consist */#ifndef PCI_VENDOR_ID_CREATIVE#define PCI_VENDOR_ID_CREATIVE 0x1102#endif#ifndef PCI_DEVICE_ID_CREATIVE_EMU10K1#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002#endif#ifndef PCI_DEVICE_ID_CREATIVE_AUDIGY#define PCI_DEVICE_ID_CREATIVE_AUDIGY 0x0004#endif#define EMU_APS_SUBID 0x40011102 enum { EMU10K1 = 0, AUDIGY,};static char *card_names[] __devinitdata = { "EMU10K1", "Audigy",};static struct pci_device_id emu10k1_pci_tbl[] = { {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, EMU10K1}, {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_AUDIGY, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AUDIGY}, {0,}};MODULE_DEVICE_TABLE(pci, emu10k1_pci_tbl);/* Global var instantiation */LIST_HEAD(emu10k1_devs);extern struct file_operations emu10k1_audio_fops;extern struct file_operations emu10k1_mixer_fops;extern struct file_operations emu10k1_midi_fops;#ifdef EMU10K1_SEQUENCERstatic struct midi_operations emu10k1_midi_operations;#endifextern irqreturn_t emu10k1_interrupt(int, void *, struct pt_regs *s);static int __devinit emu10k1_audio_init(struct emu10k1_card *card){ /* Assign default playback voice parameters */ if (card->is_audigy) card->mchannel_fx = 0; else card->mchannel_fx = 8; if (card->is_audigy) { /* mono voice */ card->waveout.send_dcba[SEND_MONO] = 0xffffffff; card->waveout.send_hgfe[SEND_MONO] = 0x0000ffff; /* stereo voice */ /* left */ card->waveout.send_dcba[SEND_LEFT] = 0x00ff00ff; card->waveout.send_hgfe[SEND_LEFT] = 0x00007f7f; /* right */ card->waveout.send_dcba[SEND_RIGHT] = 0xff00ff00; card->waveout.send_hgfe[SEND_RIGHT] = 0x00007f7f; card->waveout.send_routing[ROUTE_PCM] = 0x03020100; // Regular pcm card->waveout.send_routing2[ROUTE_PCM] = 0x07060504; card->waveout.send_routing[ROUTE_PT] = 0x3f3f3d3c; // Passthrough card->waveout.send_routing2[ROUTE_PT] = 0x3f3f3f3f; card->waveout.send_routing[ROUTE_PCM1] = 0x03020100; // Spare card->waveout.send_routing2[ROUTE_PCM1] = 0x07060404; } else { /* mono voice */ card->waveout.send_dcba[SEND_MONO] = 0x0000ffff; /* stereo voice */ /* left */ card->waveout.send_dcba[SEND_LEFT] = 0x000000ff; /* right */ card->waveout.send_dcba[SEND_RIGHT] = 0x0000ff00; card->waveout.send_routing[ROUTE_PCM] = 0x3210; // pcm card->waveout.send_routing[ROUTE_PT] = 0x3210; // passthrough card->waveout.send_routing[ROUTE_PCM1] = 0x7654; // /dev/dsp1 } /* Assign default recording parameters */ /* FIXME */ if (card->is_aps) card->wavein.recsrc = WAVERECORD_FX; else card->wavein.recsrc = WAVERECORD_AC97; card->wavein.fxwc = 0x0003; return 0;}static void emu10k1_audio_cleanup(struct emu10k1_card *card){}static int __devinit emu10k1_register_devices(struct emu10k1_card *card){ card->audio_dev = register_sound_dsp(&emu10k1_audio_fops, -1); if (card->audio_dev < 0) { printk(KERN_ERR "emu10k1: cannot register first audio device!\n"); goto err_dev; } card->audio_dev1 = register_sound_dsp(&emu10k1_audio_fops, -1); if (card->audio_dev1 < 0) { printk(KERN_ERR "emu10k1: cannot register second audio device!\n"); goto err_dev1; } card->ac97->dev_mixer = register_sound_mixer(&emu10k1_mixer_fops, -1); if (card->ac97->dev_mixer < 0) { printk(KERN_ERR "emu10k1: cannot register mixer device\n"); goto err_mixer; } card->midi_dev = register_sound_midi(&emu10k1_midi_fops, -1); if (card->midi_dev < 0) { printk(KERN_ERR "emu10k1: cannot register midi device!\n"); goto err_midi; }#ifdef EMU10K1_SEQUENCER card->seq_dev = sound_alloc_mididev(); if (card->seq_dev == -1) printk(KERN_WARNING "emu10k1: unable to register sequencer device!"); else { std_midi_synth.midi_dev = card->seq_dev; midi_devs[card->seq_dev] = (struct midi_operations *) kmalloc(sizeof(struct midi_operations), GFP_KERNEL); if (midi_devs[card->seq_dev] == NULL) { printk(KERN_ERR "emu10k1: unable to allocate memory!"); sound_unload_mididev(card->seq_dev); card->seq_dev = -1; /* return without error */ } else { memcpy((char *)midi_devs[card->seq_dev], (char *)&emu10k1_midi_operations, sizeof(struct midi_operations)); midi_devs[card->seq_dev]->devc = card; sequencer_init(); card->seq_mididev = NULL; } }#endif return 0;err_midi: unregister_sound_mixer(card->ac97->dev_mixer);err_mixer: unregister_sound_dsp(card->audio_dev);err_dev1: unregister_sound_dsp(card->audio_dev);err_dev: return -ENODEV;}static void emu10k1_unregister_devices(struct emu10k1_card *card){#ifdef EMU10K1_SEQUENCER if (card->seq_dev > -1) { kfree(midi_devs[card->seq_dev]); midi_devs[card->seq_dev] = NULL; sound_unload_mididev(card->seq_dev); card->seq_dev = -1; }#endif unregister_sound_midi(card->midi_dev); unregister_sound_mixer(card->ac97->dev_mixer); unregister_sound_dsp(card->audio_dev1); unregister_sound_dsp(card->audio_dev);}static int emu10k1_info_proc (char *page, char **start, off_t off, int count, int *eof, void *data){ struct emu10k1_card *card = data; int len = 0; if (card == NULL) return -ENODEV; len += sprintf (page + len, "Driver Version : %s\n", DRIVER_VERSION); len += sprintf (page + len, "Card type : %s\n", card->is_aps ? "Aps" : (card->is_audigy ? "Audigy" : "Emu10k1")); len += sprintf (page + len, "Revision : %d\n", card->chiprev); len += sprintf (page + len, "Model : %#06x\n", card->model); len += sprintf (page + len, "IO : %#06lx-%#06lx\n", card->iobase, card->iobase + card->length - 1); len += sprintf (page + len, "IRQ : %d\n\n", card->irq); len += sprintf (page + len, "Registered /dev Entries:\n"); len += sprintf (page + len, "/dev/dsp%d\n", card->audio_dev / 16); len += sprintf (page + len, "/dev/dsp%d\n", card->audio_dev1 / 16); len += sprintf (page + len, "/dev/mixer%d\n", card->ac97->dev_mixer / 16); len += sprintf (page + len, "/dev/midi%d\n", card->midi_dev / 16);#ifdef EMU10K1_SEQUENCER len += sprintf (page + len, "/dev/sequencer\n");#endif return len;}static int __devinit emu10k1_proc_init(struct emu10k1_card *card){ char s[48]; if (!proc_mkdir ("driver/emu10k1", NULL)) { printk(KERN_ERR "emu10k1: unable to create proc directory driver/emu10k1\n"); goto err_out; } sprintf(s, "driver/emu10k1/%s", pci_name(card->pci_dev)); if (!proc_mkdir (s, NULL)) { printk(KERN_ERR "emu10k1: unable to create proc directory %s\n", s); goto err_emu10k1_proc; } sprintf(s, "driver/emu10k1/%s/info", pci_name(card->pci_dev)); if (!create_proc_read_entry (s, 0, NULL, emu10k1_info_proc, card)) { printk(KERN_ERR "emu10k1: unable to create proc entry %s\n", s); goto err_dev_proc; } if (!card->is_aps) { sprintf(s, "driver/emu10k1/%s/ac97", pci_name(card->pci_dev)); if (!create_proc_read_entry (s, 0, NULL, ac97_read_proc, card->ac97)) { printk(KERN_ERR "emu10k1: unable to create proc entry %s\n", s); goto err_proc_ac97; } } return 0;err_proc_ac97: sprintf(s, "driver/emu10k1/%s/info", pci_name(card->pci_dev)); remove_proc_entry(s, NULL);err_dev_proc: sprintf(s, "driver/emu10k1/%s", pci_name(card->pci_dev)); remove_proc_entry(s, NULL);err_emu10k1_proc: remove_proc_entry("driver/emu10k1", NULL);err_out: return -EIO;}static void emu10k1_proc_cleanup(struct emu10k1_card *card){ char s[48]; if (!card->is_aps) { sprintf(s, "driver/emu10k1/%s/ac97", pci_name(card->pci_dev)); remove_proc_entry(s, NULL); } sprintf(s, "driver/emu10k1/%s/info", pci_name(card->pci_dev)); remove_proc_entry(s, NULL); sprintf(s, "driver/emu10k1/%s", pci_name(card->pci_dev)); remove_proc_entry(s, NULL); remove_proc_entry("driver/emu10k1", NULL);}static int __devinit emu10k1_mixer_init(struct emu10k1_card *card){ struct ac97_codec *codec = ac97_alloc_codec(); if(codec == NULL) { printk(KERN_ERR "emu10k1: cannot allocate mixer\n"); return -EIO; } card->ac97 = codec; card->ac97->private_data = card; if (!card->is_aps) { card->ac97->id = 0; card->ac97->codec_read = emu10k1_ac97_read; card->ac97->codec_write = emu10k1_ac97_write; if (ac97_probe_codec (card->ac97) == 0) { printk(KERN_ERR "emu10k1: unable to probe AC97 codec\n"); goto err_out; } /* 5.1: Enable the additional AC97 Slots and unmute extra channels on AC97 codec */ if (codec->codec_read(codec, AC97_EXTENDED_ID) & 0x0080){ printk(KERN_INFO "emu10k1: SBLive! 5.1 card detected\n"); sblive_writeptr(card, AC97SLOT, 0, AC97SLOT_CNTR | AC97SLOT_LFE); codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0); } // Force 5bit: //card->ac97->bit_resolution=5; /* these will store the original values and never be modified */ card->ac97_supported_mixers = card->ac97->supported_mixers; card->ac97_stereo_mixers = card->ac97->stereo_mixers; } return 0; err_out: ac97_release_codec(card->ac97); return -EIO;}static void emu10k1_mixer_cleanup(struct emu10k1_card *card){ ac97_release_codec(card->ac97);}static int __devinit emu10k1_midi_init(struct emu10k1_card *card){ int ret; card->mpuout = kmalloc(sizeof(struct emu10k1_mpuout), GFP_KERNEL); if (card->mpuout == NULL) { printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuout: out of memory\n"); ret = -ENOMEM; goto err_out1; } memset(card->mpuout, 0, sizeof(struct emu10k1_mpuout)); card->mpuout->intr = 1; card->mpuout->status = FLAGS_AVAILABLE; card->mpuout->state = CARDMIDIOUT_STATE_DEFAULT; tasklet_init(&card->mpuout->tasklet, emu10k1_mpuout_bh, (unsigned long) card); spin_lock_init(&card->mpuout->lock); card->mpuin = kmalloc(sizeof(struct emu10k1_mpuin), GFP_KERNEL); if (card->mpuin == NULL) { printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuin: out of memory\n"); ret = -ENOMEM; goto err_out2; } memset(card->mpuin, 0, sizeof(struct emu10k1_mpuin)); card->mpuin->status = FLAGS_AVAILABLE; tasklet_init(&card->mpuin->tasklet, emu10k1_mpuin_bh, (unsigned long) card->mpuin); spin_lock_init(&card->mpuin->lock); /* Reset the MPU port */ if (emu10k1_mpu_reset(card) < 0) { ERROR(); ret = -EIO;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -