* can anyone help me to test my ac97 driver
@ 2007-07-13 5:22 silicom
2007-07-18 20:01 ` Joachim Förster
0 siblings, 1 reply; 2+ messages in thread
From: silicom @ 2007-07-13 5:22 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 13110 bytes --]
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 <linux/module.h>
#include <linux/version.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 <asm/io.h>
#include <asm/dma.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/smp_lock.h>
#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>
#include <asm/uaccess.h>
#include <asm/hardirq.h>
#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 <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;
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.
[-- Attachment #2: Type: text/html, Size: 23187 bytes --]
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: can anyone help me to test my ac97 driver
2007-07-13 5:22 can anyone help me to test my ac97 driver silicom
@ 2007-07-18 20:01 ` Joachim Förster
0 siblings, 0 replies; 2+ messages in thread
From: Joachim Förster @ 2007-07-18 20:01 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 1476 bytes --]
Hi silicom,
On Fri, 2007-07-13 at 13:22 +0800, silicom wrote:
> 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?
Today I took some time and tried to compile your driver, but one of the
first things I saw was that there is a file missing: "xac97_l.h". I
think, it contains your "low level" functions. If you post the file, and
I have some time, I'll test your driver and what it does on the board,
which I have available.
Furthermore your driver depends on xbasic_types.c/h, xio.c/h, which some
people might not have, too ... especially xio.c/h (in my
experience ;-) ) ...
In my last mail (last week) I announced my driver for the AC97
Controller of Xilinx and said that I'm going to release/post it. Since
then, I worked on it once more and now it seems to be pretty stable and
usable (playback support). I added capture support, too.
[Capturing basically works, but there is a problem with higher rates and
ALSA not reading from the intermediate buffer anymore ... not yet
investigated.]
My driver will be published on a website soon. I'll post the link as
soon as possible. Meanwhile, if you or anyone want to try it, just mail
me (JOFT@gmx.de).
Joachim
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 191 bytes --]
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2007-07-18 20:01 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-07-13 5:22 can anyone help me to test my ac97 driver silicom
2007-07-18 20:01 ` Joachim Förster
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).