?? s3c2410-uda1341.c
字號:
__get_user(v, (const u_short *)from);
*dst = v | (v << 16);
}
return 0;
}
static ssize_t smdk2410_audio_write(struct file *file, const char *buffer,
size_t count, loff_t * ppos)
{
const char *buffer0 = buffer;
audio_stream_t *s = &output_stream;
int chunksize, ret = 0;
DPRINTK("audio_write : start count=%d\n", count);
switch (file->f_flags & O_ACCMODE) {
case O_WRONLY:
case O_RDWR:
break;
default:
return -EPERM;
}
if (!s->buffers && audio_setup_buf(s))
return -ENOMEM;
count &= ~0x03;
while (count > 0) {
audio_buf_t *b = s->buf;
if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
if (down_trylock(&b->sem))
break;
} else {
ret = -ERESTARTSYS;
if (down_interruptible(&b->sem))
break;
}
if (audio_channels == 2) {
chunksize = s->fragsize - b->size;
if (chunksize > count)
chunksize = count;
DPRINTK("write %d to %d\n", chunksize, s->buf_idx);
if (copy_from_user(b->start + b->size, buffer, chunksize)) {
up(&b->sem);
return -EFAULT;
}
b->size += chunksize;
} else {
chunksize = (s->fragsize - b->size) >> 1;
if (chunksize > count)
chunksize = count;
DPRINTK("write %d to %d\n", chunksize*2, s->buf_idx);
if (copy_from_user_mono_stereo(b->start + b->size,
buffer, chunksize)) {
up(&b->sem);
return -EFAULT;
}
b->size += chunksize*2;
}
buffer += chunksize;
count -= chunksize;
if (b->size < s->fragsize) {
up(&b->sem);
break;
}
if((ret = s3c2410_dma_enqueue(s->dma_ch, (void *) b, b->dma_addr, b->size))) {
printk(PFX"dma enqueue failed.\n");
return ret;
}
b->size = 0;
NEXT_BUF(s, buf);
}
if ((buffer - buffer0))
ret = buffer - buffer0;
DPRINTK("audio_write : end count=%d\n\n", ret);
return ret;
}
static ssize_t smdk2410_audio_read(struct file *file, char *buffer,
size_t count, loff_t * ppos)
{
const char *buffer0 = buffer;
audio_stream_t *s = &input_stream;
int chunksize, ret = 0;
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;
}
b->size -= chunksize;
buffer += chunksize;
count -= chunksize;
if (b->size > 0) {
up(&b->sem);
break;
}
/* Make current buffer available for DMA again */
s3c2410_dma_enqueue(s->dma_ch, (void *) b, b->dma_addr, s->fragsize);
NEXT_BUF(s, buf);
}
if ((buffer - buffer0))
ret = buffer - buffer0;
// DPRINTK("audio_read: return=%d\n", ret);
return ret;
}
static unsigned int smdk2410_audio_poll(struct file *file,
struct poll_table_struct *wait)
{
unsigned int mask = 0;
int i;
DPRINTK("audio_poll(): mode=%s\n",
(file->f_mode & FMODE_WRITE) ? "w" : "");
if (file->f_mode & FMODE_READ) {
if (!input_stream.buffers && audio_setup_buf(&input_stream))
return -ENOMEM;
poll_wait(file, &input_stream.buf->sem.wait, wait);
for (i = 0; i < input_stream.nbfrags; i++) {
if (atomic_read(&input_stream.buffers[i].sem.count) > 0)
mask |= POLLIN | POLLWRNORM;
break;
}
}
if (file->f_mode & FMODE_WRITE) {
if (!output_stream.buffers && audio_setup_buf(&output_stream))
return -ENOMEM;
poll_wait(file, &output_stream.buf->sem.wait, wait);
for (i = 0; i < output_stream.nbfrags; i++) {
if (atomic_read(&output_stream.buffers[i].sem.count) > 0)
mask |= POLLOUT | POLLWRNORM;
break;
}
}
DPRINTK("audio_poll() returned mask of %s\n",
(mask & POLLOUT) ? "w" : "");
return mask;
}
static loff_t smdk2410_audio_llseek(struct file *file, loff_t offset,
int origin)
{
return -ESPIPE;
}
static int smdk2410_mixer_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int ret;
long val = 0;
switch (cmd) {
case SOUND_MIXER_INFO:
{
mixer_info info;
strncpy(info.id, "UDA1341", sizeof(info.id));
strncpy(info.name,"Philips UDA1341", sizeof(info.name));
info.modify_counter = audio_mix_modcnt;
return copy_to_user((void *)arg, &info, sizeof(info));
}
case SOUND_OLD_MIXER_INFO:
{
_old_mixer_info info;
strncpy(info.id, "UDA1341", sizeof(info.id));
strncpy(info.name,"Philips UDA1341", sizeof(info.name));
return copy_to_user((void *)arg, &info, sizeof(info));
}
case SOUND_MIXER_READ_STEREODEVS:
return put_user(0, (long *) arg);
case SOUND_MIXER_READ_CAPS:
val = SOUND_CAP_EXCL_INPUT;
return put_user(val, (long *) arg);
case SOUND_MIXER_WRITE_VOLUME:
ret = get_user(val, (long *) arg);
if (ret)
return ret;
uda1341_volume = 63 - (((val & 0xff) + 1) * 63) / 100;
uda1341_l3_address(UDA1341_REG_DATA0);
uda1341_l3_data(uda1341_volume);
break;
case SOUND_MIXER_READ_VOLUME:
val = ((63 - uda1341_volume) * 100) / 63;
val |= val << 8;
return put_user(val, (long *) arg);
case SOUND_MIXER_READ_IGAIN:
val = ((31- mixer_igain) * 100) / 31;
return put_user(val, (int *) arg);
case SOUND_MIXER_WRITE_IGAIN:
ret = get_user(val, (int *) arg);
if (ret)
return ret;
mixer_igain = 31 - (val * 31 / 100);
/* use mixer gain channel 1*/
uda1341_l3_address(UDA1341_REG_DATA0);
uda1341_l3_data(EXTADDR(EXT0));
uda1341_l3_data(EXTDATA(EXT0_CH1_GAIN(mixer_igain)));
break;
default:
DPRINTK("mixer ioctl %u unknown\n", cmd);
return -ENOSYS;
}
audio_mix_modcnt++;
return 0;
}
static int iispsr_value(int s_bit_clock, int sample_rate)
{
int i, prescaler = 0;
unsigned long tmpval;
unsigned long tmpval384;
unsigned long tmpval384min = 0xffff;
tmpval384 = clk_get_rate(iis_clock) / s_bit_clock;
for (i = 0; i < 32; i++) {
tmpval = tmpval384/(i+1);
if (PCM_ABS((sample_rate - tmpval)) < tmpval384min) {
tmpval384min = PCM_ABS((sample_rate - tmpval));
prescaler = i;
}
}
DPRINTK("prescaler = %d\n", prescaler);
return prescaler;
}
static long audio_set_dsp_speed(long val)
{
unsigned int prescaler;
prescaler=(IISPSR_A(iispsr_value(S_CLOCK_FREQ, val))
| IISPSR_B(iispsr_value(S_CLOCK_FREQ, val)));
writel(prescaler, iis_base + S3C2410_IISPSR);
printk(PFX "audio_set_dsp_speed:%ld prescaler:%i\n",val,prescaler);
return (audio_rate = val);
}
static int smdk2410_audio_ioctl(struct inode *inode, struct file *file,
uint cmd, ulong arg)
{
long val;
switch (cmd) {
case SNDCTL_DSP_SETFMT:
get_user(val, (long *) arg);
if (val & AUDIO_FMT_MASK) {
audio_fmt = val;
break;
} else
return -EINVAL;
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;
audio_channels = val;
break;
case SOUND_PCM_READ_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_GETBLKSIZE:
if(file->f_mode & FMODE_WRITE)
return put_user(audio_fragsize, (long *) arg);
else
return put_user(audio_fragsize, (int *) arg);
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 = verify_area(VERIFY_WRITE, inf, sizeof(*inf));
int i;
int frags = 0, bytes = 0;
if (err)
return err;
for (i = 0; i < s->nbfrags; i++) {
if (atomic_read(&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);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -