⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s3c2410-uda1341.c

📁 2410uda1341的测试代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		__get_user(v, (const u_short *)from); from += 2;
		*dst++ = v | (v << 16);
	}

	while (from < end-2) {
		u_int v, x, y;
		__get_user(v, (const u_int *)from); from += 4;
		x = v << 16;
		x |= x >> 16;
		y = v >> 16;
		y |= y << 16;
		*dst++ = x;
		*dst++ = y;
	}

	if (from < end) {
		u_int v;
		__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;
		}

		s3c2410_dma_queue_buffer(s->dma_ch, (void *) b,
					   b->dma_addr, b->size, DMA_BUF_WR);
		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_queue_buffer(s->dma_ch, (void *) b,
                                         b->dma_addr, s->fragsize, DMA_BUF_RD);
                         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_queue_buffer(s->dma_ch, (void *) b,
					 b->dma_addr, s->fragsize, DMA_BUF_RD);

                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 = s3c2410_get_bus_clk(GET_PCLK) / 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)
{
	switch (val) {
		case 48000:
		case 44100:
			IISPSR = (IISPSR_A(iispsr_value(S_CLOCK_FREQ, 44100)) 
				| IISPSR_B(iispsr_value(S_CLOCK_FREQ, 44100)));
			break;
		case 22050:
			IISPSR = (IISPSR_A(iispsr_value(S_CLOCK_FREQ, 22050)) 
				| IISPSR_B(iispsr_value(S_CLOCK_FREQ, 22050)));
			break;
		case 11025:
			IISPSR = (IISPSR_A(iispsr_value(S_CLOCK_FREQ, 11025)) 
				| IISPSR_B(iispsr_value(S_CLOCK_FREQ, 11025)));
			break;
		case 8000:
			IISPSR = (IISPSR_A(iispsr_value(S_CLOCK_FREQ, 8000)) 
				| IISPSR_B(iispsr_value(S_CLOCK_FREQ, 8000)));
			break;
		default:
			return -1;
	}

	audio_rate = val;
	
	return audio_rate;
}

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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -