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

📄 harmony.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
				if (harmony.nb_filled_record < 2)			return -EBUSY;				buf_to_read = harmony.first_filled_record;		/* Copy the page to an aligned buffer */		if (copy_to_user(buffer+count, recorded_buf.addr +				 (HARMONY_BUF_SIZE*buf_to_read),				 HARMONY_BUF_SIZE)) {			count = -EFAULT;			break;		}				harmony.nb_filled_record--;		harmony.first_filled_record++;		harmony.first_filled_record %= MAX_BUFS;						count += HARMONY_BUF_SIZE;	}	return count;}/* * Here is the place where we try to recognize file format. * Sun/NeXT .au files begin with the string .snd * At offset 12 is specified the encoding. * At offset 16 is specified speed rate * At Offset 20 is specified the numbers of voices */#define four_bytes_to_u32(start) (file_header[start] << 24)|\                                  (file_header[start+1] << 16)|\                                  (file_header[start+2] << 8)|\                                  (file_header[start+3]);#define test_rate(tested,real_value,harmony_value) if ((tested)<=(real_value))\                                                    static int harmony_format_auto_detect(const char *buffer, int block_size){	u8 file_header[24];	u32 start_string;	int ret = 0;		if (block_size>24) {		if (copy_from_user(file_header, buffer, sizeof(file_header)))			ret = -EFAULT;					start_string = four_bytes_to_u32(0);				if ((file_header[4]==0) && (start_string==0x2E736E64)) {			u32 format;			u32 nb_voices;			u32 speed;						format = four_bytes_to_u32(12);			nb_voices = four_bytes_to_u32(20);			speed = four_bytes_to_u32(16);						switch (format) {			case HARMONY_MAGIC_8B_ULAW:				harmony.data_format = HARMONY_DF_8BIT_ULAW;				break;			case HARMONY_MAGIC_8B_ALAW:				harmony.data_format = HARMONY_DF_8BIT_ALAW;				break;			case HARMONY_MAGIC_16B_LINEAR:				harmony.data_format = HARMONY_DF_16BIT_LINEAR;				break;			default:				harmony_set_control(HARMONY_DF_16BIT_LINEAR,						HARMONY_SR_44KHZ, HARMONY_SS_STEREO);				goto out;			}			switch (nb_voices) {			case HARMONY_MAGIC_MONO:				harmony.stereo_select = HARMONY_SS_MONO;				break;			case HARMONY_MAGIC_STEREO:				harmony.stereo_select = HARMONY_SS_STEREO;				break;			default:				harmony.stereo_select = HARMONY_SS_MONO;				break;			}			harmony_set_rate(harmony_detect_rate(&speed));			harmony.dac_rate = speed;			goto out;		}	}	harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO);out:	return ret;}#undef four_bytes_to_u32static ssize_t harmony_audio_write(struct file *file,                                 const char *buffer,                                 size_t size_count,                                 loff_t *ppos){	int total_count = (int) size_count;	int count = 0;	int frame_size;	int buf_to_fill;	int fresh_buffer;	if (!harmony.format_initialized) {		if (harmony_format_auto_detect(buffer, total_count))			return -EFAULT;	}		while (count<total_count) {		/* Wait until we're out of control mode */		harmony_wait_CNTL();		/* Figure out which buffer to fill in */		if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset) {			harmony.blocked_playing = 1;			interruptible_sleep_on(&harmony.wq_play);			harmony.blocked_playing = 0;		}		if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset)			return -EBUSY;						buf_to_fill = (harmony.first_filled_play+harmony.nb_filled_play); 		if (harmony.play_offset) {			buf_to_fill--;			buf_to_fill += MAX_BUFS;		}		buf_to_fill %= MAX_BUFS;				fresh_buffer = (harmony.play_offset == 0);				/* Figure out the size of the frame */		if ((total_count-count) >= HARMONY_BUF_SIZE - harmony.play_offset) {			frame_size = HARMONY_BUF_SIZE - harmony.play_offset;		} else {			frame_size = total_count - count;			/* Clear out the buffer, since there we'll only be 			   overlaying part of the old buffer with the new one */			harmony_silence(&played_buf, 				HARMONY_BUF_SIZE*buf_to_fill+frame_size+harmony.play_offset,				HARMONY_BUF_SIZE-frame_size-harmony.play_offset);		}		/* Copy the page to an aligned buffer */		if (copy_from_user(played_buf.addr +(HARMONY_BUF_SIZE*buf_to_fill) + harmony.play_offset, 				   buffer+count, frame_size))			return -EFAULT;		CHECK_WBACK_INV_OFFSET(played_buf, (HARMONY_BUF_SIZE*buf_to_fill + harmony.play_offset), 				frame_size);			if (fresh_buffer)			harmony.nb_filled_play++;				count += frame_size;		harmony.play_offset += frame_size;		harmony.play_offset %= HARMONY_BUF_SIZE;		if (harmony.suspended_playing && (harmony.nb_filled_play>=4))			harmony_enable_interrupts();	}		return count;}static unsigned int harmony_audio_poll(struct file *file,                                     struct poll_table_struct *wait){	unsigned int mask = 0;		if (file->f_mode & FMODE_READ) {		if (!harmony.suspended_recording)			poll_wait(file, &harmony.wq_record, wait);		if (harmony.nb_filled_record)			mask |= POLLIN | POLLRDNORM;	}	if (file->f_mode & FMODE_WRITE) {		if (!harmony.suspended_playing)			poll_wait(file, &harmony.wq_play, wait);		if (harmony.nb_filled_play)			mask |= POLLOUT | POLLWRNORM;	}	return mask;}static int harmony_audio_ioctl(struct inode *inode,                                struct file *file,				unsigned int cmd,                                unsigned long arg){	int ival, new_format;	int frag_size, frag_buf;	struct audio_buf_info info;		switch (cmd) {	case OSS_GETVERSION:		return put_user(SOUND_VERSION, (int *) arg);	case SNDCTL_DSP_GETCAPS:		ival = DSP_CAP_DUPLEX;		return put_user(ival, (int *) arg);	case SNDCTL_DSP_GETFMTS:		ival = (AFMT_S16_BE | AFMT_MU_LAW | AFMT_A_LAW ); 		return put_user(ival, (int *) arg);		case SNDCTL_DSP_SETFMT:		if (get_user(ival, (int *) arg)) 			return -EFAULT;		if (ival != AFMT_QUERY) {			switch (ival) {			case AFMT_MU_LAW:	new_format = HARMONY_DF_8BIT_ULAW; break;			case AFMT_A_LAW:	new_format = HARMONY_DF_8BIT_ALAW; break;			case AFMT_S16_BE:	new_format = HARMONY_DF_16BIT_LINEAR; break;			default: {				DPRINTK(KERN_WARNING PFX 					"unsupported sound format 0x%04x requested.\n",					ival);				ival = AFMT_S16_BE;				return put_user(ival, (int *) arg);			}			}			harmony_set_format(new_format);			return 0;		} else {			switch (harmony.data_format) {			case HARMONY_DF_8BIT_ULAW:	ival = AFMT_MU_LAW; break;			case HARMONY_DF_8BIT_ALAW:	ival = AFMT_A_LAW;  break;			case HARMONY_DF_16BIT_LINEAR:	ival = AFMT_U16_BE; break;			default: ival = 0;			}			return put_user(ival, (int *) arg);		}	case SOUND_PCM_READ_RATE:		ival = harmony.dac_rate;		return put_user(ival, (int *) arg);	case SNDCTL_DSP_SPEED:		if (get_user(ival, (int *) arg))			return -EFAULT;		harmony_set_rate(harmony_detect_rate(&ival));		harmony.dac_rate = ival;		return put_user(ival, (int*) arg);	case SNDCTL_DSP_STEREO:		if (get_user(ival, (int *) arg))			return -EFAULT;		if (ival != 0 && ival != 1)			return -EINVAL;		harmony_set_stereo(ival); 		return 0;  	case SNDCTL_DSP_CHANNELS: 		if (get_user(ival, (int *) arg)) 			return -EFAULT; 		if (ival != 1 && ival != 2) { 			ival = harmony.stereo_select == HARMONY_SS_MONO ? 1 : 2; 			return put_user(ival, (int *) arg); 		} 		harmony_set_stereo(ival-1); 		return 0;	case SNDCTL_DSP_GETBLKSIZE:		ival = HARMONY_BUF_SIZE;		return put_user(ival, (int *) arg);		        case SNDCTL_DSP_NONBLOCK:                file->f_flags |= O_NONBLOCK;                return 0;        case SNDCTL_DSP_RESET:		if (!harmony.suspended_recording) {			/* TODO: stop_recording() */		}		return 0;	case SNDCTL_DSP_SETFRAGMENT:		if (get_user(ival, (int *)arg))			return -EFAULT;		frag_size = ival & 0xffff;		frag_buf = (ival>>16) & 0xffff;		/* TODO: We use hardcoded fragment sizes and numbers for now */		frag_size = 12;  /* 4096 == 2^12 */		frag_buf  = MAX_BUFS;		ival = (frag_buf << 16) + frag_size;		return put_user(ival, (int *) arg);			case SNDCTL_DSP_GETOSPACE:		if (!(file->f_mode & FMODE_WRITE))			return -EINVAL;		info.fragstotal = MAX_BUFS;                info.fragments = MAX_BUFS - harmony.nb_filled_play;		info.fragsize = HARMONY_BUF_SIZE;                info.bytes = info.fragments * info.fragsize;		return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;	case SNDCTL_DSP_GETISPACE:		if (!(file->f_mode & FMODE_READ))			return -EINVAL;		info.fragstotal = MAX_BUFS;                info.fragments = /*MAX_BUFS-*/ harmony.nb_filled_record;		info.fragsize = HARMONY_BUF_SIZE;                info.bytes = info.fragments * info.fragsize;		return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;		case SNDCTL_DSP_SYNC:		return 0;	}		return -EINVAL;}/* * harmony_interrupt() * * harmony interruption service routine *  */static irqreturn_t harmony_interrupt(int irq, void *dev, struct pt_regs *regs){	u32 dstatus;	struct harmony_hpa *hpa;	/* Setup the hpa */	hpa = ((struct harmony_dev *)dev)->hpa;	harmony_wait_CNTL();	/* Read dstatus and pcuradd (the current address) */	dstatus = gsc_readl(&hpa->dstatus);		/* Turn off interrupts */	harmony_disable_interrupts();		/* Check if this is a request to get the next play buffer */	if (dstatus & DSTATUS_PN) {		if (!harmony.nb_filled_play) {			harmony.suspended_playing = 1;			gsc_writel((unsigned long)silent.dma_handle, &hpa->pnxtadd);									if (!harmony.suspended_recording)				harmony_enable_interrupts();		} else {			harmony.suspended_playing = 0;			gsc_writel((unsigned long)played_buf.dma_handle + 					(HARMONY_BUF_SIZE*harmony.first_filled_play),					&hpa->pnxtadd);			harmony.first_filled_play++;			harmony.first_filled_play %= MAX_BUFS;			harmony.nb_filled_play--;					       	harmony_enable_interrupts();		}				if (harmony.blocked_playing)			wake_up_interruptible(&harmony.wq_play);	}		/* Check if we're being asked to fill in a recording buffer */	if (dstatus & DSTATUS_RN) {		if((harmony.nb_filled_record+2>=MAX_BUFS) || harmony.suspended_recording)		{			harmony.nb_filled_record = 0;			harmony.first_filled_record = 0;			harmony.suspended_recording = 1;			gsc_writel((unsigned long)graveyard.dma_handle, &hpa->rnxtadd);			if (!harmony.suspended_playing)				harmony_enable_interrupts();		} else {			int buf_to_fill;			buf_to_fill = (harmony.first_filled_record+harmony.nb_filled_record) % MAX_BUFS;			CHECK_WBACK_INV_OFFSET(recorded_buf, HARMONY_BUF_SIZE*buf_to_fill, HARMONY_BUF_SIZE);			gsc_writel((unsigned long)recorded_buf.dma_handle +					HARMONY_BUF_SIZE*buf_to_fill,					&hpa->rnxtadd);			harmony.nb_filled_record++;			harmony_enable_interrupts();		}		if (harmony.blocked_recording && harmony.nb_filled_record>3)			wake_up_interruptible(&harmony.wq_record);	}	return IRQ_HANDLED;}/* * Sound playing functions */static struct file_operations harmony_audio_fops = {	.owner		= THIS_MODULE,	.llseek		= no_llseek,	.read		= harmony_audio_read,	.write		= harmony_audio_write,	.poll		= harmony_audio_poll,	.ioctl		= harmony_audio_ioctl,	.open		= harmony_audio_open,	.release	= harmony_audio_release,};static int harmony_audio_init(void){	/* Request that IRQ */	if (request_irq(harmony.dev->irq, harmony_interrupt, 0 ,"harmony", &harmony)) {		printk(KERN_ERR PFX "Error requesting irq %d.\n", harmony.dev->irq);		return -EFAULT;	}   	harmony.dsp_unit = register_sound_dsp(&harmony_audio_fops, -1);	if (harmony.dsp_unit < 0) {		printk(KERN_ERR PFX "Error registering dsp\n");		free_irq(harmony.dev->irq, &harmony);		return -EFAULT;	}		/* Clear the buffers so you don't end up with crap in the buffers. */ 	harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);	/* Make sure this makes it to cache */	CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);	/* Clear out the silent buffer and flush to cache */	harmony_silence(&silent, 0, HARMONY_BUF_SIZE);	CHECK_WBACK_INV_OFFSET(silent, 0, HARMONY_BUF_SIZE);		harmony.audio_open = 0;		return 0;}/* * mixer functions 

⌨️ 快捷键说明

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