static int s3c2410iis_probe(struct platform_device
*pdev) {
struct resource *res;
unsigned long flags;
int ret;
DPRINTK("s3c2410iis_probe/n");
//获得平台设备资源
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL)
{
printk(KERN_INFO PFX "failed to get memory region resouce/n");
return -ENOENT;
}
//申请可用内存
res = request_mem_region(res->start, RESSIZE(res), pdev->name);
if(res == 0){
printk(KERN_INFO PFX "failed to request io memory region./n");
return -ENOENT;
}
DPRINTK("audio_read: count=%d/n", count);
/*
if (ppos != &file->f_pos)
return -ESPIPE;
*/
if (!s->buffers)
{
int i;
if (audio_setup_buf(s))
return -ENOMEM;
for (i = 0; i < s->nbfrags; i++)
{
audio_buf_t *b = s->buf;
down(&b->sem);
s3c2410_dma_enqueue(s->dma_ch,
(void *) b, b->dma_addr, s->fragsize);
NEXT_BUF(s, buf);
}
}
while (count > 0)
{
audio_buf_t *b = s->buf;
/* Wait for a buffer to become full */
if (file->f_flags
& O_NONBLOCK) {
ret = -EAGAIN;
if (down_trylock(&b->sem))
break;
} else {
ret = -ERESTARTSYS;
if (down_interruptible(&b->sem))
break;
}
chunksize = b->size;
if (chunksize > count)
chunksize = count;
DPRINTK("read %d from %d/n", chunksize, s->buf_idx);
if (copy_to_user(buffer, b->start
+ s->fragsize - b->size,
chunksize)) {
up(&b->sem);
return -EFAULT;
}
case SNDCTL_DSP_CHANNELS:
case SNDCTL_DSP_STEREO:
get_user(val, (long *)
arg);
if (cmd == SNDCTL_DSP_STEREO)
val = val ? 2 : 1;
if (val != 1 && val
!= 2)
return -EINVAL;
DPRINTK("audio_channels set to %d/n", val);
audio_channels = val;
break;
case SOUND_PCM_READ_CHANNELS:
DPRINTK("audio_channels is %d/n", audio_channels);
put_user(audio_channels, (long
*) arg);
break;
case SNDCTL_DSP_SPEED:
get_user(val, (long *)
arg);
val = audio_set_dsp_speed(val);
if (val < 0)
return -EINVAL;
put_user(val, (long *)
arg);
break;
case SOUND_PCM_READ_RATE:
put_user(audio_rate, (long
*) arg);
break;
case SNDCTL_DSP_GETFMTS:
put_user(AUDIO_FMT_MASK, (long
*) arg);
break;
case SNDCTL_DSP_SETFRAGMENT:
if (file->f_mode
& FMODE_WRITE) {
if (output_stream.buffers)
return -EBUSY;
get_user(val, (long *)
arg);
audio_fragsize = 1 << (val
& 0xFFFF);
if (audio_fragsize < 16)
audio_fragsize = 16;
if (audio_fragsize > 16384)
audio_fragsize = 16384;
audio_nbfrags = (val >> 16)
& 0x7FFF;
if (audio_nbfrags < 2)
audio_nbfrags = 2;
if (audio_nbfrags * audio_fragsize > 128
* 1024)
audio_nbfrags = 128 * 1024 / audio_fragsize;
if (audio_setup_buf(&output_stream))
return -ENOMEM;
}
if (file->f_mode
& FMODE_READ) {
if (input_stream.buffers)
return -EBUSY;
get_user(val, (int *)
arg);
audio_fragsize = 1 << (val
& 0xFFFF);
if (audio_fragsize < 16)
audio_fragsize = 16;
if (audio_fragsize > 16384)
audio_fragsize = 16384;
audio_nbfrags = (val >> 16)
& 0x7FFF;
if (audio_nbfrags < 2)
audio_nbfrags = 2;
if (audio_nbfrags * audio_fragsize > 128
* 1024)
audio_nbfrags = 128 * 1024 / audio_fragsize;
if (audio_setup_buf(&input_stream))
return -ENOMEM;
}
break;
case SNDCTL_DSP_SYNC:
return audio_sync(file);
case SNDCTL_DSP_GETOSPACE:
{
audio_stream_t *s = &output_stream;
audio_buf_info *inf = (audio_buf_info
*) arg;
int err = access_ok(VERIFY_WRITE, inf,
sizeof(*inf));
int i;
int frags = 0, bytes = 0;
if (err)
return err;
for (i = 0; i < s->nbfrags; i++)
{
if (s->buffers[i].sem.count
> 0) {
if (s->buffers[i].size
== 0) frags++;
bytes += s->fragsize - s->buffers[i].size;
}
}
put_user(frags, &inf->fragments);
put_user(s->nbfrags, &inf->fragstotal);
put_user(s->fragsize, &inf->fragsize);
put_user(bytes, &inf->bytes);
break;
}
case SNDCTL_DSP_GETISPACE:
{
audio_stream_t *s = &input_stream;
audio_buf_info *inf = (audio_buf_info
*) arg;
int err = access_ok(VERIFY_WRITE, inf,
sizeof(*inf));
int i;
int frags = 0, bytes = 0;
if (!(file->f_mode
& FMODE_READ))
return -EINVAL;
if (err)
return err;
for(i = 0; i < s->nbfrags; i++){
if (s->buffers[i].sem.count
> 0)
{
if (s->buffers[i].size
== s->fragsize)
frags++;
bytes += s->buffers[i].size;
}
}
put_user(frags, &inf->fragments);
put_user(s->nbfrags, &inf->fragstotal);
put_user(s->fragsize, &inf->fragsize);
put_user(bytes, &inf->bytes);
break;
}
case SNDCTL_DSP_RESET:
if (file->f_mode
& FMODE_READ) {
audio_clear_buf(&input_stream);
}
if (file->f_mode
& FMODE_WRITE) {
audio_clear_buf(&output_stream);
}
return 0;
case SNDCTL_DSP_NONBLOCK:
file->f_flags |= O_NONBLOCK;
return 0;
case SNDCTL_DSP_POST:
case SNDCTL_DSP_SUBDIVIDE:
case SNDCTL_DSP_GETCAPS:
case SNDCTL_DSP_GETTRIGGER:
case SNDCTL_DSP_SETTRIGGER:
case SNDCTL_DSP_GETIPTR:
case SNDCTL_DSP_GETOPTR:
case SNDCTL_DSP_MAPINBUF:
case SNDCTL_DSP_MAPOUTBUF:
case SNDCTL_DSP_SETSYNCRO:
case SNDCTL_DSP_SETDUPLEX:
return -ENOSYS;
default:
return smdk2410_mixer_ioctl(inode, file, cmd,
arg);
}
return 0;
}
open:
判断设备是否正忙->设置相关参数->初始化iis总线->清除缓冲区
static int smdk2410_audio_open(struct inode
*inode, struct file *file)
{
int cold = !audio_active;
DPRINTK("audio_open/n");
if ((file->f_flags
& O_ACCMODE) == O_RDONLY)
{
if (audio_rd_refcount || audio_wr_refcount)
return -EBUSY;
audio_rd_refcount++;
} else if ((file->f_flags
& O_ACCMODE) == O_WRONLY)
{
if (audio_wr_refcount)
return -EBUSY;
audio_wr_refcount++;
} else if ((file->f_flags
& O_ACCMODE) == O_RDWR)
{
if (audio_rd_refcount || audio_wr_refcount)
return -EBUSY;
audio_rd_refcount++;
audio_wr_refcount++;
} else
return -EINVAL;
if (cold) {
audio_rate = AUDIO_RATE_DEFAULT;
audio_channels = AUDIO_CHANNELS_DEFAULT;
audio_fragsize = AUDIO_FRAGSIZE_DEFAULT;
audio_nbfrags = AUDIO_NBFRAGS_DEFAULT;
if ((file->f_mode
& FMODE_WRITE)){
init_s3c2410_iis_bus_tx();//可写则初始化iis发送
audio_clear_buf(&output_stream);
}
if ((file->f_mode
& FMODE_READ)){
init_s3c2410_iis_bus_rx();//可读则初始化iis接收
audio_clear_buf(&input_stream);
}
}
return 0;
}
release:
清除缓冲区,读写计数归0
static int smdk2410_audio_release(struct inode
*inode, struct file *file)
{
DPRINTK("audio_release/n");
if (file->f_mode
& FMODE_READ) {
if (audio_rd_refcount == 1)
audio_clear_buf(&input_stream);
audio_rd_refcount = 0;
}
typedef struct {
int size; /* buffer size */
char *start; /* point to actual buffer */
dma_addr_t dma_addr; /* physical buffer address */
struct semaphore sem; /* down before touching the buffer */
wait_queue_head_t wait;
int master; /* owner for buffer allocation, contain size when true */
} audio_buf_t;
内存块结构:
typedef struct {
audio_buf_t *buffers; /* pointer to audio buffer structures */
audio_buf_t *buf; /* current buffer used by read/write */
u_int buf_idx; /* index for the pointer above */
u_int fragsize; /* fragment i.e. buffer size */
u_int nbfrags; /* nbr of fragments */
dmach_t dma_ch; /* DMA channel (channel2 for audio) */
u_int dma_ok;
} audio_stream_t;
(2)dma使用过程:
首先是在probe函数中调用audio_init_dma初始化dma:
static int __init audio_init_dma(audio_stream_t
* s, char *desc)
{
int ret ;
enum s3c2410_dmasrc source;
int hwcfg;
unsigned long devaddr;
int dcon;
unsigned int flags = 0;