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

📄 ca0106_main.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	return result;}/* trigger_capture callback */static int snd_ca0106_pcm_trigger_capture(struct snd_pcm_substream *substream,				    int cmd){	struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_ca0106_pcm *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(struct snd_pcm_substream *substream){	struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_ca0106_pcm *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(struct snd_pcm_substream *substream){	struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_ca0106_pcm *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 struct snd_pcm_ops 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 struct snd_pcm_ops 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 struct snd_pcm_ops 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 struct snd_pcm_ops 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 struct snd_pcm_ops 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 struct snd_pcm_ops 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 struct snd_pcm_ops 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 struct snd_pcm_ops 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(struct snd_ac97 *ac97,					     unsigned short reg){	struct snd_ca0106 *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(struct snd_ac97 *ac97,				    unsigned short reg, unsigned short val){	struct snd_ca0106 *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(struct snd_ca0106 *chip){	struct snd_ac97_bus *pbus;	struct snd_ac97_template ac97;	int err;	static struct snd_ac97_bus_ops 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;	ac97.scaps = AC97_SCAP_NO_SPDIF;	return snd_ac97_mixer(pbus, &ac97, &chip->ac97);}static int snd_ca0106_free(struct snd_ca0106 *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	release_and_free_resource(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(struct snd_device *device){	struct snd_ca0106 *chip = device->device_data;	return snd_ca0106_free(chip);}static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id,					  struct pt_regs *regs){	unsigned int status;	struct snd_ca0106 *chip = dev_id;	int i;	int mask;        unsigned int stat76;	struct snd_ca0106_channel *pchannel;	status = inl(chip->port + IPR);	if (! status)		return IRQ_NONE;        stat76 = snd_ca0106_ptr_read(chip, EXTENDED_INT, 0);	//snd_printk("interrupt status = 0x%08x, stat76=0x%08x\n", status, stat76);	//snd_printk("ptr=0x%08x\n",snd_ca0106_ptr_read(chip, PLAYBACK_POINTER, 0));        mask = 0x11; /* 0x1 for one half, 0x10 for the other half period. */	for(i = 0; i < 4; i++) {		pchannel = &(chip->playback_channels[i]);		if (stat76 & mask) {/* FIXME: Select the correct substream for period elapsed */			if(pchannel->use) {				snd_pcm_period_elapsed(pchannel->epcm->substream);				//printk(KERN_INFO "interrupt [%d] used\n", i);                        }		}	        //printk(KERN_INFO "channel=%p\n",pchannel);	        //printk(KERN_INFO "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number);		mask <<= 1;	}        mask = 0x110000; /* 0x1 for one half, 0x10 for the other half period. */	for(i = 0; i < 4; i++) {		pchannel = &(chip->capture_channels[i]);		if (stat76 & mask) {/* FIXME: Select the correct substream for period elapsed */			if(pchannel->use) {				snd_pcm_period_elapsed(pchannel->epcm->substream);				//printk(KERN_INFO "interrupt [%d] used\n", i);                        }		}	        //printk(KERN_INFO "channel=%p\n",pchannel);	        //printk(KERN_INFO "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number);		mask <<= 1;	}        snd_ca0106_ptr_write(chip, EXTENDED_INT, 0, stat76);	if (chip->midi.dev_id &&	    (status & (chip->midi.ipr_tx|chip->midi.ipr_rx))) {		if (chip->midi.interrupt)			chip->midi.interrupt(&chip->midi, status);		else			chip->midi.interrupt_disable(&chip->midi, chip->midi.tx_enable | chip->midi.rx_enable);	}	// acknowledge the interrupt if necessary	outl(status, chip->port+IPR);	return IRQ_HANDLED;}static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct snd_pcm **rpcm){	struct snd_pcm *pcm;	struct snd_pcm_substream *substream;	int err;  	if (rpcm)		*rpcm = NULL;	if ((err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm)) < 0)		return err;  	pcm->private_data = emu;	switch (device) {	case 0:	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_front_ops);	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_0_ops);          break;	case 1:	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_rear_ops);	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_1_ops);          break;	case 2:	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_center_lfe_ops);	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_2_ops);          break;	case 3:	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_unknown_ops);	  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_3_ops);          break;        }	pcm->info_flags = 0;	pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;	strcpy(pcm->name, "CA0106");	emu->pcm = pcm;	for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 	    substream; 	    substream = substream->next) {		if ((err = snd_pcm_lib_preallocate_pages(substream, 							 SNDRV_DMA_TYPE_DEV, 							 snd_dma_pci_data(emu->pci), 							 64*1024, 64*1024)) < 0) /* FIXME: 32*1024 for sound buffer, between 32and64 for Periods table. */			return err;	}	for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; 	      substream; 	      substream = substream->next) { 		if ((err = snd_pcm_lib_preallocate_pages(substream, 	                                           SNDRV_DMA_TYPE_DEV, 	                                           snd_dma_pci_data(emu->pci), 	                                           64*1024, 64*1024)) < 0)			return err;	}  	if (rpcm)		*rpcm = pcm;  	return 0;}static unsigned int spi_dac_init[] = {	0x00ff,	0x02ff,	0x0400,	0x0520,	0x0600,	0x08ff,	0x0aff,	0x0cff,	0x0eff,	0x10ff,	0x1200,	0x1400,	0x1480,	0x1800,	0x1aff,

⌨️ 快捷键说明

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