⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 maestro3.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 5 页
字号:
/***************************************************************************** * *      ESS Maestro3/Allegro driver for Linux 2.4.x * *      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. * *    (c) Copyright 2000 Zach Brown <zab@zabbo.net> * * I need to thank many people for helping make this driver happen.   * As always, Eric Brombaugh was a hacking machine and killed many bugs * that I was too dumb to notice.  Howard Kim at ESS provided reference boards  * and as much docs as he could.  Todd and Mick at Dell tested snapshots on  * an army of laptops.  msw and deviant at Red Hat also humoured me by hanging * their laptops every few hours in the name of science. *  * Shouts go out to Mike "DJ XPCom" Ang. * * History *  v1.22 - Feb 28 2001 - Zach Brown <zab@zabbo.net> *   allocate mem at insmod/setup, rather than open *   limit pci dma addresses to 28bit, thanks guys. *  v1.21 - Feb 04 2001 - Zach Brown <zab@zabbo.net> *   fix up really dumb notifier -> suspend oops *  v1.20 - Jan 30 2001 - Zach Brown <zab@zabbo.net> *   get rid of pm callback and use pci_dev suspend/resume instead *   m3_probe cleanups, including pm oops think-o *  v1.10 - Jan 6 2001 - Zach Brown <zab@zabbo.net> *   revert to lame remap_page_range mmap() just to make it work *   record mmap fixed. *   fix up incredibly broken open/release resource management *   duh.  fix record format setting. *   add SMP locking and cleanup formatting here and there *  v1.00 - Dec 16 2000 - Zach Brown <zab@zabbo.net> *   port to sexy 2.4 interfaces *   properly align instance allocations so recording works *   clean up function namespace a little :/ *   update PCI IDs based on mail from ESS *   arbitrarily bump version number to show its 2.4 now,  *      2.2 will stay 0., oss_audio port gets 2. *  v0.03 - Nov 05 2000 - Zach Brown <zab@zabbo.net> *   disable recording but allow dsp to be opened read  *   pull out most silly compat defines *  v0.02 - Nov 04 2000 - Zach Brown <zab@zabbo.net> *   changed clocking setup for m3, slowdown fixed. *   codec reset is hopefully reliable now *   rudimentary apm/power management makes suspend/resume work *  v0.01 - Oct 31 2000 - Zach Brown <zab@zabbo.net> *   first release *  v0.00 - Sep 09 2000 - Zach Brown <zab@zabbo.net> *   first pass derivation from maestro.c * * TODO *  in/out allocated contiguously so fullduplex mmap will work? *  no beep on init (mute) *  resetup msrc data memory if freq changes? * *  -- * *  Allow me to ramble a bit about the m3 architecture.  The core of the *  chip is the 'assp', the custom ESS dsp that runs the show.  It has *  a small amount of code and data ram.  ESS drops binary dsp code images *  on our heads, but we don't get to see specs on the dsp.   * *  The constant piece of code on the dsp is the 'kernel'.  It also has a  *  chunk of the dsp memory that is statically set aside for its control *  info.  This is the KDATA defines in maestro3.h.  Part of its core *  data is a list of code addresses that point to the pieces of DSP code *  that it should walk through in its loop.  These other pieces of code *  do the real work.  The kernel presumably jumps into each of them in turn. *  These code images tend to have their own data area, and one can have *  multiple data areas representing different states for each of the 'client *  instance' code portions.  There is generally a list in the kernel data *  that points to the data instances for a given piece of code. * *  We've only been given the binary image for the 'minisrc', mini sample  *  rate converter.  This is rather annoying because it limits the work *  we can do on the dsp, but it also greatly simplifies the job of managing *  dsp data memory for the code and data for our playing streams :).  We *  statically allocate the minisrc code into a region we 'know' to be free *  based on the map of the binary kernel image we're loading.  We also  *  statically allocate the data areas for the maximum number of pcm streams *  we can be dealing with.  This max is set by the length of the static list *  in the kernel data that records the number of minisrc data regions we *  can have.  Thats right, all software dsp mixing with static code list *  limits.  Rock. * *  How sound goes in and out is still a relative mystery.  It appears *  that the dsp has the ability to get input and output through various *  'connections'.  To do IO from or to a connection, you put the address *  of the minisrc client area in the static kernel data lists for that  *  input or output.  so for pcm -> dsp -> mixer, we put the minisrc data *  instance in the DMA list and also in the list for the mixer.  I guess *  it Just Knows which is in/out, and we give some dma control info that *  helps.  There are all sorts of cool inputs/outputs that it seems we can't *  use without dsp code images that know how to use them. * *  So at init time we preload all the memory allocation stuff and set some *  system wide parameters.  When we really get a sound to play we build *  up its minisrc header (stream parameters, buffer addresses, input/output *  settings).  Then we throw its header on the various lists.  We also *  tickle some KDATA settings that ask the assp to raise clock interrupts *  and do some amount of software mixing before handing data to the ac97. * *  Sorry for the vague details.  Feel free to ask Eric or myself if you *  happen to be trying to use this driver elsewhere.  Please accept my *  apologies for the quality of the OSS support code, its passed through *  too many hands now and desperately wants to be rethought. *//*****************************************************************************/#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/ctype.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/sound.h>#include <linux/slab.h>#include <linux/soundcard.h>#include <linux/pci.h>#include <linux/vmalloc.h>#include <asm/io.h>#include <asm/dma.h>#include <linux/init.h>#include <linux/poll.h>#include <linux/reboot.h>#include <asm/uaccess.h>#include <asm/hardirq.h>#include <linux/spinlock.h>#include <linux/ac97_codec.h> /*  * for crizappy mmap()  */#include <linux/wrapper.h>#include "maestro3.h"#define M_DEBUG 1#define DRIVER_VERSION      "1.22"#define M3_MODULE_NAME      "maestro3"#define PFX                 M3_MODULE_NAME ": "#define M3_STATE_MAGIC      0x734d724d#define M3_CARD_MAGIC       0x646e6f50#define ESS_FMT_STEREO      0x01#define ESS_FMT_16BIT       0x02#define ESS_FMT_MASK        0x03#define ESS_DAC_SHIFT       0   #define ESS_ADC_SHIFT       4#define DAC_RUNNING         1#define ADC_RUNNING         2#define SND_DEV_DSP16       5    #ifdef M_DEBUGstatic int debug;#define DPMOD   1   /* per module load */#define DPSTR   2   /* per 'stream' */#define DPSYS   3   /* per syscall */#define DPCRAP  4   /* stuff the user shouldn't see unless they're really debuggin */#define DPINT   5   /* per interrupt, LOTS */#define DPRINTK(DP, args...) {if (debug >= (DP)) printk(KERN_DEBUG PFX args);}#else#define DPRINTK(x)#endifstruct m3_list {    int curlen;    u16 mem_addr;    int max;};int external_amp = 1;struct m3_state {    unsigned int magic;    struct m3_card *card;    unsigned char fmt, enable;    int index;    /* this locks around the oss state in the driver */    spinlock_t lock;    struct semaphore open_sem;    wait_queue_head_t open_wait;    mode_t open_mode;    int dev_audio;    struct assp_instance {        u16 code, data;    } dac_inst, adc_inst;    /* should be in dmabuf */    unsigned int rateadc, ratedac;    struct dmabuf {        void *rawbuf;        unsigned buforder;        unsigned numfrag;        unsigned fragshift;        unsigned hwptr, swptr;        unsigned total_bytes;        int count;        unsigned error; /* over/underrun */        wait_queue_head_t wait;        /* redundant, but makes calculations easier */        unsigned fragsize;        unsigned dmasize;        unsigned fragsamples;        /* OSS stuff */        unsigned mapped:1;        unsigned ready:1;            unsigned endcleared:1;        unsigned ossfragshift;        int ossmaxfrags;        unsigned subdivision;        /* new in m3 */        int mixer_index, dma_index, msrc_index, adc1_index;        int in_lists;        /* 2.4.. */        dma_addr_t handle;    } dma_dac, dma_adc;};    struct m3_card {    unsigned int magic;    struct m3_card *next;    struct ac97_codec *ac97;    spinlock_t ac97_lock;    int card_type;#define NR_DSPS 1#define MAX_DSPS NR_DSPS    struct m3_state channels[MAX_DSPS];    /* this locks around the physical registers on the card */    spinlock_t lock;    /* hardware resources */    struct pci_dev *pcidev;    u32 iobase;    u32 irq;    int dacs_active;    int timer_users;    struct m3_list  msrc_list,                    mixer_list,                    adc1_list,                    dma_list;    /* for storing reset state..*/    u8 reset_state;    u16 *suspend_mem;    int in_suspend;    wait_queue_head_t suspend_queue;};/* * an arbitrary volume we set the internal * volume settings to so that the ac97 volume * range is a little less insane.  0x7fff is  * max. */#define ARB_VOLUME ( 0x6800 )static const unsigned sample_shift[] = { 0, 1, 1, 2 };enum {    ESS_ALLEGRO,    ESS_MAESTRO3,    /*     * a maestro3 with 'hardware strapping', only     * found inside ESS?     */    ESS_MAESTRO3HW,};static char *card_names[] = {    [ESS_ALLEGRO] = "Allegro",    [ESS_MAESTRO3] = "Maestro3(i)",    [ESS_MAESTRO3HW] = "Maestro3(i)hw"};#ifndef PCI_VENDOR_ESS#define PCI_VENDOR_ESS      0x125D#endif#define M3_DEVICE(DEV, TYPE)                \{                                           \vendor: PCI_VENDOR_ESS,                     \device: DEV,                                \subvendor: PCI_ANY_ID,                      \subdevice: PCI_ANY_ID,                      \class:  PCI_CLASS_MULTIMEDIA_AUDIO << 8,    \class_mask: 0xffff << 8,                    \driver_data: TYPE,                          \}static struct pci_device_id m3_id_table[] __initdata = {    M3_DEVICE(0x1988, ESS_ALLEGRO),    M3_DEVICE(0x1998, ESS_MAESTRO3),    M3_DEVICE(0x199a, ESS_MAESTRO3HW),    {0,}};MODULE_DEVICE_TABLE (pci, m3_id_table);/* * reports seem to indicate that the m3 is limited * to 28bit bus addresses.  aaaargggh... */#define M3_PCI_DMA_MASK 0x0fffffffstatic unsigned ld2(unsigned int x){    unsigned r = 0;        if (x >= 0x10000) {        x >>= 16;        r += 16;    }    if (x >= 0x100) {        x >>= 8;        r += 8;    }    if (x >= 0x10) {        x >>= 4;        r += 4;    }    if (x >= 4) {        x >>= 2;        r += 2;    }    if (x >= 2)        r++;    return r;}static struct m3_card *devs;/* * I'm not very good at laying out functions in a file :) */static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf);static int m3_suspend(struct pci_dev *pci_dev, u32 state);static void check_suspend(struct m3_card *card);struct notifier_block m3_reboot_nb = {m3_notifier, NULL, 0};static void m3_outw(struct m3_card *card,        u16 value, unsigned long reg){    check_suspend(card);    outw(value, card->iobase + reg);}static u16 m3_inw(struct m3_card *card, unsigned long reg){    check_suspend(card);    return inw(card->iobase + reg);}static void m3_outb(struct m3_card *card,         u8 value, unsigned long reg){    check_suspend(card);    outb(value, card->iobase + reg);}static u8 m3_inb(struct m3_card *card, unsigned long reg){    check_suspend(card);    return inb(card->iobase + reg);}/* * access 16bit words to the code or data regions of the dsp's memory. * index addresses 16bit words. */static u16 __m3_assp_read(struct m3_card *card, u16 region, u16 index){    m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);    m3_outw(card, index, DSP_PORT_MEMORY_INDEX);    return m3_inw(card, DSP_PORT_MEMORY_DATA);}static u16 m3_assp_read(struct m3_card *card, u16 region, u16 index){    unsigned long flags;    u16 ret;    spin_lock_irqsave(&(card->lock), flags);    ret = __m3_assp_read(card, region, index);    spin_unlock_irqrestore(&(card->lock), flags);    return ret;}static void __m3_assp_write(struct m3_card *card,         u16 region, u16 index, u16 data){    m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);    m3_outw(card, index, DSP_PORT_MEMORY_INDEX);    m3_outw(card, data, DSP_PORT_MEMORY_DATA);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -