Commit a9855917 authored by Mike Thomas's avatar Mike Thomas Committed by Greg Kroah-Hartman

staging: easycap: add ALSA support

This is necessary because some distributions are disabling OSS entirely.
Signed-off-by: default avatarMike Thomas <rmthomas@sciolus.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent b54a28a4
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
......
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
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
......@@ -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 *);
/*---------------------------------------------------------------------------*/
/*
......
......@@ -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*/
/*****************************************************************************/
......@@ -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*/
......@@ -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)
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 ???
......
/*****************************************************************************
* *
* 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*/
......@@ -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);
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;
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);
bInterfaceNumber, ndong);
break;
}
}
}
}
if (DONGLE_MANY <= dongle_this) {
if (DONGLE_MANY <= ndong) {
SAM("ERROR: too many dongles\n");
mutex_unlock(&mutex_dongle);
return -ENOMEM;
}
mutex_unlock(&mutex_dongle);
}
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*/
......@@ -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("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) {
err("Not able to get a minor for this device.");
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
......
/*****************************************************************************
* *
* 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*/
......@@ -26,7 +26,7 @@
/*****************************************************************************/
#include "easycap.h"
#include "easycap_debug.h"
#include "easycap_settings.h"
/*---------------------------------------------------------------------------*/
/*
......
/*****************************************************************************
* *
* 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*/
......@@ -29,9 +29,890 @@
/*****************************************************************************/
#include "easycap.h"
#include "easycap_debug.h"
#include "easycap_sound.h"
#if defined(EASYCAP_NEEDS_ALSA)
/*--------------------------------------------------------------------------*/
/*
* PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
*/
/*--------------------------------------------------------------------------*/
static const struct snd_pcm_hardware alsa_hardware = {
.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_32000 | SNDRV_PCM_RATE_48000,
.rate_min = 32000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = PAGE_SIZE * PAGES_PER_AUDIO_FRAGMENT * \
AUDIO_FRAGMENT_MANY,
.period_bytes_min = PAGE_SIZE * PAGES_PER_AUDIO_FRAGMENT,
.period_bytes_max = PAGE_SIZE * PAGES_PER_AUDIO_FRAGMENT * 2,
.periods_min = AUDIO_FRAGMENT_MANY,
.periods_max = AUDIO_FRAGMENT_MANY * 2,
};
static struct snd_pcm_ops easycap_alsa_pcm_ops = {
.open = easycap_alsa_open,
.close = easycap_alsa_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = easycap_alsa_hw_params,
.hw_free = easycap_alsa_hw_free,
.prepare = easycap_alsa_prepare,
.ack = easycap_alsa_ack,
.trigger = easycap_alsa_trigger,
.pointer = easycap_alsa_pointer,
.page = easycap_alsa_page,
};
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
* THE FUNCTION snd_card_create() HAS THIS_MODULE AS AN ARGUMENT. THIS
* MEANS MODULE easycap. BEWARE.
*/
/*---------------------------------------------------------------------------*/
int
easycap_alsa_probe(struct easycap *peasycap)
{
int rc;
struct snd_card *psnd_card;
struct snd_pcm *psnd_pcm;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -ENODEV;
}
if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
SAY("ERROR: bad peasycap\n");
return -EFAULT;
}
if (0 > peasycap->minor) {
SAY("ERROR: no minor\n");
return -ENODEV;
}
peasycap->alsa_hardware = alsa_hardware;
if (true == peasycap->microphone) {
peasycap->alsa_hardware.rates = SNDRV_PCM_RATE_32000;
peasycap->alsa_hardware.rate_min = 32000;
peasycap->alsa_hardware.rate_max = 32000;
} else {
peasycap->alsa_hardware.rates = SNDRV_PCM_RATE_48000;
peasycap->alsa_hardware.rate_min = 48000;
peasycap->alsa_hardware.rate_max = 48000;
}
#if defined(EASYCAP_NEEDS_CARD_CREATE)
if (0 != snd_card_create(SNDRV_DEFAULT_IDX1, "easycap_alsa", \
THIS_MODULE, 0, \
&psnd_card)) {
SAY("ERROR: Cannot do ALSA snd_card_create()\n");
return -EFAULT;
}
#else
psnd_card = snd_card_new(SNDRV_DEFAULT_IDX1, "easycap_alsa", \
THIS_MODULE, 0);
if (NULL == psnd_card) {
SAY("ERROR: Cannot do ALSA snd_card_new()\n");
return -EFAULT;
}
#endif /*EASYCAP_NEEDS_CARD_CREATE*/
sprintf(&psnd_card->id[0], "EasyALSA%i", peasycap->minor);
strcpy(&psnd_card->driver[0], EASYCAP_DRIVER_DESCRIPTION);
strcpy(&psnd_card->shortname[0], "easycap_alsa");
sprintf(&psnd_card->longname[0], "%s", &psnd_card->shortname[0]);
psnd_card->dev = &peasycap->pusb_device->dev;
psnd_card->private_data = peasycap;
peasycap->psnd_card = psnd_card;
rc = snd_pcm_new(psnd_card, "easycap_pcm", 0, 0, 1, &psnd_pcm);
if (0 != rc) {
SAM("ERROR: Cannot do ALSA snd_pcm_new()\n");
snd_card_free(psnd_card);
return -EFAULT;
}
snd_pcm_set_ops(psnd_pcm, SNDRV_PCM_STREAM_CAPTURE, \
&easycap_alsa_pcm_ops);
psnd_pcm->info_flags = 0;
strcpy(&psnd_pcm->name[0], &psnd_card->id[0]);
psnd_pcm->private_data = peasycap;
peasycap->psnd_pcm = psnd_pcm;
peasycap->psubstream = (struct snd_pcm_substream *)NULL;
rc = snd_card_register(psnd_card);
if (0 != rc) {
SAM("ERROR: Cannot do ALSA snd_card_register()\n");
snd_card_free(psnd_card);
return -EFAULT;
} else {
;
SAM("registered %s\n", &psnd_card->id[0]);
}
return 0;
}
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
* ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE DAM BUFFER
* PROVIDED peasycap->audio_idle IS ZERO. REGARDLESS OF THIS BEING TRUE,
* IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
*/
/*---------------------------------------------------------------------------*/
void
easycap_alsa_complete(struct urb *purb)
{
struct easycap *peasycap;
struct snd_pcm_substream *pss;
struct snd_pcm_runtime *prt;
int dma_bytes, fragment_bytes;
int isfragment;
__u8 *p1, *p2;
__s16 s16;
int i, j, more, much, rc;
#if defined(UPSAMPLE)
int k;
__s16 oldaudio, newaudio, delta;
#endif /*UPSAMPLE*/
JOT(16, "\n");
if (NULL == purb) {
SAY("ERROR: purb is NULL\n");
return;
}
peasycap = purb->context;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return;
}
if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
SAY("ERROR: bad peasycap\n");
return;
}
much = 0;
if (peasycap->audio_idle) {
JOM(16, "%i=audio_idle %i=audio_isoc_streaming\n", \
peasycap->audio_idle, peasycap->audio_isoc_streaming);
if (peasycap->audio_isoc_streaming)
goto resubmit;
}
/*---------------------------------------------------------------------------*/
pss = peasycap->psubstream;
if (NULL == pss)
goto resubmit;
prt = pss->runtime;
if (NULL == prt)
goto resubmit;
dma_bytes = (int)prt->dma_bytes;
if (0 == dma_bytes)
goto resubmit;
fragment_bytes = 4 * ((int)prt->period_size);
if (0 == fragment_bytes)
goto resubmit;
/* -------------------------------------------------------------------------*/
if (purb->status) {
if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
JOM(16, "urb status -ESHUTDOWN or -ENOENT\n");
return;
}
SAM("ERROR: non-zero urb status:\n");
switch (purb->status) {
case -EINPROGRESS: {
SAM("-EINPROGRESS\n");
break;
}
case -ENOSR: {
SAM("-ENOSR\n");
break;
}
case -EPIPE: {
SAM("-EPIPE\n");
break;
}
case -EOVERFLOW: {
SAM("-EOVERFLOW\n");
break;
}
case -EPROTO: {
SAM("-EPROTO\n");
break;
}
case -EILSEQ: {
SAM("-EILSEQ\n");
break;
}
case -ETIMEDOUT: {
SAM("-ETIMEDOUT\n");
break;
}
case -EMSGSIZE: {
SAM("-EMSGSIZE\n");
break;
}
case -EOPNOTSUPP: {
SAM("-EOPNOTSUPP\n");
break;
}
case -EPFNOSUPPORT: {
SAM("-EPFNOSUPPORT\n");
break;
}
case -EAFNOSUPPORT: {
SAM("-EAFNOSUPPORT\n");
break;
}
case -EADDRINUSE: {
SAM("-EADDRINUSE\n");
break;
}
case -EADDRNOTAVAIL: {
SAM("-EADDRNOTAVAIL\n");
break;
}
case -ENOBUFS: {
SAM("-ENOBUFS\n");
break;
}
case -EISCONN: {
SAM("-EISCONN\n");
break;
}
case -ENOTCONN: {
SAM("-ENOTCONN\n");
break;
}
case -ESHUTDOWN: {
SAM("-ESHUTDOWN\n");
break;
}
case -ENOENT: {
SAM("-ENOENT\n");
break;
}
case -ECONNRESET: {
SAM("-ECONNRESET\n");
break;
}
case -ENOSPC: {
SAM("ENOSPC\n");
break;
}
default: {
SAM("unknown error: %i\n", purb->status);
break;
}
}
goto resubmit;
}
/*---------------------------------------------------------------------------*/
/*
* PROCEED HERE WHEN NO ERROR
*/
/*---------------------------------------------------------------------------*/
#if defined(UPSAMPLE)
oldaudio = peasycap->oldaudio;
#endif /*UPSAMPLE*/
for (i = 0; i < purb->number_of_packets; i++) {
switch (purb->iso_frame_desc[i].status) {
case 0: {
break;
}
case -ENOENT: {
SAM("-ENOENT\n");
break;
}
case -EINPROGRESS: {
SAM("-EINPROGRESS\n");
break;
}
case -EPROTO: {
SAM("-EPROTO\n");
break;
}
case -EILSEQ: {
SAM("-EILSEQ\n");
break;
}
case -ETIME: {
SAM("-ETIME\n");
break;
}
case -ETIMEDOUT: {
SAM("-ETIMEDOUT\n");
break;
}
case -EPIPE: {
SAM("-EPIPE\n");
break;
}
case -ECOMM: {
SAM("-ECOMM\n");
break;
}
case -ENOSR: {
SAM("-ENOSR\n");
break;
}
case -EOVERFLOW: {
SAM("-EOVERFLOW\n");
break;
}
case -EREMOTEIO: {
SAM("-EREMOTEIO\n");
break;
}
case -ENODEV: {
SAM("-ENODEV\n");
break;
}
case -EXDEV: {
SAM("-EXDEV\n");
break;
}
case -EINVAL: {
SAM("-EINVAL\n");
break;
}
case -ECONNRESET: {
SAM("-ECONNRESET\n");
break;
}
case -ENOSPC: {
SAM("-ENOSPC\n");
break;
}
case -ESHUTDOWN: {
SAM("-ESHUTDOWN\n");
break;
}
case -EPERM: {
SAM("-EPERM\n");
break;
}
default: {
SAM("unknown error: %i\n", purb->iso_frame_desc[i].status);
break;
}
}
if (!purb->iso_frame_desc[i].status) {
more = purb->iso_frame_desc[i].actual_length;
if (!more)
peasycap->audio_mt++;
else {
if (peasycap->audio_mt) {
JOM(12, "%4i empty audio urb frames\n", \
peasycap->audio_mt);
peasycap->audio_mt = 0;
}
p1 = (__u8 *)(purb->transfer_buffer + \
purb->iso_frame_desc[i].offset);
/*---------------------------------------------------------------------------*/
/*
* COPY more BYTES FROM ISOC BUFFER TO THE DMA BUFFER,
* CONVERTING 8-BIT MONO TO 16-BIT SIGNED LITTLE-ENDIAN SAMPLES IF NECESSARY
*/
/*---------------------------------------------------------------------------*/
while (more) {
if (0 > more) {
SAM("MISTAKE: more is negative\n");
return;
}
much = dma_bytes - peasycap->dma_fill;
if (0 > much) {
SAM("MISTAKE: much is negative\n");
return;
}
if (0 == much) {
peasycap->dma_fill = 0;
peasycap->dma_next = fragment_bytes;
JOM(8, "wrapped dma buffer\n");
}
if (false == peasycap->microphone) {
if (much > more)
much = more;
memcpy(prt->dma_area + \
peasycap->dma_fill, \
p1, much);
p1 += much;
more -= much;
} else {
#if defined(UPSAMPLE)
if (much % 16)
JOM(8, "MISTAKE? much" \
" is not divisible by 16\n");
if (much > (16 * \
more))
much = 16 * \
more;
p2 = (__u8 *)(prt->dma_area + \
peasycap->dma_fill);
for (j = 0; j < (much/16); j++) {
newaudio = ((int) *p1) - 128;
newaudio = 128 * \
newaudio;
delta = (newaudio - oldaudio) \
/ 4;
s16 = oldaudio + delta;
for (k = 0; k < 4; k++) {
*p2 = (0x00FF & s16);
*(p2 + 1) = (0xFF00 & \
s16) >> 8;
p2 += 2;
*p2 = (0x00FF & s16);
*(p2 + 1) = (0xFF00 & \
s16) >> 8;
p2 += 2;
s16 += delta;
}
p1++;
more--;
oldaudio = s16;
}
#else /*!UPSAMPLE*/
if (much > (2 * more))
much = 2 * more;
p2 = (__u8 *)(prt->dma_area + \
peasycap->dma_fill);
for (j = 0; j < (much / 2); j++) {
s16 = ((int) *p1) - 128;
s16 = 128 * \
s16;
*p2 = (0x00FF & s16);
*(p2 + 1) = (0xFF00 & s16) >> \
8;
p1++; p2 += 2;
more--;
}
#endif /*UPSAMPLE*/
}
peasycap->dma_fill += much;
if (peasycap->dma_fill >= peasycap->dma_next) {
isfragment = peasycap->dma_fill / \
fragment_bytes;
if (0 > isfragment) {
SAM("MISTAKE: isfragment is " \
"negative\n");
return;
}
peasycap->dma_read = (isfragment \
- 1) * fragment_bytes;
peasycap->dma_next = (isfragment \
+ 1) * fragment_bytes;
if (dma_bytes < peasycap->dma_next) {
peasycap->dma_next = \
fragment_bytes;
}
if (0 <= peasycap->dma_read) {
JOM(8, "snd_pcm_period_elap" \
"sed(), %i=" \
"isfragment\n", \
isfragment);
snd_pcm_period_elapsed(pss);
}
}
}
}
} else {
JOM(12, "discarding audio samples because " \
"%i=purb->iso_frame_desc[i].status\n", \
purb->iso_frame_desc[i].status);
}
#if defined(UPSAMPLE)
peasycap->oldaudio = oldaudio;
#endif /*UPSAMPLE*/
}
/*---------------------------------------------------------------------------*/
/*
* RESUBMIT THIS URB
*/
/*---------------------------------------------------------------------------*/
resubmit:
if (peasycap->audio_isoc_streaming) {
rc = usb_submit_urb(purb, GFP_ATOMIC);
if (0 != rc) {
if ((-ENODEV != rc) && (-ENOENT != rc)) {
SAM("ERROR: while %i=audio_idle, " \
"usb_submit_urb() failed " \
"with rc:\n", peasycap->audio_idle);
}
switch (rc) {
case -ENODEV:
case -ENOENT:
break;
case -ENOMEM: {
SAM("-ENOMEM\n");
break;
}
case -ENXIO: {
SAM("-ENXIO\n");
break;
}
case -EINVAL: {
SAM("-EINVAL\n");
break;
}
case -EAGAIN: {
SAM("-EAGAIN\n");
break;
}
case -EFBIG: {
SAM("-EFBIG\n");
break;
}
case -EPIPE: {
SAM("-EPIPE\n");
break;
}
case -EMSGSIZE: {
SAM("-EMSGSIZE\n");
break;
}
case -ENOSPC: {
SAM("-ENOSPC\n");
break;
}
case -EPERM: {
SAM("-EPERM\n");
break;
}
default: {
SAM("unknown error: %i\n", rc);
break;
}
}
if (0 < peasycap->audio_isoc_streaming)
(peasycap->audio_isoc_streaming)--;
}
}
return;
}
/*****************************************************************************/
int
easycap_alsa_open(struct snd_pcm_substream *pss)
{
struct snd_pcm *psnd_pcm;
struct snd_card *psnd_card;
struct easycap *peasycap;
JOT(4, "\n");
if (NULL == pss) {
SAY("ERROR: pss is NULL\n");
return -EFAULT;
}
psnd_pcm = pss->pcm;
if (NULL == psnd_pcm) {
SAY("ERROR: psnd_pcm is NULL\n");
return -EFAULT;
}
psnd_card = psnd_pcm->card;
if (NULL == psnd_card) {
SAY("ERROR: psnd_card is NULL\n");
return -EFAULT;
}
peasycap = psnd_card->private_data;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
SAY("ERROR: bad peasycap\n");
return -EFAULT;
}
if (peasycap->psnd_card != psnd_card) {
SAM("ERROR: bad peasycap->psnd_card\n");
return -EFAULT;
}
if (NULL != peasycap->psubstream) {
SAM("ERROR: bad peasycap->psubstream\n");
return -EFAULT;
}
pss->private_data = peasycap;
peasycap->psubstream = pss;
pss->runtime->hw = peasycap->alsa_hardware;
pss->runtime->private_data = peasycap;
pss->private_data = peasycap;
if (0 != easycap_sound_setup(peasycap)) {
JOM(4, "ending unsuccessfully\n");
return -EFAULT;
}
JOM(4, "ending successfully\n");
return 0;
}
/*****************************************************************************/
int
easycap_alsa_close(struct snd_pcm_substream *pss)
{
struct easycap *peasycap;
JOT(4, "\n");
if (NULL == pss) {
SAY("ERROR: pss is NULL\n");
return -EFAULT;
}
peasycap = snd_pcm_substream_chip(pss);
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
SAY("ERROR: bad peasycap\n");
return -EFAULT;
}
pss->private_data = NULL;
peasycap->psubstream = (struct snd_pcm_substream *)NULL;
JOT(4, "ending successfully\n");
return 0;
}
/*****************************************************************************/
int
easycap_alsa_hw_params(struct snd_pcm_substream *pss, \
struct snd_pcm_hw_params *phw)
{
int rc;
JOT(4, "%i\n", (params_buffer_bytes(phw)));
if (NULL == pss) {
SAY("ERROR: pss is NULL\n");
return -EFAULT;
}
rc = easycap_alsa_vmalloc(pss, params_buffer_bytes(phw));
if (0 != rc)
return rc;
return 0;
}
/*****************************************************************************/
int
easycap_alsa_vmalloc(struct snd_pcm_substream *pss, size_t sz)
{
struct snd_pcm_runtime *prt;
JOT(4, "\n");
if (NULL == pss) {
SAY("ERROR: pss is NULL\n");
return -EFAULT;
}
prt = pss->runtime;
if (NULL == prt) {
SAY("ERROR: substream.runtime is NULL\n");
return -EFAULT;
}
if (prt->dma_area) {
if (prt->dma_bytes > sz)
return 0;
vfree(prt->dma_area);
}
prt->dma_area = vmalloc(sz);
if (NULL == prt->dma_area)
return -ENOMEM;
prt->dma_bytes = sz;
return 0;
}
/*****************************************************************************/
int
easycap_alsa_hw_free(struct snd_pcm_substream *pss)
{
struct snd_pcm_runtime *prt;
JOT(4, "\n");
if (NULL == pss) {
SAY("ERROR: pss is NULL\n");
return -EFAULT;
}
prt = pss->runtime;
if (NULL == prt) {
SAY("ERROR: substream.runtime is NULL\n");
return -EFAULT;
}
if (NULL != prt->dma_area) {
JOT(8, "0x%08lX=prt->dma_area\n", (unsigned long int)prt->dma_area);
vfree(prt->dma_area);
prt->dma_area = NULL;
} else
JOT(8, "dma_area already freed\n");
return 0;
}
/*****************************************************************************/
int
easycap_alsa_prepare(struct snd_pcm_substream *pss)
{
struct easycap *peasycap;
struct snd_pcm_runtime *prt;
JOT(4, "\n");
if (NULL == pss) {
SAY("ERROR: pss is NULL\n");
return -EFAULT;
}
prt = pss->runtime;
peasycap = snd_pcm_substream_chip(pss);
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
SAY("ERROR: bad peasycap\n");
return -EFAULT;
}
JOM(16, "ALSA decides %8i Hz=rate\n", (int)pss->runtime->rate);
JOM(16, "ALSA decides %8i =period_size\n", (int)pss->runtime->period_size);
JOM(16, "ALSA decides %8i =periods\n", (int)pss->runtime->periods);
JOM(16, "ALSA decides %8i =buffer_size\n", (int)pss->runtime->buffer_size);
JOM(16, "ALSA decides %8i =dma_bytes\n", (int)pss->runtime->dma_bytes);
JOM(16, "ALSA decides %8i =boundary\n", (int)pss->runtime->boundary);
JOM(16, "ALSA decides %8i =period_step\n", (int)pss->runtime->period_step);
JOM(16, "ALSA decides %8i =sample_bits\n", (int)pss->runtime->sample_bits);
JOM(16, "ALSA decides %8i =frame_bits\n", (int)pss->runtime->frame_bits);
JOM(16, "ALSA decides %8i =min_align\n", (int)pss->runtime->min_align);
JOM(12, "ALSA decides %8i =hw_ptr_base\n", (int)pss->runtime->hw_ptr_base);
JOM(12, "ALSA decides %8i =hw_ptr_interrupt\n", \
(int)pss->runtime->hw_ptr_interrupt);
if (prt->dma_bytes != 4 * ((int)prt->period_size) * ((int)prt->periods)) {
SAY("MISTAKE: unexpected ALSA parameters\n");
return -ENOENT;
}
return 0;
}
/*****************************************************************************/
int
easycap_alsa_ack(struct snd_pcm_substream *pss)
{
return 0;
}
/*****************************************************************************/
int
easycap_alsa_trigger(struct snd_pcm_substream *pss, int cmd)
{
struct easycap *peasycap;
int retval;
JOT(4, "%i=cmd cf %i=START %i=STOP\n", cmd, SNDRV_PCM_TRIGGER_START, \
SNDRV_PCM_TRIGGER_STOP);
if (NULL == pss) {
SAY("ERROR: pss is NULL\n");
return -EFAULT;
}
peasycap = snd_pcm_substream_chip(pss);
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
SAY("ERROR: bad peasycap\n");
return -EFAULT;
}
switch (cmd) {
case SNDRV_PCM_TRIGGER_START: {
peasycap->audio_idle = 0;
break;
}
case SNDRV_PCM_TRIGGER_STOP: {
peasycap->audio_idle = 1;
break;
}
default:
retval = -EINVAL;
}
return 0;
}
/*****************************************************************************/
snd_pcm_uframes_t
easycap_alsa_pointer(struct snd_pcm_substream *pss)
{
struct easycap *peasycap;
snd_pcm_uframes_t offset;
JOT(16, "\n");
if (NULL == pss) {
SAY("ERROR: pss is NULL\n");
return -EFAULT;
}
peasycap = snd_pcm_substream_chip(pss);
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
SAY("ERROR: bad peasycap\n");
return -EFAULT;
}
if ((0 != peasycap->audio_eof) || (0 != peasycap->audio_idle)) {
JOM(8, "returning -EIO because " \
"%i=audio_idle %i=audio_eof\n", \
peasycap->audio_idle, peasycap->audio_eof);
return -EIO;
}
/*---------------------------------------------------------------------------*/
if (0 > peasycap->dma_read) {
JOM(8, "returning -EBUSY\n");
return -EBUSY;
}
offset = ((snd_pcm_uframes_t)peasycap->dma_read)/4;
JOM(8, "ALSA decides %8i =hw_ptr_base\n", (int)pss->runtime->hw_ptr_base);
JOM(8, "ALSA decides %8i =hw_ptr_interrupt\n", \
(int)pss->runtime->hw_ptr_interrupt);
JOM(8, "%7i=offset %7i=dma_read %7i=dma_next\n", \
(int)offset, peasycap->dma_read, peasycap->dma_next);
return offset;
}
/*****************************************************************************/
struct page *
easycap_alsa_page(struct snd_pcm_substream *pss, unsigned long offset)
{
return vmalloc_to_page(pss->runtime->dma_area + offset);
}
/*****************************************************************************/
#else /*!EASYCAP_NEEDS_ALSA*/
/*****************************************************************************/
/**************************** **************************/
/**************************** Open Sound System **************************/
/**************************** **************************/
/*****************************************************************************/
/*--------------------------------------------------------------------------*/
/*
* PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
*/
/*--------------------------------------------------------------------------*/
const struct file_operations easyoss_fops = {
.owner = THIS_MODULE,
.open = easyoss_open,
.release = easyoss_release,
#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)
.unlocked_ioctl = easyoss_ioctl_noinode,
#else
.ioctl = easyoss_ioctl,
#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/
.read = easyoss_read,
.llseek = no_llseek,
};
struct usb_class_driver easyoss_class = {
.name = "usb/easyoss%d",
.fops = &easyoss_fops,
.minor_base = USB_SKEL_MINOR_BASE,
};
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
......@@ -41,7 +922,7 @@
*/
/*---------------------------------------------------------------------------*/
void
easysnd_complete(struct urb *purb)
easyoss_complete(struct urb *purb)
{
struct easycap *peasycap;
struct data_buffer *paudio_buffer;
......@@ -68,27 +949,26 @@ if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
SAY("ERROR: bad peasycap\n");
return;
}
much = 0;
if (peasycap->audio_idle) {
JOM(16, "%i=audio_idle %i=audio_isoc_streaming\n", \
peasycap->audio_idle, peasycap->audio_isoc_streaming);
if (peasycap->audio_isoc_streaming) {
rc = usb_submit_urb(purb, GFP_ATOMIC);
if (0 != rc) {
if (-ENODEV != rc)
if (-ENODEV != rc && -ENOENT != rc) {
SAM("ERROR: while %i=audio_idle, " \
"usb_submit_urb() failed with rc:\n", \
peasycap->audio_idle);
}
switch (rc) {
case -ENODEV:
case -ENOENT:
break;
case -ENOMEM: {
SAM("-ENOMEM\n");
break;
}
case -ENODEV: {
break;
}
case -ENXIO: {
SAM("-ENXIO\n");
break;
......@@ -117,8 +997,12 @@ if (peasycap->audio_idle) {
SAM("-ENOSPC\n");
break;
}
case -EPERM: {
SAM("-EPERM\n");
break;
}
default: {
SAM("unknown error: 0x%08X\n", rc);
SAM("unknown error: %i\n", rc);
break;
}
}
......@@ -214,63 +1098,16 @@ if (purb->status) {
SAM("ENOSPC\n");
break;
}
default: {
SAM("unknown error code 0x%08X\n", purb->status);
break;
}
}
/*---------------------------------------------------------------------------*/
/*
* RESUBMIT THIS URB AFTER AN ERROR
*
* (THIS IS DUPLICATE CODE TO REDUCE INDENTATION OF THE NO-ERROR PATH)
*/
/*---------------------------------------------------------------------------*/
if (peasycap->audio_isoc_streaming) {
rc = usb_submit_urb(purb, GFP_ATOMIC);
if (0 != rc) {
SAM("ERROR: while %i=audio_idle, usb_submit_urb() "
"failed with rc:\n", peasycap->audio_idle);
switch (rc) {
case -ENOMEM: {
SAM("-ENOMEM\n");
break;
}
case -ENODEV: {
SAM("-ENODEV\n");
break;
}
case -ENXIO: {
SAM("-ENXIO\n");
break;
}
case -EINVAL: {
SAM("-EINVAL\n");
break;
}
case -EAGAIN: {
SAM("-EAGAIN\n");
break;
}
case -EFBIG: {
SAM("-EFBIG\n");
break;
}
case -EPIPE: {
SAM("-EPIPE\n");
break;
}
case -EMSGSIZE: {
SAM("-EMSGSIZE\n");
case -EPERM: {
SAM("-EPERM\n");
break;
}
default: {
SAM("0x%08X\n", rc); break;
}
}
SAM("unknown error: %i\n", purb->status);
break;
}
}
return;
goto resubmit;
}
/*---------------------------------------------------------------------------*/
/*
......@@ -286,6 +1123,10 @@ for (i = 0; i < purb->number_of_packets; i++) {
case 0: {
break;
}
case -ENODEV: {
SAM("-ENODEV\n");
break;
}
case -ENOENT: {
SAM("-ENOENT\n");
break;
......@@ -330,10 +1171,6 @@ for (i = 0; i < purb->number_of_packets; i++) {
SAM("-EREMOTEIO\n");
break;
}
case -ENODEV: {
SAM("-ENODEV\n");
break;
}
case -EXDEV: {
SAM("-EXDEV\n");
break;
......@@ -354,8 +1191,12 @@ for (i = 0; i < purb->number_of_packets; i++) {
SAM("-ESHUTDOWN\n");
break;
}
case -EPERM: {
SAM("-EPERM\n");
break;
}
default: {
SAM("unknown error:0x%08X\n", purb->iso_frame_desc[i].status);
SAM("unknown error: %i\n", purb->iso_frame_desc[i].status);
break;
}
}
......@@ -371,7 +1212,7 @@ for (i = 0; i < purb->number_of_packets; i++) {
peasycap->audio_mt++;
else {
if (peasycap->audio_mt) {
JOM(16, "%4i empty audio urb frames\n", \
JOM(12, "%4i empty audio urb frames\n", \
peasycap->audio_mt);
peasycap->audio_mt = 0;
}
......@@ -390,8 +1231,7 @@ for (i = 0; i < purb->number_of_packets; i++) {
/*---------------------------------------------------------------------------*/
while (more) {
if (0 > more) {
SAM("easysnd_complete: MISTAKE: " \
"more is negative\n");
SAM("MISTAKE: more is negative\n");
return;
}
if (peasycap->audio_buffer_page_many <= \
......@@ -412,7 +1252,7 @@ for (i = 0; i < purb->number_of_packets; i++) {
paudio_buffer->pgo)) {
#if defined(TESTTONE)
easysnd_testtone(peasycap, \
easyoss_testtone(peasycap, \
peasycap->audio_fill);
#endif /*TESTTONE*/
......@@ -424,7 +1264,7 @@ for (i = 0; i < purb->number_of_packets; i++) {
peasycap->audio_fill)
peasycap->audio_fill = 0;
JOM(12, "bumped peasycap->" \
JOM(8, "bumped peasycap->" \
"audio_fill to %i\n", \
peasycap->audio_fill);
......@@ -497,7 +1337,7 @@ for (i = 0; i < purb->number_of_packets; i++) {
more--;
oldaudio = s16;
}
#else
#else /*!UPSAMPLE*/
if (much > (2 * more))
much = 2 * more;
p2 = (__u8 *)paudio_buffer->pto;
......@@ -530,25 +1370,26 @@ peasycap->oldaudio = oldaudio;
}
/*---------------------------------------------------------------------------*/
/*
* RESUBMIT THIS URB AFTER NO ERROR
* RESUBMIT THIS URB
*/
/*---------------------------------------------------------------------------*/
resubmit:
if (peasycap->audio_isoc_streaming) {
rc = usb_submit_urb(purb, GFP_ATOMIC);
if (0 != rc) {
if (-ENODEV != rc) {
if (-ENODEV != rc && -ENOENT != rc) {
SAM("ERROR: while %i=audio_idle, " \
"usb_submit_urb() failed " \
"with rc:\n", peasycap->audio_idle);
}
switch (rc) {
case -ENODEV:
case -ENOENT:
break;
case -ENOMEM: {
SAM("-ENOMEM\n");
break;
}
case -ENODEV: {
break;
}
case -ENXIO: {
SAM("-ENXIO\n");
break;
......@@ -577,8 +1418,12 @@ if (peasycap->audio_isoc_streaming) {
SAM("-ENOSPC\n");
break;
}
case -EPERM: {
SAM("-EPERM\n");
break;
}
default: {
SAM("unknown error: 0x%08X\n", rc);
SAM("unknown error: %i\n", rc);
break;
}
}
......@@ -590,16 +1435,16 @@ return;
/*---------------------------------------------------------------------------*/
/*
* THE AUDIO URBS ARE SUBMITTED AT THIS EARLY STAGE SO THAT IT IS POSSIBLE TO
* STREAM FROM /dev/easysnd1 WITH SIMPLE PROGRAMS SUCH AS cat WHICH DO NOT
* STREAM FROM /dev/easyoss1 WITH SIMPLE PROGRAMS SUCH AS cat WHICH DO NOT
* HAVE AN IOCTL INTERFACE.
*/
/*---------------------------------------------------------------------------*/
int
easysnd_open(struct inode *inode, struct file *file)
easyoss_open(struct inode *inode, struct file *file)
{
struct usb_interface *pusb_interface;
struct easycap *peasycap;
int subminor, rc;
int subminor;
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
......@@ -660,59 +1505,15 @@ if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
file->private_data = peasycap;
/*---------------------------------------------------------------------------*/
/*
* INITIALIZATION
*/
/*---------------------------------------------------------------------------*/
JOM(4, "starting initialization\n");
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device is NULL\n");
return -ENODEV;
}
JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device);
rc = audio_setup(peasycap);
if (0 <= rc)
JOM(8, "audio_setup() returned %i\n", rc);
else
JOM(8, "easysnd open(): ERROR: audio_setup() returned %i\n", rc);
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device has become NULL\n");
return -ENODEV;
}
/*---------------------------------------------------------------------------*/
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device has become NULL\n");
return -ENODEV;
if (0 != easycap_sound_setup(peasycap)) {
;
;
}
rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, \
peasycap->audio_altsetting_on);
JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, \
peasycap->audio_altsetting_on, rc);
rc = wakeup_device(peasycap->pusb_device);
if (0 == rc)
JOM(8, "wakeup_device() returned %i\n", rc);
else
JOM(8, "ERROR: wakeup_device() returned %i\n", rc);
peasycap->audio_eof = 0;
peasycap->audio_idle = 0;
peasycap->timeval1.tv_sec = 0;
peasycap->timeval1.tv_usec = 0;
submit_audio_urbs(peasycap);
JOM(4, "finished initialization\n");
return 0;
}
/*****************************************************************************/
int
easysnd_release(struct inode *inode, struct file *file)
easyoss_release(struct inode *inode, struct file *file)
{
struct easycap *peasycap;
......@@ -736,7 +1537,7 @@ return 0;
}
/*****************************************************************************/
ssize_t
easysnd_read(struct file *file, char __user *puserspacebuffer, \
easyoss_read(struct file *file, char __user *puserspacebuffer, \
size_t kount, loff_t *poff)
{
struct timeval timeval;
......@@ -760,7 +1561,7 @@ size_t szret;
*/
/*---------------------------------------------------------------------------*/
JOT(8, "===== easysnd_read(): kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
JOT(8, "%5i=kount %5i=*poff\n", (int)kount, (int)(*poff));
if (NULL == file) {
SAY("ERROR: file is NULL\n");
......@@ -768,7 +1569,7 @@ if (NULL == file) {
}
peasycap = file->private_data;
if (NULL == peasycap) {
SAY("ERROR in easysnd_read(): peasycap is NULL\n");
SAY("ERROR in easyoss_read(): peasycap is NULL\n");
return -EFAULT;
}
if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
......@@ -776,16 +1577,17 @@ if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
return -EFAULT;
}
if (NULL == peasycap->pusb_device) {
SAY("ERROR in easysnd_read(): peasycap->pusb_device is NULL\n");
SAY("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
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,
......@@ -797,24 +1599,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: 0x%08lX\n", \
(unsigned long int) peasycap);
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -ERESTARTSYS;
}
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 {
......@@ -835,13 +1637,13 @@ else
if ((0 > peasycap->audio_read) || \
(peasycap->audio_buffer_page_many <= peasycap->audio_read)) {
SAM("ERROR: peasycap->audio_read out of range\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
if ((struct data_buffer *)NULL == pdata_buffer) {
SAM("ERROR: pdata_buffer is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
JOM(12, "before wait, %i=frag read %i=frag fill\n", \
......@@ -853,7 +1655,7 @@ while ((fragment == (peasycap->audio_fill / \
(0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) {
if (file->f_flags & O_NONBLOCK) {
JOM(16, "returning -EAGAIN as instructed\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EAGAIN;
}
rc = wait_event_interruptible(peasycap->wq_audio, \
......@@ -863,25 +1665,25 @@ while ((fragment == (peasycap->audio_fill / \
(0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo))))));
if (0 != rc) {
SAM("aborted by signal\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -ERESTARTSYS;
}
if (peasycap->audio_eof) {
JOM(8, "returning 0 because %i=audio_eof\n", \
peasycap->audio_eof);
kill_audio_urbs(peasycap);
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return 0;
}
if (peasycap->audio_idle) {
JOM(16, "returning 0 because %i=audio_idle\n", \
peasycap->audio_idle);
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return 0;
}
if (!peasycap->audio_isoc_streaming) {
JOM(16, "returning 0 because audio urbs not streaming\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return 0;
}
}
......@@ -889,22 +1691,23 @@ JOM(12, "after wait, %i=frag read %i=frag fill\n", \
(peasycap->audio_read / peasycap->audio_pages_per_fragment), \
(peasycap->audio_fill / peasycap->audio_pages_per_fragment));
szret = (size_t)0;
fragment = (peasycap->audio_read / peasycap->audio_pages_per_fragment);
while (fragment == (peasycap->audio_read / \
peasycap->audio_pages_per_fragment)) {
if (NULL == pdata_buffer->pgo) {
SAM("ERROR: pdata_buffer->pgo is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
if (NULL == pdata_buffer->pto) {
SAM("ERROR: pdata_buffer->pto is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
if (0 > kount1) {
SAM("easysnd_read: MISTAKE: kount1 is negative\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
SAM("MISTAKE: kount1 is negative\n");
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -ERESTARTSYS;
}
if (!kount1) {
......@@ -922,23 +1725,23 @@ while (fragment == (peasycap->audio_read / \
(peasycap->audio_buffer_page_many <= \
peasycap->audio_read)) {
SAM("ERROR: peasycap->audio_read out of range\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
if ((struct data_buffer *)NULL == pdata_buffer) {
SAM("ERROR: pdata_buffer is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
if (NULL == pdata_buffer->pgo) {
SAM("ERROR: pdata_buffer->pgo is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
if (NULL == pdata_buffer->pto) {
SAM("ERROR: pdata_buffer->pto is NULL\n");
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
......@@ -967,7 +1770,7 @@ while (fragment == (peasycap->audio_read / \
rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more);
if (0 != rc) {
SAM("ERROR: copy_to_user() returned %li\n", rc);
mutex_unlock(&easycap_dongle[kd].mutex_audio);
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
return -EFAULT;
}
*poff += (loff_t)more;
......@@ -1029,11 +1832,75 @@ if (!peasycap->timeval1.tv_sec) {
JOM(8, "audio streaming at %lli bytes/second\n", sdr.quotient);
peasycap->dnbydt = sdr.quotient;
mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
JOM(4, "unlocked easycapdc60_dongle[%i].mutex_audio\n", kd);
JOM(8, "returning %li\n", (long int)szret);
mutex_unlock(&easycap_dongle[kd].mutex_audio);
return szret;
}
/*****************************************************************************/
#endif /*!EASYCAP_NEEDS_ALSA*/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
* COMMON AUDIO INITIALIZATION
*/
/*---------------------------------------------------------------------------*/
int
easycap_sound_setup(struct easycap *peasycap)
{
int rc;
JOM(4, "starting initialization\n");
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL.\n");
return -EFAULT;
}
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device is NULL\n");
return -ENODEV;
}
JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device);
rc = audio_setup(peasycap);
JOM(8, "audio_setup() returned %i\n", rc);
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device has become NULL\n");
return -ENODEV;
}
/*---------------------------------------------------------------------------*/
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device has become NULL\n");
return -ENODEV;
}
rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, \
peasycap->audio_altsetting_on);
JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, \
peasycap->audio_altsetting_on, rc);
rc = wakeup_device(peasycap->pusb_device);
JOM(8, "wakeup_device() returned %i\n", rc);
peasycap->audio_eof = 0;
peasycap->audio_idle = 0;
peasycap->timeval1.tv_sec = 0;
peasycap->timeval1.tv_usec = 0;
submit_audio_urbs(peasycap);
JOM(4, "finished initialization\n");
return 0;
}
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
* SUBMIT ALL AUDIO URBS.
......@@ -1087,7 +1954,11 @@ if (!peasycap->audio_isoc_streaming) {
peasycap->audio_isoc_buffer[isbuf].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 = \
......@@ -1109,14 +1980,18 @@ if (!peasycap->audio_isoc_streaming) {
SAM("ERROR: usb_submit_urb() failed" \
" for urb with rc:\n");
switch (rc) {
case -ENOMEM: {
SAM("-ENOMEM\n");
break;
}
case -ENODEV: {
SAM("-ENODEV\n");
break;
}
case -ENOENT: {
SAM("-ENOENT\n");
break;
}
case -ENOMEM: {
SAM("-ENOMEM\n");
break;
}
case -ENXIO: {
SAM("-ENXIO\n");
break;
......@@ -1145,9 +2020,12 @@ if (!peasycap->audio_isoc_streaming) {
nospc++;
break;
}
case -EPERM: {
SAM("-EPERM\n");
break;
}
default: {
SAM("unknown error code %i\n",\
rc);
SAM("unknown error: %i\n", rc);
break;
}
}
......@@ -1179,7 +2057,7 @@ if (!peasycap->audio_isoc_streaming) {
}
peasycap->audio_isoc_streaming = 0;
} else {
peasycap->audio_isoc_streaming = 1;
peasycap->audio_isoc_streaming = m;
JOM(4, "submitted %i audio urbs\n", m);
}
} else
......
......@@ -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*/
......@@ -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;
......
/*****************************************************************************
* *
* 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*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment