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

📄 audio.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 3 页
字号:
			break;	}	if (entry == &emu10k1_devs)		return -ENODEV;	if ((wave_dev = (struct emu10k1_wavedevice *)	     kmalloc(sizeof(struct emu10k1_wavedevice), GFP_KERNEL)) == NULL) {		ERROR();		return -EINVAL;	}	wave_dev->card = card;	wave_dev->wiinst = NULL;	wave_dev->woinst = NULL;	wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT;	/* Default */	if (file->f_mode & FMODE_READ) {		/* Recording */		struct wiinst *wiinst;		if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) {			ERROR();			return -ENODEV;		}		wiinst->recsrc = card->wavein.recsrc;                wiinst->fxwc = card->wavein.fxwc;		switch (wiinst->recsrc) {		case WAVERECORD_AC97:			wiinst->format.samplingrate = 8000;			wiinst->format.bitsperchannel = 16;			wiinst->format.channels = 1;			break;		case WAVERECORD_MIC:			wiinst->format.samplingrate = 8000;			wiinst->format.bitsperchannel = 16;			wiinst->format.channels = 1;			break;		case WAVERECORD_FX:			wiinst->format.samplingrate = 48000;			wiinst->format.bitsperchannel = 16;			wiinst->format.channels = hweight32(wiinst->fxwc);			break;		default:			BUG();			break;		}		wiinst->state = WAVE_STATE_CLOSED;		wiinst->buffer.ossfragshift = 0;		wiinst->buffer.fragment_size = 0;		wiinst->buffer.numfrags = 0;		init_waitqueue_head(&wiinst->wait_queue);		wiinst->mmapped = 0;		wiinst->total_recorded = 0;		wiinst->blocks = 0;		wiinst->lock = SPIN_LOCK_UNLOCKED;		tasklet_init(&wiinst->timer.tasklet, emu10k1_wavein_bh, (unsigned long) wave_dev);		wave_dev->wiinst = wiinst;		emu10k1_wavein_setformat(wave_dev, &wiinst->format);	}	if (file->f_mode & FMODE_WRITE) {		struct woinst *woinst;		if ((woinst = (struct woinst *) kmalloc(sizeof(struct woinst), GFP_KERNEL)) == NULL) {			ERROR();			return -ENODEV;		}		if (wave_dev->wiinst != NULL) {			woinst->format = wave_dev->wiinst->format;		} else {			woinst->format.samplingrate = 8000;			woinst->format.bitsperchannel = 8;			woinst->format.channels = 1;		}		woinst->state = WAVE_STATE_CLOSED;		woinst->buffer.fragment_size = 0;		woinst->buffer.ossfragshift = 0;		woinst->buffer.numfrags = 0;		woinst->device = (card->audio1_num == minor);		init_waitqueue_head(&woinst->wait_queue);		woinst->mmapped = 0;		woinst->total_copied = 0;		woinst->total_played = 0;		woinst->blocks = 0;		woinst->lock = SPIN_LOCK_UNLOCKED;		tasklet_init(&woinst->timer.tasklet, emu10k1_waveout_bh, (unsigned long) wave_dev);		wave_dev->woinst = woinst;		emu10k1_waveout_setformat(wave_dev, &woinst->format);#ifdef PRIVATE_PCM_VOLUME		{			int i;			int j = -1;			/*			 * find out if we've already been in this table			 * xmms reopens dsp on every move of slider			 * this way we keep the same local pcm for such			 * process			 */			for (i = 0; i < MAX_PCM_CHANNELS; i++) {				if (sblive_pcm_volume[i].files == current->files)					break;				// here we should select last used memeber				// improve me in case its not sufficient				if (j < 0 && !sblive_pcm_volume[i].opened)					j = i;			}			// current task not found			if (i == MAX_PCM_CHANNELS) {				// add new entry				if (j < 0)					printk(KERN_WARNING "emu10k1: too many writters!\n");				i = (j >= 0) ? j : 0;				DPD(2, "new pcm private %p\n", current->files);				sblive_pcm_volume[i].files = current->files;				sblive_pcm_volume[i].mixer = pcm_last_mixer;				sblive_pcm_volume[i].attn_l = 0;				sblive_pcm_volume[i].attn_r = 0;				sblive_pcm_volume[i].channel_l = NUM_G;				sblive_pcm_volume[i].channel_r = NUM_G;			} else				DPD(2, "old pcm private %p  0x%x\n", current->files,				    sblive_pcm_volume[i].mixer);			sblive_pcm_volume[i].opened++;		}#endif	}	file->private_data = (void *) wave_dev;	return 0;}static int emu10k1_audio_release(struct inode *inode, struct file *file){	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;	struct emu10k1_card *card;	unsigned long flags;	lock_kernel();	card = wave_dev->card;	DPF(2, "emu10k1_audio_release()\n");	if (file->f_mode & FMODE_WRITE) {		struct woinst *woinst = wave_dev->woinst;		spin_lock_irqsave(&woinst->lock, flags);		if (woinst->state & WAVE_STATE_OPEN) {			if (woinst->state & WAVE_STATE_STARTED) {				if (!(file->f_flags & O_NONBLOCK)) {					while (!signal_pending(current)					       && (woinst->total_played < woinst->total_copied)) {						DPF(4, "Buffer hasn't been totally played, sleep....\n");						spin_unlock_irqrestore(&woinst->lock, flags);						interruptible_sleep_on(&woinst->wait_queue);						spin_lock_irqsave(&woinst->lock, flags);					}				}			}			if (woinst->mmapped) {				int i;				/* Undo marking the pages as reserved */				for (i = 0; i < woinst->buffer.pages; i++)					mem_map_reserve(virt_to_page(woinst->buffer.addr[i]));			}			emu10k1_waveout_close(wave_dev);		}#ifdef PRIVATE_PCM_VOLUME		{			int i;			/* mark as closed			 * NOTE: structure remains unchanged for next reopen */			for (i = 0; i < MAX_PCM_CHANNELS; i++) {				if (sblive_pcm_volume[i].files == current->files) {					sblive_pcm_volume[i].opened--;					break;				}			}		}#endif		spin_unlock_irqrestore(&woinst->lock, flags);		/* wait for the tasklet (bottom-half) to finish */		tasklet_unlock_wait(&woinst->timer.tasklet);		kfree(wave_dev->woinst);	}	if (file->f_mode & FMODE_READ) {		struct wiinst *wiinst = wave_dev->wiinst;		spin_lock_irqsave(&wiinst->lock, flags);		if (wiinst->state & WAVE_STATE_OPEN)			emu10k1_wavein_close(wave_dev);		spin_unlock_irqrestore(&wiinst->lock, flags);		tasklet_unlock_wait(&wiinst->timer.tasklet);		kfree(wave_dev->wiinst);	}	kfree(wave_dev);	wake_up_interruptible(&card->open_wait);	unlock_kernel();	return 0;}static unsigned int emu10k1_audio_poll(struct file *file, struct poll_table_struct *wait){	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;	struct woinst *woinst = wave_dev->woinst;	struct wiinst *wiinst = wave_dev->wiinst;	unsigned int mask = 0;	u32 bytestocopy;	unsigned long flags;	DPF(4, "emu10k1_audio_poll()\n");	if (file->f_mode & FMODE_WRITE)		poll_wait(file, &woinst->wait_queue, wait);	if (file->f_mode & FMODE_READ)		poll_wait(file, &wiinst->wait_queue, wait);	if (file->f_mode & FMODE_WRITE) {		spin_lock_irqsave(&woinst->lock, flags);		if (woinst->state & WAVE_STATE_OPEN) {			emu10k1_waveout_update(woinst);			emu10k1_waveout_getxfersize(woinst, &bytestocopy);			if (bytestocopy >= woinst->buffer.fragment_size)				mask |= POLLOUT | POLLWRNORM;		} else			mask |= POLLOUT | POLLWRNORM;		if(woinst->mmapped) {			spin_unlock_irqrestore(&woinst->lock, flags);			return mask;		}		spin_unlock_irqrestore(&woinst->lock, flags);	}	if (file->f_mode & FMODE_READ) {		spin_lock_irqsave(&wiinst->lock, flags);		if (wiinst->state == WAVE_STATE_CLOSED) {			calculate_ifrag(wiinst);			if (emu10k1_wavein_open(wave_dev) < 0) {				spin_unlock_irqrestore(&wiinst->lock, flags);				return (mask |= POLLERR);			}		}		if (!(wiinst->state & WAVE_STATE_STARTED)) {			wave_dev->enablebits |= PCM_ENABLE_INPUT;			emu10k1_wavein_start(wave_dev);		}		emu10k1_wavein_update(wave_dev->card, wiinst);		emu10k1_wavein_getxfersize(wiinst, &bytestocopy);		if (bytestocopy >= wiinst->buffer.fragment_size)			mask |= POLLIN | POLLRDNORM;		spin_unlock_irqrestore(&wiinst->lock, flags);	}	return mask;}static void calculate_ofrag(struct woinst *woinst){	struct waveout_buffer *buffer = &woinst->buffer;	u32 fragsize;	if (buffer->fragment_size)		return;	if (!buffer->ossfragshift) {		fragsize = (woinst->format.bytespersec * WAVEOUT_DEFAULTFRAGLEN) / 1000 - 1;		while (fragsize) {			fragsize >>= 1;			buffer->ossfragshift++;		}	}	if (buffer->ossfragshift < WAVEOUT_MINFRAGSHIFT)		buffer->ossfragshift = WAVEOUT_MINFRAGSHIFT;	buffer->fragment_size = 1 << buffer->ossfragshift;	if (!buffer->numfrags) {		u32 numfrags;		numfrags = (woinst->format.bytespersec * WAVEOUT_DEFAULTBUFLEN) / (buffer->fragment_size * 1000) - 1;		buffer->numfrags = 1;		while (numfrags) {			numfrags >>= 1;			buffer->numfrags <<= 1;		}	}	if (buffer->numfrags < MINFRAGS)		buffer->numfrags = MINFRAGS;	if (buffer->numfrags * buffer->fragment_size > WAVEOUT_MAXBUFSIZE) {		buffer->numfrags = WAVEOUT_MAXBUFSIZE / buffer->fragment_size;		if (buffer->numfrags < MINFRAGS) {			buffer->numfrags = MINFRAGS;			buffer->fragment_size = WAVEOUT_MAXBUFSIZE / MINFRAGS;		}	} else if (buffer->numfrags * buffer->fragment_size < WAVEOUT_MINBUFSIZE)		buffer->numfrags = WAVEOUT_MINBUFSIZE / buffer->fragment_size;	buffer->size = buffer->fragment_size * buffer->numfrags;	buffer->pages = buffer->size / PAGE_SIZE + ((buffer->size % PAGE_SIZE) ? 1 : 0);	DPD(2, " calculated playback fragment_size -> %d\n", buffer->fragment_size);	DPD(2, " calculated playback numfrags -> %d\n", buffer->numfrags);	return;}static void calculate_ifrag(struct wiinst *wiinst){	struct wavein_buffer *buffer = &wiinst->buffer;	u32 fragsize, bufsize, size[4];	int i, j;	if (buffer->fragment_size)		return;	if (!buffer->ossfragshift) {		fragsize = (wiinst->format.bytespersec * WAVEIN_DEFAULTFRAGLEN) / 1000 - 1;		while (fragsize) {			fragsize >>= 1;			buffer->ossfragshift++;		}	}	if (buffer->ossfragshift < WAVEIN_MINFRAGSHIFT)		buffer->ossfragshift = WAVEIN_MINFRAGSHIFT;	buffer->fragment_size = 1 << buffer->ossfragshift;	if (!buffer->numfrags)		buffer->numfrags = (wiinst->format.bytespersec * WAVEIN_DEFAULTBUFLEN) / (buffer->fragment_size * 1000) - 1;	if (buffer->numfrags < MINFRAGS)		buffer->numfrags = MINFRAGS;	if (buffer->numfrags * buffer->fragment_size > WAVEIN_MAXBUFSIZE) {		buffer->numfrags = WAVEIN_MAXBUFSIZE / buffer->fragment_size;		if (buffer->numfrags < MINFRAGS) {			buffer->numfrags = MINFRAGS;			buffer->fragment_size = WAVEIN_MAXBUFSIZE / MINFRAGS;		}	} else if (buffer->numfrags * buffer->fragment_size < WAVEIN_MINBUFSIZE)		buffer->numfrags = WAVEIN_MINBUFSIZE / buffer->fragment_size;	bufsize = buffer->fragment_size * buffer->numfrags;	if (bufsize >= 0x10000) {		buffer->size = 0x10000;		buffer->sizeregval = 0x1f;	} else {		buffer->size = 0;		size[0] = 384;		size[1] = 448;		size[2] = 512;		size[3] = 640;		for (i = 0; i < 8; i++)			for (j = 0; j < 4; j++)				if (bufsize >= size[j]) {					buffer->size = size[j];					size[j] *= 2;					buffer->sizeregval = i * 4 + j + 1;				} else					goto exitloop;	      exitloop:		if (buffer->size == 0) {			buffer->size = 384;			buffer->sizeregval = 0x01;		}	}	buffer->numfrags = buffer->size / buffer->fragment_size;	if (buffer->size % buffer->fragment_size)		BUG();	DPD(2, " calculated recording fragment_size -> %d\n", buffer->fragment_size);	DPD(2, " calculated recording numfrags -> %d\n", buffer->numfrags);	DPD(2, " buffer size register -> 0x%2x\n", buffer->sizeregval);	return;}void emu10k1_wavein_bh(unsigned long refdata){	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata;	struct wiinst *wiinst = wave_dev->wiinst;	u32 bytestocopy;	unsigned long flags;	spin_lock_irqsave(&wiinst->lock, flags);	if (!(wiinst->state & WAVE_STATE_STARTED)) {		spin_unlock_irqrestore(&wiinst->lock, flags);		return;	}	emu10k1_wavein_update(wave_dev->card, wiinst);	if (wiinst->mmapped) {		spin_unlock_irqrestore(&wiinst->lock, flags);		return;	}	emu10k1_wavein_getxfersize(wiinst, &bytestocopy);	spin_unlock_irqrestore(&wiinst->lock, flags);	if (bytestocopy >= wiinst->buffer.fragment_size)		wake_up_interruptible(&wiinst->wait_queue);	else		DPD(3, "Not enough transfer size, %d\n", bytestocopy);	return;}void emu10k1_waveout_bh(unsigned long refdata){	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata;	struct woinst *woinst = wave_dev->woinst;	u32 bytestocopy;	unsigned long flags;	spin_lock_irqsave(&woinst->lock, flags);	if (!(woinst->state & WAVE_STATE_STARTED)) {		spin_unlock_irqrestore(&woinst->lock, flags);		return;	}	emu10k1_waveout_update(woinst);	emu10k1_waveout_getxfersize(woinst, &bytestocopy);	if (woinst->buffer.fill_silence) {		spin_unlock_irqrestore(&woinst->lock, flags);		emu10k1_waveout_fillsilence(woinst);	} else		spin_unlock_irqrestore(&woinst->lock, flags);	if (bytestocopy >= woinst->buffer.fragment_size)		wake_up_interruptible(&woinst->wait_queue);	else		DPD(3, "Not enough transfer size -> %d\n", bytestocopy);	return;}struct file_operations emu10k1_audio_fops = {	owner:		THIS_MODULE,	llseek:		emu10k1_audio_llseek,	read:		emu10k1_audio_read,	write:		emu10k1_audio_write,	poll:		emu10k1_audio_poll,	ioctl:		emu10k1_audio_ioctl,	mmap:		emu10k1_audio_mmap,	open:		emu10k1_audio_open,	release:	emu10k1_audio_release,};

⌨️ 快捷键说明

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