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

📄 trident.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				if (val == AFMT_S16_LE)					dmabuf->fmt |= TRIDENT_FMT_16BIT;				else					dmabuf->fmt &= ~TRIDENT_FMT_16BIT;			}			if (file->f_mode & FMODE_READ) {				stop_adc(state);				dmabuf->ready = 0;				if (val == AFMT_S16_LE)					dmabuf->fmt |= TRIDENT_FMT_16BIT;				else					dmabuf->fmt &= ~TRIDENT_FMT_16BIT;			}		}		unlock_set_fmt(state);		return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ?				AFMT_S16_LE : AFMT_U8, (int *)arg);	case SNDCTL_DSP_CHANNELS:		if (get_user(val, (int *)arg))			return -EFAULT;		if (val != 0) {			lock_set_fmt(state);			if (file->f_mode & FMODE_WRITE) {				stop_dac(state);				dmabuf->ready = 0;												//prevent from memory leak				if ((state->chans_num > 2) && (state->chans_num != val)) {					ali_free_other_states_resources(state);					state->chans_num = 1;				}								if (val >= 2) {					dmabuf->fmt |= TRIDENT_FMT_STEREO;					if ((val == 6) && (state->card->pci_id == PCI_DEVICE_ID_ALI_5451)) {						ali_setup_multi_channels(state->card, 6);						down(&state->card->open_sem);						ret = ali_allocate_other_states_resources(state, 6);						up(&state->card->open_sem);						if (ret < 0) {							unlock_set_fmt(state);							return ret;						}					}					else val = 2;	/*yield to 2-channels*/				}				else					dmabuf->fmt &= ~TRIDENT_FMT_STEREO;				state->chans_num = val;			}			if (file->f_mode & FMODE_READ) {				stop_adc(state);				dmabuf->ready = 0;				if (val >= 2) {					if (!((file->f_mode & FMODE_WRITE) && (val == 6)))						val = 2;					dmabuf->fmt |= TRIDENT_FMT_STEREO;				}				else					dmabuf->fmt &= ~TRIDENT_FMT_STEREO;				state->chans_num = val;			}			unlock_set_fmt(state);		}		return put_user(val, (int *)arg);	case SNDCTL_DSP_POST:		/* FIXME: the same as RESET ?? */		return 0;	case SNDCTL_DSP_SUBDIVIDE:		if (dmabuf->subdivision)			return -EINVAL;		if (get_user(val, (int *)arg))			return -EFAULT;		if (val != 1 && val != 2 && val != 4)			return -EINVAL;		dmabuf->subdivision = val;		return 0;	case SNDCTL_DSP_SETFRAGMENT:		if (get_user(val, (int *)arg))			return -EFAULT;		dmabuf->ossfragshift = val & 0xffff;		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;		if (dmabuf->ossfragshift < 4)			dmabuf->ossfragshift = 4;		if (dmabuf->ossfragshift > 15)			dmabuf->ossfragshift = 15;		if (dmabuf->ossmaxfrags < 4)			dmabuf->ossmaxfrags = 4;		return 0;	case SNDCTL_DSP_GETOSPACE:		if (!(file->f_mode & FMODE_WRITE))			return -EINVAL;		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)			return val;		spin_lock_irqsave(&state->card->lock, flags);		trident_update_ptr(state);		abinfo.fragsize = dmabuf->fragsize;		abinfo.bytes = dmabuf->dmasize - dmabuf->count;		abinfo.fragstotal = dmabuf->numfrag;		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;		spin_unlock_irqrestore(&state->card->lock, flags);		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;	case SNDCTL_DSP_GETISPACE:		if (!(file->f_mode & FMODE_READ))			return -EINVAL;		if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)			return val;		spin_lock_irqsave(&state->card->lock, flags);		trident_update_ptr(state);		abinfo.fragsize = dmabuf->fragsize;		abinfo.bytes = dmabuf->count;		abinfo.fragstotal = dmabuf->numfrag;		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;		spin_unlock_irqrestore(&state->card->lock, flags);		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;	case SNDCTL_DSP_NONBLOCK:		file->f_flags |= O_NONBLOCK;		return 0;	case SNDCTL_DSP_GETCAPS:	    return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND,			    (int *)arg);	case SNDCTL_DSP_GETTRIGGER:		val = 0;		if (file->f_mode & FMODE_READ && dmabuf->enable)			val |= PCM_ENABLE_INPUT;		if (file->f_mode & FMODE_WRITE && dmabuf->enable)			val |= PCM_ENABLE_OUTPUT;		return put_user(val, (int *)arg);	case SNDCTL_DSP_SETTRIGGER:		if (get_user(val, (int *)arg))			return -EFAULT;		if (file->f_mode & FMODE_READ) {			if (val & PCM_ENABLE_INPUT) {				if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))					return ret;				start_adc(state);			} else				stop_adc(state);		}		if (file->f_mode & FMODE_WRITE) {			if (val & PCM_ENABLE_OUTPUT) {				if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))					return ret;				start_dac(state);			} else				stop_dac(state);		}		return 0;	case SNDCTL_DSP_GETIPTR:		if (!(file->f_mode & FMODE_READ))			return -EINVAL;		if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)			return val;		spin_lock_irqsave(&state->card->lock, flags);		trident_update_ptr(state);		cinfo.bytes = dmabuf->total_bytes;		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;		cinfo.ptr = dmabuf->hwptr;		if (dmabuf->mapped)			dmabuf->count &= dmabuf->fragsize-1;		spin_unlock_irqrestore(&state->card->lock, flags);		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));	case SNDCTL_DSP_GETOPTR:		if (!(file->f_mode & FMODE_WRITE))			return -EINVAL;		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)			return val;		spin_lock_irqsave(&state->card->lock, flags);		trident_update_ptr(state);		cinfo.bytes = dmabuf->total_bytes;		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;		cinfo.ptr = dmabuf->hwptr;		if (dmabuf->mapped)			dmabuf->count &= dmabuf->fragsize-1;		spin_unlock_irqrestore(&state->card->lock, flags);		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));	case SNDCTL_DSP_SETDUPLEX:		return -EINVAL;	case SNDCTL_DSP_GETODELAY:		if (!(file->f_mode & FMODE_WRITE))			return -EINVAL;		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)			return val;		spin_lock_irqsave(&state->card->lock, flags);		trident_update_ptr(state);		val = dmabuf->count;		spin_unlock_irqrestore(&state->card->lock, flags);		return put_user(val, (int *)arg);	case SOUND_PCM_READ_RATE:		return put_user(dmabuf->rate, (int *)arg);	case SOUND_PCM_READ_CHANNELS:		return put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1,				(int *)arg);	case SOUND_PCM_READ_BITS:		return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ?				AFMT_S16_LE : AFMT_U8, (int *)arg);	case SNDCTL_DSP_GETCHANNELMASK:		return put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE,				(int *)arg);	case SNDCTL_DSP_BIND_CHANNEL:		if (state->card->pci_id != PCI_DEVICE_ID_SI_7018)			return -EINVAL;		if (get_user(val, (int *)arg))			return -EFAULT;		if (val == DSP_BIND_QUERY) {			val = dmabuf->channel->attribute | 0x3c00;			val = attr2mask[val >> 8];		} else {			dmabuf->ready = 0;			if (file->f_mode & FMODE_READ)				dmabuf->channel->attribute = (CHANNEL_REC|SRC_ENABLE);			if (file->f_mode & FMODE_WRITE)				dmabuf->channel->attribute = (CHANNEL_SPC_PB|SRC_ENABLE);			dmabuf->channel->attribute |= mask2attr[ffs(val)];		}		return put_user(val, (int *)arg);	case SNDCTL_DSP_MAPINBUF:	case SNDCTL_DSP_MAPOUTBUF:	case SNDCTL_DSP_SETSYNCRO:	case SOUND_PCM_WRITE_FILTER:	case SOUND_PCM_READ_FILTER:		return -EINVAL;			}	return -EINVAL;}static int trident_open(struct inode *inode, struct file *file){	int i = 0;	int minor = MINOR(inode->i_rdev);	struct trident_card *card = devs;	struct trident_state *state = NULL;	struct dmabuf *dmabuf = NULL;	/* find an avaiable virtual channel (instance of /dev/dsp) */	while (card != NULL) {		down(&card->open_sem);		for (i = 0; i < NR_HW_CH; i++) {			if (card->states[i] == NULL) {				state = card->states[i] = (struct trident_state *)					kmalloc(sizeof(struct trident_state), GFP_KERNEL);				if (state == NULL) {					return -ENOMEM;				}				memset(state, 0, sizeof(struct trident_state));				dmabuf = &state->dmabuf;				goto found_virt;			}		}		up(&card->open_sem);		card = card->next;	}	/* no more virtual channel avaiable */	if (!state) {		return -ENODEV;	} found_virt:	/* found a free virtual channel, allocate hardware channels */	if(file->f_mode & FMODE_READ)		dmabuf->channel = card->alloc_rec_pcm_channel(card);	else		dmabuf->channel = card->alloc_pcm_channel(card);			if (dmabuf->channel == NULL) {		kfree (card->states[i]);		card->states[i] = NULL;		return -ENODEV;	}	/* initialize the virtual channel */	state->virt = i;	state->card = card;	state->magic = TRIDENT_STATE_MAGIC;	init_waitqueue_head(&dmabuf->wait);	file->private_data = state;	/* set default sample format. According to OSS Programmer's Guide  /dev/dsp	   should be default to unsigned 8-bits, mono, with sample rate 8kHz and	   /dev/dspW will accept 16-bits sample */	if (file->f_mode & FMODE_WRITE) {		dmabuf->fmt &= ~TRIDENT_FMT_MASK;		if ((minor & 0x0f) == SND_DEV_DSP16)			dmabuf->fmt |= TRIDENT_FMT_16BIT;		dmabuf->ossfragshift = 0;		dmabuf->ossmaxfrags  = 0;		dmabuf->subdivision  = 0;		if (card->pci_id == PCI_DEVICE_ID_SI_7018) {			/* set default channel attribute to normal playback */			dmabuf->channel->attribute = CHANNEL_PB;		}		trident_set_dac_rate(state, 8000);	}	if (file->f_mode & FMODE_READ) {		/* FIXME: Trident 4d can only record in signed 16-bits stereo, 48kHz sample,		   to be dealed with in trident_set_adc_rate() ?? */		dmabuf->fmt &= ~TRIDENT_FMT_MASK;		if ((minor & 0x0f) == SND_DEV_DSP16)			dmabuf->fmt |= TRIDENT_FMT_16BIT;		dmabuf->ossfragshift = 0;		dmabuf->ossmaxfrags  = 0;		dmabuf->subdivision  = 0;		if (card->pci_id == PCI_DEVICE_ID_SI_7018) {			/* set default channel attribute to 0x8a80, record from			   PCM L/R FIFO and mono = (left + right + 1)/2*/			dmabuf->channel->attribute =				(CHANNEL_REC|PCM_LR|MONO_MIX);		}		trident_set_adc_rate(state, 8000);	}	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);	up(&card->open_sem);#ifdef DEBUG       printk(KERN_ERR "trident: open virtual channel %d, hard channel %d\n",               state->virt, dmabuf->channel->num);#endif	return 0;}static int trident_release(struct inode *inode, struct file *file){	struct trident_state *state = (struct trident_state *)file->private_data;	struct trident_card *card;	struct dmabuf *dmabuf;	unsigned long flags;	lock_kernel();	card = state->card;	dmabuf = &state->dmabuf;	VALIDATE_STATE(state);	if (file->f_mode & FMODE_WRITE) {		trident_clear_tail(state);		drain_dac(state, file->f_flags & O_NONBLOCK);	}	/* stop DMA state machine and free DMA buffers/channels */	down(&card->open_sem);	if (file->f_mode & FMODE_WRITE) {		stop_dac(state);		lock_set_fmt(state);		if (state->chans_num > 2)			ali_free_other_states_resources(state);		unlock_set_fmt(state);		dealloc_dmabuf(state);		state->card->free_pcm_channel(state->card, dmabuf->channel->num);	}	if (file->f_mode & FMODE_READ) {		stop_adc(state);		dealloc_dmabuf(state);		state->card->free_pcm_channel(state->card, dmabuf->channel->num);	}	card->states[state->virt] = NULL;	kfree(state);	/* we're covered by the open_sem */	up(&card->open_sem);	unlock_kernel();	return 0;}static /*const*/ struct file_operations trident_audio_fops = {	owner:		THIS_MODULE,	llseek:		trident_llseek,	read:		trident_read,	write:		trident_write,	poll:		trident_poll,	ioctl:		trident_ioctl,	mmap:		trident_mmap,	open:		trident_open,	release:	trident_release,};/* trident specific AC97 functions *//* Write AC97 codec registers */static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val){	struct trident_card *card = (struct trident_card *)codec->private_data;	unsigned int address, mask, busy;	unsigned short count  = 0xffff;	unsigned long flags;	u32 data;	data = ((u32) val) << 16;	switch (card->pci_id)	{	default:	case PCI_DEVICE_ID_SI_7018:		address = SI_AC97_WRITE;		mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY;		if (codec->id)			mask |= SI_AC97_SECONDARY;		busy = SI_AC97_BUSY_WRITE;		break;	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:		address = DX_ACR0_AC97_W;		mask = busy = DX_AC97_BUSY_WRITE;		break;	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:		address = NX_ACR1_AC97_W;		mask = NX_AC97_BUSY_WRITE;		if (codec->id)			mask |= NX_AC97_WRITE_SECONDARY;		busy = NX_AC97_BUSY_WRITE;		break;	}	spin_lock_irqsave(&card->lock, flags);	do {		if ((inw(TRID_REG(card, address)

⌨️ 快捷键说明

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