From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from m13-130.163.com (m13-130.163.com [220.181.13.130]) by ozlabs.org (Postfix) with SMTP id 30A99DDDD8 for ; Fri, 13 Jul 2007 15:22:57 +1000 (EST) Date: Fri, 13 Jul 2007 13:22:54 +0800 (CST) From: silicom To: linuxppc-embedded@ozlabs.org Message-ID: <165516780.1952051184304174471.JavaMail.coremail@bj163app130.163.com> Subject: can anyone help me to test my ac97 driver MIME-Version: 1.0 Content-Type: multipart/Alternative; boundary="----=_Part_199439_1166067786.1184304174470" List-Id: Linux on Embedded PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , ------=_Part_199439_1166067786.1184304174470 Content-Type: text/plain; charset=gbk Content-Transfer-Encoding: 7bit Hi I have a simple oss ac97 playback driver for xilinx ml403 and linux2.6.17 kernel,but when I test it with a *.wav file with sample rate 44.1k, there is much noisy, and I want to know whether there's problem with my ml403 board or ac97 driver,could anyone be kind to help me test it on your board or point out my problem? thanks below is my code "xilinx_ac97_adapter.c" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include #include "xparameters.h" #include "xac97_l.h" #include "xio.h" #define XILINX_AC97 #define DRIVER_VERSION "1.00a" #define AC97_BASEADDR XPAR_OPB_AC97_CONTROLLER_REF_0_BASEADDR #define AC97_HIGHADDR XPAR_OPB_AC97_CONTROLLER_REF_0_HIGHADDR /* AC97 codec initialisation. */ static struct ac97_codec *xilinx_ac97_codec = NULL; static int dev_audio = -1; #define BUFFER_SIZE 32768 #define XILINX_AC97_PLAYBACK_INTERRUPT 7 struct xilinx_ac97_state { struct semaphore open_sem; /* Device access */ struct semaphore sem; /* File access */ spinlock_t lock; /* State */ spinlock_t ac97_lock; struct ac97_codec *ac97; char *buffer; int multichannel; int dsp; /* OSS handle */ int trigger; /* mmap I/O trigger */ int halfFull; // struct forte_channel play; // struct forte_channel rec; }; static struct xilinx_ac97_state *state; static int halfEmpty; static DECLARE_WAIT_QUEUE_HEAD(ac97_queue); static int emptyTime; static u16 xilinx_ac97_get(struct ac97_codec *dev, u8 reg); static void xilinx_ac97_set(struct ac97_codec *dev, u8 reg, u16 data); static void xilinx_ac97_codec_wait(struct ac97_codec *dev); static irqreturn_t xilinx_ac97_interrupt(int irq, void * dev_id, struct pt_regs *regs) { disable_irq(XILINX_AC97_PLAYBACK_INTERRUPT); halfEmpty = 1; wake_up_interruptible(&ac97_queue); return IRQ_HANDLED; } static u16 xilinx_ac97_get(struct ac97_codec *dev, u8 reg) { return XAC97_ReadReg((u32)dev->private_data, reg); } static void xilinx_ac97_set(struct ac97_codec *dev, u8 reg, u16 data) { XAC97_WriteReg((u32)dev->private_data, reg, data); } static void xilinx_ac97_codec_wait(struct ac97_codec *dev) { XAC97_AwaitCodecReady((u32)dev->private_data); } /* OSS /dev/mixer file operation methods */ static int xilinx_ac97_open_mixdev(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); if (xilinx_ac97_codec && xilinx_ac97_codec->dev_mixer == minor) { file->private_data = xilinx_ac97_codec; return 0; } return -ENODEV; } static int xilinx_ac97_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct ac97_codec *codec = (struct ac97_codec *) file->private_data; return codec->mixer_ioctl(codec, cmd, arg); } static /*const */ struct file_operations xilinx_ac97_mixer_fops = { owner:THIS_MODULE, llseek:no_llseek, ioctl:xilinx_ac97_ioctl_mixdev, open:xilinx_ac97_open_mixdev, }; static int xilinx_ac97_open(struct inode *inode, struct file *file) { u32 baseAddress; if (!state) BUG(); if (!xilinx_ac97_codec) BUG(); baseAddress = (u32)xilinx_ac97_codec->private_data; if (file->f_flags & O_NONBLOCK) { if (down_trylock (&state->open_sem)) { printk ("%s: returning -EAGAIN\n", __FUNCTION__); return -EAGAIN; } } else { if (down_interruptible (&state->open_sem)) { printk ("%s: returning -ERESTARTSYS\n", __FUNCTION__); return -ERESTARTSYS; } } file->private_data = state; printk ("%s: dsp opened by %d\n", __FUNCTION__, current->pid); state->buffer = (char *)kmalloc(BUFFER_SIZE, GFP_KERNEL); /** Reset AC97 **/ //added by myself XAC97_WriteReg(baseAddress, AC97_Reset, 0); XAC97_Delay(1000); /** Wait for the ready signal **/ XAC97_AwaitCodecReady(baseAddress); XAC97_WriteReg(baseAddress, AC97_PCM_DAC_Rate0, AC97_PCM_RATE_48000_HZ); XAC97_WriteReg(baseAddress, AC97_PCM_DAC_Rate1, AC97_PCM_RATE_48000_HZ); /** Clear FIFOs **/ XAC97_ClearFifos(baseAddress); XAC97_WriteReg(baseAddress, AC97_GeneralPurpose, 0x0000); XAC97_WriteReg(baseAddress, AC97_SerialConfig, 0x7000); /** Enable VRA Mode **/ XAC97_WriteReg(baseAddress, AC97_ExtendedAudioStat, AC97_EXTENDED_AUDIO_CONTROL_VRA); if (file->f_mode & FMODE_WRITE) { printk(KERN_INFO "setting volume\n"); /** Play Volume Settings **/ XAC97_WriteReg(baseAddress, AC97_MasterVol, AC97_VOL_MAX); XAC97_WriteReg(baseAddress, AC97_AuxOutVol, AC97_VOL_MAX); XAC97_WriteReg(baseAddress, AC97_MasterVolMono, AC97_VOL_MAX); XAC97_WriteReg(baseAddress, AC97_PCBeepVol, AC97_VOL_MAX); XAC97_WriteReg(baseAddress, AC97_PCMOutVol, AC97_VOL_MAX); } //firstly disable interrupt disable_irq(XILINX_AC97_PLAYBACK_INTERRUPT); if(request_irq(XILINX_AC97_PLAYBACK_INTERRUPT,xilinx_ac97_interrupt,SA_INTERRUPT,"ac97",NULL)) { printk(KERN_ALERT "cannot register interrupt handler\n"); } return 0; } static ssize_t xilinx_ac97_write (struct file *file, const char *buffer, size_t bytes, loff_t *ppos) { struct xilinx_ac97_state *state; unsigned int i = 0;// sz = 0; u32 baseAddress; char* sound_ptr; size_t words; ssize_t ret; int j; if (!access_ok (VERIFY_READ, buffer, bytes)) return -EFAULT; state = (struct xilinx_ac97_state *) file->private_data; if (!state) BUG(); if (!xilinx_ac97_codec) BUG(); if (down_interruptible(&state->sem)) return -ERESTARTSYS; baseAddress = (u32)xilinx_ac97_codec->private_data; size_t buffer_size =(size_t)BUFFER_SIZE; size_t tmp = bytes; bytes = min(tmp,buffer_size); if(XAC97_isInFIFOEmpty(baseAddress)) emptyTime++;//there's some time when playback FIFO is empty,I don't know how to fix it if (copy_from_user(state->buffer, buffer, bytes)) { ret = -EFAULT; goto out; } words = bytes >> 1; sound_ptr = (char *)state->buffer; i = 0; while(i < words) { j = *sound_ptr; sound_ptr++; j |= (*sound_ptr)<<8; if(!XAC97_isInFIFOFull(baseAddress)) XAC97_WriteFifo(baseAddress, j); else { halfEmpty = 0; enable_irq(XILINX_AC97_PLAYBACK_INTERRUPT); wait_event_interruptible(ac97_queue,halfEmpty != 0); XAC97_WriteFifo(baseAddress,j); } sound_ptr++; i++; j = 0; } ret = i << 1; out: up(&state->sem); return ret; } static ssize_t xilinx_ac97_read (struct file *file, const char *buffer, size_t bytes, loff_t *ppos) { struct xilinx_ac97_state *state; unsigned int i = 0;// sz = 0; u32 baseAddress; u32* sound_ptr; size_t words; if (ppos != &file->f_pos) return -ESPIPE; if (!access_ok (VERIFY_WRITE, buffer, bytes)) return -EFAULT; state = (struct xilinx_ac97_state *) file->private_data; if (!state) BUG(); if (!xilinx_ac97_codec) BUG(); baseAddress = (u32)xilinx_ac97_codec->private_data; // Check if already opened for read? // Compute the number of words to transfer. words = bytes >> 2; sound_ptr = (u32*)buffer; i = 0; while(i < words && !XAC97_isOutFIFOEmpty(baseAddress)) { *sound_ptr = XAC97_mGetOutFifoData(baseAddress); sound_ptr++; i++; } // Return the number of bytes transferred. return i << 2; } static int xilinx_ac97_release (struct inode *inode, struct file *file) { u32 baseAddress; kfree(state->buffer); baseAddress = (u32)xilinx_ac97_codec->private_data; XAC97_ClearFifos(baseAddress); XAC97_SoftReset(baseAddress); free_irq(XILINX_AC97_PLAYBACK_INTERRUPT,NULL); up (&state->open_sem); printk(KERN_ALERT "Empyt time is %d\n",emptyTime); emptyTime = 0; return 0; } static int xilinx_ac97_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int ival=0, rd, wr;//ret, count, rval=0; struct xilinx_ac97_state *state; u32 baseAddress = (u32)xilinx_ac97_codec->private_data; state = (struct xilinx_ac97_state *)file->private_data; if (file->f_mode & FMODE_WRITE) wr = 1; else wr = 0; if (file->f_mode & FMODE_READ) rd = 1; else rd = 0; switch(cmd){ default:break; } return -EINVAL; } static /*const */ struct file_operations xilinx_ac97_audio_fops = { owner:THIS_MODULE, llseek:no_llseek, read:xilinx_ac97_read, write:xilinx_ac97_write, // poll:xilinx_ac97_poll, ioctl:xilinx_ac97_ioctl, // mmap:xilinx_ac97_mmap, open:xilinx_ac97_open, release:xilinx_ac97_release, }; MODULE_AUTHOR("Xilinx"); MODULE_DESCRIPTION("Xilinx AC97 driver"); MODULE_LICENSE("GPL"); static int __init xilinx_ac97_init_module(void) { struct ac97_codec *codec; u32 baseAddress; printk(KERN_INFO "Xilinx AC97 Audio, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); baseAddress = (u32)ioremap(AC97_BASEADDR,AC97_HIGHADDR-AC97_BASEADDR); printk(KERN_INFO "XAC97_HardReset\n"); XAC97_HardReset(baseAddress); if ((codec = ac97_alloc_codec()) == NULL) return -ENOMEM; codec->private_data = (void *)baseAddress; codec->id = 0; codec->codec_read = xilinx_ac97_get; codec->codec_write = xilinx_ac97_set; codec->codec_wait = xilinx_ac97_codec_wait; if (!ac97_probe_codec(codec)) { printk(KERN_ERR "Failed to init Xilinx AC97"); kfree(codec); return -ENODEV; /* it didn't work */ } XAC97_InitAudio((u32)codec->private_data,0); if ((codec->dev_mixer = register_sound_mixer(&xilinx_ac97_mixer_fops, -1)) < 0) { printk(KERN_ERR "xilinx_ac97_audio: couldn't register mixer!\n"); kfree(codec); return -ENODEV; } if ((dev_audio = register_sound_dsp(&xilinx_ac97_audio_fops, -1)) < 0) { printk(KERN_ERR "xilinx_ac97_audio: couldn't register DSP device!\n"); unregister_sound_mixer(xilinx_ac97_codec->dev_mixer); kfree(xilinx_ac97_codec); return -ENODEV; } xilinx_ac97_codec = codec; state = (struct xilinx_ac97_state *) kmalloc(sizeof(struct xilinx_ac97_state), GFP_KERNEL); init_MUTEX(&state->open_sem); init_MUTEX(&state->sem); return 0; } static void __exit xilinx_ac97_cleanup_module(void) { unregister_sound_mixer(xilinx_ac97_codec->dev_mixer); ac97_release_codec(xilinx_ac97_codec); xilinx_ac97_codec = NULL; unregister_sound_dsp(dev_audio); dev_audio = -1; } module_init(xilinx_ac97_init_module); module_exit(xilinx_ac97_cleanup_module); /* Local Variables: c-basic-offset: 8 End: */ below is the test file "test_oss.c" #include #include #include #include #define BUFFER_SIZE 1024 static int audio_fd; void init_audio_device() { int fmts; int init_channels; int speed; if ( (audio_fd = open("/dev/dsp", O_WRONLY)) == -1) { perror("open error\n"); printf("soundcard open error"); exit(1); } printf("successfully init soundcard\n\n"); } int audio_close(void) { if (audio_fd) { close(audio_fd); printf("the device has been closed!\n"); } return 0; } int audio_play(char *buf, int len) { int temp; temp = write(audio_fd, buf, len); return temp; } int main() { init_audio_device(); int fd = open("/root/********.wav",O_RDONLY); int len = 0; char buffer[BUFFER_SIZE]; int i=0; char tempt; while(1) { len = read(fd,buffer,sizeof(buffer)); if(len == 0) { printf("reach the end\n"); break; } audio_play(buffer,len); } audio_close(); close(fd); return 0; } in the write process,firstly check whether playback FIFO is full,if not, then send PCM data to FIFO;else sleep until FIFO half-empty interrupt,in the interrupt handler,wake up write process,then go on send data to playback FIFO until full. ------=_Part_199439_1166067786.1184304174470 Content-Type: text/html; charset=gbk Content-Transfer-Encoding: quoted-printable
 
Hi
    I have a simple oss ac97 pla= yback driver for xilinx ml403 and linux2.6.17 kernel,but when I test it wit= h a *.wav file with sample rate 44.1k, there is much noisy, and I want to k= now whether there's problem with my ml403 board or ac97 driver,could anyone= be kind to help me test it on your board or point out my problem?
 = ;
thanks
below is my code "xilinx_ac97_adapter.c"
#include <lin= ux/module.h>
#include <linux/version.h>
#include <linux/s= tring.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>
#inclu= de <linux/soundcard.h>
#include <asm/io.h>
#include <a= sm/dma.h>
#include <linux/init.h>
#include <linux/poll.h&= gt;
#include <linux/spinlock.h>
#include <linux/smp_lock.h&g= t;
#include <linux/sound.h>
#include <linux/ac97_codec.h>=
#include <linux/interrupt.h>
#include <linux/irq.h>
#= include <linux/signal.h>
//#include <linux/wrapper.h>
#in= clude <asm/uaccess.h>
#include <asm/hardirq.h>
#include "= xparameters.h"
#include "xac97_l.h"
#include "xio.h"
#define XILIN= X_AC97

#define DRIVER_VERSION "1.00a"
#define AC97_BASEADDR XPAR_= OPB_AC97_CONTROLLER_REF_0_BASEADDR
#define AC97_HIGHADDR XPAR_OPB_AC97_C= ONTROLLER_REF_0_HIGHADDR
/* AC97 codec initialisation. */

