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

📄 audio.c

📁 ep9315平台下USB驱动的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
#	define AFMT_S24_BE	        0x00001000	#endif#ifndef AFMT_U24_LE#	define AFMT_U24_LE	        0x00002000	#endif#ifndef AFMT_U24_BE#	define AFMT_U24_BE	        0x00004000	#endif#ifndef AFMT_S32_LE#	define AFMT_S32_LE	        0x00008000	#endif#ifndef AFMT_S32_BE#	define AFMT_S32_BE	        0x00010000	#endif#ifndef AFMT_U32_LE#	define AFMT_U32_LE	        0x00020000	#endif#ifndef AFMT_U32_BE#	define AFMT_U32_BE	        0x00040000	#endif/* private audio format extensions */#define AFMT_STEREO         0x01000000#define AFMT_CHMASK         0xff000000#define AFMT_8MASK          (AFMT_U8 | AFMT_S8)#define AFMT_16MASK         (AFMT_U16_LE | AFMT_S16_LE | AFMT_U16_BE | AFMT_S16_BE)#define AFMT_24MASK         (AFMT_U24_LE | AFMT_S24_LE | AFMT_U24_BE | AFMT_S24_BE)#define AFMT_32MASK         (AFMT_U32_LE | AFMT_S32_LE | AFMT_U32_BE | AFMT_S32_BE)#define AFMT_SIGNMASK       (AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE |\                                       AFMT_S24_LE | AFMT_S24_BE |\                                       AFMT_S32_LE | AFMT_S32_BE)/* a little odd, but the code counts on byte formats being identified as 'big endian' */#define AFMT_ENDIANMASK     (AFMT_S8 | AFMT_U8 |\			               AFMT_S16_BE | AFMT_U16_BE |\                                       AFMT_S24_BE | AFMT_U24_BE |\                                       AFMT_S32_BE | AFMT_U32_BE)#define AFMT_ISSTEREO(x)    (((x) & 0xff000000) == AFMT_STEREO)#define AFMT_CHANNELS(x)    (((unsigned)(x) >> 24) + 1)#define AFMT_BYTES(x)       ( (((x)&AFMT_8MASK)!=0)+\                              (((x)&AFMT_16MASK)!=0)*2+\                              (((x)&AFMT_24MASK)!=0)*3+\                              (((x)&AFMT_32MASK)!=0)*4 )#define AFMT_SAMPLEBYTES(x) (AFMT_BYTES(x)*AFMT_CHANNELS(x))#define AFMT_SIGN(x)        ((x)&AFMT_SIGNMASK)#define AFMT_ENDIAN(x)      ((x)&AFMT_ENDIANMASK)/* --------------------------------------------------------------------- *//* prevent picking up a bogus abs macro */#undef absstatic inline int abs(int x){        if (x < 0)		return -x;	return x;}                                /* --------------------------------------------------------------------- */static inline unsigned ld2(unsigned int x){	unsigned r = 0;		if (x >= 0x10000) {		x >>= 16;		r += 16;	}	if (x >= 0x100) {		x >>= 8;		r += 8;	}	if (x >= 0x10) {		x >>= 4;		r += 4;	}	if (x >= 4) {		x >>= 2;		r += 2;	}	if (x >= 2)		r++;	return r;}/* --------------------------------------------------------------------- *//* * OSS compatible ring buffer management. The ring buffer may be mmap'ed into * an application address space. * * I first used the rvmalloc stuff copied from bttv. Alan Cox did not like it, so * we now use an array of pointers to a single page each. This saves us the * kernel page table manipulations, but we have to do a page table alike mechanism * (though only one indirection) in software. */static void dmabuf_release(struct dmabuf *db){	unsigned int nr;	void *p;	for(nr = 0; nr < NRSGBUF; nr++) {		if (!(p = db->sgbuf[nr]))			continue;		mem_map_unreserve(virt_to_page(p));		free_page((unsigned long)p);		db->sgbuf[nr] = NULL;	}	db->mapped = db->ready = 0;}static int dmabuf_init(struct dmabuf *db){	unsigned int nr, bytepersec, bufs;	void *p;	/* initialize some fields */	db->rdptr = db->wrptr = db->total_bytes = db->count = db->error = 0;	/* calculate required buffer size */	bytepersec = db->srate * AFMT_SAMPLEBYTES(db->format);	bufs = 1U << DMABUFSHIFT;	if (db->ossfragshift) {		if ((1000 << db->ossfragshift) < bytepersec)			db->fragshift = ld2(bytepersec/1000);		else			db->fragshift = db->ossfragshift;	} else {		db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));		if (db->fragshift < 3)			db->fragshift = 3;	}	db->numfrag = bufs >> db->fragshift;	while (db->numfrag < 4 && db->fragshift > 3) {		db->fragshift--;		db->numfrag = bufs >> db->fragshift;	}	db->fragsize = 1 << db->fragshift;	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)		db->numfrag = db->ossmaxfrags;	db->dmasize = db->numfrag << db->fragshift;	for(nr = 0; nr < NRSGBUF; nr++) {		if (!db->sgbuf[nr]) {			p = (void *)get_free_page(GFP_KERNEL);			if (!p)				return -ENOMEM;			db->sgbuf[nr] = p;			mem_map_reserve(virt_to_page(p));		}		memset(db->sgbuf[nr], AFMT_SIGN(db->format) ? 0 : 0x80, PAGE_SIZE);		if ((nr << PAGE_SHIFT) >= db->dmasize)			break;	}	db->bufsize = nr << PAGE_SHIFT;	db->ready = 1;	dprintk((KERN_DEBUG "usbaudio: dmabuf_init bytepersec %d bufs %d ossfragshift %d ossmaxfrags %d "	         "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d fmt 0x%x srate %d\n",	         bytepersec, bufs, db->ossfragshift, db->ossmaxfrags, db->fragshift, db->fragsize,	         db->numfrag, db->dmasize, db->bufsize, db->format, db->srate));	return 0;}static int dmabuf_mmap(struct dmabuf *db, unsigned long start, unsigned long size, pgprot_t prot){	unsigned int nr;	if (!db->ready || db->mapped || (start | size) & (PAGE_SIZE-1) || size > db->bufsize)		return -EINVAL;	size >>= PAGE_SHIFT;	for(nr = 0; nr < size; nr++)		if (!db->sgbuf[nr])			return -EINVAL;	db->mapped = 1;	for(nr = 0; nr < size; nr++) {		if (remap_page_range(start, virt_to_phys(db->sgbuf[nr]), PAGE_SIZE, prot))			return -EAGAIN;		start += PAGE_SIZE;	}	return 0;}static void dmabuf_copyin(struct dmabuf *db, const void *buffer, unsigned int size){	unsigned int pgrem, rem;	db->total_bytes += size;	for (;;) {		if (size <= 0)			return;		pgrem = ((~db->wrptr) & (PAGE_SIZE-1)) + 1;		if (pgrem > size)			pgrem = size;		rem = db->dmasize - db->wrptr;		if (pgrem > rem)			pgrem = rem;		memcpy((db->sgbuf[db->wrptr >> PAGE_SHIFT]) + (db->wrptr & (PAGE_SIZE-1)), buffer, pgrem);		size -= pgrem;		(char *)buffer += pgrem;		db->wrptr += pgrem;		if (db->wrptr >= db->dmasize)			db->wrptr = 0;	}}static void dmabuf_copyout(struct dmabuf *db, void *buffer, unsigned int size){	unsigned int pgrem, rem;	db->total_bytes += size;	for (;;) {		if (size <= 0)			return;		pgrem = ((~db->rdptr) & (PAGE_SIZE-1)) + 1;		if (pgrem > size)			pgrem = size;		rem = db->dmasize - db->rdptr;		if (pgrem > rem)			pgrem = rem;		memcpy(buffer, (db->sgbuf[db->rdptr >> PAGE_SHIFT]) + (db->rdptr & (PAGE_SIZE-1)), pgrem);		size -= pgrem;		(char *)buffer += pgrem;		db->rdptr += pgrem;		if (db->rdptr >= db->dmasize)			db->rdptr = 0;	}}static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void *buffer, unsigned int size){	unsigned int pgrem, rem;	if (!db->ready || db->mapped)		return -EINVAL;	for (;;) {		if (size <= 0)			return 0;		pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1;		if (pgrem > size)			pgrem = size;		rem = db->dmasize - ptr;		if (pgrem > rem)			pgrem = rem;		if (copy_from_user((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem))			return -EFAULT;		size -= pgrem;		(char *)buffer += pgrem;		ptr += pgrem;		if (ptr >= db->dmasize)			ptr = 0;	}}static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void *buffer, unsigned int size){	unsigned int pgrem, rem;	if (!db->ready || db->mapped)		return -EINVAL;	for (;;) {		if (size <= 0)			return 0;		pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1;		if (pgrem > size)			pgrem = size;		rem = db->dmasize - ptr;		if (pgrem > rem)			pgrem = rem;		if (copy_to_user(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem))			return -EFAULT;		size -= pgrem;		(char *)buffer += pgrem;		ptr += pgrem;		if (ptr >= db->dmasize)			ptr = 0;	}}/* --------------------------------------------------------------------- *//* * USB I/O code. We do sample format conversion if necessary */static void usbin_stop(struct usb_audiodev *as){	struct usbin *u = &as->usbin;	unsigned long flags;	unsigned int i, notkilled = 1;	spin_lock_irqsave(&as->lock, flags);	u->flags &= ~FLG_RUNNING;	i = u->flags;	spin_unlock_irqrestore(&as->lock, flags);	while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {		set_current_state(notkilled ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);		schedule_timeout(1);		spin_lock_irqsave(&as->lock, flags);		i = u->flags;		spin_unlock_irqrestore(&as->lock, flags);		if (notkilled && signal_pending(current)) {			if (i & FLG_URB0RUNNING)				usb_unlink_urb(&u->durb[0].urb);			if (i & FLG_URB1RUNNING)				usb_unlink_urb(&u->durb[1].urb);			if (i & FLG_SYNC0RUNNING)				usb_unlink_urb(&u->surb[0].urb);			if (i & FLG_SYNC1RUNNING)				usb_unlink_urb(&u->surb[1].urb);			notkilled = 0;		}	}	set_current_state(TASK_RUNNING);	if (u->durb[0].urb.transfer_buffer)		kfree(u->durb[0].urb.transfer_buffer);	if (u->durb[1].urb.transfer_buffer)		kfree(u->durb[1].urb.transfer_buffer);	if (u->surb[0].urb.transfer_buffer)		kfree(u->surb[0].urb.transfer_buffer);	if (u->surb[1].urb.transfer_buffer)		kfree(u->surb[1].urb.transfer_buffer);	u->durb[0].urb.transfer_buffer = u->durb[1].urb.transfer_buffer = 		u->surb[0].urb.transfer_buffer = u->surb[1].urb.transfer_buffer = NULL;}static inline void usbin_release(struct usb_audiodev *as){	usbin_stop(as);}static void usbin_disc(struct usb_audiodev *as){	struct usbin *u = &as->usbin;	unsigned long flags;	spin_lock_irqsave(&as->lock, flags);	u->flags &= ~(FLG_RUNNING | FLG_CONNECTED);	spin_unlock_irqrestore(&as->lock, flags);	usbin_stop(as);}static inline int iconvert(unsigned char **xx,int jump){  int value=0;  unsigned char *x=*xx;			  /* conversion fall-through cascade compiles to a jump table */  switch(jump){  case 0:    /* 32 bit BE */    value  = x[3];  case 1:    /* 24 bit BE */    value |= x[2] << 8;  case 2:    /* 16 bit BE */    value |= x[1] << 16;  case 3:    /* 8 bit */    value |= x[0] << 24;    x+=(4-jump);    break;  case 4:    /* 32 bit LE */    value  = *x++;  case 5:    /* 24 bit LE */    value |= *x++ << 8;  case 6:    /* 16 bit LE */    value |= *x++ << 16;    value |= *x++ << 24;    break;  }  *xx=x;  return(value);}static inline void oconvert(unsigned char **yy,int jump,int value){  unsigned char *y=*yy;  /* conversion fall-through cascade compiles to a jump table */  switch(jump){  case 0:    /* 32 bit BE */    y[3] = value;  case 1:    /* 24 bit BE */    y[2] = value >> 8;  case 2:    /* 16 bit BE */    y[1] = value >> 16;  case 3:    /* 8 bit */    y[0] = value >> 24;    y+=(4-jump);    break;  case 4:    /* 32 bit LE */    *y++ = value;  case 5:    /* 24 bit LE */

⌨️ 快捷键说明

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