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;