static = struct ac97_codec *xilinx_ac97_codec =3D NULL;
static int dev_audio =3D = -1;
#define BUFFER_SIZE 32768
#define XILINX_AC97_PLAYBACK_INTERRUPT = 7

struct xilinx_ac97_state {
    struct semaphore&= nbsp;   open_sem;     /* Device access */
=     struct semaphore    sem;   = ;          /* File access */    spinlock_t        l= ock;        /* State */

 &nb= sp;  spinlock_t        ac97_lock;    struct ac97_codec    *ac97;
 &n= bsp;  char          =   *buffer;
    int     &nbs= p;      multichannel;
    int&nb= sp;           dsp; &= nbsp;       /* OSS handle */
  &= nbsp; int           =           trigger;  =   /* mmap I/O trigger */
    int   &n= bsp;        halfFull;
  &nb= sp; //    struct forte_channel    play;
&n= bsp;   //    struct forte_channel   = ; rec;
};
static struct xilinx_ac97_state *state;
static int halfE= mpty;
static DECLARE_WAIT_QUEUE_HEAD(ac97_queue);
static int emptyTim= e;
static u16 xilinx_ac97_get(struct ac97_codec *dev, u8 reg);
static= void xilinx_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
static = void xilinx_ac97_codec_wait(struct ac97_codec *dev);
static irqreturn_t = xilinx_ac97_interrupt(int irq, void * dev_id, struct pt_regs *regs)
{    disable_irq(XILINX_AC97_PLAYBACK_INTERRUPT);
 &= nbsp;  halfEmpty =3D 1;
    wake_up_interruptible(&a= mp;ac97_queue);
    return IRQ_HANDLED;  
}=
static u16 xilinx_ac97_get(struct ac97_codec *dev, u8 reg)
{
&nbs= p;       return XAC97_ReadReg((u32)dev->pr= ivate_data, reg);
}

