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

📄 riptide.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	SET_AIACK(cif->hwport);	SET_AIE(cif->hwport);	SET_AIACK(cif->hwport);	cif->is_reset = 1;	if (chip) {		for (i = 0; i < 4; i++)			chip->firmware.ret.retwords[i] =			    firmware.ret.retwords[i];	}	return 0;}static struct snd_pcm_hardware snd_riptide_playback = {	.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |		 SNDRV_PCM_INFO_BLOCK_TRANSFER |		 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID),	.formats =	    SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8	    | SNDRV_PCM_FMTBIT_U16_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 = (64 * 1024),	.period_bytes_min = PAGE_SIZE >> 1,	.period_bytes_max = PAGE_SIZE << 8,	.periods_min = 2,	.periods_max = 64,	.fifo_size = 0,};static struct snd_pcm_hardware snd_riptide_capture = {	.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |		 SNDRV_PCM_INFO_BLOCK_TRANSFER |		 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID),	.formats =	    SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8	    | SNDRV_PCM_FMTBIT_U16_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 = (64 * 1024),	.period_bytes_min = PAGE_SIZE >> 1,	.period_bytes_max = PAGE_SIZE << 3,	.periods_min = 2,	.periods_max = 64,	.fifo_size = 0,};static snd_pcm_uframes_t snd_riptide_pointer(struct snd_pcm_substream					     *substream){	struct snd_riptide *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct pcmhw *data = get_pcmhwdev(substream);	struct cmdif *cif = chip->cif;	union cmdret rptr = CMDRET_ZERO;	snd_pcm_uframes_t ret;	SEND_GPOS(cif, 0, data->id, &rptr);	if (data->size && runtime->period_size) {		snd_printdd		    ("pointer stream %d position 0x%x(0x%x in buffer) bytes 0x%lx(0x%lx in period) frames\n",		     data->id, rptr.retlongs[1], rptr.retlongs[1] % data->size,		     bytes_to_frames(runtime, rptr.retlongs[1]),		     bytes_to_frames(runtime,				     rptr.retlongs[1]) % runtime->period_size);		if (rptr.retlongs[1] > data->pointer)			ret =			    bytes_to_frames(runtime,					    rptr.retlongs[1] % data->size);		else			ret =			    bytes_to_frames(runtime,					    data->pointer % data->size);	} else {		snd_printdd("stream not started or strange parms (%d %ld)\n",			    data->size, runtime->period_size);		ret = bytes_to_frames(runtime, 0);	}	return ret;}static int snd_riptide_trigger(struct snd_pcm_substream *substream, int cmd){	int i, j;	struct snd_riptide *chip = snd_pcm_substream_chip(substream);	struct pcmhw *data = get_pcmhwdev(substream);	struct cmdif *cif = chip->cif;	union cmdret rptr = CMDRET_ZERO;	spin_lock(&chip->lock);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:	case SNDRV_PCM_TRIGGER_RESUME:		if (!(data->state & ST_PLAY)) {			SEND_SSTR(cif, data->id, data->sgdlist.addr);			SET_AIE(cif->hwport);			data->state = ST_PLAY;			if (data->mixer != 0xff)				setmixer(cif, data->mixer, 0x7fff, 0x7fff);			chip->openstreams++;			data->oldpos = 0;			data->pointer = 0;		}		break;	case SNDRV_PCM_TRIGGER_STOP:	case SNDRV_PCM_TRIGGER_SUSPEND:		if (data->mixer != 0xff)			setmixer(cif, data->mixer, 0, 0);		setmixer(cif, data->mixer, 0, 0);		SEND_KSTR(cif, data->id);		data->state = ST_STOP;		chip->openstreams--;		j = 0;		do {			i = rptr.retlongs[1];			SEND_GPOS(cif, 0, data->id, &rptr);			udelay(1);		} while (i != rptr.retlongs[1] && j++ < MAX_WRITE_RETRY);		if (j >= MAX_WRITE_RETRY)			snd_printk(KERN_ERR "Riptide: Could not stop stream!");		break;	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:		if (!(data->state & ST_PAUSE)) {			SEND_PSTR(cif, data->id);			data->state |= ST_PAUSE;			chip->openstreams--;		}		break;	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:		if (data->state & ST_PAUSE) {			SEND_SSTR(cif, data->id, data->sgdlist.addr);			data->state &= ~ST_PAUSE;			chip->openstreams++;		}		break;	default:		spin_unlock(&chip->lock);		return -EINVAL;	}	spin_unlock(&chip->lock);	return 0;}static int snd_riptide_prepare(struct snd_pcm_substream *substream){	struct snd_riptide *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);	struct pcmhw *data = get_pcmhwdev(substream);	struct cmdif *cif = chip->cif;	unsigned char *lbuspath = NULL;	unsigned int rate, channels;	int err = 0;	snd_pcm_format_t format;	snd_assert(cif && data, return -EINVAL);	snd_printdd("prepare id %d ch: %d f:0x%x r:%d\n", data->id,		    runtime->channels, runtime->format, runtime->rate);	spin_lock_irq(&chip->lock);	channels = runtime->channels;	format = runtime->format;	rate = runtime->rate;	switch (channels) {	case 1:		if (rate == 48000 && format == SNDRV_PCM_FORMAT_S16_LE)			lbuspath = data->paths.noconv;		else			lbuspath = data->paths.mono;		break;	case 2:		if (rate == 48000 && format == SNDRV_PCM_FORMAT_S16_LE)			lbuspath = data->paths.noconv;		else			lbuspath = data->paths.stereo;		break;	}	snd_printdd("use sgdlist at 0x%p and buffer at 0x%p\n",		    data->sgdlist.area, sgbuf);	if (data->sgdlist.area && sgbuf) {		unsigned int i, j, size, pages, f, pt, period;		struct sgd *c, *p = NULL;		size = frames_to_bytes(runtime, runtime->buffer_size);		period = frames_to_bytes(runtime, runtime->period_size);		f = PAGE_SIZE;		while ((size + (f >> 1) - 1) <= (f << 7) && (f << 1) > period)			f = f >> 1;		pages = (size + f - 1) / f;		data->size = size;		data->pages = pages;		snd_printdd		    ("create sgd size: 0x%x pages %d of size 0x%x for period 0x%x\n",		     size, pages, f, period);		pt = 0;		j = 0;		for (i = 0; i < pages; i++) {			c = &data->sgdbuf[i];			if (p)				p->dwNextLink = cpu_to_le32(data->sgdlist.addr +							    (i *							     sizeof(struct								    sgd)));			c->dwNextLink = cpu_to_le32(data->sgdlist.addr);			c->dwSegPtrPhys =			    cpu_to_le32(sgbuf->table[j].addr + pt);			pt = (pt + f) % PAGE_SIZE;			if (pt == 0)				j++;			c->dwSegLen = cpu_to_le32(f);			c->dwStat_Ctl =			    cpu_to_le32(IEOB_ENABLE | IEOS_ENABLE |					IEOC_ENABLE);			p = c;			size -= f;		}		data->sgdbuf[i].dwSegLen = cpu_to_le32(size);	}	if (lbuspath && lbuspath != data->lbuspath) {		if (data->lbuspath)			freelbuspath(cif, data->source, data->lbuspath);		alloclbuspath(cif, data->source, lbuspath,			      &data->mixer, data->intdec);		data->lbuspath = lbuspath;		data->rate = 0;	}	if (data->rate != rate || data->format != format ||	    data->channels != channels) {		data->rate = rate;		data->format = format;		data->channels = channels;		if (setsampleformat		    (cif, data->mixer, data->id, channels, format)		    || setsamplerate(cif, data->intdec, rate))			err = -EIO;	}	spin_unlock_irq(&chip->lock);	return err;}static intsnd_riptide_hw_params(struct snd_pcm_substream *substream,		      struct snd_pcm_hw_params *hw_params){	struct snd_riptide *chip = snd_pcm_substream_chip(substream);	struct pcmhw *data = get_pcmhwdev(substream);	struct snd_dma_buffer *sgdlist = &data->sgdlist;	int err;	snd_printdd("hw params id %d (sgdlist: 0x%p 0x%lx %d)\n", data->id,		    sgdlist->area, (unsigned long)sgdlist->addr,		    (int)sgdlist->bytes);	if (sgdlist->area)		snd_dma_free_pages(sgdlist);	if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,				       snd_dma_pci_data(chip->pci),				       sizeof(struct sgd) * (DESC_MAX_MASK + 1),				       sgdlist)) < 0) {		snd_printk(KERN_ERR "Riptide: failed to alloc %d dma bytes\n",			   (int)sizeof(struct sgd) * (DESC_MAX_MASK + 1));		return err;	}	data->sgdbuf = (struct sgd *)sgdlist->area;	return snd_pcm_lib_malloc_pages(substream,					params_buffer_bytes(hw_params));}static int snd_riptide_hw_free(struct snd_pcm_substream *substream){	struct snd_riptide *chip = snd_pcm_substream_chip(substream);	struct pcmhw *data = get_pcmhwdev(substream);	struct cmdif *cif = chip->cif;	if (cif && data) {		if (data->lbuspath)			freelbuspath(cif, data->source, data->lbuspath);		data->lbuspath = NULL;		data->source = 0xff;		data->intdec[0] = 0xff;		data->intdec[1] = 0xff;		if (data->sgdlist.area) {			snd_dma_free_pages(&data->sgdlist);			data->sgdlist.area = NULL;		}	}	return snd_pcm_lib_free_pages(substream);}static int snd_riptide_playback_open(struct snd_pcm_substream *substream){	struct snd_riptide *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct pcmhw *data;	int index = substream->number;	chip->playback_substream[index] = substream;	runtime->hw = snd_riptide_playback;	data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL);	data->paths = lbus_play_paths[index];	data->id = play_ids[index];	data->source = play_sources[index];	data->intdec[0] = 0xff;	data->intdec[1] = 0xff;	data->state = ST_STOP;	runtime->private_data = data;	return snd_pcm_hw_constraint_integer(runtime,					     SNDRV_PCM_HW_PARAM_PERIODS);}static int snd_riptide_capture_open(struct snd_pcm_substream *substream){	struct snd_riptide *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct pcmhw *data;	chip->capture_substream = substream;	runtime->hw = snd_riptide_capture;	data = kzalloc(sizeof(struct pcmhw), GFP_KERNEL);	data->paths = lbus_rec_path;	data->id = PADC;	data->source = ACLNK2PADC;	data->intdec[0] = 0xff;	data->intdec[1] = 0xff;	data->state = ST_STOP;	runtime->private_data = data;	return snd_pcm_hw_constraint_integer(runtime,					     SNDRV_PCM_HW_PARAM_PERIODS);}static int snd_riptide_playback_close(struct snd_pcm_substream *substream){	struct snd_riptide *chip = snd_pcm_substream_chip(substream);	struct pcmhw *data = get_pcmhwdev(substream);	int index = substream->number;	substream->runtime->private_data = NULL;	chip->playback_substream[index] = NULL;	kfree(data);	return 0;}static int snd_riptide_capture_close(struct snd_pcm_substream *substream){	struct snd_riptide *chip = snd_pcm_substream_chip(substream);	struct pcmhw *data = get_pcmhwdev(substream);	substream->runtime->private_data = NULL;	chip->capture_substream = NULL;	kfree(data);	return 0;}static struct snd_pcm_ops snd_riptide_playback_ops = {	.open = snd_riptide_playback_open,	.close = snd_riptide_playback_close,	.ioctl = snd_pcm_lib_ioctl,	.hw_params = snd_riptide_hw_params,	.hw_free = snd_riptide_hw_free,	.prepare = snd_riptide_prepare,	.page = snd_pcm_sgbuf_ops_page,	.trigger = snd_riptide_trigger,	.pointer = snd_riptide_pointer,};static struct snd_pcm_ops snd_riptide_capture_ops = {	.open = snd_riptide_capture_open,	.close = snd_riptide_capture_close,	.ioctl = snd_pcm_lib_ioctl,	.hw_params = snd_riptide_hw_params,	.hw_free = snd_riptide_hw_free,	.prepare = snd_riptide_prepare,	.page = snd_pcm_sgbuf_ops_page,	.trigger = snd_riptide_trigger,	.pointer = snd_riptide_pointer,};static int __devinitsnd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm){	struct snd_pcm *pcm;	int err;	if (rpcm)		*rpcm = NULL;	if ((err =	     snd_pcm_new(chip->card, "RIPTIDE", device, PLAYBACK_SUBSTREAMS, 1,			 &pcm)) < 0)		return err;	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,			&snd_riptide_playback_ops);	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,			&snd_riptide_capture_ops);	pcm->private_data = chip;	pcm->info_flags = 0;	strcpy(pcm->name, "RIPTIDE");	chip->pcm = pcm;	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,					      snd_dma_pci_data(chip->pci),					      64 * 1024, 128 * 1024);	if (rpcm)		*rpcm = pcm;	return 0;}static irqreturn_tsnd_riptide_interrupt(int irq, void *dev_id){	struct snd_riptide *chip = dev_id;	struct cmdif *cif = chip->cif;	if (cif) {		chip->received_irqs++;		if (IS_EOBIRQ(cif->hwport) || IS_EOSIRQ(cif->hwport) ||		    IS_EOCIRQ(cif->hwport)) {			chip->handled_irqs++;			tasklet_hi_schedule(&chip->riptide_tq);		}		if (chip->rmidi && IS_MPUIRQ(cif->hwport)) {			chip->handled_irqs++;			snd_mpu401_uart_interrupt(irq,						  chip->rmidi->private_data);		}		SET_AIACK(cif->hwport);	}	return IRQ_HANDLED;}static voidsnd_riptide_codec_write(struct snd_ac97 *ac97, unsigned short reg,			unsigned short val){	struct snd_riptide *chip = ac97->private_data;	struct cmdif *cif = chip->cif;	union cmdret rptr = CMDRET_ZERO;	int i = 0;	snd_assert(cif, return);

⌨️ 快捷键说明

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