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

📄 fm801.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		break;	case SNDRV_PCM_TRIGGER_STOP:		chip->cap_ctrl &= ~(FM801_START | FM801_PAUSE);		break;	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:	case SNDRV_PCM_TRIGGER_SUSPEND:		chip->cap_ctrl |= FM801_PAUSE;		break;	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:	case SNDRV_PCM_TRIGGER_RESUME:		chip->cap_ctrl &= ~FM801_PAUSE;		break;	default:		spin_unlock(&chip->reg_lock);		snd_BUG();		return -EINVAL;	}	outw(chip->cap_ctrl, FM801_REG(chip, CAP_CTRL));	spin_unlock(&chip->reg_lock);	return 0;}static int snd_fm801_hw_params(struct snd_pcm_substream *substream,			       struct snd_pcm_hw_params *hw_params){	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_fm801_hw_free(struct snd_pcm_substream *substream){	return snd_pcm_lib_free_pages(substream);}static int snd_fm801_playback_prepare(struct snd_pcm_substream *substream){	struct fm801 *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	chip->ply_size = snd_pcm_lib_buffer_bytes(substream);	chip->ply_count = snd_pcm_lib_period_bytes(substream);	spin_lock_irq(&chip->reg_lock);	chip->ply_ctrl &= ~(FM801_START | FM801_16BIT |			     FM801_STEREO | FM801_RATE_MASK |			     FM801_CHANNELS_MASK);	if (snd_pcm_format_width(runtime->format) == 16)		chip->ply_ctrl |= FM801_16BIT;	if (runtime->channels > 1) {		chip->ply_ctrl |= FM801_STEREO;		if (runtime->channels == 4)			chip->ply_ctrl |= FM801_CHANNELS_4;		else if (runtime->channels == 6)			chip->ply_ctrl |= FM801_CHANNELS_6;	}	chip->ply_ctrl |= snd_fm801_rate_bits(runtime->rate) << FM801_RATE_SHIFT;	chip->ply_buf = 0;	outw(chip->ply_ctrl, FM801_REG(chip, PLY_CTRL));	outw(chip->ply_count - 1, FM801_REG(chip, PLY_COUNT));	chip->ply_buffer = runtime->dma_addr;	chip->ply_pos = 0;	outl(chip->ply_buffer, FM801_REG(chip, PLY_BUF1));	outl(chip->ply_buffer + (chip->ply_count % chip->ply_size), FM801_REG(chip, PLY_BUF2));	spin_unlock_irq(&chip->reg_lock);	return 0;}static int snd_fm801_capture_prepare(struct snd_pcm_substream *substream){	struct fm801 *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	chip->cap_size = snd_pcm_lib_buffer_bytes(substream);	chip->cap_count = snd_pcm_lib_period_bytes(substream);	spin_lock_irq(&chip->reg_lock);	chip->cap_ctrl &= ~(FM801_START | FM801_16BIT |			     FM801_STEREO | FM801_RATE_MASK);	if (snd_pcm_format_width(runtime->format) == 16)		chip->cap_ctrl |= FM801_16BIT;	if (runtime->channels > 1)		chip->cap_ctrl |= FM801_STEREO;	chip->cap_ctrl |= snd_fm801_rate_bits(runtime->rate) << FM801_RATE_SHIFT;	chip->cap_buf = 0;	outw(chip->cap_ctrl, FM801_REG(chip, CAP_CTRL));	outw(chip->cap_count - 1, FM801_REG(chip, CAP_COUNT));	chip->cap_buffer = runtime->dma_addr;	chip->cap_pos = 0;	outl(chip->cap_buffer, FM801_REG(chip, CAP_BUF1));	outl(chip->cap_buffer + (chip->cap_count % chip->cap_size), FM801_REG(chip, CAP_BUF2));	spin_unlock_irq(&chip->reg_lock);	return 0;}static snd_pcm_uframes_t snd_fm801_playback_pointer(struct snd_pcm_substream *substream){	struct fm801 *chip = snd_pcm_substream_chip(substream);	size_t ptr;	if (!(chip->ply_ctrl & FM801_START))		return 0;	spin_lock(&chip->reg_lock);	ptr = chip->ply_pos + (chip->ply_count - 1) - inw(FM801_REG(chip, PLY_COUNT));	if (inw(FM801_REG(chip, IRQ_STATUS)) & FM801_IRQ_PLAYBACK) {		ptr += chip->ply_count;		ptr %= chip->ply_size;	}	spin_unlock(&chip->reg_lock);	return bytes_to_frames(substream->runtime, ptr);}static snd_pcm_uframes_t snd_fm801_capture_pointer(struct snd_pcm_substream *substream){	struct fm801 *chip = snd_pcm_substream_chip(substream);	size_t ptr;	if (!(chip->cap_ctrl & FM801_START))		return 0;	spin_lock(&chip->reg_lock);	ptr = chip->cap_pos + (chip->cap_count - 1) - inw(FM801_REG(chip, CAP_COUNT));	if (inw(FM801_REG(chip, IRQ_STATUS)) & FM801_IRQ_CAPTURE) {		ptr += chip->cap_count;		ptr %= chip->cap_size;	}	spin_unlock(&chip->reg_lock);	return bytes_to_frames(substream->runtime, ptr);}static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id){	struct fm801 *chip = dev_id;	unsigned short status;	unsigned int tmp;	status = inw(FM801_REG(chip, IRQ_STATUS));	status &= FM801_IRQ_PLAYBACK|FM801_IRQ_CAPTURE|FM801_IRQ_MPU|FM801_IRQ_VOLUME;	if (! status)		return IRQ_NONE;	/* ack first */	outw(status, FM801_REG(chip, IRQ_STATUS));	if (chip->pcm && (status & FM801_IRQ_PLAYBACK) && chip->playback_substream) {		spin_lock(&chip->reg_lock);		chip->ply_buf++;		chip->ply_pos += chip->ply_count;		chip->ply_pos %= chip->ply_size;		tmp = chip->ply_pos + chip->ply_count;		tmp %= chip->ply_size;		outl(chip->ply_buffer + tmp,				(chip->ply_buf & 1) ?					FM801_REG(chip, PLY_BUF1) :					FM801_REG(chip, PLY_BUF2));		spin_unlock(&chip->reg_lock);		snd_pcm_period_elapsed(chip->playback_substream);	}	if (chip->pcm && (status & FM801_IRQ_CAPTURE) && chip->capture_substream) {		spin_lock(&chip->reg_lock);		chip->cap_buf++;		chip->cap_pos += chip->cap_count;		chip->cap_pos %= chip->cap_size;		tmp = chip->cap_pos + chip->cap_count;		tmp %= chip->cap_size;		outl(chip->cap_buffer + tmp,				(chip->cap_buf & 1) ?					FM801_REG(chip, CAP_BUF1) :					FM801_REG(chip, CAP_BUF2));		spin_unlock(&chip->reg_lock);		snd_pcm_period_elapsed(chip->capture_substream);	}	if (chip->rmidi && (status & FM801_IRQ_MPU))		snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);	if (status & FM801_IRQ_VOLUME)		;/* TODO */	return IRQ_HANDLED;}static struct snd_pcm_hardware snd_fm801_playback ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |				 SNDRV_PCM_INFO_MMAP_VALID),	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,	.rate_min =		5500,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	64,	.period_bytes_max =	(128*1024),	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};static struct snd_pcm_hardware snd_fm801_capture ={	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |				 SNDRV_PCM_INFO_BLOCK_TRANSFER |				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |				 SNDRV_PCM_INFO_MMAP_VALID),	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,	.rates =		SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,	.rate_min =		5500,	.rate_max =		48000,	.channels_min =		1,	.channels_max =		2,	.buffer_bytes_max =	(128*1024),	.period_bytes_min =	64,	.period_bytes_max =	(128*1024),	.periods_min =		1,	.periods_max =		1024,	.fifo_size =		0,};static int snd_fm801_playback_open(struct snd_pcm_substream *substream){	struct fm801 *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	int err;	chip->playback_substream = substream;	runtime->hw = snd_fm801_playback;	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,				   &hw_constraints_rates);	if (chip->multichannel) {		runtime->hw.channels_max = 6;		snd_pcm_hw_constraint_list(runtime, 0,					   SNDRV_PCM_HW_PARAM_CHANNELS,					   &hw_constraints_channels);	}	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)		return err;	return 0;}static int snd_fm801_capture_open(struct snd_pcm_substream *substream){	struct fm801 *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	int err;	chip->capture_substream = substream;	runtime->hw = snd_fm801_capture;	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,				   &hw_constraints_rates);	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)		return err;	return 0;}static int snd_fm801_playback_close(struct snd_pcm_substream *substream){	struct fm801 *chip = snd_pcm_substream_chip(substream);	chip->playback_substream = NULL;	return 0;}static int snd_fm801_capture_close(struct snd_pcm_substream *substream){	struct fm801 *chip = snd_pcm_substream_chip(substream);	chip->capture_substream = NULL;	return 0;}static struct snd_pcm_ops snd_fm801_playback_ops = {	.open =		snd_fm801_playback_open,	.close =	snd_fm801_playback_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_fm801_hw_params,	.hw_free =	snd_fm801_hw_free,	.prepare =	snd_fm801_playback_prepare,	.trigger =	snd_fm801_playback_trigger,	.pointer =	snd_fm801_playback_pointer,};static struct snd_pcm_ops snd_fm801_capture_ops = {	.open =		snd_fm801_capture_open,	.close =	snd_fm801_capture_close,	.ioctl =	snd_pcm_lib_ioctl,	.hw_params =	snd_fm801_hw_params,	.hw_free =	snd_fm801_hw_free,	.prepare =	snd_fm801_capture_prepare,	.trigger =	snd_fm801_capture_trigger,	.pointer =	snd_fm801_capture_pointer,};static int __devinit snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm ** rpcm){	struct snd_pcm *pcm;	int err;	if (rpcm)		*rpcm = NULL;	if ((err = snd_pcm_new(chip->card, "FM801", device, 1, 1, &pcm)) < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_fm801_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_fm801_capture_ops);	pcm->private_data = chip;	pcm->info_flags = 0;	strcpy(pcm->name, "FM801");	chip->pcm = pcm;	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,					      snd_dma_pci_data(chip->pci),					      chip->multichannel ? 128*1024 : 64*1024, 128*1024);	if (rpcm)		*rpcm = pcm;	return 0;}/* *  TEA5757 radio */#ifdef TEA575X_RADIO/* 256PCS GPIO numbers */#define TEA_256PCS_DATA			1#define TEA_256PCS_WRITE_ENABLE		2	/* inverted */#define TEA_256PCS_BUS_CLOCK		3static void snd_fm801_tea575x_256pcs_write(struct snd_tea575x *tea, unsigned int val){	struct fm801 *chip = tea->private_data;	unsigned short reg;	int i = 25;	spin_lock_irq(&chip->reg_lock);	reg = inw(FM801_REG(chip, GPIO_CTRL));	/* use GPIO lines and set write enable bit */	reg |= FM801_GPIO_GS(TEA_256PCS_DATA) |	       FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) |	       FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK);	/* all of lines are in the write direction */	/* clear data and clock lines */	reg &= ~(FM801_GPIO_GD(TEA_256PCS_DATA) |	         FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) |	         FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) |	         FM801_GPIO_GP(TEA_256PCS_DATA) |	         FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK) |		 FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE));	outw(reg, FM801_REG(chip, GPIO_CTRL));	udelay(1);	while (i--) {		if (val & (1 << i))			reg |= FM801_GPIO_GP(TEA_256PCS_DATA);		else			reg &= ~FM801_GPIO_GP(TEA_256PCS_DATA);		outw(reg, FM801_REG(chip, GPIO_CTRL));		udelay(1);		reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);		outw(reg, FM801_REG(chip, GPIO_CTRL));		reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);		outw(reg, FM801_REG(chip, GPIO_CTRL));		udelay(1);	}	/* and reset the write enable bit */	reg |= FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE) |	       FM801_GPIO_GP(TEA_256PCS_DATA);	outw(reg, FM801_REG(chip, GPIO_CTRL));	spin_unlock_irq(&chip->reg_lock);}static unsigned int snd_fm801_tea575x_256pcs_read(struct snd_tea575x *tea){	struct fm801 *chip = tea->private_data;	unsigned short reg;	unsigned int val = 0;	int i;		spin_lock_irq(&chip->reg_lock);	reg = inw(FM801_REG(chip, GPIO_CTRL));	/* use GPIO lines, set data direction to input */	reg |= FM801_GPIO_GS(TEA_256PCS_DATA) |	       FM801_GPIO_GS(TEA_256PCS_WRITE_ENABLE) |	       FM801_GPIO_GS(TEA_256PCS_BUS_CLOCK) |	       FM801_GPIO_GD(TEA_256PCS_DATA) |	       FM801_GPIO_GP(TEA_256PCS_DATA) |	       FM801_GPIO_GP(TEA_256PCS_WRITE_ENABLE);	/* all of lines are in the write direction, except data */	/* clear data, write enable and clock lines */	reg &= ~(FM801_GPIO_GD(TEA_256PCS_WRITE_ENABLE) |	         FM801_GPIO_GD(TEA_256PCS_BUS_CLOCK) |	         FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK));	for (i = 0; i < 24; i++) {		reg &= ~FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);		outw(reg, FM801_REG(chip, GPIO_CTRL));		udelay(1);		reg |= FM801_GPIO_GP(TEA_256PCS_BUS_CLOCK);		outw(reg, FM801_REG(chip, GPIO_CTRL));

⌨️ 快捷键说明

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