static void xilinx_ac97_set(struct ac97_codec= *dev, u8 reg, u16 data) {
        XA= C97_WriteReg((u32)dev->private_data, reg, data);
}

static void= xilinx_ac97_codec_wait(struct ac97_codec *dev) {
   &nbs= p;    XAC97_AwaitCodecReady((u32)dev->private_data);
}=

/* OSS /dev/mixer file operation methods */

static int xilin= x_ac97_open_mixdev(struct inode *inode, struct file *file)
{
 &n= bsp;  int minor =3D MINOR(inode->i_rdev);
    if = (xilinx_ac97_codec && xilinx_ac97_codec->dev_mixer =3D=3D minor)= {
        file->private_data =3D = xilinx_ac97_codec;
        return 0;<= br>    }
    return -ENODEV;
}

s= tatic int xilinx_ac97_ioctl_mixdev(struct inode *inode,
  &nbs= p;            &= nbsp;    struct file *file,
     = ;            &n= bsp;  unsigned int cmd, unsigned long arg)
{
    = struct ac97_codec *codec =3D (struct ac97_codec *) file->private_data;    return codec->mixer_ioctl(codec, cmd, arg);
}
static /*const */ struct file_operations xilinx_ac97_mixer_fops =3D {<= br>    owner:THIS_MODULE,
    llseek:no_ll= seek,
    ioctl:xilinx_ac97_ioctl_mixdev,
  =   open:xilinx_ac97_open_mixdev,
};

