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

📄 ali5455.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
static inline void __start_spdifout(struct ali_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&	    (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {		if (codec_independent_spdif_locked > 0) {			dmabuf->enable |= CODEC_SPDIFOUT_RUNNING;			outb((1 << 4) | (1 << 2), state->card->iobase + CODECSPDIFOUT_CR);			outl((1 << 3), state->card->iobase + 0x08);	//dma control register		} else {			if (controller_independent_spdif_locked > 0) {				dmabuf->enable |= CONTROLLER_SPDIFOUT_RUNNING;				outb((1 << 4) | (1 << 2), state->card->iobase + CONTROLLERSPDIFOUT_CR);				outl((1 << 7), state->card->iobase + 0x08);	//dma control register			}		}	}}static void start_spdifout(struct ali_state *state){	struct ali_card *card = state->card;	unsigned long flags;	spin_lock_irqsave(&card->lock, flags);	__start_spdifout(state);	spin_unlock_irqrestore(&card->lock, flags);}#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)#define DMABUF_MINORDER 1/* allocate DMA buffer, playback , recording,spdif out  buffer should be allocated separately */static int alloc_dmabuf(struct ali_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	void *rawbuf = NULL;	int order, size;	struct page *page, *pend;	/* If we don't have any oss frag params, then use our default ones */	if (dmabuf->ossmaxfrags == 0)		dmabuf->ossmaxfrags = 4;	if (dmabuf->ossfragsize == 0)		dmabuf->ossfragsize = (PAGE_SIZE << DMABUF_DEFAULTORDER) / dmabuf->ossmaxfrags;	size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;	if (dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size)		return 0;	/* alloc enough to satisfy the oss params */	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {		if ((PAGE_SIZE << order) > size)			continue;		if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,						   PAGE_SIZE << order,						   &dmabuf->dma_handle)))			break;	}	if (!rawbuf)		return -ENOMEM;	dmabuf->ready = dmabuf->mapped = 0;	dmabuf->rawbuf = rawbuf;	dmabuf->buforder = order;	/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */	pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);	for (page = virt_to_page(rawbuf); page <= pend; page++)		SetPageReserved(page);	return 0;}/* free DMA buffer */static void dealloc_dmabuf(struct ali_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	struct page *page, *pend;	if (dmabuf->rawbuf) {		/* undo marking the pages as reserved */		pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);		for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)			ClearPageReserved(page);		pci_free_consistent(state->card->pci_dev,				    PAGE_SIZE << dmabuf->buforder,				    dmabuf->rawbuf, dmabuf->dma_handle);	}	dmabuf->rawbuf = NULL;	dmabuf->mapped = dmabuf->ready = 0;}static int prog_dmabuf(struct ali_state *state, unsigned rec){	struct dmabuf *dmabuf = &state->dmabuf;	struct ali_channel *c = NULL;	struct sg_item *sg;	unsigned long flags;	int ret;	unsigned fragint;	int i;	spin_lock_irqsave(&state->card->lock, flags);	if (dmabuf->enable & DAC_RUNNING)		__stop_dac(state);	if (dmabuf->enable & ADC_RUNNING)		__stop_adc(state);	if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)		__stop_spdifout(state);	if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)		__stop_spdifout(state);	dmabuf->total_bytes = 0;	dmabuf->count = dmabuf->error = 0;	dmabuf->swptr = dmabuf->hwptr = 0;	spin_unlock_irqrestore(&state->card->lock, flags);	/* allocate DMA buffer, let alloc_dmabuf determine if we are already	 * allocated well enough or if we should replace the current buffer	 * (assuming one is already allocated, if it isn't, then allocate it).	 */	if ((ret = alloc_dmabuf(state)))		return ret;	/* FIXME: figure out all this OSS fragment stuff */	/* I did, it now does what it should according to the OSS API.  DL */	/* We may not have realloced our dmabuf, but the fragment size to	 * fragment number ratio may have changed, so go ahead and reprogram	 * things	 */	dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder;	dmabuf->numfrag = SG_LEN;	dmabuf->fragsize = dmabuf->dmasize / dmabuf->numfrag;	dmabuf->fragsamples = dmabuf->fragsize >> 1;	dmabuf->userfragsize = dmabuf->ossfragsize;	dmabuf->userfrags = dmabuf->dmasize / dmabuf->ossfragsize;	memset(dmabuf->rawbuf, 0, dmabuf->dmasize);	if (dmabuf->ossmaxfrags == 4) {		fragint = 8;		dmabuf->fragshift = 2;	} else if (dmabuf->ossmaxfrags == 8) {		fragint = 4;		dmabuf->fragshift = 3;	} else if (dmabuf->ossmaxfrags == 16) {		fragint = 2;		dmabuf->fragshift = 4;	} else {		fragint = 1;		dmabuf->fragshift = 5;	}	/*	 *      Now set up the ring 	 */	if (rec == 1)		c = dmabuf->read_channel;	else if (rec == 2)		c = dmabuf->codec_spdifout_channel;	else if (rec == 3)		c = dmabuf->controller_spdifout_channel;	else if (rec == 0)		c = dmabuf->write_channel;	if (c != NULL) {		sg = &c->sg[0];		/*		 *      Load up 32 sg entries and take an interrupt at half		 *      way (we might want more interrupts later..) 		 */		for (i = 0; i < dmabuf->numfrag; i++) {			sg->busaddr =			    virt_to_bus(dmabuf->rawbuf +					dmabuf->fragsize * i);			// the card will always be doing 16bit stereo			sg->control = dmabuf->fragsamples;			sg->control |= CON_BUFPAD;	//I modify			// set us up to get IOC interrupts as often as needed to			// satisfy numfrag requirements, no more			if (((i + 1) % fragint) == 0) {				sg->control |= CON_IOC;			}			sg++;		}		spin_lock_irqsave(&state->card->lock, flags);		outb(2, state->card->iobase + c->port + OFF_CR);	/* reset DMA machine */		outl(virt_to_bus(&c->sg[0]), state->card->iobase + c->port + OFF_BDBAR);		outb(0, state->card->iobase + c->port + OFF_CIV);		outb(0, state->card->iobase + c->port + OFF_LVI);		spin_unlock_irqrestore(&state->card->lock, flags);	}	/* set the ready flag for the dma buffer */	dmabuf->ready = 1;	return 0;}static void __ali_update_lvi(struct ali_state *state, int rec){	struct dmabuf *dmabuf = &state->dmabuf;	int x, port;	port = state->card->iobase;	if (rec == 1)		port += dmabuf->read_channel->port;	else if (rec == 2)		port += dmabuf->codec_spdifout_channel->port;	else if (rec == 3)		port += dmabuf->controller_spdifout_channel->port;	else if (rec == 0)		port += dmabuf->write_channel->port;	/* if we are currently stopped, then our CIV is actually set to our	 * *last* sg segment and we are ready to wrap to the next.  However,	 * if we set our LVI to the last sg segment, then it won't wrap to	 * the next sg segment, it won't even get a start.  So, instead, when	 * we are stopped, we set both the LVI value and also we increment	 * the CIV value to the next sg segment to be played so that when	 * we call start_{dac,adc}, things will operate properly	 */	if (!dmabuf->enable && dmabuf->ready) {		if (rec && dmabuf->count < dmabuf->dmasize && (dmabuf->trigger & PCM_ENABLE_INPUT)) {			outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);			__start_adc(state);			while (! (inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))				cpu_relax();		} else if (!rec && dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {			outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);			__start_dac(state);			while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))				cpu_relax();		} else if (rec && dmabuf->count && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {			if (codec_independent_spdif_locked > 0) {				// outb((inb(port+OFF_CIV))&31, port+OFF_LVI);				outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);				__start_spdifout(state);				while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))					cpu_relax();			} else {				if (controller_independent_spdif_locked > 0) {					outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);					__start_spdifout(state);					while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))						cpu_relax();				}			}		}	}	/* swptr - 1 is the tail of our transfer */	x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize;	x /= dmabuf->fragsize;	outb(x, port + OFF_LVI);}static void ali_update_lvi(struct ali_state *state, int rec){	struct dmabuf *dmabuf = &state->dmabuf;	unsigned long flags;	if (!dmabuf->ready)		return;	spin_lock_irqsave(&state->card->lock, flags);	__ali_update_lvi(state, rec);	spin_unlock_irqrestore(&state->card->lock, flags);}/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */static void ali_update_ptr(struct ali_state *state){	struct dmabuf *dmabuf = &state->dmabuf;	unsigned hwptr;	int diff;		/* error handling and process wake up for DAC */	if (dmabuf->enable == ADC_RUNNING) {		/* update hardware pointer */		hwptr = ali_get_dma_addr(state, 1);		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;		dmabuf->hwptr = hwptr;		dmabuf->total_bytes += diff;		dmabuf->count += diff;		if (dmabuf->count > dmabuf->dmasize) {			/* buffer underrun or buffer overrun */			/* this is normal for the end of a read */			/* only give an error if we went past the */			/* last valid sg entry */			if ((inb(state->card->iobase + PI_CIV) & 31) != (inb(state->card->iobase + PI_LVI) & 31)) {				printk(KERN_WARNING "ali_audio: DMA overrun on read\n");				dmabuf->error++;			}		}		if (dmabuf->count > dmabuf->userfragsize)			wake_up(&dmabuf->wait);	}	/* error handling and process wake up for DAC */	if (dmabuf->enable == DAC_RUNNING) {		/* update hardware pointer */		hwptr = ali_get_dma_addr(state, 0);		diff =		    (dmabuf->dmasize + hwptr -		     dmabuf->hwptr) % dmabuf->dmasize;#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)		printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);#endif		dmabuf->hwptr = hwptr;		dmabuf->total_bytes += diff;		dmabuf->count -= diff;		if (dmabuf->count < 0) {			/* buffer underrun or buffer overrun */			/* this is normal for the end of a write */			/* only give an error if we went past the */			/* last valid sg entry */			if ((inb(state->card->iobase + PO_CIV) & 31) != (inb(state->card->iobase + PO_LVI) & 31)) {				printk(KERN_WARNING "ali_audio: DMA overrun on write\n");				printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n",				     			inb(state->card->iobase + PO_CIV) & 31,				     			inb(state->card->iobase + PO_LVI) & 31, 							dmabuf->hwptr,							dmabuf->count);				dmabuf->error++;			}		}		if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))		    	wake_up(&dmabuf->wait);	}	/* error handling and process wake up for CODEC SPDIF OUT */	if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {		/* update hardware pointer */		hwptr = ali_get_dma_addr(state, 2);		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;		dmabuf->hwptr = hwptr;		dmabuf->total_bytes += diff;		dmabuf->count -= diff;		if (dmabuf->count < 0) {			/* buffer underrun or buffer overrun */			/* this is normal for the end of a write */			/* only give an error if we went past the */			/* last valid sg entry */			if ((inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31)) {				printk(KERN_WARNING "ali_audio: DMA overrun on write\n");				printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n", 				        inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31,					inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31,					dmabuf->hwptr, dmabuf->count);				dmabuf->error++;			}		}		if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))			wake_up(&dmabuf->wait);	}	/* error handling and process wake up for CONTROLLER SPDIF OUT */	if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {		/* update hardware pointer */		hwptr = ali_get_dma_addr(state, 3);		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;		dmabuf->hwptr = hwptr;		dmabuf->total_bytes += diff;		dmabuf->count -= diff;		if (dmabuf->count < 0) {			/* buffer underrun or buffer overrun */			/* this is normal for the end of a write */			/* only give an error if we went past the */			/* last valid sg entry */			if ((inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31)) {				printk(KERN_WARNING				       "ali_audio: DMA overrun on write\n");				printk("ali_audio: CIV %d, LVI %d, hwptr %x, "					"count %d\n",				     		inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31,				     		inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31,				     		dmabuf->hwptr, dmabuf->count);				dmabuf->error++;			}		}		if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))			wake_up(&dmabuf->wait);	}}static inline int ali_get_free_write_space(struct					   ali_state					   *state){	struct dmabuf *dmabuf = &state->dmabuf;	int free;	if (dmabuf->count < 0) {		dmabuf->count = 0;		dmabuf->swptr = dmabuf->hwptr;	}	free = dmabuf->dmasize - dmabuf->swptr;	if ((dmabuf->count + free) > dmabuf->dmasize){		free = dmabuf->dmasize - dmabuf->count;	}	return free;}static inline int ali_get_available_read_data(struct					      ali_state					      *state){	struct dmabuf *dmabuf = &state->dmabuf;	int avail;	ali_update_ptr(state);	// catch overruns during record	if (dmabuf->count > dmabuf->dmasize) {		dmabuf->count = dmabuf->dmasize;		dmabuf->swptr = dmabuf->hwptr;	}	avail = dmabuf->count;	avail -= (dmabuf->hwptr % dmabuf->fragsize);	if (avail < 0)		return (0);	return (avail);}static int drain_dac(struct ali_state *state, int signals_allowed){	DECLARE_WAITQUEUE(wait, current);	struct dmabuf *dmabuf = &state->dmabuf;	unsigned long flags;	unsigned long tmo;	int count;	if (!dmabuf->ready)		return 0;	if (dmabuf->mapped) {		stop_dac(state);		return 0;	}	add_wait_queue(&dmabuf->wait, &wait);	for (;;) {		spin_lock_irqsave(&state->card->lock, flags);		ali_update_ptr(state);		count = dmabuf->count;		spin_unlock_irqrestore(&state->card->lock, flags);		if (count <= 0)			break;

⌨️ 快捷键说明

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