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

📄 ymfpci.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
				ymf_playback_trigger(unit, &state->wpcm, 1);			}			spin_unlock_irqrestore(&unit->reg_lock, flags);			if (file->f_flags & O_NONBLOCK) {				if (!ret) ret = -EAGAIN;				break;			}			schedule();			set_current_state(TASK_INTERRUPTIBLE);			if (signal_pending(current)) {				if (!ret) ret = -ERESTARTSYS;				break;			}			continue;		}		if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {			if (!ret) ret = -EFAULT;			break;		}		if ((swptr += cnt) >= dmabuf->dmasize) {			swptr -= dmabuf->dmasize;		}		spin_lock_irqsave(&unit->reg_lock, flags);		if (unit->suspended) {			spin_unlock_irqrestore(&unit->reg_lock, flags);			continue;		}		dmabuf->swptr = swptr;		dmabuf->count += cnt;		/*		 * Start here is a bad idea - may cause startup click		 * in /bin/play when dmabuf is not full yet.		 * However, some broken applications do not make		 * any use of SNDCTL_DSP_SYNC (Doom is the worst).		 * One frame is about 5.3ms, Doom write size is 46ms.		 */		delay = state->format.rate / 20;	/* 50ms */		delay <<= state->format.shift;		if (dmabuf->count >= delay && !state->wpcm.running) {			ymf_playback_trigger(unit, &state->wpcm, 1);		}		spin_unlock_irqrestore(&unit->reg_lock, flags);		count -= cnt;		buffer += cnt;		ret += cnt;	}	set_current_state(TASK_RUNNING);	remove_wait_queue(&dmabuf->wait, &waita);	YMFDBGW("ymf_write: ret %d dmabuf.count %d\n", ret, dmabuf->count);	return ret;}static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait){	struct ymf_state *state = (struct ymf_state *)file->private_data;	struct ymf_dmabuf *dmabuf;	int redzone;	unsigned long flags;	unsigned int mask = 0;	if (file->f_mode & FMODE_WRITE)		poll_wait(file, &state->wpcm.dmabuf.wait, wait);	if (file->f_mode & FMODE_READ)		poll_wait(file, &state->rpcm.dmabuf.wait, wait);	spin_lock_irqsave(&state->unit->reg_lock, flags);	if (file->f_mode & FMODE_READ) {		dmabuf = &state->rpcm.dmabuf;		if (dmabuf->count >= (signed)dmabuf->fragsize)			mask |= POLLIN | POLLRDNORM;	}	if (file->f_mode & FMODE_WRITE) {		redzone = ymf_calc_lend(state->format.rate);		redzone <<= state->format.shift;		redzone *= 3;		dmabuf = &state->wpcm.dmabuf;		if (dmabuf->mapped) {			if (dmabuf->count >= (signed)dmabuf->fragsize)				mask |= POLLOUT | POLLWRNORM;		} else {			/*			 * Don't select unless a full fragment is available.			 * Otherwise artsd does GETOSPACE, sees 0, and loops.			 */			if (dmabuf->count + redzone + dmabuf->fragsize			     <= dmabuf->dmasize)				mask |= POLLOUT | POLLWRNORM;		}	}	spin_unlock_irqrestore(&state->unit->reg_lock, flags);	return mask;}static int ymf_mmap(struct file *file, struct vm_area_struct *vma){	struct ymf_state *state = (struct ymf_state *)file->private_data;	struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf;	int ret;	unsigned long size;	if (vma->vm_flags & VM_WRITE) {		if ((ret = prog_dmabuf(state, 0)) != 0)			return ret;	} else if (vma->vm_flags & VM_READ) {		if ((ret = prog_dmabuf(state, 1)) != 0)			return ret;	} else 		return -EINVAL;	if (vma->vm_pgoff != 0)		return -EINVAL;	size = vma->vm_end - vma->vm_start;	if (size > (PAGE_SIZE << dmabuf->buforder))		return -EINVAL;	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),			     size, vma->vm_page_prot))		return -EAGAIN;	dmabuf->mapped = 1;/* P3 */ printk(KERN_INFO "ymfpci: using memory mapped sound, untested!\n");	return 0;}static int ymf_ioctl(struct inode *inode, struct file *file,    unsigned int cmd, unsigned long arg){	struct ymf_state *state = (struct ymf_state *)file->private_data;	struct ymf_dmabuf *dmabuf;	unsigned long flags;	audio_buf_info abinfo;	count_info cinfo;	int redzone;	int val;	switch (cmd) {	case OSS_GETVERSION:		YMFDBGX("ymf_ioctl: cmd 0x%x(GETVER) arg 0x%lx\n", cmd, arg);		return put_user(SOUND_VERSION, (int *)arg);	case SNDCTL_DSP_RESET:		YMFDBGX("ymf_ioctl: cmd 0x%x(RESET)\n", cmd);		if (file->f_mode & FMODE_WRITE) {			ymf_wait_dac(state);			dmabuf = &state->wpcm.dmabuf;			spin_lock_irqsave(&state->unit->reg_lock, flags);			dmabuf->ready = 0;			dmabuf->swptr = dmabuf->hwptr;			dmabuf->count = dmabuf->total_bytes = 0;			spin_unlock_irqrestore(&state->unit->reg_lock, flags);		}		if (file->f_mode & FMODE_READ) {			ymf_stop_adc(state);			dmabuf = &state->rpcm.dmabuf;			spin_lock_irqsave(&state->unit->reg_lock, flags);			dmabuf->ready = 0;			dmabuf->swptr = dmabuf->hwptr;			dmabuf->count = dmabuf->total_bytes = 0;			spin_unlock_irqrestore(&state->unit->reg_lock, flags);		}		return 0;	case SNDCTL_DSP_SYNC:		YMFDBGX("ymf_ioctl: cmd 0x%x(SYNC)\n", cmd);		if (file->f_mode & FMODE_WRITE) {			dmabuf = &state->wpcm.dmabuf;			if (file->f_flags & O_NONBLOCK) {				spin_lock_irqsave(&state->unit->reg_lock, flags);				if (dmabuf->count != 0 && !state->wpcm.running) {					ymf_start_dac(state);				}				spin_unlock_irqrestore(&state->unit->reg_lock, flags);			} else {				ymf_wait_dac(state);			}		}		/* XXX What does this do for reading? dmabuf->count=0; ? */		return 0;	case SNDCTL_DSP_SPEED: /* set smaple rate */		if (get_user(val, (int *)arg))			return -EFAULT;		YMFDBGX("ymf_ioctl: cmd 0x%x(SPEED) sp %d\n", cmd, val);		if (val >= 8000 && val <= 48000) {			if (file->f_mode & FMODE_WRITE) {				ymf_wait_dac(state);				dmabuf = &state->wpcm.dmabuf;				spin_lock_irqsave(&state->unit->reg_lock, flags);				dmabuf->ready = 0;				state->format.rate = val;				ymf_pcm_update_shift(&state->format);				spin_unlock_irqrestore(&state->unit->reg_lock, flags);			}			if (file->f_mode & FMODE_READ) {				ymf_stop_adc(state);				dmabuf = &state->rpcm.dmabuf;				spin_lock_irqsave(&state->unit->reg_lock, flags);				dmabuf->ready = 0;				state->format.rate = val;				ymf_pcm_update_shift(&state->format);				spin_unlock_irqrestore(&state->unit->reg_lock, flags);			}		}		return put_user(state->format.rate, (int *)arg);	/*	 * OSS manual does not mention SNDCTL_DSP_STEREO at all.	 * All channels are mono and if you want stereo, you	 * play into two channels with SNDCTL_DSP_CHANNELS.	 * However, mpg123 calls it. I wonder, why Michael Hipp used it.	 */	case SNDCTL_DSP_STEREO: /* set stereo or mono channel */		if (get_user(val, (int *)arg))			return -EFAULT;		YMFDBGX("ymf_ioctl: cmd 0x%x(STEREO) st %d\n", cmd, val);		if (file->f_mode & FMODE_WRITE) {			ymf_wait_dac(state); 			dmabuf = &state->wpcm.dmabuf;			spin_lock_irqsave(&state->unit->reg_lock, flags);			dmabuf->ready = 0;			state->format.voices = val ? 2 : 1;			ymf_pcm_update_shift(&state->format);			spin_unlock_irqrestore(&state->unit->reg_lock, flags);		}		if (file->f_mode & FMODE_READ) {			ymf_stop_adc(state);			dmabuf = &state->rpcm.dmabuf;			spin_lock_irqsave(&state->unit->reg_lock, flags);			dmabuf->ready = 0;			state->format.voices = val ? 2 : 1;			ymf_pcm_update_shift(&state->format);			spin_unlock_irqrestore(&state->unit->reg_lock, flags);		}		return 0;	case SNDCTL_DSP_GETBLKSIZE:		YMFDBGX("ymf_ioctl: cmd 0x%x(GETBLK)\n", cmd);		if (file->f_mode & FMODE_WRITE) {			if ((val = prog_dmabuf(state, 0)))				return val;			val = state->wpcm.dmabuf.fragsize;			YMFDBGX("ymf_ioctl: GETBLK w %d\n", val);			return put_user(val, (int *)arg);		}		if (file->f_mode & FMODE_READ) {			if ((val = prog_dmabuf(state, 1)))				return val;			val = state->rpcm.dmabuf.fragsize;			YMFDBGX("ymf_ioctl: GETBLK r %d\n", val);			return put_user(val, (int *)arg);		}		return -EINVAL;	case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/		YMFDBGX("ymf_ioctl: cmd 0x%x(GETFMTS)\n", cmd);		return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);	case SNDCTL_DSP_SETFMT: /* Select sample format */		if (get_user(val, (int *)arg))			return -EFAULT;		YMFDBGX("ymf_ioctl: cmd 0x%x(SETFMT) fmt %d\n", cmd, val);		if (val == AFMT_S16_LE || val == AFMT_U8) {			if (file->f_mode & FMODE_WRITE) {				ymf_wait_dac(state);				dmabuf = &state->wpcm.dmabuf;				spin_lock_irqsave(&state->unit->reg_lock, flags);				dmabuf->ready = 0;				state->format.format = val;				ymf_pcm_update_shift(&state->format);				spin_unlock_irqrestore(&state->unit->reg_lock, flags);			}			if (file->f_mode & FMODE_READ) {				ymf_stop_adc(state);				dmabuf = &state->rpcm.dmabuf;				spin_lock_irqsave(&state->unit->reg_lock, flags);				dmabuf->ready = 0;				state->format.format = val;				ymf_pcm_update_shift(&state->format);				spin_unlock_irqrestore(&state->unit->reg_lock, flags);			}		}		return put_user(state->format.format, (int *)arg);	case SNDCTL_DSP_CHANNELS:		if (get_user(val, (int *)arg))			return -EFAULT;		YMFDBGX("ymf_ioctl: cmd 0x%x(CHAN) ch %d\n", cmd, val);		if (val != 0) {			if (file->f_mode & FMODE_WRITE) {				ymf_wait_dac(state);				if (val == 1 || val == 2) {					spin_lock_irqsave(&state->unit->reg_lock, flags);					dmabuf = &state->wpcm.dmabuf;					dmabuf->ready = 0;					state->format.voices = val;					ymf_pcm_update_shift(&state->format);					spin_unlock_irqrestore(&state->unit->reg_lock, flags);				}			}			if (file->f_mode & FMODE_READ) {				ymf_stop_adc(state);				if (val == 1 || val == 2) {					spin_lock_irqsave(&state->unit->reg_lock, flags);					dmabuf = &state->rpcm.dmabuf;					dmabuf->ready = 0;					state->format.voices = val;					ymf_pcm_update_shift(&state->format);					spin_unlock_irqrestore(&state->unit->reg_lock, flags);				}			}		}		return put_user(state->format.voices, (int *)arg);	case SNDCTL_DSP_POST:		YMFDBGX("ymf_ioctl: cmd 0x%x(POST)\n", cmd);		/*		 * Quoting OSS PG:		 *    The ioctl SNDCTL_DSP_POST is a lightweight version of		 *    SNDCTL_DSP_SYNC. It just tells to the driver that there		 *    is likely to be a pause in the output. This makes it		 *    possible for the device to handle the pause more		 *    intelligently. This ioctl doesn't block the application.		 *		 * The paragraph above is a clumsy way to say "flush ioctl".		 * This ioctl is used by mpg123.		 */		spin_lock_irqsave(&state->unit->reg_lock, flags);		if (state->wpcm.dmabuf.count != 0 && !state->wpcm.running) {			ymf_start_dac(state);		}		spin_unlock_irqrestore(&state->unit->reg_lock, flags);		return 0;	case SNDCTL_DSP_SETFRAGMENT:		if (get_user(val, (int *)arg))			return -EFAULT;		YMFDBGX("ymf_ioctl: cmd 0x%x(SETFRAG) fr 0x%04x:%04x(%d:%d)\n",		    cmd,		    (val >> 16) & 0xFFFF, val & 0xFFFF,		    (val >> 16) & 0xFFFF, val & 0xFFFF);		dmabuf = &state->wpcm.dmabuf;		dmabuf->ossfragshift = val & 0xffff;		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;		if (dmabuf->ossfragshift < 4)			dmabuf->ossfragshift = 4;		if (dmabuf->ossfragshift > 15)			dmabuf->ossfragshift = 15;		return 0;	case SNDCTL_DSP_GETOSPACE:		YMFDBGX("ymf_ioctl: cmd 0x%x(GETOSPACE)\n", cmd);		if (!(file->f_mode & FMODE_WRITE))			return -EINVAL;		dmabuf = &state->wpcm.dmabuf;		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)			return val;		redzone = ymf_calc_lend(state->format.rate);		redzone <<= state->format.shift;		redzone *= 3;		spin_lock_irqsave(&state->unit->reg_lock, flags);		abinfo.fragsize = dmabuf->fragsize;		abinfo.bytes = dmabuf->dmasize - dmabuf->count - redzone;		abinfo.fragstotal = dmabuf->numfrag;		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;		spin_unlock_irqrestore(&state->unit->reg_lock, flags);		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;	case SNDCTL_DSP_GETISPACE:		YMFDBGX("ymf_ioctl: cmd 0x%x(GETISPACE)\n", cmd);		if (!(file->f_mode & FMODE_READ))			return -EINVAL;		dmabuf = &state->rpcm.dmabuf;		if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)			return val;		spin_lock_irqsave(&state->unit->reg_lock, flags);		abinfo.fragsize = dmabuf->fragsize;		abinfo.bytes = dmabuf->count;		abinfo.fragstotal = dmabuf->numfrag;		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;		spin_unlock_irqrestore(&state->unit->reg_lock, flags);		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;	case SNDCTL_DSP_NONBLOCK:		YMFDBGX("ymf_ioctl: cmd 0x%x(NONBLOCK)\n", cmd);		file->f_flags |= O_NONBLOCK;		return 0;	case SNDCTL_DSP_GETCAPS:		YMFDBGX("ymf_ioctl: cmd 0x%x(GETCAPS)\n", cmd);		/* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,			    (int *)arg); */		return put_user(0, (int *)arg);	case SNDCTL_DSP_GETIPTR:		YMFDBGX("ymf_ioctl: cmd 0x%x(GETIPTR)\n", cmd);		if (!(file->f_mode & FMODE_READ))			return -EINVAL;		dmabuf = &state->rpcm.dmabuf;		spin_lock_irqsave(&state->unit->reg_lock, flags);		cinfo.bytes = dmabuf->total_bytes;		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;		cinfo.ptr = dmabuf->hwptr;		spin_unlock_irqrestore(&state->unit->reg_lock, flags);		YMFDBGX("ymf_ioctl: GETIPTR ptr %d bytes %d\n",		    cinfo.ptr, cinfo.bytes);		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;	case SNDCTL_DSP_GETOPTR:		YMFDBGX("ymf_ioctl: cmd 0x%x(GETOPTR)\n", cmd);		if (!(file->f_mode & FMODE_WRITE))			return -EINVAL;		dmabuf = &state->wpcm.dmabuf;		spin_lock_irqsave(&state->unit->reg_lock, flags);		cinfo.bytes = dmabuf->total_bytes;		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;		cinfo.ptr = dmabuf->hwptr;		spin_unlock_irqrestore(&state->unit->reg_lock, flags);		YMFDBGX("ymf_ioctl: GETOPTR ptr %d bytes %d\n",		    cinfo.ptr, cinfo.bytes);		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;	case SNDCTL_DSP_SETDUPLEX:	/* XXX TODO */		YMFDBGX("ymf_ioctl: cmd 0x%x(SETDUPLEX)\n", cmd);		return -EINVAL;	case SOUND_PCM_READ_RATE:		YMFDBGX("ymf_ioctl: cmd 0x%x(READ_RATE)\n", cmd);		return put_user(state->format.rate, (int *)arg);	case SOUND_PCM_READ_CHANNELS:		YMFDBGX("ymf_ioctl: cmd 0x%x(READ_CH)\n", cmd);		return put_user(state->format.voices, (int *)arg);	case SOUND_PCM_READ_BITS:		YMFDBGX("ymf_ioctl: cmd 0x%x(READ_BITS)\n", cmd);		return put_user(AFMT_S16_LE, (int *)arg);	case SNDCTL_DSP_MAPINBUF:	case SNDCTL_DSP_MAPOUTBUF:	case SNDCTL_DSP_SETSYNCRO:	case SOUND_PCM_WRITE_FILTER:	case SOUND_PCM_READ_FILTER:		YMFDBGX("ymf_ioctl: cmd 0x%x unsupported\n", cmd);		return -ENOTTY;	default:		/*		 * Some programs mix up audio devices and ioctls		 * or perhaps they expect "universal" ioctls,		 * for instance we get SNDCTL_TMR_CONTINUE here.		 */		YMFDBGX("ymf_ioctl: cmd 0x%x unknown\n", cmd);		break;

⌨️ 快捷键说明

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