static int xilinx_ac97_op= en(struct inode *inode, struct file *file)
{
    u32 b= aseAddress;
    if (!state)
    &n= bsp;   BUG();

    if (!xilinx_ac97_codec)        BUG();
  
&nb= sp;   baseAddress =3D (u32)xilinx_ac97_codec->private_data;    if (file->f_flags & O_NONBLOCK) {
  = ;      if (down_trylock (&state->open_sem))= {
            pr= intk ("%s: returning -EAGAIN\n", __FUNCTION__);
    =         return -EAGAIN;
  &= nbsp;     }
    }
  &nbs= p; else {
        if (down_interrupti= ble (&state->open_sem)) {
      &nb= sp;     printk ("%s: returning -ERESTARTSYS\n", __FUNCT= ION__);
          &nbs= p; return -ERESTARTSYS;
        }
=     }

    file->private_data =3D st= ate;
    printk ("%s: dsp opened by %d\n", __FUNCTION__, = current->pid);
    state->buffer =3D (char *)kmallo= c(BUFFER_SIZE, GFP_KERNEL);
    /** Reset AC97 **/ &= nbsp;           &nbs= p;       //added by myself
  &nb= sp; XAC97_WriteReg(baseAddress, AC97_Reset, 0);
    XAC97= _Delay(1000);
  
    /** Wait for the ready= signal **/
    XAC97_AwaitCodecReady(baseAddress);
&n= bsp;   XAC97_WriteReg(baseAddress, AC97_PCM_DAC_Rate0, AC97_PCM_R= ATE_48000_HZ);
    XAC97_WriteReg(baseAddress, AC97_PCM_D= AC_Rate1, AC97_PCM_RATE_48000_HZ);
    /** Clear FIFOs **= /
    XAC97_ClearFifos(baseAddress);   &nb= sp;  
    XAC97_WriteReg(baseAddress, AC97_Gen= eralPurpose, 0x0000);
    XAC97_WriteReg(baseAddress, AC9= 7_SerialConfig, 0x7000);
    /** Enable VRA Mode **/
&= nbsp;   XAC97_WriteReg(baseAddress, AC97_ExtendedAudioStat, AC97_= EXTENDED_AUDIO_CONTROL_VRA);
  
    if (fil= e->f_mode & FMODE_WRITE) {
      &n= bsp; printk(KERN_INFO "setting volume\n");
     = ;   /** Play Volume Settings **/
     = ;   XAC97_WriteReg(baseAddress, AC97_MasterVol, AC97_VOL_MAX);        XAC97_WriteReg(baseAddress, AC9= 7_AuxOutVol, AC97_VOL_MAX);
        X= AC97_WriteReg(baseAddress, AC97_MasterVolMono, AC97_VOL_MAX);
 &nbs= p;      XAC97_WriteReg(baseAddress, AC97_PCBeepVol= , AC97_VOL_MAX);
        XAC97_WriteR= eg(baseAddress, AC97_PCMOutVol, AC97_VOL_MAX);

   &nb= sp;     }
    //firstly disable inter= rupt
    disable_irq(XILINX_AC97_PLAYBACK_INTERRUPT);
=     if(request_irq(XILINX_AC97_PLAYBACK_INTERRUPT,xilinx_ac9= 7_interrupt,SA_INTERRUPT,"ac97",NULL))
    {
 &nb= sp;      printk(KERN_ALERT "cannot register interr= upt handler\n");
    }  
   = return 0;
}

