staging: easycap: add ALSA support

This is necessary because some distributions are disabling OSS entirely.

Signed-off-by: Mike Thomas <rmthomas@sciolus.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Mike Thomas 2011-01-10 18:41:11 +00:00 committed by Greg Kroah-Hartman
parent b54a28a418
commit a985591729
15 changed files with 1621 additions and 499 deletions

View File

@ -1,6 +1,6 @@
config EASYCAP
tristate "EasyCAP USB ID 05e1:0408 support"
depends on USB && VIDEO_DEV
depends on USB && VIDEO_DEV && SND
---help---
This is an integrated audio/video driver for EasyCAP cards with

View File

@ -1,14 +1,13 @@
easycap-objs := easycap_main.o easycap_low.o easycap_sound.o \
easycap_ioctl.o easycap_settings.o easycap_testcard.o
obj-$(CONFIG_EASYCAP) += easycap.o
easycap-y := easycap_main.o easycap_low.o easycap_sound.o
easycap-y += easycap_ioctl.o easycap_settings.o
easycap-y += easycap_testcard.o
obj-$(CONFIG_EASYCAP) += easycap.o
ccflags-y := -Wall
# Impose all or none of the following:
ccflags-y += -DEASYCAP_IS_VIDEODEV_CLIENT
ccflags-y += -DEASYCAP_NEEDS_V4L2_DEVICE_H
ccflags-y += -DEASYCAP_NEEDS_V4L2_FOPS
ccflags-y += -DEASYCAP_NEEDS_UNLOCKED_IOCTL
ccflags-y += -DEASYCAP_NEEDS_ALSA
ccflags-y += -DEASYCAP_NEEDS_CARD_CREATE

View File

