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

📄 ca0106_main.c

📁 鼎力推荐!本程序是基于嵌入式LUNUX系统开发的源程序代码
💻 C
📖 第 1 页 / 共 3 页
字号:
{	return snd_pcm_lib_free_pages(substream);}/* prepare playback callback */static int snd_ca0106_pcm_prepare_playback(snd_pcm_substream_t *substream){	ca0106_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	ca0106_pcm_t *epcm = runtime->private_data;	int channel = epcm->channel_id;	u32 *table_base = (u32 *)(emu->buffer.area+(8*16*channel));	u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size);	u32 hcfg_mask = HCFG_PLAYBACK_S32_LE;	u32 hcfg_set = 0x00000000;	u32 hcfg;	u32 reg40_mask = 0x30000 << (channel<<1);	u32 reg40_set = 0;	u32 reg40;	/* FIXME: Depending on mixer selection of SPDIF out or not, select the spdif rate or the DAC rate. */	u32 reg71_mask = 0x03030000 ; /* Global. Set SPDIF rate. We only support 44100 to spdif, not to DAC. */	u32 reg71_set = 0;	u32 reg71;	int i;	        //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1));        //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base);	//snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);	/* Rate can be set per channel. */	/* reg40 control host to fifo */	/* reg71 controls DAC rate. */	switch (runtime->rate) {	case 44100:		reg40_set = 0x10000 << (channel<<1);		reg71_set = 0x01010000; 		break;        case 48000:		reg40_set = 0;		reg71_set = 0; 		break;	case 96000:		reg40_set = 0x20000 << (channel<<1);		reg71_set = 0x02020000; 		break;	case 192000:		reg40_set = 0x30000 << (channel<<1);		reg71_set = 0x03030000; 		break;	default:		reg40_set = 0;		reg71_set = 0; 		break;	}	/* Format is a global setting */	/* FIXME: Only let the first channel accessed set this. */	switch (runtime->format) {	case SNDRV_PCM_FORMAT_S16_LE:		hcfg_set = 0;		break;	case SNDRV_PCM_FORMAT_S32_LE:		hcfg_set = HCFG_PLAYBACK_S32_LE;		break;	default:		hcfg_set = 0;		break;	}	hcfg = inl(emu->port + HCFG) ;	hcfg = (hcfg & ~hcfg_mask) | hcfg_set;	outl(hcfg, emu->port + HCFG);	reg40 = snd_ca0106_ptr_read(emu, 0x40, 0);	reg40 = (reg40 & ~reg40_mask) | reg40_set;	snd_ca0106_ptr_write(emu, 0x40, 0, reg40);	reg71 = snd_ca0106_ptr_read(emu, 0x71, 0);	reg71 = (reg71 & ~reg71_mask) | reg71_set;	snd_ca0106_ptr_write(emu, 0x71, 0, reg71);	/* FIXME: Check emu->buffer.size before actually writing to it. */        for(i=0; i < runtime->periods; i++) {		table_base[i*2]=runtime->dma_addr+(i*period_size_bytes);		table_base[(i*2)+1]=period_size_bytes<<16;	} 	snd_ca0106_ptr_write(emu, PLAYBACK_LIST_ADDR, channel, emu->buffer.addr+(8*16*channel));	snd_ca0106_ptr_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19);	snd_ca0106_ptr_write(emu, PLAYBACK_LIST_PTR, channel, 0);	snd_ca0106_ptr_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr);	snd_ca0106_ptr_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes	snd_ca0106_ptr_write(emu, PLAYBACK_POINTER, channel, 0);	snd_ca0106_ptr_write(emu, 0x07, channel, 0x0);	snd_ca0106_ptr_write(emu, 0x08, channel, 0);        snd_ca0106_ptr_write(emu, PLAYBACK_MUTE, 0x0, 0x0); /* Unmute output */#if 0	snd_ca0106_ptr_write(emu, SPCS0, 0,			       SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |			       SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |			       SPCS_GENERATIONSTATUS | 0x00001200 |			       0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT );	}#endif	return 0;}/* prepare capture callback */static int snd_ca0106_pcm_prepare_capture(snd_pcm_substream_t *substream){	ca0106_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	ca0106_pcm_t *epcm = runtime->private_data;	int channel = epcm->channel_id;        //printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size,  frames_to_bytes(runtime, 1));	snd_ca0106_ptr_write(emu, 0x13, channel, 0);	snd_ca0106_ptr_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr);	snd_ca0106_ptr_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes	snd_ca0106_ptr_write(emu, CAPTURE_POINTER, channel, 0);	return 0;}/* trigger_playback callback */static int snd_ca0106_pcm_trigger_playback(snd_pcm_substream_t *substream,				    int cmd){	ca0106_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime;	ca0106_pcm_t *epcm;	int channel;	int result = 0;	struct list_head *pos;        snd_pcm_substream_t *s;	u32 basic = 0;	u32 extended = 0;	int running=0;	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		running=1;		break;	case SNDRV_PCM_TRIGGER_STOP:	default:		running=0;		break;	}        snd_pcm_group_for_each(pos, substream) {                s = snd_pcm_group_substream_entry(pos);		runtime = s->runtime;		epcm = runtime->private_data;		channel = epcm->channel_id;		//snd_printk("channel=%d\n",channel);		epcm->running = running;		basic |= (0x1<<channel);		extended |= (0x10<<channel);                snd_pcm_trigger_done(s, substream);        }	//snd_printk("basic=0x%x, extended=0x%x\n",basic, extended);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) | (extended));		snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0)|(basic));		break;	case SNDRV_PCM_TRIGGER_STOP:		snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0) & ~(basic));		snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) & ~(extended));		break;	default:		result = -EINVAL;		break;	}	return result;}/* trigger_capture callback */static int snd_ca0106_pcm_trigger_capture(snd_pcm_substream_t *substream,				    int cmd){	ca0106_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	ca0106_pcm_t *epcm = runtime->private_data;	int channel = epcm->channel_id;	int result = 0;	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel));		snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0)|(0x100<<channel));		epcm->running = 1;		break;	case SNDRV_PCM_TRIGGER_STOP:		snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0) & ~(0x100<<channel));		snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) & ~(0x110000<<channel));		epcm->running = 0;		break;	default:		result = -EINVAL;		break;	}	return result;}/* pointer_playback callback */static snd_pcm_uframes_tsnd_ca0106_pcm_pointer_playback(snd_pcm_substream_t *substream){	ca0106_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	ca0106_pcm_t *epcm = runtime->private_data;	snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0;	int channel = epcm->channel_id;	if (!epcm->running)		return 0;	ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);	ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);	ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);	if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);	ptr2 = bytes_to_frames(runtime, ptr1);	ptr2+= (ptr4 >> 3) * runtime->period_size;	ptr=ptr2;        if (ptr >= runtime->buffer_size)		ptr -= runtime->buffer_size;	//printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate);	return ptr;}/* pointer_capture callback */static snd_pcm_uframes_tsnd_ca0106_pcm_pointer_capture(snd_pcm_substream_t *substream){	ca0106_t *emu = snd_pcm_substream_chip(substream);	snd_pcm_runtime_t *runtime = substream->runtime;	ca0106_pcm_t *epcm = runtime->private_data;	snd_pcm_uframes_t ptr, ptr1, ptr2 = 0;	int channel = channel=epcm->channel_id;	if (!epcm->running)		return 0;	ptr1 = snd_ca0106_ptr_read(emu, CAPTURE_POINTER, channel);	ptr2 = bytes_to_frames(runtime, ptr1);	ptr=ptr2;        if (ptr >= runtime->buffer_size)		ptr -= runtime->buffer_size;	//printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate);	return ptr;}/* operators */static snd_pcm_ops_t snd_ca0106_playback_front_ops = {	.open =        snd_ca0106_pcm_open_playback_front,	.close =       snd_ca0106_pcm_close_playback,	.ioctl =       snd_pcm_lib_ioctl,	.hw_params =   snd_ca0106_pcm_hw_params_playback,	.hw_free =     snd_ca0106_pcm_hw_free_playback,	.prepare =     snd_ca0106_pcm_prepare_playback,	.trigger =     snd_ca0106_pcm_trigger_playback,	.pointer =     snd_ca0106_pcm_pointer_playback,};static snd_pcm_ops_t snd_ca0106_capture_0_ops = {	.open =        snd_ca0106_pcm_open_0_capture,	.close =       snd_ca0106_pcm_close_capture,	.ioctl =       snd_pcm_lib_ioctl,	.hw_params =   snd_ca0106_pcm_hw_params_capture,	.hw_free =     snd_ca0106_pcm_hw_free_capture,	.prepare =     snd_ca0106_pcm_prepare_capture,	.trigger =     snd_ca0106_pcm_trigger_capture,	.pointer =     snd_ca0106_pcm_pointer_capture,};static snd_pcm_ops_t snd_ca0106_capture_1_ops = {	.open =        snd_ca0106_pcm_open_1_capture,	.close =       snd_ca0106_pcm_close_capture,	.ioctl =       snd_pcm_lib_ioctl,	.hw_params =   snd_ca0106_pcm_hw_params_capture,	.hw_free =     snd_ca0106_pcm_hw_free_capture,	.prepare =     snd_ca0106_pcm_prepare_capture,	.trigger =     snd_ca0106_pcm_trigger_capture,	.pointer =     snd_ca0106_pcm_pointer_capture,};static snd_pcm_ops_t snd_ca0106_capture_2_ops = {	.open =        snd_ca0106_pcm_open_2_capture,	.close =       snd_ca0106_pcm_close_capture,	.ioctl =       snd_pcm_lib_ioctl,	.hw_params =   snd_ca0106_pcm_hw_params_capture,	.hw_free =     snd_ca0106_pcm_hw_free_capture,	.prepare =     snd_ca0106_pcm_prepare_capture,	.trigger =     snd_ca0106_pcm_trigger_capture,	.pointer =     snd_ca0106_pcm_pointer_capture,};static snd_pcm_ops_t snd_ca0106_capture_3_ops = {	.open =        snd_ca0106_pcm_open_3_capture,	.close =       snd_ca0106_pcm_close_capture,	.ioctl =       snd_pcm_lib_ioctl,	.hw_params =   snd_ca0106_pcm_hw_params_capture,	.hw_free =     snd_ca0106_pcm_hw_free_capture,	.prepare =     snd_ca0106_pcm_prepare_capture,	.trigger =     snd_ca0106_pcm_trigger_capture,	.pointer =     snd_ca0106_pcm_pointer_capture,};static snd_pcm_ops_t snd_ca0106_playback_center_lfe_ops = {        .open =         snd_ca0106_pcm_open_playback_center_lfe,        .close =        snd_ca0106_pcm_close_playback,        .ioctl =        snd_pcm_lib_ioctl,        .hw_params =    snd_ca0106_pcm_hw_params_playback,        .hw_free =      snd_ca0106_pcm_hw_free_playback,        .prepare =      snd_ca0106_pcm_prepare_playback,             .trigger =      snd_ca0106_pcm_trigger_playback,          .pointer =      snd_ca0106_pcm_pointer_playback, };static snd_pcm_ops_t snd_ca0106_playback_unknown_ops = {        .open =         snd_ca0106_pcm_open_playback_unknown,        .close =        snd_ca0106_pcm_close_playback,        .ioctl =        snd_pcm_lib_ioctl,        .hw_params =    snd_ca0106_pcm_hw_params_playback,        .hw_free =      snd_ca0106_pcm_hw_free_playback,        .prepare =      snd_ca0106_pcm_prepare_playback,             .trigger =      snd_ca0106_pcm_trigger_playback,          .pointer =      snd_ca0106_pcm_pointer_playback, };static snd_pcm_ops_t snd_ca0106_playback_rear_ops = {        .open =         snd_ca0106_pcm_open_playback_rear,        .close =        snd_ca0106_pcm_close_playback,        .ioctl =        snd_pcm_lib_ioctl,        .hw_params =    snd_ca0106_pcm_hw_params_playback,		.hw_free =      snd_ca0106_pcm_hw_free_playback,        .prepare =      snd_ca0106_pcm_prepare_playback,             .trigger =      snd_ca0106_pcm_trigger_playback,          .pointer =      snd_ca0106_pcm_pointer_playback, };static unsigned short snd_ca0106_ac97_read(ac97_t *ac97,					     unsigned short reg){	ca0106_t *emu = ac97->private_data;	unsigned long flags;	unsigned short val;	spin_lock_irqsave(&emu->emu_lock, flags);	outb(reg, emu->port + AC97ADDRESS);	val = inw(emu->port + AC97DATA);	spin_unlock_irqrestore(&emu->emu_lock, flags);	return val;}static void snd_ca0106_ac97_write(ac97_t *ac97,				    unsigned short reg, unsigned short val){	ca0106_t *emu = ac97->private_data;	unsigned long flags;  	spin_lock_irqsave(&emu->emu_lock, flags);	outb(reg, emu->port + AC97ADDRESS);	outw(val, emu->port + AC97DATA);	spin_unlock_irqrestore(&emu->emu_lock, flags);}static int snd_ca0106_ac97(ca0106_t *chip){	ac97_bus_t *pbus;	ac97_template_t ac97;	int err;	static ac97_bus_ops_t ops = {		.write = snd_ca0106_ac97_write,		.read = snd_ca0106_ac97_read,	};  	if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0)		return err;	pbus->no_vra = 1; /* we don't need VRA */	memset(&ac97, 0, sizeof(ac97));	ac97.private_data = chip;	return snd_ac97_mixer(pbus, &ac97, &chip->ac97);}static int snd_ca0106_free(ca0106_t *chip){	if (chip->res_port != NULL) {    /* avoid access to already used hardware */		// disable interrupts		snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0);		outl(0, chip->port + INTE);		snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0);		udelay(1000);		// disable audio		//outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG);		outl(0, chip->port + HCFG);		/* FIXME: We need to stop and DMA transfers here.		 *        But as I am not sure how yet, we cannot from the dma pages.		 * So we can fix: snd-malloc: Memory leak?  pages not freed = 8		 */	}	// release the data#if 1	if (chip->buffer.area)		snd_dma_free_pages(&chip->buffer);#endif	// release the i/o port	if (chip->res_port) {		release_resource(chip->res_port);		kfree_nocheck(chip->res_port);	}	// release the irq	if (chip->irq >= 0)		free_irq(chip->irq, (void *)chip);	pci_disable_device(chip->pci);	kfree(chip);	return 0;}static int snd_ca0106_dev_free(snd_device_t *device){	ca0106_t *chip = device->device_data;	return snd_ca0106_free(chip);}

⌨️ 快捷键说明

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