static ssize_t
xilinx_ac97_write (struct file *fi= le, const char *buffer, size_t bytes,
     &nbs= p;   loff_t *ppos)
{
    struct xilinx_ac97_= state *state;
    unsigned int i =3D 0;// sz =3D 0;
&n= bsp;   u32 baseAddress;
    char* sound_ptr;    size_t words;
    ssize_t ret;
&nb= sp;   int j;
     if (!access_ok (VERIFY_R= EAD, buffer, bytes))
         re= turn -EFAULT;
    state =3D (struct xilinx_ac97_state *) = file->private_data;

    if (!state)
  = ;      BUG();

    if (!xilin= x_ac97_codec)
        BUG();

&= nbsp;   if (down_interruptible(&state->sem))
 &nbs= p;      return -ERESTARTSYS;

  &n= bsp; baseAddress =3D (u32)xilinx_ac97_codec->private_data;


&n= bsp;   size_t buffer_size =3D(size_t)BUFFER_SIZE;
  =   size_t tmp =3D bytes;
    bytes =3D min(tmp,buffer= _size);

    if(XAC97_isInFIFOEmpty(baseAddress))
&= nbsp;   emptyTime++;//there's some time when playback FIFO is emp= ty,I don't know how to fix it
    if (copy_from_user(stat= e->buffer, buffer, bytes)) {
      &nbs= p; ret =3D -EFAULT;
        goto out;=
    }

    words =3D bytes >>= 1;
    sound_ptr =3D (char *)state->buffer;
 =    i =3D 0;
    while(i < words) {

&n= bsp;       j =3D *sound_ptr;
  &= nbsp;     sound_ptr++;
     = ;   j |=3D (*sound_ptr)<<8;
    &nbs= p;   if(!XAC97_isInFIFOFull(baseAddress))
   &n= bsp;        XAC97_WriteFifo(baseAddress,= j);
        else
  &nbs= p;     {
       &= nbsp;    halfEmpty =3D 0;
     &= nbsp;      enable_irq(XILINX_AC97_PLAYBACK_INTERRU= PT);
            = wait_event_interruptible(ac97_queue,halfEmpty !=3D 0);
   = ;         XAC97_WriteFifo(baseAddre= ss,j);
        }
   = ;     sound_ptr++;
     &nb= sp;  i++;
        j =3D 0;
&n= bsp;   }

    ret =3D i << 1;

<= br> out:
    up(&state->sem);

 &n= bsp;  return ret;
}
  
