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

📄 em28xx-audio.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  Empiatech em28x1 audio extension * *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com> * *  Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@infradead.org> *	- Port to work with the in-kernel driver *	- Several cleanups * *  This driver is based on my previous au600 usb pstn audio driver *  and inherits all the copyrights * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/kernel.h>#include <linux/usb.h>#include <linux/init.h>#include <linux/sound.h>#include <linux/spinlock.h>#include <linux/soundcard.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/proc_fs.h>#include <linux/module.h>#include "compat.h"#include <sound/core.h>#include <sound/pcm.h>#include <sound/pcm_params.h>#include <sound/info.h>#include <sound/initval.h>#include <sound/control.h>#include <media/v4l2-common.h>#include "em28xx.h"static int debug;module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "activates debug info");#define dprintk(fmt, arg...) do {					\	    if (debug)							\		printk(KERN_INFO "em28xx-audio %s: " fmt,		\				  __func__, ##arg); 		\	} while (0)static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;static int em28xx_isoc_audio_deinit(struct em28xx *dev){	int i;	dprintk("Stopping isoc\n");	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {		usb_kill_urb(dev->adev->urb[i]);		usb_free_urb(dev->adev->urb[i]);		dev->adev->urb[i] = NULL;	}	return 0;}#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)static void em28xx_audio_isocirq(struct urb *urb, struct pt_regs *regs)#elsestatic void em28xx_audio_isocirq(struct urb *urb)#endif{	struct em28xx            *dev = urb->context;	int                      i;	unsigned int             oldptr;	unsigned long            flags;	int                      period_elapsed = 0;	int                      status;	unsigned char            *cp;	unsigned int             stride;#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)	snd_pcm_substream_t *substream;	snd_pcm_runtime_t   *runtime;#else	struct snd_pcm_substream *substream;	struct snd_pcm_runtime   *runtime;#endif	if (dev->adev->capture_pcm_substream) {		substream = dev->adev->capture_pcm_substream;		runtime = substream->runtime;		stride = runtime->frame_bits >> 3;		for (i = 0; i < urb->number_of_packets; i++) {			int length =			    urb->iso_frame_desc[i].actual_length / stride;			cp = (unsigned char *)urb->transfer_buffer +			    urb->iso_frame_desc[i].offset;			if (!length)				continue;			spin_lock_irqsave(&dev->adev->slock, flags);			oldptr = dev->adev->hwptr_done_capture;			dev->adev->hwptr_done_capture += length;			if (dev->adev->hwptr_done_capture >=			    runtime->buffer_size)				dev->adev->hwptr_done_capture -=				    runtime->buffer_size;			dev->adev->capture_transfer_done += length;			if (dev->adev->capture_transfer_done >=			    runtime->period_size) {				dev->adev->capture_transfer_done -=				    runtime->period_size;				period_elapsed = 1;			}			spin_unlock_irqrestore(&dev->adev->slock, flags);			if (oldptr + length >= runtime->buffer_size) {				unsigned int cnt =				    runtime->buffer_size - oldptr;				memcpy(runtime->dma_area + oldptr * stride, cp,				       cnt * stride);				memcpy(runtime->dma_area, cp + cnt * stride,				       length * stride - cnt * stride);			} else {				memcpy(runtime->dma_area + oldptr * stride, cp,				       length * stride);			}		}		if (period_elapsed)			snd_pcm_period_elapsed(substream);	}	urb->status = 0;	if (dev->adev->shutdown)		return;	status = usb_submit_urb(urb, GFP_ATOMIC);	if (status < 0) {		em28xx_errdev("resubmit of audio urb failed (error=%i)\n",			      status);	}	return;}static int em28xx_init_audio_isoc(struct em28xx *dev){	int       i, errCode;	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *			    EM28XX_AUDIO_MAX_PACKET_SIZE;	dprintk("Starting isoc transfers\n");	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {		struct urb *urb;		int j, k;		dev->adev->transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);		if (!dev->adev->transfer_buffer[i])			return -ENOMEM;		memset(dev->adev->transfer_buffer[i], 0x80, sb_size);		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);		if (!urb) {			em28xx_errdev("usb_alloc_urb failed!\n");			for (j = 0; j < i; j++) {				usb_free_urb(dev->adev->urb[j]);				kfree(dev->adev->transfer_buffer[j]);			}			return -ENOMEM;		}		urb->dev = dev->udev;		urb->context = dev;		urb->pipe = usb_rcvisocpipe(dev->udev, 0x83);		urb->transfer_flags = URB_ISO_ASAP;		urb->transfer_buffer = dev->adev->transfer_buffer[i];		urb->interval = 1;		urb->complete = em28xx_audio_isocirq;		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;		urb->transfer_buffer_length = sb_size;		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {			urb->iso_frame_desc[j].offset = k;			urb->iso_frame_desc[j].length =			    EM28XX_AUDIO_MAX_PACKET_SIZE;		}		dev->adev->urb[i] = urb;	}	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {		errCode = usb_submit_urb(dev->adev->urb[i], GFP_ATOMIC);		if (errCode) {			em28xx_isoc_audio_deinit(dev);			return errCode;		}	}	return 0;}static int em28xx_cmd(struct em28xx *dev, int cmd, int arg){	dprintk("%s transfer\n", (dev->adev->capture_stream == STREAM_ON)?				 "stop" : "start");	switch (cmd) {	case EM28XX_CAPTURE_STREAM_EN:		if (dev->adev->capture_stream == STREAM_OFF && arg == 1) {			dev->adev->capture_stream = STREAM_ON;			em28xx_init_audio_isoc(dev);		} else if (dev->adev->capture_stream == STREAM_ON && arg == 0) {			dev->adev->capture_stream = STREAM_OFF;			em28xx_isoc_audio_deinit(dev);		} else {			printk(KERN_ERR "An underrun very likely occurred. "					"Ignoring it.\n");		}		return 0;	default:		return -EINVAL;	}}#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs,					size_t size)#elsestatic int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,					size_t size)#endif{#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)	snd_pcm_runtime_t      *runtime = subs->runtime;#else	struct snd_pcm_runtime *runtime = subs->runtime;#endif	dprintk("Alocating vbuffer\n");	if (runtime->dma_area) {		if (runtime->dma_bytes > size)			return 0;		vfree(runtime->dma_area);	}	runtime->dma_area = vmalloc(size);	if (!runtime->dma_area)		return -ENOMEM;	runtime->dma_bytes = size;	return 0;}#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)static snd_pcm_hardware_t snd_em28xx_hw_capture = {#elsestatic struct snd_pcm_hardware snd_em28xx_hw_capture = {#endif	.info = SNDRV_PCM_INFO_BLOCK_TRANSFER |		SNDRV_PCM_INFO_MMAP           |		SNDRV_PCM_INFO_INTERLEAVED    |		SNDRV_PCM_INFO_MMAP_VALID,	.formats = SNDRV_PCM_FMTBIT_S16_LE,	.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,	.rate_min = 48000,	.rate_max = 48000,	.channels_min = 2,	.channels_max = 2,	.buffer_bytes_max = 62720 * 8,	/* just about the value in usbaudio.c */	.period_bytes_min = 64,		/* 12544/2, */	.period_bytes_max = 12544,	.periods_min = 2,	.periods_max = 98,		/* 12544, */};#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 16)static int snd_em28xx_capture_open(snd_pcm_substream_t *substream)#elsestatic int snd_em28xx_capture_open(struct snd_pcm_substream *substream)

⌨️ 快捷键说明

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