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

📄 hal2.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
                }		return 0;	case SNDCTL_DSP_CHANNELS:		if (get_user(val, (int *)arg))			return -EFAULT;		if (val != 0) {			if (file->f_mode & FMODE_READ) {				hal2_stop_adc(hal2);				hal2->adc.voices = (val == 1) ? 1 : 2;				hal2_setup_adc(hal2);			}			if (file->f_mode & FMODE_WRITE) {				hal2_stop_dac(hal2);				hal2->dac.voices = (val == 1) ? 1 : 2;				hal2_setup_dac(hal2);			}		}		val = -EINVAL;		if (file->f_mode & FMODE_READ)			val = hal2->adc.voices;		if (file->f_mode & FMODE_WRITE)			val = hal2->dac.voices;		return put_user(val, (int *)arg);	case SNDCTL_DSP_GETFMTS: /* Returns a mask */                return put_user(H2_SUPPORTED_FORMATS, (int *)arg);	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/		if (get_user(val, (int *)arg))			return -EFAULT;		if (val != AFMT_QUERY) {			if (!(val & H2_SUPPORTED_FORMATS))				return -EINVAL;			if (file->f_mode & FMODE_READ) {				hal2_stop_adc(hal2);				hal2->adc.format = val;				hal2_setup_adc(hal2);			}			if (file->f_mode & FMODE_WRITE) {				hal2_stop_dac(hal2);				hal2->dac.format = val;				hal2_setup_dac(hal2);			}		} else {			val = -EINVAL;			if (file->f_mode & FMODE_READ)				val = hal2->adc.format;			if (file->f_mode & FMODE_WRITE)				val = hal2->dac.format;		}		return put_user(val, (int *)arg);	case SNDCTL_DSP_POST:		return 0;	case SNDCTL_DSP_GETOSPACE: {		audio_buf_info info;		int i;		unsigned long flags;		struct hal2_codec *dac = &hal2->dac;		if (!(file->f_mode & FMODE_WRITE))			return -EINVAL;		info.fragments = 0;		spin_lock_irqsave(&dac->lock, flags);		for (i = 0; i < dac->desc_count; i++)			if (dac->desc[i].cnt == 0)				info.fragments++;		spin_unlock_irqrestore(&dac->lock, flags);		info.fragstotal = dac->desc_count;		info.fragsize = H2_BLOCK_SIZE;                info.bytes = info.fragsize * info.fragments;		return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;	}	case SNDCTL_DSP_GETISPACE: {		audio_buf_info info;		int i;		unsigned long flags;		struct hal2_codec *adc = &hal2->adc;		if (!(file->f_mode & FMODE_READ))			return -EINVAL;		info.fragments = 0;		info.bytes = 0;		spin_lock_irqsave(&adc->lock, flags);		for (i = 0; i < adc->desc_count; i++)			if (adc->desc[i].cnt > 0) {				info.fragments++;				info.bytes += adc->desc[i].cnt;			}		spin_unlock_irqrestore(&adc->lock, flags);		info.fragstotal = adc->desc_count;		info.fragsize = H2_BLOCK_SIZE;		return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;	}	case SNDCTL_DSP_NONBLOCK:		file->f_flags |= O_NONBLOCK;		return 0;	case SNDCTL_DSP_GETBLKSIZE:		return put_user(H2_BLOCK_SIZE, (int *)arg);	case SNDCTL_DSP_SETFRAGMENT:		return 0;	case SOUND_PCM_READ_RATE:		val = -EINVAL;		if (file->f_mode & FMODE_READ)			val = hal2->adc.sample_rate;		if (file->f_mode & FMODE_WRITE)			val = hal2->dac.sample_rate;		return put_user(val, (int *)arg);	case SOUND_PCM_READ_CHANNELS:		val = -EINVAL;		if (file->f_mode & FMODE_READ)			val = hal2->adc.voices;		if (file->f_mode & FMODE_WRITE)			val = hal2->dac.voices;		return put_user(val, (int *)arg);	case SOUND_PCM_READ_BITS:		return put_user(16, (int *)arg);	}	return hal2_mixer_ioctl(hal2, cmd, arg);}static ssize_t hal2_read(struct file *file, char *buffer,			 size_t count, loff_t *ppos){	ssize_t err;	struct hal2_card *hal2 = (struct hal2_card *) file->private_data;	struct hal2_codec *adc = &hal2->adc;	if (!count)		return 0;	if (mutex_lock_interruptible(&adc->sem))		return -EINTR;	if (file->f_flags & O_NONBLOCK) {		err = hal2_get_buffer(hal2, buffer, count);		err = err == 0 ? -EAGAIN : err;	} else {		do {			/* ~10% longer */			signed long timeout = 1000 * H2_BLOCK_SIZE *				2 * adc->voices * HZ / adc->sample_rate / 900;			unsigned long flags;			DECLARE_WAITQUEUE(wait, current);			ssize_t cnt = 0;			err = hal2_get_buffer(hal2, buffer, count);			if (err > 0) {				count -= err;				cnt += err;				buffer += err;				err = cnt;			}			if (count > 0 && err >= 0) {				add_wait_queue(&adc->dma_wait, &wait);				set_current_state(TASK_INTERRUPTIBLE);				schedule_timeout(timeout);				spin_lock_irqsave(&adc->lock, flags);				if (!adc->desc[adc->tail].cnt)					err = -EAGAIN;				spin_unlock_irqrestore(&adc->lock, flags);				if (signal_pending(current))					err = -ERESTARTSYS;				remove_wait_queue(&adc->dma_wait, &wait);				if (err < 0) {					hal2_stop_adc(hal2);					hal2_reset_adc_pointer(hal2);				}			}		} while (count > 0 && err >= 0);	}	mutex_unlock(&adc->sem);	return err;}static ssize_t hal2_write(struct file *file, const char *buffer,			  size_t count, loff_t *ppos){	ssize_t err;	char *buf = (char*) buffer;	struct hal2_card *hal2 = (struct hal2_card *) file->private_data;	struct hal2_codec *dac = &hal2->dac;	if (!count)		return 0;	if (mutex_lock_interruptible(&dac->sem))		return -EINTR;	if (file->f_flags & O_NONBLOCK) {		err = hal2_add_buffer(hal2, buf, count);		err = err == 0 ? -EAGAIN : err;	} else {		do {			/* ~10% longer */			signed long timeout = 1000 * H2_BLOCK_SIZE *				2 * dac->voices * HZ / dac->sample_rate / 900;			unsigned long flags;			DECLARE_WAITQUEUE(wait, current);			ssize_t cnt = 0;			err = hal2_add_buffer(hal2, buf, count);			if (err > 0) {				count -= err;				cnt += err;				buf += err;				err = cnt;			}			if (count > 0 && err >= 0) {				add_wait_queue(&dac->dma_wait, &wait);				set_current_state(TASK_INTERRUPTIBLE);				schedule_timeout(timeout);				spin_lock_irqsave(&dac->lock, flags);				if (dac->desc[dac->head].cnt)					err = -EAGAIN;				spin_unlock_irqrestore(&dac->lock, flags);				if (signal_pending(current))					err = -ERESTARTSYS;				remove_wait_queue(&dac->dma_wait, &wait);				if (err < 0) {					hal2_stop_dac(hal2);					hal2_reset_dac_pointer(hal2);				}			}		} while (count > 0 && err >= 0);	}	mutex_unlock(&dac->sem);	return err;}static unsigned int hal2_poll(struct file *file, struct poll_table_struct *wait){	unsigned long flags;	unsigned int mask = 0;	struct hal2_card *hal2 = (struct hal2_card *) file->private_data;	if (file->f_mode & FMODE_READ) {		struct hal2_codec *adc = &hal2->adc;		poll_wait(file, &adc->dma_wait, wait);		spin_lock_irqsave(&adc->lock, flags);		if (adc->desc[adc->tail].cnt > 0)			mask |= POLLIN;		spin_unlock_irqrestore(&adc->lock, flags);	}	if (file->f_mode & FMODE_WRITE) {		struct hal2_codec *dac = &hal2->dac;		poll_wait(file, &dac->dma_wait, wait);		spin_lock_irqsave(&dac->lock, flags);		if (dac->desc[dac->head].cnt == 0)			mask |= POLLOUT;		spin_unlock_irqrestore(&dac->lock, flags);	}	return mask;}static int hal2_open(struct inode *inode, struct file *file){	int err;	struct hal2_card *hal2 = hal2_dsp_find_card(iminor(inode));	if (!hal2)		return -ENODEV;	file->private_data = hal2;	if (file->f_mode & FMODE_READ) {		struct hal2_codec *adc = &hal2->adc;		if (adc->usecount)			return -EBUSY;		/* OSS spec wanted us to use 8 bit, 8 kHz mono by default,		 * but HAL2 can't do 8bit audio */		adc->format = AFMT_S16_BE;		adc->voices = 1;		adc->sample_rate = hal2_compute_rate(adc, 8000);		hal2_set_adc_rate(hal2);		err = hal2_alloc_adc_dmabuf(adc);		if (err)			return err;		hal2_setup_adc(hal2);		adc->usecount++;	}	if (file->f_mode & FMODE_WRITE) {		struct hal2_codec *dac = &hal2->dac;		if (dac->usecount)			return -EBUSY;		dac->format = AFMT_S16_BE;		dac->voices = 1;		dac->sample_rate = hal2_compute_rate(dac, 8000);		hal2_set_dac_rate(hal2);		err = hal2_alloc_dac_dmabuf(dac);		if (err)			return err;		hal2_setup_dac(hal2);		dac->usecount++;	}	return nonseekable_open(inode, file);}static int hal2_release(struct inode *inode, struct file *file){	struct hal2_card *hal2 = (struct hal2_card *) file->private_data;	if (file->f_mode & FMODE_READ) {		struct hal2_codec *adc = &hal2->adc;		mutex_lock(&adc->sem);		hal2_stop_adc(hal2);		hal2_free_adc_dmabuf(adc);		adc->usecount--;		mutex_unlock(&adc->sem);	}	if (file->f_mode & FMODE_WRITE) {		struct hal2_codec *dac = &hal2->dac;		mutex_lock(&dac->sem);		hal2_sync_dac(hal2);		hal2_free_dac_dmabuf(dac);		dac->usecount--;		mutex_unlock(&dac->sem);	}	return 0;}static const struct file_operations hal2_audio_fops = {	.owner		= THIS_MODULE,	.llseek		= no_llseek,	.read		= hal2_read,	.write		= hal2_write,	.poll		= hal2_poll,	.ioctl		= hal2_ioctl,	.open		= hal2_open,	.release	= hal2_release,};static const struct file_operations hal2_mixer_fops = {	.owner		= THIS_MODULE,	.llseek		= no_llseek,	.ioctl		= hal2_ioctl_mixdev,	.open		= hal2_open_mixdev,	.release	= hal2_release_mixdev,};static void hal2_init_codec(struct hal2_codec *codec, struct hpc3_regs *hpc3,			    int index){	codec->pbus.pbusnr = index;	codec->pbus.pbus = &hpc3->pbdma[index];	init_waitqueue_head(&codec->dma_wait);	mutex_init(&codec->sem);	spin_lock_init(&codec->lock);}static int hal2_detect(struct hal2_card *hal2){	unsigned short board, major, minor;	unsigned short rev;	/* reset HAL2 */	hal2_isr_write(hal2, 0);	/* release reset */	hal2_isr_write(hal2, H2_ISR_GLOBAL_RESET_N | H2_ISR_CODEC_RESET_N);	hal2_i_write16(hal2, H2I_RELAY_C, H2I_RELAY_C_STATE); 	if ((rev = hal2_rev_look(hal2)) & H2_REV_AUDIO_PRESENT)		return -ENODEV;	board = (rev & H2_REV_BOARD_M) >> 12;	major = (rev & H2_REV_MAJOR_CHIP_M) >> 4;	minor = (rev & H2_REV_MINOR_CHIP_M);	printk(KERN_INFO "SGI HAL2 revision %i.%i.%i\n",	       board, major, minor);	return 0;}static int hal2_init_card(struct hal2_card **phal2, struct hpc3_regs *hpc3){	int ret = 0;	struct hal2_card *hal2;	hal2 = kzalloc(sizeof(struct hal2_card), GFP_KERNEL);	if (!hal2)		return -ENOMEM;	hal2->ctl_regs = (struct hal2_ctl_regs *)hpc3->pbus_extregs[0];	hal2->aes_regs = (struct hal2_aes_regs *)hpc3->pbus_extregs[1];	hal2->vol_regs = (struct hal2_vol_regs *)hpc3->pbus_extregs[2];	hal2->syn_regs = (struct hal2_syn_regs *)hpc3->pbus_extregs[3];	if (hal2_detect(hal2) < 0) {		ret = -ENODEV;		goto free_card;	}	hal2_init_codec(&hal2->dac, hpc3, 0);	hal2_init_codec(&hal2->adc, hpc3, 1);	/*	 * All DMA channel interfaces in HAL2 are designed to operate with	 * PBUS programmed for 2 cycles in D3, 2 cycles in D4 and 2 cycles	 * in D5. HAL2 is a 16-bit device which can accept both big and little	 * endian format. It assumes that even address bytes are on high	 * portion of PBUS (15:8) and assumes that HPC3 is programmed to	 * accept a live (unsynchronized) version of P_DREQ_N from HAL2.	 */#define HAL2_PBUS_DMACFG ((0 << HPC3_DMACFG_D3R_SHIFT) | \			  (2 << HPC3_DMACFG_D4R_SHIFT) | \			  (2 << HPC3_DMACFG_D5R_SHIFT) | \			  (0 << HPC3_DMACFG_D3W_SHIFT) | \			  (2 << HPC3_DMACFG_D4W_SHIFT) | \			  (2 << HPC3_DMACFG_D5W_SHIFT) | \				HPC3_DMACFG_DS16 | \				HPC3_DMACFG_EVENHI | \				HPC3_DMACFG_RTIME | \			  (8 << HPC3_DMACFG_BURST_SHIFT) | \				HPC3_DMACFG_DRQLIVE)	/*	 * Ignore what's mentioned in the specification and write value which	 * works in The Real World (TM)	 */	hpc3->pbus_dmacfg[hal2->dac.pbus.pbusnr][0] = 0x8208844;	hpc3->pbus_dmacfg[hal2->adc.pbus.pbusnr][0] = 0x8208844;	if (request_irq(SGI_HPCDMA_IRQ, hal2_interrupt, IRQF_SHARED,			hal2str, hal2)) {		printk(KERN_ERR "HAL2: Can't get irq %d\n", SGI_HPCDMA_IRQ);		ret = -EAGAIN;		goto free_card;	}	hal2->dev_dsp = register_sound_dsp(&hal2_audio_fops, -1);	if (hal2->dev_dsp < 0) {		ret = hal2->dev_dsp;		goto free_irq;	}	hal2->dev_mixer = register_sound_mixer(&hal2_mixer_fops, -1);	if (hal2->dev_mixer < 0) {		ret = hal2->dev_mixer;		goto unregister_dsp;	}	hal2_init_mixer(hal2);	*phal2 = hal2;	return 0;unregister_dsp:	unregister_sound_dsp(hal2->dev_dsp);free_irq:	free_irq(SGI_HPCDMA_IRQ, hal2);free_card:	kfree(hal2);	return ret;}extern void (*indy_volume_button)(int);/*  * Assuming only one HAL2 card. Mail me if you ever meet machine with * more than one. */static int __init init_hal2(void){	int i, error;	for (i = 0; i < MAXCARDS; i++)		hal2_card[i] = NULL;	error = hal2_init_card(&hal2_card[0], hpc3c0);	/* let Indy's volume buttons work */	if (!error && !ip22_is_fullhouse())		indy_volume_button = hal2_volume_control;	return error;}static void __exit exit_hal2(void){	int i;	/* unregister volume butons callback function */	indy_volume_button = NULL;		for (i = 0; i < MAXCARDS; i++)		if (hal2_card[i]) {			free_irq(SGI_HPCDMA_IRQ, hal2_card[i]);			unregister_sound_dsp(hal2_card[i]->dev_dsp);			unregister_sound_mixer(hal2_card[i]->dev_mixer);			kfree(hal2_card[i]);	}}module_init(init_hal2);module_exit(exit_hal2);MODULE_DESCRIPTION("OSS compatible driver for SGI HAL2 audio");MODULE_AUTHOR("Ladislav Michl");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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