static ssize_t
xilinx_ac= 97_read (struct file *file, const char *buffer, size_t bytes,
 &nbs= p;       loff_t *ppos)
{
  &n= bsp; struct xilinx_ac97_state *state;
    unsigned int i = =3D 0;// sz =3D 0;
    u32 baseAddress;
  &n= bsp; u32* sound_ptr;
    size_t words;

  = ;  if (ppos !=3D &file->f_pos)
     = ;   return -ESPIPE;

    if (!access_ok (VER= IFY_WRITE, buffer, bytes))
        re= turn -EFAULT;

    state =3D (struct xilinx_ac97_state= *) file->private_data;

    if (!state)
 &= nbsp;      BUG();

    if (!x= ilinx_ac97_codec)
        BUG();
<= br>    baseAddress =3D (u32)xilinx_ac97_codec->private_da= ta;

    // Check if already opened for read?

&= nbsp;   // Compute the number of words to transfer.
 &nbs= p;  words =3D bytes >> 2;
    sound_ptr =3D (u= 32*)buffer;
    i =3D 0;
    while(i &l= t; words && !XAC97_isOutFIFOEmpty(baseAddress)) {
  &n= bsp;     *sound_ptr =3D XAC97_mGetOutFifoData(baseAddre= ss);
        sound_ptr++;
 &n= bsp;      i++;
    }

&nbs= p;   // Return the number of bytes transferred.
  &n= bsp; return i << 2;
}
       = ;  
static int
xilinx_ac97_release (struct inode *inode, s= truct file *file)
{
    u32 baseAddress;

 =    kfree(state->buffer);

    baseAddress= =3D (u32)xilinx_ac97_codec->private_data;

    XAC= 97_ClearFifos(baseAddress);      
 &= nbsp;  XAC97_SoftReset(baseAddress);
    free_irq(XI= LINX_AC97_PLAYBACK_INTERRUPT,NULL);

    up (&stat= e->open_sem);
    printk(KERN_ALERT "Empyt time is %d\= n",emptyTime);
    emptyTime =3D 0;
   = return 0;
}

static int
xilinx_ac97_ioctl (struct inode *inode= , struct file *file, unsigned int cmd,
     &nb= sp;   unsigned long arg)
{
    int ival=3D0,= rd, wr;//ret, count, rval=3D0;
    struct xilinx_ac97_st= ate *state;
    u32 baseAddress =3D (u32)xilinx_ac97_code= c->private_data;

    state =3D (struct xilinx_ac97= _state *)file->private_data;  
  
 &nbs= p;  if (file->f_mode & FMODE_WRITE)
    =     wr =3D 1;
    else
  &nbs= p;     wr =3D 0;

    if (file->= ;f_mode & FMODE_READ)
        rd = =3D 1;
    else
      &n= bsp; rd =3D 0;
    switch(cmd){
    def= ault:break;
    }
    return -EINVAL;}

  
static /*const */ struct file_operations xilinx= _ac97_audio_fops =3D {
    owner:THIS_MODULE,
 &n= bsp;  llseek:no_llseek,
    read:xilinx_ac97_read,    write:xilinx_ac97_write,
    // = ;   poll:xilinx_ac97_poll,
    ioctl:xilinx_ac9= 7_ioctl,
    //    mmap:xilinx_ac97_mmap,<= br>    open:xilinx_ac97_open,
    release:= xilinx_ac97_release,
};

MODULE_AUTHOR("Xilinx");
MODULE_DESCRI= PTION("Xilinx AC97 driver");
MODULE_LICENSE("GPL");

static int __= init xilinx_ac97_init_module(void)
{
    struct ac97_c= odec *codec;
        u32 baseAddress;=

    printk(KERN_INFO "Xilinx AC97 Audio, version "           DRIVER_VERSI= ON ", " __TIME__ " " __DATE__ "\n");
      = ;  baseAddress =3D (u32)ioremap(AC97_BASEADDR,AC97_HIGHADDR-AC97_BASEA= DDR);
        printk(KERN_INFO "XAC97= _HardReset\n");
    XAC97_HardReset(baseAddress);
&nbs= p;       if ((codec =3D ac97_alloc_codec()) = =3D=3D NULL)
          = ;      return -ENOMEM;
    =     codec->private_data =3D (void *)baseAddress;
 = ;       codec->id =3D 0;
  &n= bsp;     codec->codec_read =3D xilinx_ac97_get;
&= nbsp;       codec->codec_write =3D xilinx_= ac97_set;
        codec->codec_wai= t =3D xilinx_ac97_codec_wait;
    if (!ac97_probe_codec(c= odec)) {
          &nb= sp;     printk(KERN_ERR "Failed to init Xilinx AC97");<= br>            =     kfree(codec);
      &nb= sp;         return -ENODEV; &n= bsp;  /* it didn't work */
      &nbs= p; }
        XAC97_InitAudio((u32)cod= ec->private_data,0);
    if ((codec->dev_mixer =3D = register_sound_mixer(&xilinx_ac97_mixer_fops, -1)) < 0) {
 &= nbsp;      printk(KERN_ERR "xilinx_ac97_audio: cou= ldn't register mixer!\n");
        kf= ree(codec);
        return -ENODEV;    }

    if ((dev_audio =3D registe= r_sound_dsp(&xilinx_ac97_audio_fops, -1)) < 0) {
  &nbs= p;     printk(KERN_ERR "xilinx_ac97_audio: couldn't reg= ister DSP device!\n");
        unregi= ster_sound_mixer(xilinx_ac97_codec->dev_mixer);
   &nb= sp;    kfree(xilinx_ac97_codec);
    =     return -ENODEV;
    }

 &nb= sp;  xilinx_ac97_codec =3D codec;

    state =3D = (struct xilinx_ac97_state *) kmalloc(sizeof(struct xilinx_ac97_state), GFP_= KERNEL);
    init_MUTEX(&state->open_sem);
&nbs= p;   init_MUTEX(&state->sem);
    retur= n 0;
}

static void __exit xilinx_ac97_cleanup_module(void)
{
    unregister_sound_mixer(xilinx_ac97_codec->dev_m= ixer);
    ac97_release_codec(xilinx_ac97_codec);
&nbs= p;   xilinx_ac97_codec =3D NULL;
    unregister= _sound_dsp(dev_audio);
    dev_audio =3D -1;
}

= module_init(xilinx_ac97_init_module);
module_exit(xilinx_ac97_cleanup_mo= dule);
/*
Local Variables:
c-basic-offset: 8
End:
*/

= below is the test file "test_oss.c"
#include <fcntl.h>
#include= <stdlib.h>
#include <linux/soundcard.h>
#include <sys= /ioctl.h>

#define BUFFER_SIZE 1024
static int audio_fd;
void init_audio_device()
{
    int fmts;
 &nb= sp;    int init_channels;
      = int speed;

      if ( (audio_fd =3D open("/= dev/dsp", O_WRONLY)) =3D=3D -1)
    {
  &nbs= p;         perror("open error\n");<= br>            print= f("soundcard open error");
       &nb= sp;    exit(1);
      }
 = ;   printf("successfully init soundcard\n\n");
}

int au= dio_close(void)
{
     if (audio_fd)
 &nb= sp;  {
        close(audio_fd);<= br>            = printf("the device has been closed!\n");
     = }    
      return 0;
= }

int audio_play(char *buf, int len)
{
    int = temp;
    temp =3D write(audio_fd, buf, len);
 &n= bsp;  return temp;
}

int main()
{  
 &= nbsp;  init_audio_device();
    int fd =3D open("/ro= ot/********.wav",O_RDONLY);
    int len =3D 0;
 &= nbsp;  char buffer[BUFFER_SIZE];
    int i=3D0;
&= nbsp;   char tempt;
    while(1)
  = ;  {
        len =3D read(fd,buf= fer,sizeof(buffer));
        if(len = =3D=3D 0)
        {
  &n= bsp;     printf("reach the end\n");
  &nbs= p;     break;
      &n= bsp; }
        audio_play(buffer,len)= ; 
    }
    audio_close();
&n= bsp;   close(fd);
    return 0;
}
 <= br>in the write process,firstly check whether playback FIFO is full,if not,= then send PCM data to FIFO;else sleep until FIFO half-empty interrupt,in t= he interrupt handler,wake up write process,then go on send data to playback= FIFO until full. 
 
 



= iPod=A1=A2=CD=F2 =B5=E3 =BE=DE =B6=EE =B5=E3 =BF=A8=A1=A2=BD=B1 =D1=A7 =BD= =F0=A1=AD=A1=AD=BA=A3 =C1=BF =BD=B1 =C6=B7=A3=AC=CF=EB =C4=C3 =BE=CD =C4=C3= =A3=A1 ------=_Part_199439_1166067786.1184304174470--