@ -34,6 +34,8 @@
* EASYCAP_NEEDS_V4L2_DEVICE_H
* EASYCAP_NEEDS_V4L2_FOPS
* EASYCAP_NEEDS_UNLOCKED_IOCTL
* EASYCAP_NEEDS_ALSA
* EASYCAP_SILENT
*
* IF REQUIRED THEY MUST BE EXTERNALLY DEFINED, FOR EXAMPLE AS COMPILER
* OPTIONS.
@ -57,9 +59,9 @@
*/
/*---------------------------------------------------------------------------*/
#undef EASYCAP_TESTCARD
#if (!defined(EASYCAP_NEEDS_ALSA))
#undef EASYCAP_TESTTONE
#undef NOREADBACK
#undef AUDIOTIME
#endif /*EASYCAP_NEEDS_ALSA*/
/*---------------------------------------------------------------------------*/
#include <linux/kernel.h>
#include <linux/errno.h>
@ -79,6 +81,16 @@
#include <linux/delay.h>
#include <linux/types.h>
#if defined(EASYCAP_NEEDS_ALSA)
#include <linux/vmalloc.h>
#include <linux/sound.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>
#endif /*EASYCAP_NEEDS_ALSA*/
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
#include <media/v4l2-dev.h>
@ -112,7 +124,7 @@
#define USB_EASYCAP_VENDOR_ID 0x05e1
#define USB_EASYCAP_PRODUCT_ID 0x0408
#define EASYCAP_DRIVER_VERSION "0.8.41"
#define EASYCAP_DRIVER_VERSION "0.9.01"
#define EASYCAP_DRIVER_DESCRIPTION "easycapdc60"
#define USB_SKEL_MINOR_BASE 192
@ -158,7 +170,8 @@
*/
/*---------------------------------------------------------------------------*/
#define AUDIO_ISOC_BUFFER_MANY 16
#define AUDIO_ISOC_ORDER 3
#define AUDIO_ISOC_ORDER 1
#define AUDIO_ISOC_FRAMESPERDESC 32
#define AUDIO_ISOC_BUFFER_SIZE (PAGE_SIZE << AUDIO_ISOC_ORDER)
/*---------------------------------------------------------------------------*/
/*
@ -166,6 +179,7 @@
*/
/*---------------------------------------------------------------------------*/
#define AUDIO_FRAGMENT_MANY 32
#define PAGES_PER_AUDIO_FRAGMENT 4
/*---------------------------------------------------------------------------*/
/*
* IT IS ESSENTIAL THAT EVEN-NUMBERED STANDARDS ARE 25 FRAMES PER SECOND,
@ -296,6 +310,7 @@ struct easycap {
#define TELLTALE "expectedstring"
char telltale[16];
int isdongle;
int minor;
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
@ -328,6 +343,7 @@ int done[FRAME_BUFFER_MANY];
wait_queue_head_t wq_video;
wait_queue_head_t wq_audio;
wait_queue_head_t wq_trigger;
int input;
int polled;
@ -428,6 +444,20 @@ int allocation_video_page;
int allocation_video_struct;
int registered_video;
/*---------------------------------------------------------------------------*/
/*
* ALSA
*/
/*---------------------------------------------------------------------------*/
#if defined(EASYCAP_NEEDS_ALSA)
struct snd_pcm_hardware alsa_hardware;
struct snd_card *psnd_card;
struct snd_pcm *psnd_pcm;
struct snd_pcm_substream *psubstream;
int dma_fill;
int dma_next;
int dma_read;
#endif /*EASYCAP_NEEDS_ALSA*/
/*---------------------------------------------------------------------------*/
/*
* SOUND PROPERTIES
*/
@ -455,10 +485,10 @@ struct list_head *purb_audio_head;
* BUFFER INDICATORS
*/
/*---------------------------------------------------------------------------*/
int audio_fill; /* Audio buffer being filled by easysnd_complete(). */
/* Bumped only by easysnd_complete(). */
int audio_read; /* Audio buffer page being read by easysnd_read(). */
/* Set by easysnd_read() to trail audio_fill by */
int audio_fill; /* Audio buffer being filled by easycap_complete(). */
/* Bumped only by easycap_complete(). */
int audio_read; /* Audio buffer page being read by easycap_read(). */
/* Set by easycap_read() to trail audio_fill by */
/* one fragment. */
/*---------------------------------------------------------------------------*/
/*
@ -532,19 +562,39 @@ int adjust_volume(struct easycap *, int);
* AUDIO FUNCTION PROTOTYPES
*/
/*---------------------------------------------------------------------------*/
void easysnd_complete(struct urb *);
ssize_t easysnd_read(struct file *, char __user *, size_t, loff_t *);
int easysnd_open(struct inode *, struct file *);
int easysnd_release(struct inode *, struct file *);
long easysnd_ioctl_noinode(struct file *, unsigned int, \
#if defined(EASYCAP_NEEDS_ALSA)
int easycap_alsa_probe(struct easycap *);
void easycap_alsa_complete(struct urb *);
int easycap_alsa_open(struct snd_pcm_substream *);
int easycap_alsa_close(struct snd_pcm_substream *);
int easycap_alsa_hw_params(struct snd_pcm_substream *, \
struct snd_pcm_hw_params *);
int easycap_alsa_vmalloc(struct snd_pcm_substream *, size_t);
int easycap_alsa_hw_free(struct snd_pcm_substream *);
int easycap_alsa_prepare(struct snd_pcm_substream *);
int easycap_alsa_ack(struct snd_pcm_substream *);
int easycap_alsa_trigger(struct snd_pcm_substream *, int);
snd_pcm_uframes_t \
easycap_alsa_pointer(struct snd_pcm_substream *);
struct page *easycap_alsa_page(struct snd_pcm_substream *, unsigned long);
#else
void easyoss_complete(struct urb *);
ssize_t easyoss_read(struct file *, char __user *, size_t, loff_t *);
int easyoss_open(struct inode *, struct file *);
int easyoss_release(struct inode *, struct file *);
long easyoss_ioctl_noinode(struct file *, unsigned int, \
unsigned long);
int easysnd_ioctl(struct inode *, struct file *, unsigned int, \
int easyoss_ioctl(struct inode *, struct file *, unsigned int, \
unsigned long);
unsigned int easysnd_poll(struct file *, poll_table *);
void easysnd_delete(struct kref *);
unsigned int easyoss_poll(struct file *, poll_table *);
void easyoss_delete(struct kref *);
#endif /*EASYCAP_NEEDS_ALSA*/
int easycap_sound_setup(struct easycap *);
int submit_audio_urbs(struct easycap *);
int kill_audio_urbs(struct easycap *);
void easysnd_testtone(struct easycap *, int);
void easyoss_testtone(struct easycap *, int);
int audio_setup(struct easycap *);
/*---------------------------------------------------------------------------*/
/*

View File

@ -27,8 +27,6 @@
#include <linux/smp_lock.h>
#include "easycap.h"
#include "easycap_debug.h"
#include "easycap_standard.h"
#include "easycap_ioctl.h"
/*--------------------------------------------------------------------------*/
@ -910,7 +908,7 @@ return -ENOENT;
* peasycap->audio_interface, \
* peasycap->audio_altsetting_off);
* HOWEVER, AFTER THIS COMMAND IS ISSUED ALL SUBSEQUENT URBS RECEIVE STATUS
* -ESHUTDOWN. THE HANDLER ROUTINE easysnd_complete() DECLINES TO RESUBMIT
* -ESHUTDOWN. THE HANDLER ROUTINE easyxxx_complete() DECLINES TO RESUBMIT
* THE URB AND THE PIPELINE COLLAPSES IRRETRIEVABLY. BEWARE.
*/
/*---------------------------------------------------------------------------*/
@ -991,11 +989,12 @@ if (NULL == p) {
}
kd = isdongle(peasycap);
if (0 <= kd && DONGLE_MANY > kd) {
if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) {
SAY("ERROR: cannot lock easycap_dongle[%i].mutex_video\n", kd);
if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
SAY("ERROR: cannot lock " \
"easycapdc60_dongle[%i].mutex_video\n", kd);
return -ERESTARTSYS;
}
JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
JOM(4, "locked easycapdc60_dongle[%i].mutex_video\n", kd);
/*---------------------------------------------------------------------------*/
/*
* MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
@ -1007,24 +1006,24 @@ if (0 <= kd && DONGLE_MANY > kd) {
return -ERESTARTSYS;
if (NULL == file) {
SAY("ERROR: file is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -ERESTARTSYS;
}
peasycap = file->private_data;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -ERESTARTSYS;
}
if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
SAY("ERROR: bad peasycap\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
p = peasycap->pusb_device;
if (NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -ERESTARTSYS;
}
} else {
@ -1048,7 +1047,7 @@ case VIDIOC_QUERYCAP: {
if (16 <= strlen(EASYCAP_DRIVER_VERSION)) {
SAM("ERROR: bad driver version string\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
strcpy(&version[0], EASYCAP_DRIVER_VERSION);
@ -1066,7 +1065,8 @@ case VIDIOC_QUERYCAP: {
if (0 != rc) {
SAM("ERROR: %i=strict_strtol(%s,.,,)\n", \
rc, p1);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].\
mutex_video);
return -EINVAL;
}
k[i] = (int)lng;
@ -1097,7 +1097,7 @@ case VIDIOC_QUERYCAP: {
}
if (0 != copy_to_user((void __user *)arg, &v4l2_capability, \
sizeof(struct v4l2_capability))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -1111,7 +1111,7 @@ case VIDIOC_ENUMINPUT: {
if (0 != copy_from_user(&v4l2_input, (void __user *)arg, \
sizeof(struct v4l2_input))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -1193,14 +1193,14 @@ case VIDIOC_ENUMINPUT: {
}
default: {
JOM(8, "%i=index: exhausts inputs\n", index);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_input, \
sizeof(struct v4l2_input))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -1213,7 +1213,7 @@ case VIDIOC_G_INPUT: {
index = (__u32)peasycap->input;
JOM(8, "user is told: %i\n", index);
if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -1227,7 +1227,7 @@ case VIDIOC_S_INPUT:
JOM(8, "VIDIOC_S_INPUT\n");
if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -1240,7 +1240,7 @@ case VIDIOC_S_INPUT:
if ((0 > index) || (INPUT_MANY <= index)) {
JOM(8, "ERROR: bad requested input: %i\n", index);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
@ -1249,7 +1249,7 @@ case VIDIOC_S_INPUT:
JOM(8, "newinput(.,%i) OK\n", (int)index);
} else {
SAM("ERROR: newinput(.,%i) returned %i\n", (int)index, rc);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -1257,7 +1257,7 @@ case VIDIOC_S_INPUT:
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUMAUDIO: {
JOM(8, "VIDIOC_ENUMAUDIO\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@ -1268,12 +1268,12 @@ case VIDIOC_ENUMAUDOUT: {
if (0 != copy_from_user(&v4l2_audioout, (void __user *)arg, \
sizeof(struct v4l2_audioout))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
if (0 != v4l2_audioout.index) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout));
@ -1282,7 +1282,7 @@ case VIDIOC_ENUMAUDOUT: {
if (0 != copy_to_user((void __user *)arg, &v4l2_audioout, \
sizeof(struct v4l2_audioout))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -1296,7 +1296,7 @@ case VIDIOC_QUERYCTRL: {
if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg, \
sizeof(struct v4l2_queryctrl))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -1313,12 +1313,12 @@ case VIDIOC_QUERYCTRL: {
}
if (0xFFFFFFFF == easycap_control[i1].id) {
JOM(8, "%i=index: exhausts controls\n", i1);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
if (0 != copy_to_user((void __user *)arg, &v4l2_queryctrl, \
sizeof(struct v4l2_queryctrl))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -1326,7 +1326,7 @@ case VIDIOC_QUERYCTRL: {
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_QUERYMENU: {
JOM(8, "VIDIOC_QUERYMENU unsupported\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@ -1337,13 +1337,13 @@ case VIDIOC_G_CTRL: {
pv4l2_control = kzalloc(sizeof(struct v4l2_control), GFP_KERNEL);
if (!pv4l2_control) {
SAM("ERROR: out of memory\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -ENOMEM;
}
if (0 != copy_from_user(pv4l2_control, (void __user *)arg, \
sizeof(struct v4l2_control))) {
kfree(pv4l2_control);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -1385,14 +1385,14 @@ case VIDIOC_G_CTRL: {
SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \
pv4l2_control->id);
kfree(pv4l2_control);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
}
if (0 != copy_to_user((void __user *)arg, pv4l2_control, \
sizeof(struct v4l2_control))) {
kfree(pv4l2_control);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
kfree(pv4l2_control);
@ -1412,7 +1412,7 @@ case VIDIOC_S_CTRL:
if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \
sizeof(struct v4l2_control))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -1463,7 +1463,7 @@ case VIDIOC_S_CTRL:
default: {
SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \
v4l2_control.id);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
}
@ -1472,7 +1472,7 @@ case VIDIOC_S_CTRL:
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_EXT_CTRLS: {
JOM(8, "VIDIOC_S_EXT_CTRLS unsupported\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@ -1484,7 +1484,7 @@ case VIDIOC_ENUM_FMT: {
if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg, \
sizeof(struct v4l2_fmtdesc))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -1539,13 +1539,13 @@ case VIDIOC_ENUM_FMT: {
}
default: {
JOM(8, "%i=index: exhausts formats\n", index);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_fmtdesc, \
sizeof(struct v4l2_fmtdesc))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -1564,7 +1564,7 @@ case VIDIOC_ENUM_FRAMESIZES: {
if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg, \
sizeof(struct v4l2_frmsizeenum))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -1616,7 +1616,7 @@ case VIDIOC_ENUM_FRAMESIZES: {
}
default: {
JOM(8, "%i=index: exhausts framesizes\n", index);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
}
@ -1674,14 +1674,14 @@ case VIDIOC_ENUM_FRAMESIZES: {
}
default: {
JOM(8, "%i=index: exhausts framesizes\n", index);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_frmsizeenum, \
sizeof(struct v4l2_frmsizeenum))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -1710,7 +1710,7 @@ case VIDIOC_ENUM_FRAMEINTERVALS: {
if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg, \
sizeof(struct v4l2_frmivalenum))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -1737,13 +1737,13 @@ case VIDIOC_ENUM_FRAMEINTERVALS: {
}
default: {
JOM(8, "%i=index: exhausts frameintervals\n", index);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_frmivalenum, \
sizeof(struct v4l2_frmivalenum))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -1757,28 +1757,28 @@ case VIDIOC_G_FMT: {
pv4l2_format = kzalloc(sizeof(struct v4l2_format), GFP_KERNEL);
if (!pv4l2_format) {
SAM("ERROR: out of memory\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -ENOMEM;
}
pv4l2_pix_format = kzalloc(sizeof(struct v4l2_pix_format), GFP_KERNEL);
if (!pv4l2_pix_format) {
SAM("ERROR: out of memory\n");
kfree(pv4l2_format);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -ENOMEM;
}
if (0 != copy_from_user(pv4l2_format, (void __user *)arg, \
sizeof(struct v4l2_format))) {
kfree(pv4l2_format);
kfree(pv4l2_pix_format);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
if (pv4l2_format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
kfree(pv4l2_format);
kfree(pv4l2_pix_format);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
@ -1794,7 +1794,7 @@ case VIDIOC_G_FMT: {
sizeof(struct v4l2_format))) {
kfree(pv4l2_format);
kfree(pv4l2_pix_format);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
kfree(pv4l2_format);
@ -1819,7 +1819,7 @@ case VIDIOC_S_FMT: {
if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \
sizeof(struct v4l2_format))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -1831,11 +1831,11 @@ case VIDIOC_S_FMT: {
try);
if (0 > best_format) {
if (-EBUSY == best_format) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EBUSY;
}
JOM(8, "WARNING: adjust_format() returned %i\n", best_format);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -ENOENT;
}
/*...........................................................................*/
@ -1848,7 +1848,7 @@ case VIDIOC_S_FMT: {
if (0 != copy_to_user((void __user *)arg, &v4l2_format, \
sizeof(struct v4l2_format))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -1861,7 +1861,7 @@ case VIDIOC_CROPCAP: {
if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg, \
sizeof(struct v4l2_cropcap))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -1885,7 +1885,7 @@ case VIDIOC_CROPCAP: {
if (0 != copy_to_user((void __user *)arg, &v4l2_cropcap, \
sizeof(struct v4l2_cropcap))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -1894,14 +1894,14 @@ case VIDIOC_CROPCAP: {
case VIDIOC_G_CROP:
case VIDIOC_S_CROP: {
JOM(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_QUERYSTD: {
JOM(8, "VIDIOC_QUERYSTD: " \
"EasyCAP is incapable of detecting standard\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
break;
}
@ -1923,7 +1923,7 @@ case VIDIOC_ENUMSTD: {
if (0 != copy_from_user(&v4l2_standard, (void __user *)arg, \
sizeof(struct v4l2_standard))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
index = v4l2_standard.index;
@ -1945,7 +1945,7 @@ case VIDIOC_ENUMSTD: {
}
if (0xFFFF == peasycap_standard->mask) {
JOM(8, "%i=index: exhausts standards\n", index);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
JOM(8, "%i=index: %s\n", index, \
@ -1957,7 +1957,7 @@ case VIDIOC_ENUMSTD: {
if (0 != copy_to_user((void __user *)arg, &v4l2_standard, \
sizeof(struct v4l2_standard))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -1972,13 +1972,13 @@ case VIDIOC_G_STD: {
if (0 > peasycap->standard_offset) {
JOM(8, "%i=peasycap->standard_offset\n", \
peasycap->standard_offset);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EBUSY;
}
if (0 != copy_from_user(&std_id, (void __user *)arg, \
sizeof(v4l2_std_id))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -1990,7 +1990,7 @@ case VIDIOC_G_STD: {
if (0 != copy_to_user((void __user *)arg, &std_id, \
sizeof(v4l2_std_id))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -2004,7 +2004,7 @@ case VIDIOC_S_STD: {
if (0 != copy_from_user(&std_id, (void __user *)arg, \
sizeof(v4l2_std_id))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -2015,7 +2015,7 @@ case VIDIOC_S_STD: {
rc = adjust_standard(peasycap, std_id);
if (0 > rc) {
JOM(8, "WARNING: adjust_standard() returned %i\n", rc);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -ENOENT;
}
break;
@ -2029,16 +2029,16 @@ case VIDIOC_REQBUFS: {
if (0 != copy_from_user(&v4l2_requestbuffers, (void __user *)arg, \
sizeof(struct v4l2_requestbuffers))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
nbuffers = v4l2_requestbuffers.count;
@ -2059,7 +2059,7 @@ case VIDIOC_REQBUFS: {
if (0 != copy_to_user((void __user *)arg, &v4l2_requestbuffers, \
sizeof(struct v4l2_requestbuffers))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -2074,18 +2074,18 @@ case VIDIOC_QUERYBUF: {
if (peasycap->video_eof) {
JOM(8, "returning -EIO because %i=video_eof\n", \
peasycap->video_eof);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EIO;
}
if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
sizeof(struct v4l2_buffer))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
index = v4l2_buffer.index;
@ -2117,7 +2117,7 @@ case VIDIOC_QUERYBUF: {
if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
sizeof(struct v4l2_buffer))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
break;
@ -2130,21 +2130,21 @@ case VIDIOC_QBUF: {
if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
sizeof(struct v4l2_buffer))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
if (v4l2_buffer.index < 0 || \
(v4l2_buffer.index >= peasycap->frame_buffer_many)) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
@ -2154,7 +2154,7 @@ case VIDIOC_QBUF: {
if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
sizeof(struct v4l2_buffer))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -2187,18 +2187,18 @@ case VIDIOC_DQBUF:
JOM(8, "returning -EIO because " \
"%i=video_idle %i=video_eof\n", \
peasycap->video_idle, peasycap->video_eof);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EIO;
}
if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
sizeof(struct v4l2_buffer))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
@ -2222,7 +2222,7 @@ case VIDIOC_DQBUF:
if (!peasycap->video_isoc_streaming) {
JOM(16, "returning -EIO because video urbs not streaming\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EIO;
}
/*---------------------------------------------------------------------------*/
@ -2239,18 +2239,19 @@ case VIDIOC_DQBUF:
if (-EIO == rcdq) {
JOM(8, "returning -EIO because " \
"dqbuf() returned -EIO\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].\
mutex_video);
return -EIO;
}
} while (0 != rcdq);
} else {
if (peasycap->video_eof) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EIO;
}
}
if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) {
SAM("ERROR: V4L2_BUF_FLAG_DONE != 0x%08X\n", \
JOM(8, "V4L2_BUF_FLAG_DONE != 0x%08X\n", \
peasycap->done[peasycap->frame_read]);
}
peasycap->polled = 0;
@ -2337,7 +2338,7 @@ case VIDIOC_DQBUF:
if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
sizeof(struct v4l2_buffer))) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -2370,7 +2371,7 @@ case VIDIOC_STREAMON: {
peasycap->merit[i] = 0;
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
submit_video_urbs(peasycap);
@ -2386,7 +2387,7 @@ case VIDIOC_STREAMOFF: {
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
@ -2400,7 +2401,12 @@ case VIDIOC_STREAMOFF: {
/*---------------------------------------------------------------------------*/
JOM(8, "calling wake_up on wq_video and wq_audio\n");
wake_up_interruptible(&(peasycap->wq_video));
#if defined(EASYCAP_NEEDS_ALSA)
if (NULL != peasycap->psubstream)
snd_pcm_period_elapsed(peasycap->psubstream);
#else
wake_up_interruptible(&(peasycap->wq_audio));
#endif /*EASYCAP_NEEDS_ALSA*/
/*---------------------------------------------------------------------------*/
break;
}
@ -2412,19 +2418,19 @@ case VIDIOC_G_PARM: {
pv4l2_streamparm = kzalloc(sizeof(struct v4l2_streamparm), GFP_KERNEL);
if (!pv4l2_streamparm) {
SAM("ERROR: out of memory\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -ENOMEM;
}
if (0 != copy_from_user(pv4l2_streamparm, (void __user *)arg, \
sizeof(struct v4l2_streamparm))) {
kfree(pv4l2_streamparm);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
if (pv4l2_streamparm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
kfree(pv4l2_streamparm);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
pv4l2_streamparm->parm.capture.capability = 0;
@ -2450,7 +2456,7 @@ case VIDIOC_G_PARM: {
if (0 != copy_to_user((void __user *)arg, pv4l2_streamparm, \
sizeof(struct v4l2_streamparm))) {
kfree(pv4l2_streamparm);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EFAULT;
}
kfree(pv4l2_streamparm);
@ -2459,25 +2465,25 @@ case VIDIOC_G_PARM: {
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_PARM: {
JOM(8, "VIDIOC_S_PARM unsupported\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_AUDIO: {
JOM(8, "VIDIOC_G_AUDIO unsupported\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_AUDIO: {
JOM(8, "VIDIOC_S_AUDIO unsupported\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_TUNER: {
JOM(8, "VIDIOC_S_TUNER unsupported\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@ -2485,45 +2491,46 @@ case VIDIOC_G_FBUF:
case VIDIOC_S_FBUF:
case VIDIOC_OVERLAY: {
JOM(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_TUNER: {
JOM(8, "VIDIOC_G_TUNER unsupported\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
case VIDIOC_G_FREQUENCY:
case VIDIOC_S_FREQUENCY: {
JOM(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
default: {
JOM(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -ENOIOCTLCMD;
}
}
mutex_unlock(&easycap_dongle[kd].mutex_video);
JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
JOM(4, "unlocked easycapdc60_dongle[%i].mutex_video\n", kd);
return 0;
}
/*****************************************************************************/
#if !defined(EASYCAP_NEEDS_ALSA)
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if ((defined(EASYCAP_IS_VIDEODEV_CLIENT)) || \
(defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)))
long
easysnd_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg) {
return (long)easysnd_ioctl((struct inode *)NULL, file, cmd, arg);
easyoss_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg) {
return (long)easyoss_ioctl((struct inode *)NULL, file, cmd, arg);
}
#endif /*EASYCAP_IS_VIDEODEV_CLIENT||EASYCAP_NEEDS_UNLOCKED_IOCTL*/
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
/*---------------------------------------------------------------------------*/
int
easysnd_ioctl(struct inode *inode, struct file *file,
easyoss_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct easycap *peasycap;
@ -2550,11 +2557,12 @@ if (NULL == p) {
}
kd = isdongle(peasycap);
if (0 <= kd && DONGLE_MANY > kd) {
if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_audio)) {
SAY("ERROR: cannot lock easycap_dongle[%i].mutex_audio\n", kd);
if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_audio)) {
SAY("ERROR: cannot lock "
"easycapdc60_dongle[%i].mutex_audio\n", kd);
return -ERESTARTSYS;
}
JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
JOM(4, "locked easycapdc60_dongle[%i].mutex_audio\n", kd);
/*---------------------------------------------------------------------------*/
/*
* MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
@ -2566,24 +2574,24 @@ if (0 <= kd && DONGLE_MANY > kd) {
return -ERESTARTSYS;
if (NULL == file) {
SAY("ERROR: file is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -ERESTARTSYS;
}
peasycap = file->private_data;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -ERESTARTSYS;
}
if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
SAY("ERROR: bad peasycap\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
p = peasycap->pusb_device;
if (NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -ERESTARTSYS;
}
} else {
@ -2614,7 +2622,7 @@ case SNDCTL_DSP_GETCAPS: {
#endif /*UPSAMPLE*/
if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int))) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
break;
@ -2636,7 +2644,7 @@ case SNDCTL_DSP_GETFMTS: {
#endif /*UPSAMPLE*/
if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
break;
@ -2645,7 +2653,7 @@ case SNDCTL_DSP_SETFMT: {
int incoming, outgoing;
JOM(8, "SNDCTL_DSP_SETFMT\n");
if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
JOM(8, "........... %i=incoming\n", incoming);
@ -2668,10 +2676,10 @@ case SNDCTL_DSP_SETFMT: {
JOM(8, " cf. %i=AFMT_U8\n", AFMT_U8);
if (0 != copy_to_user((void __user *)arg, &outgoing, \
sizeof(int))) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EINVAL ;
}
break;
@ -2680,7 +2688,7 @@ case SNDCTL_DSP_STEREO: {
int incoming;
JOM(8, "SNDCTL_DSP_STEREO\n");
if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
JOM(8, "........... %i=incoming\n", incoming);
@ -2698,7 +2706,7 @@ case SNDCTL_DSP_STEREO: {
#endif /*UPSAMPLE*/
if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
break;
@ -2707,7 +2715,7 @@ case SNDCTL_DSP_SPEED: {
int incoming;
JOM(8, "SNDCTL_DSP_SPEED\n");
if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
JOM(8, "........... %i=incoming\n", incoming);
@ -2725,7 +2733,7 @@ case SNDCTL_DSP_SPEED: {
#endif /*UPSAMPLE*/
if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
break;
@ -2734,14 +2742,14 @@ case SNDCTL_DSP_GETTRIGGER: {
int incoming;
JOM(8, "SNDCTL_DSP_GETTRIGGER\n");
if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
JOM(8, "........... %i=incoming\n", incoming);
incoming = PCM_ENABLE_INPUT;
if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
break;
@ -2750,7 +2758,7 @@ case SNDCTL_DSP_SETTRIGGER: {
int incoming;
JOM(8, "SNDCTL_DSP_SETTRIGGER\n");
if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
JOM(8, "........... %i=incoming\n", incoming);
@ -2767,13 +2775,13 @@ case SNDCTL_DSP_GETBLKSIZE: {
int incoming;
JOM(8, "SNDCTL_DSP_GETBLKSIZE\n");
if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
JOM(8, "........... %i=incoming\n", incoming);
incoming = peasycap->audio_bytes_per_fragment;
if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
break;
@ -2790,7 +2798,7 @@ case SNDCTL_DSP_GETISPACE: {
if (0 != copy_to_user((void __user *)arg, &audio_buf_info, \
sizeof(int))) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
break;
@ -2802,18 +2810,18 @@ case 0x00005404:
case 0x00005405:
case 0x00005406: {
JOM(8, "SNDCTL_TMR_...: 0x%08X unsupported\n", cmd);
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -ENOIOCTLCMD;
}
default: {
JOM(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd);
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -ENOIOCTLCMD;
}
}
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return 0;
}
#endif /*EASYCAP_NEEDS_ALSA*/
/*****************************************************************************/

View File

@ -24,5 +24,14 @@
*
*/
/*****************************************************************************/
#if !defined(EASYCAP_IOCTL_H)
#define EASYCAP_IOCTL_H
extern int easycap_debug;
extern int easycap_gain;
extern struct easycap_dongle easycapdc60_dongle[];
extern struct easycap_standard easycap_standard[];
extern struct easycap_format easycap_format[];
extern struct v4l2_queryctrl easycap_control[];
#endif /*EASYCAP_IOCTL_H*/

View File

@ -39,7 +39,7 @@
/****************************************************************************/
#include "easycap.h"
#include "easycap_debug.h"
#include "easycap_low.h"
/*--------------------------------------------------------------------------*/
const struct stk1160config { int reg; int set; } stk1160configPAL[256] = {
@ -1052,9 +1052,18 @@ rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \
(int)50000);
JOT(8, "0x%02X=buffer\n", *((__u8 *) &buffer[0]));
if (rc != (int)length)
SAY("ERROR: usb_control_msg returned %i\n", rc);
if (rc != (int)length) {
switch (rc) {
case -EPIPE: {
SAY("usb_control_msg returned -EPIPE\n");
break;
}
default: {
SAY("ERROR: usb_control_msg returned %i\n", rc);
break;
}
}
}
/*--------------------------------------------------------------------------*/
/*
* REGISTER 500: SETTING VALUE TO 0x0094 RESETS AUDIO CONFIGURATION ???

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* *
* easycap_debug.h *
* easycap_low.h *
* *
*****************************************************************************/
/*
@ -24,6 +24,11 @@
*
*/
/*****************************************************************************/
#if !defined(EASYCAP_LOW_H)
#define EASYCAP_LOW_H
extern int easycap_debug;
extern int easycap_gain;
extern struct easycap_dongle easycap_dongle[];
extern struct easycap_dongle easycapdc60_dongle[];
#endif /*EASYCAP_LOW_H*/

View File

@ -29,30 +29,17 @@
/*****************************************************************************/
#include "easycap.h"
#include "easycap_standard.h"
#include "easycap_ioctl.h"
#include "easycap_main.h"
int easycap_debug;
static int easycap_bars;
static int easycap_bars = 1;
int easycap_gain = 16;
module_param_named(debug, easycap_debug, int, S_IRUGO | S_IWUSR);
module_param_named(bars, easycap_bars, int, S_IRUGO | S_IWUSR);
module_param_named(gain, easycap_gain, int, S_IRUGO | S_IWUSR);
/*---------------------------------------------------------------------------*/
/*
* dongle_this IS INDISPENSIBLY static BECAUSE FUNCTION easycap_usb_probe()
* IS CALLED SUCCESSIVELY FOR INTERFACES 0, 1, 2 AND THE POINTER peasycap
* ALLOCATED DURING THE PROBING OF INTERFACE 0 MUST BE REMEMBERED WHEN
* PROBING INTERFACES 1 AND 2.
*
* IOCTL LOCKING IS DONE AT MODULE LEVEL, NOT DEVICE LEVEL.
*/
/*---------------------------------------------------------------------------*/
struct easycap_dongle easycap_dongle[DONGLE_MANY];
static int dongle_this;
static int dongle_done;
struct easycap_dongle easycapdc60_dongle[DONGLE_MANY];
static struct mutex mutex_dongle;
/*---------------------------------------------------------------------------*/
/*
@ -120,28 +107,6 @@ const struct v4l2_file_operations v4l2_fops = {
#endif /*EASYCAP_NEEDS_V4L2_FOPS*/
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
/*--------------------------------------------------------------------------*/
/*
* PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
*/
/*--------------------------------------------------------------------------*/
const struct file_operations easysnd_fops = {
.owner = THIS_MODULE,
.open = easysnd_open,
.release = easysnd_release,
#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)
.unlocked_ioctl = easysnd_ioctl_noinode,
#else
.ioctl = easysnd_ioctl,
#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/
.read = easysnd_read,
.llseek = no_llseek,
};
struct usb_class_driver easysnd_class = {
.name = "usb/easysnd%d",
.fops = &easysnd_fops,
.minor_base = USB_SKEL_MINOR_BASE,
};
/****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
@ -155,7 +120,7 @@ int k;
if (NULL == peasycap)
return -2;
for (k = 0; k < DONGLE_MANY; k++) {
if (easycap_dongle[k].peasycap == peasycap) {
if (easycapdc60_dongle[k].peasycap == peasycap) {
peasycap->isdongle = k;
return k;
}
@ -1055,9 +1020,10 @@ for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
m++;
}
}
JOM(4, "easysnd_delete(): isoc audio buffers freed: %i pages\n", \
JOM(4, "easyoss_delete(): isoc audio buffers freed: %i pages\n", \
m * (0x01 << AUDIO_ISOC_ORDER));
/*---------------------------------------------------------------------------*/
#if !defined(EASYCAP_NEEDS_ALSA)
JOM(4, "freeing audio buffers.\n");
gone = 0;
for (k = 0; k < peasycap->audio_buffer_page_many; k++) {
@ -1068,7 +1034,8 @@ for (k = 0; k < peasycap->audio_buffer_page_many; k++) {
gone++;
}
}
JOM(4, "easysnd_delete(): audio buffers freed: %i pages\n", gone);
JOM(4, "easyoss_delete(): audio buffers freed: %i pages\n", gone);
#endif /*!EASYCAP_NEEDS_ALSA*/
/*---------------------------------------------------------------------------*/
JOM(4, "freeing easycap structure.\n");
allocation_video_urb = peasycap->allocation_video_urb;
@ -1081,12 +1048,20 @@ allocation_audio_struct = peasycap->allocation_audio_struct;
registered_audio = peasycap->registered_audio;
kfree(peasycap);
if (0 <= kd && DONGLE_MANY > kd) {
easycap_dongle[kd].peasycap = (struct easycap *)NULL;
JOT(4, " null-->easycap_dongle[%i].peasycap\n", kd);
allocation_video_struct -= sizeof(struct easycap);
if (mutex_lock_interruptible(&mutex_dongle)) {
SAY("ERROR: cannot down mutex_dongle\n");
} else {
JOM(4, "locked mutex_dongle\n");
easycapdc60_dongle[kd].peasycap = (struct easycap *)NULL;
mutex_unlock(&mutex_dongle);
JOM(4, "unlocked mutex_dongle\n");
JOT(4, " null-->easycapdc60_dongle[%i].peasycap\n", kd);
allocation_video_struct -= sizeof(struct easycap);
}
} else {
SAY("ERROR: cannot purge easycap_dongle[].peasycap");
SAY("ERROR: cannot purge easycapdc60_dongle[].peasycap");
}
/*---------------------------------------------------------------------------*/
SAY("%8i= video urbs after all deletions\n", allocation_video_urb);
@ -1131,11 +1106,12 @@ if (NULL == peasycap->pusb_device) {
/*---------------------------------------------------------------------------*/
kd = isdongle(peasycap);
if (0 <= kd && DONGLE_MANY > kd) {
if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) {
SAY("ERROR: cannot down easycap_dongle[%i].mutex_video\n", kd);
if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
SAY("ERROR: cannot down "
"easycapdc60_dongle[%i].mutex_video\n", kd);
return -ERESTARTSYS;
}
JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
JOM(4, "locked easycapdc60_dongle[%i].mutex_video\n", kd);
/*-------------------------------------------------------------------*/
/*
* MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER
@ -1147,24 +1123,24 @@ if (0 <= kd && DONGLE_MANY > kd) {
return -ERESTARTSYS;
if (NULL == file) {
SAY("ERROR: file is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -ERESTARTSYS;
}
peasycap = file->private_data;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -ERESTARTSYS;
}
if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
SAY("ERROR: bad peasycap: 0x%08lX\n", \
(unsigned long int) peasycap);
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -ERESTARTSYS;
}
if (NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return -ERESTARTSYS;
}
} else
@ -1179,7 +1155,7 @@ if (0 <= kd && DONGLE_MANY > kd) {
/*---------------------------------------------------------------------------*/
rc = easycap_dqbuf(peasycap, 0);
peasycap->polled = 1;
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
if (0 == rc)
return POLLIN | POLLRDNORM;
else
@ -3391,20 +3367,13 @@ return;
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
*
* FIXME
*
*
* THIS FUNCTION ASSUMES THAT, ON EACH AND EVERY OCCASION THAT THE EasyCAP
* IS PHYSICALLY PLUGGED IN, INTERFACE 0 IS PROBED FIRST.
* IF THIS IS NOT TRUE, THERE IS THE POSSIBILITY OF AN Oops.
*
* THIS HAS NEVER BEEN A PROBLEM IN PRACTICE, BUT SOMETHING SEEMS WRONG HERE.
* WHEN THE EasyCAP IS PHYSICALLY PLUGGED IN, THIS FUNCTION IS CALLED THREE
* TIMES, ONCE FOR EACH OF THE THREE INTERFACES. BEWARE.
*/
/*---------------------------------------------------------------------------*/
int
easycap_usb_probe(struct usb_interface *pusb_interface, \
const struct usb_device_id *id)
const struct usb_device_id *pusb_device_id)
{
struct usb_device *pusb_device, *pusb_device1;
struct usb_host_interface *pusb_host_interface;
@ -3413,6 +3382,7 @@ struct usb_interface_descriptor *pusb_interface_descriptor;
struct usb_interface_assoc_descriptor *pusb_interface_assoc_descriptor;
struct urb *purb;
struct easycap *peasycap;
int ndong;
struct data_urb *pdata_urb;
size_t wMaxPacketSize;
int ISOCwMaxPacketSize;
@ -3434,24 +3404,19 @@ int maxpacketsize;
__u16 mask;
__s32 value;
struct easycap_format *peasycap_format;
JOT(4, "\n");
if (!dongle_done) {
dongle_done = 1;
for (k = 0; k < DONGLE_MANY; k++) {
easycap_dongle[k].peasycap = (struct easycap *)NULL;
mutex_init(&easycap_dongle[k].mutex_video);
mutex_init(&easycap_dongle[k].mutex_audio);
}
}
peasycap = (struct easycap *)NULL;
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
struct v4l2_device *pv4l2_device;
#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
if ((struct usb_interface *)NULL == pusb_interface) {
SAY("ERROR: pusb_interface is NULL\n");
return -EFAULT;
}
peasycap = (struct easycap *)NULL;
/*---------------------------------------------------------------------------*/
/*
* GET POINTER TO STRUCTURE usb_device
@ -3472,9 +3437,7 @@ if ((unsigned long int)pusb_device1 != (unsigned long int)pusb_device) {
JOT(4, "ERROR: pusb_device1 != pusb_device\n");
return -EFAULT;
}
JOT(4, "bNumConfigurations=%i\n", pusb_device->descriptor.bNumConfigurations);
/*---------------------------------------------------------------------------*/
pusb_host_interface = pusb_interface->cur_altsetting;
if (NULL == pusb_host_interface) {
@ -3553,9 +3516,6 @@ JOT(4, "intf[%i]: pusb_interface_assoc_descriptor is NULL\n", \
*
* THE POINTER peasycap TO THE struct easycap IS REMEMBERED WHEN
* INTERFACES 1 AND 2 ARE PROBED.
*
* IF TWO EasyCAPs ARE PLUGGED IN NEARLY SIMULTANEOUSLY THERE WILL
* BE TROUBLE. BEWARE.
*/
/*---------------------------------------------------------------------------*/
if (0 == bInterfaceNumber) {
@ -3580,6 +3540,7 @@ if (0 == bInterfaceNumber) {
* PERFORM URGENT INTIALIZATIONS ...
*/
/*---------------------------------------------------------------------------*/
peasycap->minor = -1;
strcpy(&peasycap->telltale[0], TELLTALE);
kref_init(&peasycap->kref);
JOM(8, "intf[%i]: after kref_init(..._video) " \
@ -3588,29 +3549,43 @@ if (0 == bInterfaceNumber) {
init_waitqueue_head(&peasycap->wq_video);
init_waitqueue_head(&peasycap->wq_audio);
init_waitqueue_head(&peasycap->wq_trigger);
for (dongle_this = 0; dongle_this < DONGLE_MANY; dongle_this++) {
if (NULL == easycap_dongle[dongle_this].peasycap) {
if (0 == mutex_is_locked(&easycap_dongle\
[dongle_this].mutex_video)) {
if (0 == mutex_is_locked(&easycap_dongle\
[dongle_this].mutex_audio)) {
easycap_dongle\
[dongle_this].peasycap = \
peasycap;
JOM(8, "intf[%i]: peasycap-->easycap" \
if (mutex_lock_interruptible(&mutex_dongle)) {
SAY("ERROR: cannot down mutex_dongle\n");
return -ERESTARTSYS;
} else {
/*---------------------------------------------------------------------------*/
/*
* FOR INTERFACES 1 AND 2 THE POINTER peasycap WILL NEED TO
* TO BE THE SAME AS THAT ALLOCATED NOW FOR INTERFACE 0.
*
* NORMALLY ndong WILL NOT HAVE CHANGED SINCE INTERFACE 0 WAS
* PROBED, BUT THIS MAY NOT BE THE CASE IF, FOR EXAMPLE, TWO
* EASYCAPs ARE PLUGGED IN SIMULTANEOUSLY.
*/
/*---------------------------------------------------------------------------*/
for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
if ((NULL == easycapdc60_dongle[ndong].peasycap) && \
(!mutex_is_locked(&easycapdc60_dongle\
[ndong].mutex_video)) && \
(!mutex_is_locked(&easycapdc60_dongle\
[ndong].mutex_audio))) {
easycapdc60_dongle[ndong].peasycap = peasycap;
peasycap->isdongle = ndong;
JOM(8, "intf[%i]: peasycap-->easycap" \
"_dongle[%i].peasycap\n", \
bInterfaceNumber, dongle_this);
break;
}
bInterfaceNumber, ndong);
break;
}
}
if (DONGLE_MANY <= ndong) {
SAM("ERROR: too many dongles\n");
mutex_unlock(&mutex_dongle);
return -ENOMEM;
}
mutex_unlock(&mutex_dongle);
}
if (DONGLE_MANY <= dongle_this) {
SAM("ERROR: too many dongles\n");
return -ENOMEM;
}
peasycap->allocation_video_struct = sizeof(struct easycap);
peasycap->allocation_video_page = 0;
peasycap->allocation_video_urb = 0;
@ -3778,26 +3753,56 @@ if (0 == bInterfaceNumber) {
JOM(4, "finished initialization\n");
} else {
/*---------------------------------------------------------------------------*/
/*
* FOR INTERFACES 1 AND 2 THE POINTER peasycap IS OBTAINED BY ASSUMING
* THAT dongle_this HAS NOT CHANGED SINCE INTERFACE 0 WAS PROBED. IF
* THIS IS NOT THE CASE, FOR EXAMPLE WHEN TWO EASYCAPs ARE PLUGGED IN
* SIMULTANEOUSLY, THERE WILL BE SERIOUS TROUBLE.
*/
/*
* FIXME
*
* IDENTIFY THE APPROPRIATE POINTER peasycap FOR INTERFACES 1 AND 2.
* THE ADDRESS OF peasycap->pusb_device IS RELUCTANTLY USED FOR THIS PURPOSE.
*/
/*---------------------------------------------------------------------------*/
if ((0 > dongle_this) || (DONGLE_MANY <= dongle_this)) {
SAY("ERROR: bad dongle count\n");
return -EFAULT;
for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
if (pusb_device == easycapdc60_dongle[ndong].peasycap->\
pusb_device) {
peasycap = easycapdc60_dongle[ndong].peasycap;
JOT(8, "intf[%i]: easycapdc60_dongle[%i].peasycap-->" \
"peasycap\n", bInterfaceNumber, ndong);
break;
}
}
peasycap = easycap_dongle[dongle_this].peasycap;
JOT(8, "intf[%i]: easycap_dongle[%i].peasycap-->peasycap\n", \
bInterfaceNumber, dongle_this);
if ((struct easycap *)NULL == peasycap) {
if (DONGLE_MANY <= ndong) {
SAY("ERROR: peasycap is unknown when probing interface %i\n", \
bInterfaceNumber);
return -ENODEV;
}
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL when probing interface %i\n", \
bInterfaceNumber);
return -EFAULT;
return -ENODEV;
}
#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
#
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#else
#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
/*---------------------------------------------------------------------------*/
/*
* SOME VERSIONS OF THE videodev MODULE OVERWRITE THE DATA WHICH HAS
* BEEN WRITTEN BY THE CALL TO usb_set_intfdata() IN easycap_usb_probe(),
* REPLACING IT WITH A POINTER TO THE EMBEDDED v4l2_device STRUCTURE.
* TO DETECT THIS, THE STRING IN THE easycap.telltale[] BUFFER IS CHECKED.
*/
/*---------------------------------------------------------------------------*/
if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
pv4l2_device = usb_get_intfdata(pusb_interface);
if ((struct v4l2_device *)NULL == pv4l2_device) {
SAY("ERROR: pv4l2_device is NULL\n");
return -ENODEV;
}
peasycap = (struct easycap *) \
container_of(pv4l2_device, struct easycap, v4l2_device);
}
#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
}
/*---------------------------------------------------------------------------*/
if ((USB_CLASS_VIDEO == bInterfaceClass) || \
@ -4368,6 +4373,7 @@ case 0: {
} else {
(peasycap->registered_video)++;
SAM("easycap attached to minor #%d\n", pusb_interface->minor);
peasycap->minor = pusb_interface->minor;
break;
}
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
@ -4383,7 +4389,7 @@ case 0: {
}
/*---------------------------------------------------------------------------*/
/*
* FIXME
* FIXME
*
*
* THIS IS BELIEVED TO BE HARMLESS, BUT MAY WELL BE UNNECESSARY OR WRONG:
@ -4414,9 +4420,11 @@ case 0: {
(peasycap->registered_video)++;
SAM("registered with videodev: %i=minor\n", \
peasycap->video_device.minor);
peasycap->minor = peasycap->video_device.minor;
}
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
break;
}
/*--------------------------------------------------------------------------*/
@ -4426,8 +4434,11 @@ case 0: {
*/
/*--------------------------------------------------------------------------*/
case 1: {
#if defined(EASYCAP_SILENT)
return -ENOENT;
#endif /*EASYCAP_SILENT*/
if (!peasycap) {
SAM("ERROR: peasycap is NULL\n");
SAM("MISTAKE: peasycap is NULL\n");
return -EFAULT;
}
/*--------------------------------------------------------------------------*/
@ -4442,6 +4453,9 @@ case 1: {
}
/*--------------------------------------------------------------------------*/
case 2: {
#if defined(EASYCAP_SILENT)
return -ENOENT;
#endif /*EASYCAP_SILENT*/
if (!peasycap) {
SAM("MISTAKE: peasycap is NULL\n");
return -EFAULT;
@ -4467,14 +4481,14 @@ case 2: {
}
if (9 == peasycap->audio_isoc_maxframesize) {
peasycap->ilk |= 0x02;
SAM("hardware is FOUR-CVBS\n");
SAM("audio hardware is microphone\n");
peasycap->microphone = true;
peasycap->audio_pages_per_fragment = 4;
peasycap->audio_pages_per_fragment = PAGES_PER_AUDIO_FRAGMENT;
} else if (256 == peasycap->audio_isoc_maxframesize) {
peasycap->ilk &= ~0x02;
SAM("hardware is CVBS+S-VIDEO\n");
SAM("audio hardware is AC'97\n");
peasycap->microphone = false;
peasycap->audio_pages_per_fragment = 4;
peasycap->audio_pages_per_fragment = PAGES_PER_AUDIO_FRAGMENT;
} else {
SAM("hardware is unidentified:\n");
SAM("%i=audio_isoc_maxframesize\n", \
@ -4496,7 +4510,7 @@ case 2: {
JOM(4, "%6i=audio_buffer_page_many\n", \
peasycap->audio_buffer_page_many);
peasycap->audio_isoc_framesperdesc = 128;
peasycap->audio_isoc_framesperdesc = AUDIO_ISOC_FRAMESPERDESC;
JOM(4, "%i=audio_isoc_framesperdesc\n", \
peasycap->audio_isoc_framesperdesc);
@ -4548,6 +4562,7 @@ case 2: {
INIT_LIST_HEAD(&(peasycap->urb_audio_head));
peasycap->purb_audio_head = &(peasycap->urb_audio_head);
#if !defined(EASYCAP_NEEDS_ALSA)
JOM(4, "allocating an audio buffer\n");
JOM(4, ".... scattered over %i pages\n", \
peasycap->audio_buffer_page_many);
@ -4572,6 +4587,7 @@ case 2: {
peasycap->audio_fill = 0;
peasycap->audio_read = 0;
JOM(4, "allocation of audio buffer done: %i pages\n", k);
#endif /*!EASYCAP_NEEDS_ALSA*/
/*---------------------------------------------------------------------------*/
JOM(4, "allocating %i isoc audio buffers of size %i\n", \
AUDIO_ISOC_BUFFER_MANY, peasycap->audio_isoc_buffer_size);
@ -4646,7 +4662,11 @@ case 2: {
"peasycap->audio_isoc_buffer[.].pgo;\n");
JOM(4, " purb->transfer_buffer_length = %i;\n", \
peasycap->audio_isoc_buffer_size);
JOM(4, " purb->complete = easysnd_complete;\n");
#if defined(EASYCAP_NEEDS_ALSA)
JOM(4, " purb->complete = easycap_alsa_complete;\n");
#else
JOM(4, " purb->complete = easyoss_complete;\n");
#endif /*EASYCAP_NEEDS_ALSA*/
JOM(4, " purb->context = peasycap;\n");
JOM(4, " purb->start_frame = 0;\n");
JOM(4, " purb->number_of_packets = %i;\n", \
@ -4669,7 +4689,11 @@ case 2: {
purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
purb->transfer_buffer_length = \
peasycap->audio_isoc_buffer_size;
purb->complete = easysnd_complete;
#if defined(EASYCAP_NEEDS_ALSA)
purb->complete = easycap_alsa_complete;
#else
purb->complete = easyoss_complete;
#endif /*EASYCAP_NEEDS_ALSA*/
purb->context = peasycap;
purb->start_frame = 0;
purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
@ -4692,9 +4716,24 @@ case 2: {
* THE AUDIO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
*/
/*---------------------------------------------------------------------------*/
rc = usb_register_dev(pusb_interface, &easysnd_class);
#if defined(EASYCAP_NEEDS_ALSA)
JOM(4, "initializing ALSA card\n");
rc = easycap_alsa_probe(peasycap);
if (0 != rc) {
err("Not able to get a minor for this device.");
err("easycap_alsa_probe() returned %i\n", rc);
return -ENODEV;
} else {
JOM(8, "kref_get() with %i=peasycap->kref.refcount.counter\n",\
(int)peasycap->kref.refcount.counter);
kref_get(&peasycap->kref);
(peasycap->registered_audio)++;
}
#else /*EASYCAP_NEEDS_ALSA*/
rc = usb_register_dev(pusb_interface, &easyoss_class);
if (0 != rc) {
SAY("ERROR: usb_register_dev() failed\n");
usb_set_intfdata(pusb_interface, NULL);
return -ENODEV;
} else {
@ -4708,7 +4747,9 @@ case 2: {
* LET THE USER KNOW WHAT NODE THE AUDIO DEVICE IS ATTACHED TO.
*/
/*---------------------------------------------------------------------------*/
SAM("easysnd attached to minor #%d\n", pusb_interface->minor);
SAM("easyoss attached to minor #%d\n", pusb_interface->minor);
#endif /*EASYCAP_NEEDS_ALSA*/
break;
}
/*---------------------------------------------------------------------------*/
@ -4721,7 +4762,7 @@ default: {
return -EINVAL;
}
}
JOM(4, "ends successfully for interface %i\n", \
SAM("ends successfully for interface %i\n", \
pusb_interface_descriptor->bInterfaceNumber);
return 0;
}
@ -4730,6 +4771,8 @@ return 0;
/*
* WHEN THIS FUNCTION IS CALLED THE EasyCAP HAS ALREADY BEEN PHYSICALLY
* UNPLUGGED. HENCE peasycap->pusb_device IS NO LONGER VALID.
*
* THIS FUNCTION AFFECTS BOTH OSS AND ALSA. BEWARE.
*/
/*---------------------------------------------------------------------------*/
void
@ -4881,14 +4924,15 @@ switch (bInterfaceNumber) {
case 0: {
if (0 <= kd && DONGLE_MANY > kd) {
wake_up_interruptible(&peasycap->wq_video);
JOM(4, "about to lock easycap_dongle[%i].mutex_video\n", kd);
if (mutex_lock_interruptible(&easycap_dongle[kd].\
JOM(4, "about to lock easycapdc60_dongle[%i].mutex_video\n", \
kd);
if (mutex_lock_interruptible(&easycapdc60_dongle[kd].\
mutex_video)) {
SAY("ERROR: cannot lock easycap_dongle[%i]." \
SAY("ERROR: cannot lock easycapdc60_dongle[%i]." \
"mutex_video\n", kd);
return;
}
JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
JOM(4, "locked easycapdc60_dongle[%i].mutex_video\n", kd);
} else
SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
/*---------------------------------------------------------------------------*/
@ -4907,7 +4951,7 @@ case 0: {
if (!peasycap->v4l2_device.name[0]) {
SAM("ERROR: peasycap->v4l2_device.name is empty\n");
if (0 <= kd && DONGLE_MANY > kd)
mutex_unlock(&easycap_dongle[kd].mutex_video);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
return;
}
v4l2_device_disconnect(&peasycap->v4l2_device);
@ -4924,34 +4968,47 @@ case 0: {
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
if (0 <= kd && DONGLE_MANY > kd) {
mutex_unlock(&easycap_dongle[kd].mutex_video);
JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
JOM(4, "unlocked easycapdc60_dongle[%i].mutex_video\n", kd);
}
break;
}
case 2: {
if (0 <= kd && DONGLE_MANY > kd) {
wake_up_interruptible(&peasycap->wq_audio);
JOM(4, "about to lock easycap_dongle[%i].mutex_audio\n", kd);
if (mutex_lock_interruptible(&easycap_dongle[kd].\
JOM(4, "about to lock easycapdc60_dongle[%i].mutex_audio\n", \
kd);
if (mutex_lock_interruptible(&easycapdc60_dongle[kd].\
mutex_audio)) {
SAY("ERROR: cannot lock easycap_dongle[%i]." \
SAY("ERROR: cannot lock easycapdc60_dongle[%i]." \
"mutex_audio\n", kd);
return;
}
JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
JOM(4, "locked easycapdc60_dongle[%i].mutex_audio\n", kd);
} else
SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
#if defined(EASYCAP_NEEDS_ALSA)
usb_deregister_dev(pusb_interface, &easysnd_class);
if (0 != snd_card_free(peasycap->psnd_card)) {
SAY("ERROR: snd_card_free() failed\n");
} else {
peasycap->psnd_card = (struct snd_card *)NULL;
(peasycap->registered_audio)--;
}
#else /*EASYCAP_NEEDS_ALSA*/
usb_deregister_dev(pusb_interface, &easyoss_class);
(peasycap->registered_audio)--;
JOM(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
SAM("easysnd detached from minor #%d\n", minor);
SAM("easyoss detached from minor #%d\n", minor);
#endif /*EASYCAP_NEEDS_ALSA*/
if (0 <= kd && DONGLE_MANY > kd) {
mutex_unlock(&easycap_dongle[kd].mutex_audio);
JOM(4, "unlocked easycap_dongle[%i].mutex_audio\n", kd);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
JOM(4, "unlocked easycapdc60_dongle[%i].mutex_audio\n", kd);
}
break;
}
@ -4961,6 +5018,7 @@ case 2: {
/*---------------------------------------------------------------------------*/
/*
* CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap
* (ALSO WHEN ALSA HAS BEEN IN USE)
*/
/*---------------------------------------------------------------------------*/
if (!peasycap->kref.refcount.counter) {
@ -4970,32 +5028,34 @@ if (!peasycap->kref.refcount.counter) {
return;
}
if (0 <= kd && DONGLE_MANY > kd) {
JOM(4, "about to lock easycap_dongle[%i].mutex_video\n", kd);
if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) {
SAY("ERROR: cannot down easycap_dongle[%i].mutex_video\n", kd);
JOM(4, "about to lock easycapdc60_dongle[%i].mutex_video\n", kd);
if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
SAY("ERROR: cannot down "
"easycapdc60_dongle[%i].mutex_video\n", kd);
SAM("ending unsuccessfully: may cause memory leak\n");
return;
}
JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
JOM(4, "about to lock easycap_dongle[%i].mutex_audio\n", kd);
if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_audio)) {
SAY("ERROR: cannot down easycap_dongle[%i].mutex_audio\n", kd);
mutex_unlock(&(easycap_dongle[kd].mutex_video));
JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
JOM(4, "locked easycapdc60_dongle[%i].mutex_video\n", kd);
JOM(4, "about to lock easycapdc60_dongle[%i].mutex_audio\n", kd);
if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_audio)) {
SAY("ERROR: cannot down "
"easycapdc60_dongle[%i].mutex_audio\n", kd);
mutex_unlock(&(easycapdc60_dongle[kd].mutex_video));
JOM(4, "unlocked easycapdc60_dongle[%i].mutex_video\n", kd);
SAM("ending unsuccessfully: may cause memory leak\n");
return;
}
JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
JOM(4, "locked easycapdc60_dongle[%i].mutex_audio\n", kd);
}
JOM(4, "intf[%i]: %i=peasycap->kref.refcount.counter\n", \
bInterfaceNumber, (int)peasycap->kref.refcount.counter);
kref_put(&peasycap->kref, easycap_delete);
JOT(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber);
if (0 <= kd && DONGLE_MANY > kd) {
mutex_unlock(&(easycap_dongle[kd].mutex_audio));
JOT(4, "unlocked easycap_dongle[%i].mutex_audio\n", kd);
mutex_unlock(&easycap_dongle[kd].mutex_video);
JOT(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
mutex_unlock(&(easycapdc60_dongle[kd].mutex_audio));
JOT(4, "unlocked easycapdc60_dongle[%i].mutex_audio\n", kd);
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
JOT(4, "unlocked easycapdc60_dongle[%i].mutex_video\n", kd);
}
/*---------------------------------------------------------------------------*/
JOM(4, "ends\n");
@ -5005,25 +5065,31 @@ return;
int __init
easycap_module_init(void)
{
int result;
int k, rc;
SAY("========easycap=======\n");
JOT(4, "begins. %i=debug %i=bars %i=gain\n", easycap_debug, easycap_bars, \
easycap_gain);
SAY("version: " EASYCAP_DRIVER_VERSION "\n");
mutex_init(&mutex_dongle);
for (k = 0; k < DONGLE_MANY; k++) {
easycapdc60_dongle[k].peasycap = (struct easycap *)NULL;
mutex_init(&easycapdc60_dongle[k].mutex_video);
mutex_init(&easycapdc60_dongle[k].mutex_audio);
}
/*---------------------------------------------------------------------------*/
/*
* REGISTER THIS DRIVER WITH THE USB SUBSYTEM.
*/
/*---------------------------------------------------------------------------*/
JOT(4, "registering driver easycap\n");
result = usb_register(&easycap_usb_driver);
if (0 != result)
SAY("ERROR: usb_register returned %i\n", result);
rc = usb_register(&easycap_usb_driver);
if (0 != rc)
SAY("ERROR: usb_register returned %i\n", rc);
JOT(4, "ends\n");
return result;
return rc;
}
/*****************************************************************************/
void __exit

View File

@ -0,0 +1,43 @@
/*****************************************************************************
* *
* easycap_main.h *
* *
*****************************************************************************/
/*
*
* Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
*
*
* This 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.
*
* The software 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 software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*****************************************************************************/
#if !defined(EASYCAP_MAIN_H)
#define EASYCAP_MAIN_H
extern struct easycap_standard easycap_standard[];
extern struct easycap_format easycap_format[];
extern struct v4l2_queryctrl easycap_control[];
extern struct usb_driver easycap_usb_driver;
#if defined(EASYCAP_NEEDS_ALSA)
extern struct snd_pcm_ops easycap_alsa_ops;
extern struct snd_pcm_hardware easycap_pcm_hardware;
extern struct snd_card *psnd_card;
#else
extern struct usb_class_driver easyoss_class;
extern const struct file_operations easyoss_fops;
#endif /*EASYCAP_NEEDS_ALSA*/
#endif /*EASYCAP_MAIN_H*/

View File

@ -26,7 +26,7 @@
/*****************************************************************************/
#include "easycap.h"
#include "easycap_debug.h"
#include "easycap_settings.h"
/*---------------------------------------------------------------------------*/
/*

View File

@ -1,6 +1,6 @@
/*****************************************************************************
* *
* easycap_standard.h *
* easycap_settings.h *
* *
*****************************************************************************/
/*
@ -24,4 +24,11 @@
*
*/
/*****************************************************************************/
extern struct easycap_standard easycap_standard[];
#if !defined(EASYCAP_SETTINGS_H)
#define EASYCAP_SETTINGS_H
extern int easycap_debug;
extern int easycap_gain;
extern struct easycap_dongle easycapdc60_dongle[];
#endif /*EASYCAP_SETTINGS_H*/

File diff suppressed because it is too large Load Diff

View File

@ -24,5 +24,19 @@
*
*/
/*****************************************************************************/
#if !defined(EASYCAP_SOUND_H)
#define EASYCAP_SOUND_H
extern int easycap_debug;
extern int easycap_gain;
extern struct easycap_dongle easycapdc60_dongle[];
extern struct easycap *peasycap;
extern struct usb_driver easycap_usb_driver;
#if defined(EASYCAP_NEEDS_ALSA)
extern struct snd_pcm_hardware easycap_pcm_hardware;
#else
extern struct usb_class_driver easyoss_class;
extern const struct file_operations easyoss_fops;
#endif /*EASYCAP_NEEDS_ALSA*/
#endif /*EASYCAP_SOUND_H*/

View File

@ -26,7 +26,7 @@
/*****************************************************************************/
#include "easycap.h"
#include "easycap_debug.h"
#include "easycap_testcard.h"
/*****************************************************************************/
#define TESTCARD_BYTESPERLINE (2 * 720)
@ -397,7 +397,7 @@ int tones[2048] = {
};
/*****************************************************************************/
void
easysnd_testtone(struct easycap *peasycap, int audio_fill)
easyoss_testtone(struct easycap *peasycap, int audio_fill)
{
int i1;
unsigned char *p2;

View File

@ -0,0 +1,34 @@
/*****************************************************************************
* *
* easycap_testcard.h *
* *
*****************************************************************************/
/*
*
* Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
*
*
* This 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.
*
* The software 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 software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*****************************************************************************/
#if !defined(EASYCAP_TESTCARD_H)
#define EASYCAP_TESTCARD_H
extern int easycap_debug;
extern int easycap_gain;
extern struct easycap_dongle easycapdc60_dongle[];
#endif /*EASYCAP_TESTCARD_H*/