📄 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. * *********************************************************************//* These are only included once per module */#include <linux/version.h>#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 #define DRIVER_VERSION "0.18"/* 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#define EMU_APS_SUBID 0x40011102 enum { EMU10K1 = 0,};static char *card_names[] __devinitdata = { "EMU10K1",};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}, {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 void emu10k1_interrupt(int, void *, struct pt_regs *s);static int __devinit emu10k1_audio_init(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; } /* Assign default playback voice parameters */ card->mchannel_fx = 8; /* mono voice */ card->waveout.send_a[0] = 0xff; card->waveout.send_b[0] = 0xff; card->waveout.send_c[0] = 0x00; card->waveout.send_d[0] = 0x00; card->waveout.send_routing[0] = 0x3210; /* stereo voice */ /* left */ card->waveout.send_a[1] = 0xff; card->waveout.send_b[1] = 0x00; card->waveout.send_c[1] = 0x00; card->waveout.send_d[1] = 0x00; card->waveout.send_routing[1] = 0x3210; /* right */ card->waveout.send_a[2] = 0x00; card->waveout.send_b[2] = 0xff; card->waveout.send_c[2] = 0x00; card->waveout.send_d[2] = 0x00; card->waveout.send_routing[2] = 0x3210; /* Assign default recording parameters */ /* FIXME */ if(card->isaps) card->wavein.recsrc = WAVERECORD_FX; else card->wavein.recsrc = WAVERECORD_AC97; card->wavein.fxwc = 0x0003; return 0;err_dev1: unregister_sound_dsp(card->audio_dev);err_dev: return -ENODEV;}static void __devinit emu10k1_audio_cleanup(struct emu10k1_card *card){ unregister_sound_dsp(card->audio_dev1); unregister_sound_dsp(card->audio_dev);}static int __devinit emu10k1_mixer_init(struct emu10k1_card *card){ char s[32]; struct ac97_codec *codec = &card->ac97; 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"); return -EIO; } card->ac97.private_data = card; if (!card->isaps) { 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; if (!proc_mkdir ("driver/emu10k1", 0)) { printk(KERN_ERR "emu10k1: unable to create proc directory driver/emu10k1\n"); goto err_out; } sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name); if (!proc_mkdir (s, 0)) { printk(KERN_ERR "emu10k1: unable to create proc directory %s\n", s); goto err_emu10k1_proc; } sprintf(s, "driver/emu10k1/%s/ac97", card->pci_dev->slot_name); if (!create_proc_read_entry (s, 0, 0, ac97_read_proc, &card->ac97)) { printk(KERN_ERR "emu10k1: unable to create proc entry %s\n", s); goto err_ac97_proc; } /* 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_ac97_proc: sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name); remove_proc_entry(s, NULL); err_emu10k1_proc: remove_proc_entry("driver/emu10k1", NULL); err_out: unregister_sound_mixer (card->ac97.dev_mixer); return -EIO;}static void __devinit emu10k1_mixer_cleanup(struct emu10k1_card *card){ char s[32]; if (!card->isaps) { sprintf(s, "driver/emu10k1/%s/ac97", card->pci_dev->slot_name); remove_proc_entry(s, NULL); sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name); remove_proc_entry(s, NULL); remove_proc_entry("driver/emu10k1", NULL); } unregister_sound_mixer (card->ac97.dev_mixer);}static int __devinit emu10k1_midi_init(struct emu10k1_card *card){ int ret; card->midi_dev = register_sound_midi(&emu10k1_midi_fops, -1); if (card->midi_dev < 0) { printk(KERN_ERR "emu10k1: cannot register midi device!\n"); return -ENODEV; } 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; goto err_out3; }#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 0; } 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 = 0;#endif return 0;err_out3: kfree(card->mpuin);err_out2: kfree(card->mpuout);err_out1: unregister_sound_midi(card->midi_dev); return ret;}static void __devinit emu10k1_midi_cleanup(struct emu10k1_card *card){ tasklet_kill(&card->mpuout->tasklet); kfree(card->mpuout); tasklet_kill(&card->mpuin->tasklet); kfree(card->mpuin);#ifdef EMU10K1_SEQUENCER if (card->seq_dev > -1) { kfree(midi_devs[card->seq_dev]); midi_devs[card->seq_dev] = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -