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

📄 via82xx_modem.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
{	struct via82xx_modem *chip = ac97->private_data;	unsigned int xval;	if(reg == AC97_GPIO_STATUS) {		outl(val, VIAREG(chip, GPI_STATUS));		return;	}		xval = !ac97->num ? VIA_REG_AC97_CODEC_ID_PRIMARY : VIA_REG_AC97_CODEC_ID_SECONDARY;	xval <<= VIA_REG_AC97_CODEC_ID_SHIFT;	xval |= reg << VIA_REG_AC97_CMD_SHIFT;	xval |= val << VIA_REG_AC97_DATA_SHIFT;	snd_via82xx_codec_xwrite(chip, xval);	snd_via82xx_codec_ready(chip, ac97->num);}static unsigned short snd_via82xx_codec_read(struct snd_ac97 *ac97, unsigned short reg){	struct via82xx_modem *chip = ac97->private_data;	unsigned int xval, val = 0xffff;	int again = 0;	xval = ac97->num << VIA_REG_AC97_CODEC_ID_SHIFT;	xval |= ac97->num ? VIA_REG_AC97_SECONDARY_VALID : VIA_REG_AC97_PRIMARY_VALID;	xval |= VIA_REG_AC97_READ;	xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;      	while (1) {      		if (again++ > 3) {			snd_printk(KERN_ERR "codec_read: codec %i is not valid [0x%x]\n",				   ac97->num, snd_via82xx_codec_xread(chip));		      	return 0xffff;		}		snd_via82xx_codec_xwrite(chip, xval);		udelay (20);		if (snd_via82xx_codec_valid(chip, ac97->num) >= 0) {			udelay(25);			val = snd_via82xx_codec_xread(chip);			break;		}	}	return val & 0xffff;}static void snd_via82xx_channel_reset(struct via82xx_modem *chip, struct viadev *viadev){	outb(VIA_REG_CTRL_PAUSE | VIA_REG_CTRL_TERMINATE | VIA_REG_CTRL_RESET,	     VIADEV_REG(viadev, OFFSET_CONTROL));	inb(VIADEV_REG(viadev, OFFSET_CONTROL));	udelay(50);	/* disable interrupts */	outb(0x00, VIADEV_REG(viadev, OFFSET_CONTROL));	/* clear interrupts */	outb(0x03, VIADEV_REG(viadev, OFFSET_STATUS));	outb(0x00, VIADEV_REG(viadev, OFFSET_TYPE)); /* for via686 */	// outl(0, VIADEV_REG(viadev, OFFSET_CURR_PTR));	viadev->lastpos = 0;}/* *  Interrupt handler */static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id){	struct via82xx_modem *chip = dev_id;	unsigned int status;	unsigned int i;	status = inl(VIAREG(chip, SGD_SHADOW));	if (! (status & chip->intr_mask)) {		return IRQ_NONE;	}// _skip_sgd:	/* check status for each stream */	spin_lock(&chip->reg_lock);	for (i = 0; i < chip->num_devs; i++) {		struct viadev *viadev = &chip->devs[i];		unsigned char c_status = inb(VIADEV_REG(viadev, OFFSET_STATUS));		c_status &= (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG|VIA_REG_STAT_STOPPED);		if (! c_status)			continue;		if (viadev->substream && viadev->running) {			spin_unlock(&chip->reg_lock);			snd_pcm_period_elapsed(viadev->substream);			spin_lock(&chip->reg_lock);		}		outb(c_status, VIADEV_REG(viadev, OFFSET_STATUS)); /* ack */	}	spin_unlock(&chip->reg_lock);	return IRQ_HANDLED;}/* *  PCM callbacks *//* * trigger callback */static int snd_via82xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd){	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);	struct viadev *viadev = substream->runtime->private_data;	unsigned char val = 0;	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:	case SNDRV_PCM_TRIGGER_SUSPEND:		val |= VIA_REG_CTRL_START;		viadev->running = 1;		break;	case SNDRV_PCM_TRIGGER_STOP:		val = VIA_REG_CTRL_TERMINATE;		viadev->running = 0;		break;	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:		val |= VIA_REG_CTRL_PAUSE;		viadev->running = 0;		break;	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:		viadev->running = 1;		break;	default:		return -EINVAL;	}	outb(val, VIADEV_REG(viadev, OFFSET_CONTROL));	if (cmd == SNDRV_PCM_TRIGGER_STOP)		snd_via82xx_channel_reset(chip, viadev);	return 0;}/* * pointer callbacks *//* * calculate the linear position at the given sg-buffer index and the rest count */#define check_invalid_pos(viadev,pos) \	((pos) < viadev->lastpos && ((pos) >= viadev->bufsize2 ||\				     viadev->lastpos < viadev->bufsize2))static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int idx,					   unsigned int count){	unsigned int size, res;	size = viadev->idx_table[idx].size;	res = viadev->idx_table[idx].offset + size - count;	/* check the validity of the calculated position */	if (size < count) {		snd_printd(KERN_ERR "invalid via82xx_cur_ptr (size = %d, count = %d)\n",			   (int)size, (int)count);		res = viadev->lastpos;	} else if (check_invalid_pos(viadev, res)) {#ifdef POINTER_DEBUG		printk(KERN_DEBUG "fail: idx = %i/%i, lastpos = 0x%x, "		       "bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, "		       "count = 0x%x\n", idx, viadev->tbl_entries, viadev->lastpos,		       viadev->bufsize2, viadev->idx_table[idx].offset,		       viadev->idx_table[idx].size, count);#endif		if (count && size < count) {			snd_printd(KERN_ERR "invalid via82xx_cur_ptr, "				   "using last valid pointer\n");			res = viadev->lastpos;		} else {			if (! count)				/* bogus count 0 on the DMA boundary? */				res = viadev->idx_table[idx].offset;			else				/* count register returns full size				 * when end of buffer is reached				 */				res = viadev->idx_table[idx].offset + size;			if (check_invalid_pos(viadev, res)) {				snd_printd(KERN_ERR "invalid via82xx_cur_ptr (2), "					   "using last valid pointer\n");				res = viadev->lastpos;			}		}	}	viadev->lastpos = res; /* remember the last position */	if (res >= viadev->bufsize)		res -= viadev->bufsize;	return res;}/* * get the current pointer on via686 */static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substream){	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);	struct viadev *viadev = substream->runtime->private_data;	unsigned int idx, ptr, count, res;	snd_assert(viadev->tbl_entries, return 0);	if (!(inb(VIADEV_REG(viadev, OFFSET_STATUS)) & VIA_REG_STAT_ACTIVE))		return 0;	spin_lock(&chip->reg_lock);	count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT)) & 0xffffff;	/* The via686a does not have the current index register,	 * so we need to calculate the index from CURR_PTR.	 */	ptr = inl(VIADEV_REG(viadev, OFFSET_CURR_PTR));	if (ptr <= (unsigned int)viadev->table.addr)		idx = 0;	else /* CURR_PTR holds the address + 8 */		idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) %			viadev->tbl_entries;	res = calc_linear_pos(viadev, idx, count);	spin_unlock(&chip->reg_lock);	return bytes_to_frames(substream->runtime, res);}/* * hw_params callback: * allocate the buffer and build up the buffer description table */static int snd_via82xx_hw_params(struct snd_pcm_substream *substream,				 struct snd_pcm_hw_params *hw_params){	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);	struct viadev *viadev = substream->runtime->private_data;	int err;	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));	if (err < 0)		return err;	err = build_via_table(viadev, substream, chip->pci,			      params_periods(hw_params),			      params_period_bytes(hw_params));	if (err < 0)		return err;	snd_ac97_write(chip->ac97, AC97_LINE1_RATE, params_rate(hw_params));	snd_ac97_write(chip->ac97, AC97_LINE1_LEVEL, 0);	return 0;}/* * hw_free callback: * clean up the buffer description table and release the buffer */static int snd_via82xx_hw_free(struct snd_pcm_substream *substream){	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);	struct viadev *viadev = substream->runtime->private_data;	clean_via_table(viadev, substream, chip->pci);	snd_pcm_lib_free_pages(substream);	return 0;}/* * set up the table pointer */static void snd_via82xx_set_table_ptr(struct via82xx_modem *chip, struct viadev *viadev){	snd_via82xx_codec_ready(chip, chip->ac97_secondary);	outl((u32)viadev->table.addr, VIADEV_REG(viadev, OFFSET_TABLE_PTR));	udelay(20);	snd_via82xx_codec_ready(chip, chip->ac97_secondary);}/* * prepare callback for playback and capture */static int snd_via82xx_pcm_prepare(struct snd_pcm_substream *substream){	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);	struct viadev *viadev = substream->runtime->private_data;	snd_via82xx_channel_reset(chip, viadev);	/* this must be set after channel_reset */	snd_via82xx_set_table_ptr(chip, viadev);	outb(VIA_REG_TYPE_AUTOSTART|VIA_REG_TYPE_INT_EOL|VIA_REG_TYPE_INT_FLAG,	     VIADEV_REG(viadev, OFFSET_TYPE));	return 0;}/* * pcm hardware definition, identical for both playback and capture */static struct snd_pcm_hardware snd_via82xx_hw ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_MMAP_VALID |				 /* SNDRV_PCM_INFO_RESUME | */				 SNDRV_PCM_INFO_PAUSE),	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_KNOT,	.rate_min =		8000,	.rate_max =		16000,	.channels_min =		1,	.channels_max =		1,	.buffer_bytes_max =	128 * 1024,	.period_bytes_min =	32,	.period_bytes_max =	128 * 1024,	.periods_min =		2,	.periods_max =		VIA_TABLE_SIZE / 2,	.fifo_size =		0,};/* * open callback skeleton */static int snd_via82xx_modem_pcm_open(struct via82xx_modem *chip, struct viadev *viadev,				      struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime = substream->runtime;	int err;        static unsigned int rates[] = { 8000,  9600, 12000, 16000 };        static struct snd_pcm_hw_constraint_list hw_constraints_rates = {                .count = ARRAY_SIZE(rates),                .list = rates,                .mask = 0,        };	runtime->hw = snd_via82xx_hw;	        if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,					      &hw_constraints_rates)) < 0)                return err;	/* we may remove following constaint when we modify table entries	   in interrupt */	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)		return err;	runtime->private_data = viadev;	viadev->substream = substream;	return 0;}/* * open callback for playback */static int snd_via82xx_playback_open(struct snd_pcm_substream *substream){	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);	struct viadev *viadev = &chip->devs[chip->playback_devno + substream->number];	return snd_via82xx_modem_pcm_open(chip, viadev, substream);}/* * open callback for capture */static int snd_via82xx_capture_open(struct snd_pcm_substream *substream){	struct via82xx_modem *chip = snd_pcm_substream_chip(substream);	struct viadev *viadev = &chip->devs[chip->capture_devno + substream->pcm->device];	return snd_via82xx_modem_pcm_open(chip, viadev, substream);}/* * close callback */static int snd_via82xx_pcm_close(struct snd_pcm_substream *substream){	struct viadev *viadev = substream->runtime->private_data;	viadev->substream = NULL;	return 0;}/* via686 playback callbacks */static struct snd_pcm_ops snd_via686_playback_ops = {	.open =		snd_via82xx_playback_open,	.close =	snd_via82xx_pcm_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_via82xx_hw_params,	.hw_free =	snd_via82xx_hw_free,	.prepare =	snd_via82xx_pcm_prepare,	.trigger =	snd_via82xx_pcm_trigger,	.pointer =	snd_via686_pcm_pointer,	.page =		snd_pcm_sgbuf_ops_page,};/* via686 capture callbacks */static struct snd_pcm_ops snd_via686_capture_ops = {	.open =		snd_via82xx_capture_open,	.close =	snd_via82xx_pcm_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_via82xx_hw_params,	.hw_free =	snd_via82xx_hw_free,	.prepare =	snd_via82xx_pcm_prepare,	.trigger =	snd_via82xx_pcm_trigger,	.pointer =	snd_via686_pcm_pointer,	.page =		snd_pcm_sgbuf_ops_page,};static void init_viadev(struct via82xx_modem *chip, int idx, unsigned int reg_offset,			int direction){	chip->devs[idx].reg_offset = reg_offset;	chip->devs[idx].direction = direction;	chip->devs[idx].port = chip->port + reg_offset;}

⌨️ 快捷键说明

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