staging: easycap: add ALSA support
authorMike Thomas <rmthomas@sciolus.org>
Mon, 10 Jan 2011 18:41:11 +0000 (18:41 +0000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 21 Jan 2011 20:25:55 +0000 (12:25 -0800)
This is necessary because some distributions are disabling OSS entirely.

Signed-off-by: Mike Thomas <rmthomas@sciolus.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
15 files changed:
drivers/staging/easycap/Kconfig
drivers/staging/easycap/Makefile
drivers/staging/easycap/easycap.h
drivers/staging/easycap/easycap_ioctl.c
drivers/staging/easycap/easycap_ioctl.h
drivers/staging/easycap/easycap_low.c
drivers/staging/easycap/easycap_low.h [moved from drivers/staging/easycap/easycap_debug.h with 86% similarity]
drivers/staging/easycap/easycap_main.c
drivers/staging/easycap/easycap_main.h [new file with mode: 0644]
drivers/staging/easycap/easycap_settings.c
drivers/staging/easycap/easycap_settings.h [moved from drivers/staging/easycap/easycap_standard.h with 82% similarity]
drivers/staging/easycap/easycap_sound.c
drivers/staging/easycap/easycap_sound.h
drivers/staging/easycap/easycap_testcard.c
drivers/staging/easycap/easycap_testcard.h [new file with mode: 0644]

index bd96f39..eaa8a86 100644 (file)
@@ -1,6 +1,6 @@
 config EASYCAP
        tristate "EasyCAP USB ID 05e1:0408 support"
-       depends on USB && VIDEO_DEV
+       depends on USB && VIDEO_DEV && SND
 
        ---help---
          This is an integrated audio/video driver for EasyCAP cards with
index f1f2fbe..977e153 100644 (file)
@@ -1,14 +1,13 @@
+easycap-objs      := easycap_main.o easycap_low.o easycap_sound.o \
+                    easycap_ioctl.o easycap_settings.o easycap_testcard.o
 
-obj-$(CONFIG_EASYCAP)  += easycap.o
-
-easycap-y      := easycap_main.o easycap_low.o easycap_sound.o
-easycap-y      += easycap_ioctl.o easycap_settings.o
-easycap-y      += easycap_testcard.o
+obj-$(CONFIG_EASYCAP)       += easycap.o
 
 ccflags-y := -Wall
-# Impose all or none of the following:
 ccflags-y += -DEASYCAP_IS_VIDEODEV_CLIENT
 ccflags-y += -DEASYCAP_NEEDS_V4L2_DEVICE_H
 ccflags-y += -DEASYCAP_NEEDS_V4L2_FOPS
 ccflags-y += -DEASYCAP_NEEDS_UNLOCKED_IOCTL
+ccflags-y += -DEASYCAP_NEEDS_ALSA
+ccflags-y += -DEASYCAP_NEEDS_CARD_CREATE
 
index 063d447..111f53c 100644 (file)
@@ -34,6 +34,8 @@
  *                EASYCAP_NEEDS_V4L2_DEVICE_H
  *                EASYCAP_NEEDS_V4L2_FOPS
  *                EASYCAP_NEEDS_UNLOCKED_IOCTL
+ *                EASYCAP_NEEDS_ALSA
+ *                EASYCAP_SILENT
  *
  *  IF REQUIRED THEY MUST BE EXTERNALLY DEFINED, FOR EXAMPLE AS COMPILER
  *  OPTIONS.
@@ -57,9 +59,9 @@
  */
 /*---------------------------------------------------------------------------*/
 #undef  EASYCAP_TESTCARD
+#if (!defined(EASYCAP_NEEDS_ALSA))
 #undef  EASYCAP_TESTTONE
-#undef  NOREADBACK
-#undef  AUDIOTIME
+#endif /*EASYCAP_NEEDS_ALSA*/
 /*---------------------------------------------------------------------------*/
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #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>
 #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
  */
 /*---------------------------------------------------------------------------*/
 #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)
 /*---------------------------------------------------------------------------*/
 /*
  */
 /*---------------------------------------------------------------------------*/
 #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 *);
 /*---------------------------------------------------------------------------*/
 /*
index 447953a..20d3033 100644 (file)
@@ -27,8 +27,6 @@
 
 #include <linux/smp_lock.h>
 #include "easycap.h"
-#include "easycap_debug.h"
-#include "easycap_standard.h"
 #include "easycap_ioctl.h"
 
 /*--------------------------------------------------------------------------*/
@@ -910,7 +908,7 @@ return -ENOENT;
  *                              peasycap->audio_interface, \
  *                              peasycap->audio_altsetting_off);
  *  HOWEVER, AFTER THIS COMMAND IS ISSUED ALL SUBSEQUENT URBS RECEIVE STATUS
- *  -ESHUTDOWN.  THE HANDLER ROUTINE easysnd_complete() DECLINES TO RESUBMIT
+ *  -ESHUTDOWN.  THE HANDLER ROUTINE easyxxx_complete() DECLINES TO RESUBMIT
  *  THE URB AND THE PIPELINE COLLAPSES IRRETRIEVABLY.  BEWARE.
  */
 /*---------------------------------------------------------------------------*/
@@ -991,11 +989,12 @@ if (NULL == p) {
 }
 kd = isdongle(peasycap);
 if (0 <= kd && DONGLE_MANY > kd) {
-       if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) {
-               SAY("ERROR: cannot lock easycap_dongle[%i].mutex_video\n", kd);
+       if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
+               SAY("ERROR: cannot lock " \
+                               "easycapdc60_dongle[%i].mutex_video\n", kd);
                return -ERESTARTSYS;
        }
-       JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
+       JOM(4, "locked easycapdc60_dongle[%i].mutex_video\n", kd);
 /*---------------------------------------------------------------------------*/
 /*
  *  MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
@@ -1007,24 +1006,24 @@ if (0 <= kd && DONGLE_MANY > kd) {
                return -ERESTARTSYS;
        if (NULL == file) {
                SAY("ERROR:  file is NULL\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -ERESTARTSYS;
        }
        peasycap = file->private_data;
        if (NULL == peasycap) {
                SAY("ERROR:  peasycap is NULL\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -ERESTARTSYS;
        }
        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
                SAY("ERROR: bad peasycap\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        p = peasycap->pusb_device;
        if (NULL == peasycap->pusb_device) {
                SAM("ERROR: peasycap->pusb_device is NULL\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -ERESTARTSYS;
        }
 } else {
@@ -1048,7 +1047,7 @@ case VIDIOC_QUERYCAP: {
 
        if (16 <= strlen(EASYCAP_DRIVER_VERSION)) {
                SAM("ERROR: bad driver version string\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        strcpy(&version[0], EASYCAP_DRIVER_VERSION);
@@ -1066,7 +1065,8 @@ case VIDIOC_QUERYCAP: {
                        if (0 != rc) {
                                SAM("ERROR: %i=strict_strtol(%s,.,,)\n", \
                                                                rc, p1);
-                               mutex_unlock(&easycap_dongle[kd].mutex_video);
+                               mutex_unlock(&easycapdc60_dongle[kd].\
+                                                               mutex_video);
                                return -EINVAL;
                        }
                        k[i] = (int)lng;
@@ -1097,7 +1097,7 @@ case VIDIOC_QUERYCAP: {
        }
        if (0 != copy_to_user((void __user *)arg, &v4l2_capability, \
                                        sizeof(struct v4l2_capability))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -1111,7 +1111,7 @@ case VIDIOC_ENUMINPUT: {
 
        if (0 != copy_from_user(&v4l2_input, (void __user *)arg, \
                                        sizeof(struct v4l2_input))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -1193,14 +1193,14 @@ case VIDIOC_ENUMINPUT: {
        }
        default: {
                JOM(8, "%i=index: exhausts inputs\n", index);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        }
 
        if (0 != copy_to_user((void __user *)arg, &v4l2_input, \
                                                sizeof(struct v4l2_input))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -1213,7 +1213,7 @@ case VIDIOC_G_INPUT: {
        index = (__u32)peasycap->input;
        JOM(8, "user is told: %i\n", index);
        if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -1227,7 +1227,7 @@ case VIDIOC_S_INPUT:
        JOM(8, "VIDIOC_S_INPUT\n");
 
        if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -1240,7 +1240,7 @@ case VIDIOC_S_INPUT:
 
        if ((0 > index) || (INPUT_MANY <= index)) {
                JOM(8, "ERROR:  bad requested input: %i\n", index);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
 
@@ -1249,7 +1249,7 @@ case VIDIOC_S_INPUT:
                JOM(8, "newinput(.,%i) OK\n", (int)index);
        } else {
                SAM("ERROR: newinput(.,%i) returned %i\n", (int)index, rc);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -1257,7 +1257,7 @@ case VIDIOC_S_INPUT:
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 case VIDIOC_ENUMAUDIO: {
        JOM(8, "VIDIOC_ENUMAUDIO\n");
-       mutex_unlock(&easycap_dongle[kd].mutex_video);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
        return -EINVAL;
 }
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -1268,12 +1268,12 @@ case VIDIOC_ENUMAUDOUT: {
 
        if (0 != copy_from_user(&v4l2_audioout, (void __user *)arg, \
                                        sizeof(struct v4l2_audioout))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
        if (0 != v4l2_audioout.index) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout));
@@ -1282,7 +1282,7 @@ case VIDIOC_ENUMAUDOUT: {
 
        if (0 != copy_to_user((void __user *)arg, &v4l2_audioout, \
                                        sizeof(struct v4l2_audioout))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -1296,7 +1296,7 @@ case VIDIOC_QUERYCTRL: {
 
        if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg, \
                                        sizeof(struct v4l2_queryctrl))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -1313,12 +1313,12 @@ case VIDIOC_QUERYCTRL: {
        }
        if (0xFFFFFFFF == easycap_control[i1].id) {
                JOM(8, "%i=index: exhausts controls\n", i1);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        if (0 != copy_to_user((void __user *)arg, &v4l2_queryctrl, \
                                        sizeof(struct v4l2_queryctrl))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -1326,7 +1326,7 @@ case VIDIOC_QUERYCTRL: {
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 case VIDIOC_QUERYMENU: {
        JOM(8, "VIDIOC_QUERYMENU unsupported\n");
-       mutex_unlock(&easycap_dongle[kd].mutex_video);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
        return -EINVAL;
 }
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -1337,13 +1337,13 @@ case VIDIOC_G_CTRL: {
        pv4l2_control = kzalloc(sizeof(struct v4l2_control), GFP_KERNEL);
        if (!pv4l2_control) {
                SAM("ERROR: out of memory\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -ENOMEM;
        }
        if (0 != copy_from_user(pv4l2_control, (void __user *)arg, \
                                        sizeof(struct v4l2_control))) {
                kfree(pv4l2_control);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -1385,14 +1385,14 @@ case VIDIOC_G_CTRL: {
                SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \
                                                        pv4l2_control->id);
                kfree(pv4l2_control);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        }
        if (0 != copy_to_user((void __user *)arg, pv4l2_control, \
                                        sizeof(struct v4l2_control))) {
                kfree(pv4l2_control);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        kfree(pv4l2_control);
@@ -1412,7 +1412,7 @@ case VIDIOC_S_CTRL:
 
        if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \
                                        sizeof(struct v4l2_control))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -1463,7 +1463,7 @@ case VIDIOC_S_CTRL:
        default: {
                SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \
                                                        v4l2_control.id);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        }
@@ -1472,7 +1472,7 @@ case VIDIOC_S_CTRL:
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 case VIDIOC_S_EXT_CTRLS: {
        JOM(8, "VIDIOC_S_EXT_CTRLS unsupported\n");
-       mutex_unlock(&easycap_dongle[kd].mutex_video);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
        return -EINVAL;
 }
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -1484,7 +1484,7 @@ case VIDIOC_ENUM_FMT: {
 
        if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg, \
                                        sizeof(struct v4l2_fmtdesc))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -1539,13 +1539,13 @@ case VIDIOC_ENUM_FMT: {
        }
        default: {
                JOM(8, "%i=index: exhausts formats\n", index);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        }
        if (0 != copy_to_user((void __user *)arg, &v4l2_fmtdesc, \
                                        sizeof(struct v4l2_fmtdesc))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -1564,7 +1564,7 @@ case VIDIOC_ENUM_FRAMESIZES: {
 
        if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg, \
                                        sizeof(struct v4l2_frmsizeenum))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -1616,7 +1616,7 @@ case VIDIOC_ENUM_FRAMESIZES: {
                }
                default: {
                        JOM(8, "%i=index: exhausts framesizes\n", index);
-                       mutex_unlock(&easycap_dongle[kd].mutex_video);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                        return -EINVAL;
                }
                }
@@ -1674,14 +1674,14 @@ case VIDIOC_ENUM_FRAMESIZES: {
                }
                default: {
                        JOM(8, "%i=index: exhausts framesizes\n", index);
-                       mutex_unlock(&easycap_dongle[kd].mutex_video);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                        return -EINVAL;
                }
                }
        }
        if (0 != copy_to_user((void __user *)arg, &v4l2_frmsizeenum, \
                                        sizeof(struct v4l2_frmsizeenum))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -1710,7 +1710,7 @@ case VIDIOC_ENUM_FRAMEINTERVALS: {
 
        if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg, \
                                        sizeof(struct v4l2_frmivalenum))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -1737,13 +1737,13 @@ case VIDIOC_ENUM_FRAMEINTERVALS: {
        }
        default: {
                JOM(8, "%i=index: exhausts frameintervals\n", index);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        }
        if (0 != copy_to_user((void __user *)arg, &v4l2_frmivalenum, \
                                        sizeof(struct v4l2_frmivalenum))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -1757,28 +1757,28 @@ case VIDIOC_G_FMT: {
        pv4l2_format = kzalloc(sizeof(struct v4l2_format), GFP_KERNEL);
        if (!pv4l2_format) {
                SAM("ERROR: out of memory\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -ENOMEM;
        }
        pv4l2_pix_format = kzalloc(sizeof(struct v4l2_pix_format), GFP_KERNEL);
        if (!pv4l2_pix_format) {
                SAM("ERROR: out of memory\n");
                kfree(pv4l2_format);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -ENOMEM;
        }
        if (0 != copy_from_user(pv4l2_format, (void __user *)arg, \
                                        sizeof(struct v4l2_format))) {
                kfree(pv4l2_format);
                kfree(pv4l2_pix_format);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
        if (pv4l2_format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                kfree(pv4l2_format);
                kfree(pv4l2_pix_format);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
 
@@ -1794,7 +1794,7 @@ case VIDIOC_G_FMT: {
                                        sizeof(struct v4l2_format))) {
                kfree(pv4l2_format);
                kfree(pv4l2_pix_format);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        kfree(pv4l2_format);
@@ -1819,7 +1819,7 @@ case VIDIOC_S_FMT: {
 
        if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \
                                        sizeof(struct v4l2_format))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -1831,11 +1831,11 @@ case VIDIOC_S_FMT: {
                                        try);
        if (0 > best_format) {
                if (-EBUSY == best_format) {
-                       mutex_unlock(&easycap_dongle[kd].mutex_video);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                        return -EBUSY;
                }
                JOM(8, "WARNING: adjust_format() returned %i\n", best_format);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -ENOENT;
        }
 /*...........................................................................*/
@@ -1848,7 +1848,7 @@ case VIDIOC_S_FMT: {
 
        if (0 != copy_to_user((void __user *)arg, &v4l2_format, \
                                        sizeof(struct v4l2_format))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -1861,7 +1861,7 @@ case VIDIOC_CROPCAP: {
 
        if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg, \
                                        sizeof(struct v4l2_cropcap))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -1885,7 +1885,7 @@ case VIDIOC_CROPCAP: {
 
        if (0 != copy_to_user((void __user *)arg, &v4l2_cropcap, \
                                        sizeof(struct v4l2_cropcap))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -1894,14 +1894,14 @@ case VIDIOC_CROPCAP: {
 case VIDIOC_G_CROP:
 case VIDIOC_S_CROP: {
        JOM(8, "VIDIOC_G_CROP|VIDIOC_S_CROP  unsupported\n");
-       mutex_unlock(&easycap_dongle[kd].mutex_video);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
        return -EINVAL;
 }
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 case VIDIOC_QUERYSTD: {
        JOM(8, "VIDIOC_QUERYSTD: " \
                        "EasyCAP is incapable of detecting standard\n");
-       mutex_unlock(&easycap_dongle[kd].mutex_video);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
        return -EINVAL;
        break;
 }
@@ -1923,7 +1923,7 @@ case VIDIOC_ENUMSTD: {
 
        if (0 != copy_from_user(&v4l2_standard, (void __user *)arg, \
                                        sizeof(struct v4l2_standard))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        index = v4l2_standard.index;
@@ -1945,7 +1945,7 @@ case VIDIOC_ENUMSTD: {
        }
        if (0xFFFF == peasycap_standard->mask) {
                JOM(8, "%i=index: exhausts standards\n", index);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        JOM(8, "%i=index: %s\n", index, \
@@ -1957,7 +1957,7 @@ case VIDIOC_ENUMSTD: {
 
        if (0 != copy_to_user((void __user *)arg, &v4l2_standard, \
                                        sizeof(struct v4l2_standard))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -1972,13 +1972,13 @@ case VIDIOC_G_STD: {
        if (0 > peasycap->standard_offset) {
                JOM(8, "%i=peasycap->standard_offset\n", \
                                        peasycap->standard_offset);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EBUSY;
        }
 
        if (0 != copy_from_user(&std_id, (void __user *)arg, \
                                                sizeof(v4l2_std_id))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -1990,7 +1990,7 @@ case VIDIOC_G_STD: {
 
        if (0 != copy_to_user((void __user *)arg, &std_id, \
                                                sizeof(v4l2_std_id))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -2004,7 +2004,7 @@ case VIDIOC_S_STD: {
 
        if (0 != copy_from_user(&std_id, (void __user *)arg, \
                                                sizeof(v4l2_std_id))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -2015,7 +2015,7 @@ case VIDIOC_S_STD: {
        rc = adjust_standard(peasycap, std_id);
        if (0 > rc) {
                JOM(8, "WARNING: adjust_standard() returned %i\n", rc);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -ENOENT;
        }
        break;
@@ -2029,16 +2029,16 @@ case VIDIOC_REQBUFS: {
 
        if (0 != copy_from_user(&v4l2_requestbuffers, (void __user *)arg, \
                                sizeof(struct v4l2_requestbuffers))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
        if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        nbuffers = v4l2_requestbuffers.count;
@@ -2059,7 +2059,7 @@ case VIDIOC_REQBUFS: {
 
        if (0 != copy_to_user((void __user *)arg, &v4l2_requestbuffers, \
                                sizeof(struct v4l2_requestbuffers))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -2074,18 +2074,18 @@ case VIDIOC_QUERYBUF: {
        if (peasycap->video_eof) {
                JOM(8, "returning -EIO because  %i=video_eof\n", \
                                                        peasycap->video_eof);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EIO;
        }
 
        if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
                                        sizeof(struct v4l2_buffer))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
        if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        index = v4l2_buffer.index;
@@ -2117,7 +2117,7 @@ case VIDIOC_QUERYBUF: {
 
        if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
                                        sizeof(struct v4l2_buffer))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        break;
@@ -2130,21 +2130,21 @@ case VIDIOC_QBUF: {
 
        if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
                                        sizeof(struct v4l2_buffer))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
        if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        if (v4l2_buffer.index < 0 || \
                 (v4l2_buffer.index >= peasycap->frame_buffer_many)) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
@@ -2154,7 +2154,7 @@ case VIDIOC_QBUF: {
 
        if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
                                        sizeof(struct v4l2_buffer))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -2187,18 +2187,18 @@ case VIDIOC_DQBUF:
                JOM(8, "returning -EIO because  " \
                                "%i=video_idle  %i=video_eof\n", \
                                peasycap->video_idle, peasycap->video_eof);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EIO;
        }
 
        if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
                                        sizeof(struct v4l2_buffer))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
        if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
 
@@ -2222,7 +2222,7 @@ case VIDIOC_DQBUF:
 
        if (!peasycap->video_isoc_streaming) {
                JOM(16, "returning -EIO because video urbs not streaming\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EIO;
        }
 /*---------------------------------------------------------------------------*/
@@ -2239,18 +2239,19 @@ case VIDIOC_DQBUF:
                        if (-EIO == rcdq) {
                                JOM(8, "returning -EIO because " \
                                                "dqbuf() returned -EIO\n");
-                               mutex_unlock(&easycap_dongle[kd].mutex_video);
+                               mutex_unlock(&easycapdc60_dongle[kd].\
+                                                               mutex_video);
                                return -EIO;
                        }
                } while (0 != rcdq);
        } else {
                if (peasycap->video_eof) {
-                       mutex_unlock(&easycap_dongle[kd].mutex_video);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                        return -EIO;
                }
        }
        if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) {
-               SAM("ERROR: V4L2_BUF_FLAG_DONE != 0x%08X\n", \
+               JOM(8, "V4L2_BUF_FLAG_DONE != 0x%08X\n", \
                                        peasycap->done[peasycap->frame_read]);
        }
        peasycap->polled = 0;
@@ -2337,7 +2338,7 @@ case VIDIOC_DQBUF:
 
        if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
                                                sizeof(struct v4l2_buffer))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -2370,7 +2371,7 @@ case VIDIOC_STREAMON: {
                peasycap->merit[i] = 0;
        if ((struct usb_device *)NULL == peasycap->pusb_device) {
                SAM("ERROR: peasycap->pusb_device is NULL\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        submit_video_urbs(peasycap);
@@ -2386,7 +2387,7 @@ case VIDIOC_STREAMOFF: {
 
        if ((struct usb_device *)NULL == peasycap->pusb_device) {
                SAM("ERROR: peasycap->pusb_device is NULL\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
@@ -2400,7 +2401,12 @@ case VIDIOC_STREAMOFF: {
 /*---------------------------------------------------------------------------*/
        JOM(8, "calling wake_up on wq_video and wq_audio\n");
        wake_up_interruptible(&(peasycap->wq_video));
+#if defined(EASYCAP_NEEDS_ALSA)
+       if (NULL != peasycap->psubstream)
+               snd_pcm_period_elapsed(peasycap->psubstream);
+#else
        wake_up_interruptible(&(peasycap->wq_audio));
+#endif /*EASYCAP_NEEDS_ALSA*/
 /*---------------------------------------------------------------------------*/
        break;
 }
@@ -2412,19 +2418,19 @@ case VIDIOC_G_PARM: {
        pv4l2_streamparm = kzalloc(sizeof(struct v4l2_streamparm), GFP_KERNEL);
        if (!pv4l2_streamparm) {
                SAM("ERROR: out of memory\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -ENOMEM;
        }
        if (0 != copy_from_user(pv4l2_streamparm, (void __user *)arg, \
                                        sizeof(struct v4l2_streamparm))) {
                kfree(pv4l2_streamparm);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
 
        if (pv4l2_streamparm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                kfree(pv4l2_streamparm);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EINVAL;
        }
        pv4l2_streamparm->parm.capture.capability = 0;
@@ -2450,7 +2456,7 @@ case VIDIOC_G_PARM: {
        if (0 != copy_to_user((void __user *)arg, pv4l2_streamparm, \
                                        sizeof(struct v4l2_streamparm))) {
                kfree(pv4l2_streamparm);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -EFAULT;
        }
        kfree(pv4l2_streamparm);
@@ -2459,25 +2465,25 @@ case VIDIOC_G_PARM: {
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 case VIDIOC_S_PARM: {
        JOM(8, "VIDIOC_S_PARM unsupported\n");
-       mutex_unlock(&easycap_dongle[kd].mutex_video);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
        return -EINVAL;
 }
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 case VIDIOC_G_AUDIO: {
        JOM(8, "VIDIOC_G_AUDIO unsupported\n");
-       mutex_unlock(&easycap_dongle[kd].mutex_video);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
        return -EINVAL;
 }
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 case VIDIOC_S_AUDIO: {
        JOM(8, "VIDIOC_S_AUDIO unsupported\n");
-       mutex_unlock(&easycap_dongle[kd].mutex_video);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
        return -EINVAL;
 }
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 case VIDIOC_S_TUNER: {
        JOM(8, "VIDIOC_S_TUNER unsupported\n");
-       mutex_unlock(&easycap_dongle[kd].mutex_video);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
        return -EINVAL;
 }
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -2485,45 +2491,46 @@ case VIDIOC_G_FBUF:
 case VIDIOC_S_FBUF:
 case VIDIOC_OVERLAY: {
        JOM(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n");
-       mutex_unlock(&easycap_dongle[kd].mutex_video);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
        return -EINVAL;
 }
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 case VIDIOC_G_TUNER: {
        JOM(8, "VIDIOC_G_TUNER unsupported\n");
-       mutex_unlock(&easycap_dongle[kd].mutex_video);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
        return -EINVAL;
 }
 case VIDIOC_G_FREQUENCY:
 case VIDIOC_S_FREQUENCY: {
        JOM(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n");
-       mutex_unlock(&easycap_dongle[kd].mutex_video);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
        return -EINVAL;
 }
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 default: {
        JOM(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd);
-       mutex_unlock(&easycap_dongle[kd].mutex_video);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
        return -ENOIOCTLCMD;
 }
 }
-mutex_unlock(&easycap_dongle[kd].mutex_video);
-JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
+mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+JOM(4, "unlocked easycapdc60_dongle[%i].mutex_video\n", kd);
 return 0;
 }
 /*****************************************************************************/
+#if !defined(EASYCAP_NEEDS_ALSA)
 /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
 #if ((defined(EASYCAP_IS_VIDEODEV_CLIENT)) || \
        (defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)))
 long
-easysnd_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg) {
-       return (long)easysnd_ioctl((struct inode *)NULL, file, cmd, arg);
+easyoss_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg) {
+       return (long)easyoss_ioctl((struct inode *)NULL, file, cmd, arg);
 }
 #endif /*EASYCAP_IS_VIDEODEV_CLIENT||EASYCAP_NEEDS_UNLOCKED_IOCTL*/
 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
 /*---------------------------------------------------------------------------*/
 int
-easysnd_ioctl(struct inode *inode, struct file *file,
+easyoss_ioctl(struct inode *inode, struct file *file,
                                        unsigned int cmd, unsigned long arg)
 {
 struct easycap *peasycap;
@@ -2550,11 +2557,12 @@ if (NULL == p) {
 }
 kd = isdongle(peasycap);
 if (0 <= kd && DONGLE_MANY > kd) {
-       if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_audio)) {
-               SAY("ERROR: cannot lock easycap_dongle[%i].mutex_audio\n", kd);
+       if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_audio)) {
+               SAY("ERROR: cannot lock "
+                               "easycapdc60_dongle[%i].mutex_audio\n", kd);
                return -ERESTARTSYS;
        }
-       JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
+       JOM(4, "locked easycapdc60_dongle[%i].mutex_audio\n", kd);
 /*---------------------------------------------------------------------------*/
 /*
  *  MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
@@ -2566,24 +2574,24 @@ if (0 <= kd && DONGLE_MANY > kd) {
                return -ERESTARTSYS;
        if (NULL == file) {
                SAY("ERROR:  file is NULL\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -ERESTARTSYS;
        }
        peasycap = file->private_data;
        if (NULL == peasycap) {
                SAY("ERROR:  peasycap is NULL\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -ERESTARTSYS;
        }
        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
                SAY("ERROR: bad peasycap\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EFAULT;
        }
        p = peasycap->pusb_device;
        if (NULL == peasycap->pusb_device) {
                SAM("ERROR: peasycap->pusb_device is NULL\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -ERESTARTSYS;
        }
 } else {
@@ -2614,7 +2622,7 @@ case SNDCTL_DSP_GETCAPS: {
 #endif /*UPSAMPLE*/
 
        if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EFAULT;
        }
        break;
@@ -2636,7 +2644,7 @@ case SNDCTL_DSP_GETFMTS: {
 #endif /*UPSAMPLE*/
 
        if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EFAULT;
        }
        break;
@@ -2645,7 +2653,7 @@ case SNDCTL_DSP_SETFMT: {
        int incoming, outgoing;
        JOM(8, "SNDCTL_DSP_SETFMT\n");
        if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EFAULT;
        }
        JOM(8, "........... %i=incoming\n", incoming);
@@ -2668,10 +2676,10 @@ case SNDCTL_DSP_SETFMT: {
                JOM(8, "        cf. %i=AFMT_U8\n", AFMT_U8);
                if (0 != copy_to_user((void __user *)arg, &outgoing, \
                                                                sizeof(int))) {
-                       mutex_unlock(&easycap_dongle[kd].mutex_audio);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                        return -EFAULT;
                }
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EINVAL ;
        }
        break;
@@ -2680,7 +2688,7 @@ case SNDCTL_DSP_STEREO: {
        int incoming;
        JOM(8, "SNDCTL_DSP_STEREO\n");
        if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EFAULT;
        }
        JOM(8, "........... %i=incoming\n", incoming);
@@ -2698,7 +2706,7 @@ case SNDCTL_DSP_STEREO: {
 #endif /*UPSAMPLE*/
 
        if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EFAULT;
        }
        break;
@@ -2707,7 +2715,7 @@ case SNDCTL_DSP_SPEED: {
        int incoming;
        JOM(8, "SNDCTL_DSP_SPEED\n");
        if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EFAULT;
        }
        JOM(8, "........... %i=incoming\n", incoming);
@@ -2725,7 +2733,7 @@ case SNDCTL_DSP_SPEED: {
 #endif /*UPSAMPLE*/
 
        if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EFAULT;
        }
        break;
@@ -2734,14 +2742,14 @@ case SNDCTL_DSP_GETTRIGGER: {
        int incoming;
        JOM(8, "SNDCTL_DSP_GETTRIGGER\n");
        if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EFAULT;
        }
        JOM(8, "........... %i=incoming\n", incoming);
 
        incoming = PCM_ENABLE_INPUT;
        if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EFAULT;
        }
        break;
@@ -2750,7 +2758,7 @@ case SNDCTL_DSP_SETTRIGGER: {
        int incoming;
        JOM(8, "SNDCTL_DSP_SETTRIGGER\n");
        if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EFAULT;
        }
        JOM(8, "........... %i=incoming\n", incoming);
@@ -2767,13 +2775,13 @@ case SNDCTL_DSP_GETBLKSIZE: {
        int incoming;
        JOM(8, "SNDCTL_DSP_GETBLKSIZE\n");
        if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EFAULT;
        }
        JOM(8, "........... %i=incoming\n", incoming);
        incoming = peasycap->audio_bytes_per_fragment;
        if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EFAULT;
        }
        break;
@@ -2790,7 +2798,7 @@ case SNDCTL_DSP_GETISPACE: {
 
        if (0 != copy_to_user((void __user *)arg, &audio_buf_info, \
                                                                sizeof(int))) {
-               mutex_unlock(&easycap_dongle[kd].mutex_audio);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
                return -EFAULT;
        }
        break;
@@ -2802,18 +2810,18 @@ case 0x00005404:
 case 0x00005405:
 case 0x00005406: {
        JOM(8, "SNDCTL_TMR_...: 0x%08X unsupported\n", cmd);
-       mutex_unlock(&easycap_dongle[kd].mutex_audio);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
        return -ENOIOCTLCMD;
 }
 default: {
        JOM(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd);
-       mutex_unlock(&easycap_dongle[kd].mutex_audio);
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
        return -ENOIOCTLCMD;
 }
 }
-mutex_unlock(&easycap_dongle[kd].mutex_audio);
+mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 return 0;
 }
+#endif /*EASYCAP_NEEDS_ALSA*/
 /*****************************************************************************/
 
-
index 210cd62..938de37 100644 (file)
  *
 */
 /*****************************************************************************/
+#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*/
index 28c4d1e..b618d4b 100644 (file)
@@ -39,7 +39,7 @@
 /****************************************************************************/
 
 #include "easycap.h"
-#include "easycap_debug.h"
+#include "easycap_low.h"
 
 /*--------------------------------------------------------------------------*/
 const struct stk1160config { int reg; int set; } stk1160configPAL[256] = {
@@ -1052,9 +1052,18 @@ rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),       \
                        (int)50000);
 
 JOT(8, "0x%02X=buffer\n", *((__u8 *) &buffer[0]));
-if (rc != (int)length)
-       SAY("ERROR: usb_control_msg returned %i\n", rc);
-
+if (rc != (int)length) {
+       switch (rc) {
+       case -EPIPE: {
+               SAY("usb_control_msg returned -EPIPE\n");
+               break;
+       }
+       default: {
+               SAY("ERROR: usb_control_msg returned %i\n", rc);
+               break;
+       }
+       }
+}
 /*--------------------------------------------------------------------------*/
 /*
  *  REGISTER 500:  SETTING VALUE TO 0x0094 RESETS AUDIO CONFIGURATION ???
similarity index 86%
rename from drivers/staging/easycap/easycap_debug.h
rename to drivers/staging/easycap/easycap_low.h
index b6b5718..d2b69e9 100644 (file)
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *                                                                            *
-*  easycap_debug.h                                                           *
+*  easycap_low.h                                                             *
 *                                                                            *
 *****************************************************************************/
 /*
  *
 */
 /*****************************************************************************/
+#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*/
index 22cf02b..84128cf 100644 (file)
 /*****************************************************************************/
 
 #include "easycap.h"
-#include "easycap_standard.h"
-#include "easycap_ioctl.h"
+#include "easycap_main.h"
 
 int easycap_debug;
-static int easycap_bars;
+static int easycap_bars = 1;
 int easycap_gain = 16;
 module_param_named(debug, easycap_debug, int, S_IRUGO | S_IWUSR);
 module_param_named(bars, easycap_bars, int, S_IRUGO | S_IWUSR);
 module_param_named(gain, easycap_gain, int, S_IRUGO | S_IWUSR);
 
-/*---------------------------------------------------------------------------*/
-/*
- *  dongle_this IS INDISPENSIBLY static BECAUSE FUNCTION easycap_usb_probe()
- *  IS CALLED SUCCESSIVELY FOR INTERFACES 0, 1, 2 AND THE POINTER peasycap
- *  ALLOCATED DURING THE PROBING OF INTERFACE 0 MUST BE REMEMBERED WHEN
- *  PROBING INTERFACES 1 AND 2.
- *
- *  IOCTL LOCKING IS DONE AT MODULE LEVEL, NOT DEVICE LEVEL.
-*/
-/*---------------------------------------------------------------------------*/
-
-struct easycap_dongle easycap_dongle[DONGLE_MANY];
-static int dongle_this;
-static int dongle_done;
+struct easycap_dongle easycapdc60_dongle[DONGLE_MANY];
+static struct mutex mutex_dongle;
 
 /*---------------------------------------------------------------------------*/
 /*
@@ -120,28 +107,6 @@ const struct v4l2_file_operations v4l2_fops = {
 #endif /*EASYCAP_NEEDS_V4L2_FOPS*/
 #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-/*--------------------------------------------------------------------------*/
-/*
- *  PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
- */
-/*--------------------------------------------------------------------------*/
-const struct file_operations easysnd_fops = {
-       .owner          = THIS_MODULE,
-       .open           = easysnd_open,
-       .release        = easysnd_release,
-#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)
-       .unlocked_ioctl = easysnd_ioctl_noinode,
-#else
-       .ioctl          = easysnd_ioctl,
-#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/
-       .read           = easysnd_read,
-       .llseek         = no_llseek,
-};
-struct usb_class_driver easysnd_class = {
-.name = "usb/easysnd%d",
-.fops = &easysnd_fops,
-.minor_base = USB_SKEL_MINOR_BASE,
-};
 /****************************************************************************/
 /*---------------------------------------------------------------------------*/
 /*
@@ -155,7 +120,7 @@ int k;
 if (NULL == peasycap)
        return -2;
 for (k = 0; k < DONGLE_MANY; k++) {
-       if (easycap_dongle[k].peasycap == peasycap) {
+       if (easycapdc60_dongle[k].peasycap == peasycap) {
                peasycap->isdongle = k;
                return k;
        }
@@ -1055,9 +1020,10 @@ for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY;  k++) {
                m++;
        }
 }
-JOM(4, "easysnd_delete(): isoc audio buffers freed: %i pages\n", \
+JOM(4, "easyoss_delete(): isoc audio buffers freed: %i pages\n", \
                                        m * (0x01 << AUDIO_ISOC_ORDER));
 /*---------------------------------------------------------------------------*/
+#if !defined(EASYCAP_NEEDS_ALSA)
 JOM(4, "freeing audio buffers.\n");
 gone = 0;
 for (k = 0;  k < peasycap->audio_buffer_page_many;  k++) {
@@ -1068,7 +1034,8 @@ for (k = 0;  k < peasycap->audio_buffer_page_many;  k++) {
                gone++;
        }
 }
-JOM(4, "easysnd_delete(): audio buffers freed: %i pages\n", gone);
+JOM(4, "easyoss_delete(): audio buffers freed: %i pages\n", gone);
+#endif /*!EASYCAP_NEEDS_ALSA*/
 /*---------------------------------------------------------------------------*/
 JOM(4, "freeing easycap structure.\n");
 allocation_video_urb    = peasycap->allocation_video_urb;
@@ -1081,12 +1048,20 @@ allocation_audio_struct = peasycap->allocation_audio_struct;
 registered_audio        = peasycap->registered_audio;
 
 kfree(peasycap);
+
 if (0 <= kd && DONGLE_MANY > kd) {
-       easycap_dongle[kd].peasycap = (struct easycap *)NULL;
-       JOT(4, "   null-->easycap_dongle[%i].peasycap\n", kd);
-       allocation_video_struct -= sizeof(struct easycap);
+       if (mutex_lock_interruptible(&mutex_dongle)) {
+               SAY("ERROR: cannot down mutex_dongle\n");
+       } else {
+               JOM(4, "locked mutex_dongle\n");
+               easycapdc60_dongle[kd].peasycap = (struct easycap *)NULL;
+               mutex_unlock(&mutex_dongle);
+               JOM(4, "unlocked mutex_dongle\n");
+               JOT(4, "   null-->easycapdc60_dongle[%i].peasycap\n", kd);
+               allocation_video_struct -= sizeof(struct easycap);
+       }
 } else {
-       SAY("ERROR: cannot purge easycap_dongle[].peasycap");
+       SAY("ERROR: cannot purge easycapdc60_dongle[].peasycap");
 }
 /*---------------------------------------------------------------------------*/
 SAY("%8i= video urbs     after all deletions\n", allocation_video_urb);
@@ -1131,11 +1106,12 @@ if (NULL == peasycap->pusb_device) {
 /*---------------------------------------------------------------------------*/
 kd = isdongle(peasycap);
 if (0 <= kd && DONGLE_MANY > kd) {
-       if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) {
-               SAY("ERROR: cannot down easycap_dongle[%i].mutex_video\n", kd);
+       if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
+               SAY("ERROR: cannot down "
+                               "easycapdc60_dongle[%i].mutex_video\n", kd);
                return -ERESTARTSYS;
        }
-       JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
+       JOM(4, "locked easycapdc60_dongle[%i].mutex_video\n", kd);
        /*-------------------------------------------------------------------*/
        /*
         *  MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER
@@ -1147,24 +1123,24 @@ if (0 <= kd && DONGLE_MANY > kd) {
                return -ERESTARTSYS;
        if (NULL == file) {
                SAY("ERROR:  file is NULL\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -ERESTARTSYS;
        }
        peasycap = file->private_data;
        if (NULL == peasycap) {
                SAY("ERROR:  peasycap is NULL\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -ERESTARTSYS;
        }
        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
                SAY("ERROR: bad peasycap: 0x%08lX\n", \
                                                (unsigned long int) peasycap);
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -ERESTARTSYS;
        }
        if (NULL == peasycap->pusb_device) {
                SAM("ERROR: peasycap->pusb_device is NULL\n");
-               mutex_unlock(&easycap_dongle[kd].mutex_video);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
                return -ERESTARTSYS;
        }
 } else
@@ -1179,7 +1155,7 @@ if (0 <= kd && DONGLE_MANY > kd) {
 /*---------------------------------------------------------------------------*/
 rc = easycap_dqbuf(peasycap, 0);
 peasycap->polled = 1;
-mutex_unlock(&easycap_dongle[kd].mutex_video);
+mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
 if (0 == rc)
        return POLLIN | POLLRDNORM;
 else
@@ -3391,20 +3367,13 @@ return;
 /*****************************************************************************/
 /*---------------------------------------------------------------------------*/
 /*
- *
- *                                  FIXME
- *
- *
- *  THIS FUNCTION ASSUMES THAT, ON EACH AND EVERY OCCASION THAT THE EasyCAP
- *  IS PHYSICALLY PLUGGED IN, INTERFACE 0 IS PROBED FIRST.
- *  IF THIS IS NOT TRUE, THERE IS THE POSSIBILITY OF AN Oops.
- *
- *  THIS HAS NEVER BEEN A PROBLEM IN PRACTICE, BUT SOMETHING SEEMS WRONG HERE.
+ *  WHEN THE EasyCAP IS PHYSICALLY PLUGGED IN, THIS FUNCTION IS CALLED THREE
+ *  TIMES, ONCE FOR EACH OF THE THREE INTERFACES.  BEWARE.
  */
 /*---------------------------------------------------------------------------*/
 int
 easycap_usb_probe(struct usb_interface *pusb_interface, \
-                                               const struct usb_device_id *id)
+                               const struct usb_device_id *pusb_device_id)
 {
 struct usb_device *pusb_device, *pusb_device1;
 struct usb_host_interface *pusb_host_interface;
@@ -3413,6 +3382,7 @@ struct usb_interface_descriptor *pusb_interface_descriptor;
 struct usb_interface_assoc_descriptor *pusb_interface_assoc_descriptor;
 struct urb *purb;
 struct easycap *peasycap;
+int ndong;
 struct data_urb *pdata_urb;
 size_t wMaxPacketSize;
 int ISOCwMaxPacketSize;
@@ -3434,24 +3404,19 @@ int maxpacketsize;
 __u16 mask;
 __s32 value;
 struct easycap_format *peasycap_format;
-
-JOT(4, "\n");
-
-if (!dongle_done) {
-       dongle_done = 1;
-       for (k = 0; k < DONGLE_MANY; k++) {
-               easycap_dongle[k].peasycap = (struct easycap *)NULL;
-               mutex_init(&easycap_dongle[k].mutex_video);
-               mutex_init(&easycap_dongle[k].mutex_audio);
-       }
-}
-
-peasycap = (struct easycap *)NULL;
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
+struct v4l2_device *pv4l2_device;
+#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
 
 if ((struct usb_interface *)NULL == pusb_interface) {
        SAY("ERROR: pusb_interface is NULL\n");
        return -EFAULT;
 }
+peasycap = (struct easycap *)NULL;
 /*---------------------------------------------------------------------------*/
 /*
  *  GET POINTER TO STRUCTURE usb_device
@@ -3472,9 +3437,7 @@ if ((unsigned long int)pusb_device1 != (unsigned long int)pusb_device) {
        JOT(4, "ERROR: pusb_device1 != pusb_device\n");
        return -EFAULT;
 }
-
 JOT(4, "bNumConfigurations=%i\n", pusb_device->descriptor.bNumConfigurations);
-
 /*---------------------------------------------------------------------------*/
 pusb_host_interface = pusb_interface->cur_altsetting;
 if (NULL == pusb_host_interface) {
@@ -3553,9 +3516,6 @@ JOT(4, "intf[%i]: pusb_interface_assoc_descriptor is NULL\n", \
  *
  *  THE POINTER peasycap TO THE struct easycap IS REMEMBERED WHEN
  *  INTERFACES 1 AND 2 ARE PROBED.
- *
- *  IF TWO EasyCAPs ARE PLUGGED IN NEARLY SIMULTANEOUSLY THERE WILL
- *  BE TROUBLE.  BEWARE.
 */
 /*---------------------------------------------------------------------------*/
 if (0 == bInterfaceNumber) {
@@ -3580,6 +3540,7 @@ if (0 == bInterfaceNumber) {
  *  PERFORM URGENT INTIALIZATIONS ...
 */
 /*---------------------------------------------------------------------------*/
+       peasycap->minor = -1;
        strcpy(&peasycap->telltale[0], TELLTALE);
        kref_init(&peasycap->kref);
        JOM(8, "intf[%i]: after kref_init(..._video) " \
@@ -3588,29 +3549,43 @@ if (0 == bInterfaceNumber) {
 
        init_waitqueue_head(&peasycap->wq_video);
        init_waitqueue_head(&peasycap->wq_audio);
+       init_waitqueue_head(&peasycap->wq_trigger);
 
-       for (dongle_this = 0; dongle_this < DONGLE_MANY; dongle_this++) {
-               if (NULL == easycap_dongle[dongle_this].peasycap) {
-                       if (0 == mutex_is_locked(&easycap_dongle\
-                                               [dongle_this].mutex_video)) {
-                               if (0 == mutex_is_locked(&easycap_dongle\
-                                               [dongle_this].mutex_audio)) {
-                                       easycap_dongle\
-                                               [dongle_this].peasycap = \
-                                                               peasycap;
-                                       JOM(8, "intf[%i]: peasycap-->easycap" \
+       if (mutex_lock_interruptible(&mutex_dongle)) {
+                       SAY("ERROR: cannot down mutex_dongle\n");
+               return -ERESTARTSYS;
+       } else {
+/*---------------------------------------------------------------------------*/
+               /*
+                *  FOR INTERFACES 1 AND 2 THE POINTER peasycap WILL NEED TO
+                *  TO BE THE SAME AS THAT ALLOCATED NOW FOR INTERFACE 0.
+                *
+                *  NORMALLY ndong WILL NOT HAVE CHANGED SINCE INTERFACE 0 WAS
+                *  PROBED, BUT THIS MAY NOT BE THE CASE IF, FOR EXAMPLE, TWO
+                *  EASYCAPs ARE PLUGGED IN SIMULTANEOUSLY.
+               */
+/*---------------------------------------------------------------------------*/
+               for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
+                       if ((NULL == easycapdc60_dongle[ndong].peasycap) && \
+                                       (!mutex_is_locked(&easycapdc60_dongle\
+                                               [ndong].mutex_video)) && \
+                                       (!mutex_is_locked(&easycapdc60_dongle\
+                                               [ndong].mutex_audio))) {
+                               easycapdc60_dongle[ndong].peasycap = peasycap;
+                               peasycap->isdongle = ndong;
+                               JOM(8, "intf[%i]: peasycap-->easycap" \
                                                "_dongle[%i].peasycap\n", \
-                                               bInterfaceNumber, dongle_this);
-                                       break;
-                               }
+                                               bInterfaceNumber, ndong);
+                               break;
                        }
                }
+               if (DONGLE_MANY <= ndong) {
+                       SAM("ERROR: too many dongles\n");
+                       mutex_unlock(&mutex_dongle);
+                       return -ENOMEM;
+               }
+               mutex_unlock(&mutex_dongle);
        }
-       if (DONGLE_MANY <= dongle_this) {
-               SAM("ERROR: too many dongles\n");
-               return -ENOMEM;
-       }
-
        peasycap->allocation_video_struct = sizeof(struct easycap);
        peasycap->allocation_video_page = 0;
        peasycap->allocation_video_urb = 0;
@@ -3778,26 +3753,56 @@ if (0 == bInterfaceNumber) {
        JOM(4, "finished initialization\n");
 } else {
 /*---------------------------------------------------------------------------*/
-       /*
-        *  FOR INTERFACES 1 AND 2 THE POINTER peasycap IS OBTAINED BY ASSUMING
-        *  THAT dongle_this HAS NOT CHANGED SINCE INTERFACE 0 WAS PROBED.  IF
-        *  THIS IS NOT THE CASE, FOR EXAMPLE WHEN TWO EASYCAPs ARE PLUGGED IN
       *  SIMULTANEOUSLY, THERE WILL BE SERIOUS TROUBLE.
      */
+/*
+ *                                 FIXME
+ *
+ *  IDENTIFY THE APPROPRIATE POINTER peasycap FOR INTERFACES 1 AND 2.
*  THE ADDRESS OF peasycap->pusb_device IS RELUCTANTLY USED FOR THIS PURPOSE.
+ */
 /*---------------------------------------------------------------------------*/
-       if ((0 > dongle_this) || (DONGLE_MANY <= dongle_this)) {
-               SAY("ERROR: bad dongle count\n");
-               return -EFAULT;
+       for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
+               if (pusb_device == easycapdc60_dongle[ndong].peasycap->\
+                                                               pusb_device) {
+                       peasycap = easycapdc60_dongle[ndong].peasycap;
+                       JOT(8, "intf[%i]: easycapdc60_dongle[%i].peasycap-->" \
+                                       "peasycap\n", bInterfaceNumber, ndong);
+                       break;
+               }
        }
-       peasycap = easycap_dongle[dongle_this].peasycap;
-       JOT(8, "intf[%i]: easycap_dongle[%i].peasycap-->peasycap\n", \
-                                               bInterfaceNumber, dongle_this);
-
-       if ((struct easycap *)NULL == peasycap) {
+       if (DONGLE_MANY <= ndong) {
+               SAY("ERROR: peasycap is unknown when probing interface %i\n", \
+                                                       bInterfaceNumber);
+               return -ENODEV;
+       }
+       if (NULL == peasycap) {
                SAY("ERROR: peasycap is NULL when probing interface %i\n", \
                                                        bInterfaceNumber);
-               return -EFAULT;
+               return -ENODEV;
        }
+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
+#
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#else
+#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
+/*---------------------------------------------------------------------------*/
+/*
+ *  SOME VERSIONS OF THE videodev MODULE OVERWRITE THE DATA WHICH HAS
+ *  BEEN WRITTEN BY THE CALL TO usb_set_intfdata() IN easycap_usb_probe(),
+ *  REPLACING IT WITH A POINTER TO THE EMBEDDED v4l2_device STRUCTURE.
+ *  TO DETECT THIS, THE STRING IN THE easycap.telltale[] BUFFER IS CHECKED.
+*/
+/*---------------------------------------------------------------------------*/
+       if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
+               pv4l2_device = usb_get_intfdata(pusb_interface);
+               if ((struct v4l2_device *)NULL == pv4l2_device) {
+                       SAY("ERROR: pv4l2_device is NULL\n");
+                       return -ENODEV;
+               }
+               peasycap = (struct easycap *) \
+                       container_of(pv4l2_device, struct easycap, v4l2_device);
+       }
+#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
 }
 /*---------------------------------------------------------------------------*/
 if ((USB_CLASS_VIDEO == bInterfaceClass) || \
@@ -4368,6 +4373,7 @@ case 0: {
        } else {
                (peasycap->registered_video)++;
                SAM("easycap attached to minor #%d\n", pusb_interface->minor);
+               peasycap->minor = pusb_interface->minor;
                break;
        }
 /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
@@ -4383,7 +4389,7 @@ case 0: {
        }
 /*---------------------------------------------------------------------------*/
 /*
- *                                   FIXME
+ *                                 FIXME
  *
  *
  *  THIS IS BELIEVED TO BE HARMLESS, BUT MAY WELL BE UNNECESSARY OR WRONG:
@@ -4414,9 +4420,11 @@ case 0: {
                (peasycap->registered_video)++;
                SAM("registered with videodev: %i=minor\n", \
                                                peasycap->video_device.minor);
+               peasycap->minor = peasycap->video_device.minor;
        }
 #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+
        break;
 }
 /*--------------------------------------------------------------------------*/
@@ -4426,8 +4434,11 @@ case 0: {
  */
 /*--------------------------------------------------------------------------*/
 case 1: {
+#if defined(EASYCAP_SILENT)
+       return -ENOENT;
+#endif /*EASYCAP_SILENT*/
        if (!peasycap) {
-               SAM("ERROR: peasycap is NULL\n");
+               SAM("MISTAKE: peasycap is NULL\n");
                return -EFAULT;
        }
 /*--------------------------------------------------------------------------*/
@@ -4442,6 +4453,9 @@ case 1: {
 }
 /*--------------------------------------------------------------------------*/
 case 2: {
+#if defined(EASYCAP_SILENT)
+       return -ENOENT;
+#endif /*EASYCAP_SILENT*/
        if (!peasycap) {
                SAM("MISTAKE: peasycap is NULL\n");
                return -EFAULT;
@@ -4467,14 +4481,14 @@ case 2: {
        }
        if (9 == peasycap->audio_isoc_maxframesize) {
                peasycap->ilk |= 0x02;
-               SAM("hardware is FOUR-CVBS\n");
+               SAM("audio hardware is microphone\n");
                peasycap->microphone = true;
-               peasycap->audio_pages_per_fragment = 4;
+               peasycap->audio_pages_per_fragment = PAGES_PER_AUDIO_FRAGMENT;
        } else if (256 == peasycap->audio_isoc_maxframesize) {
                peasycap->ilk &= ~0x02;
-               SAM("hardware is CVBS+S-VIDEO\n");
+               SAM("audio hardware is AC'97\n");
                peasycap->microphone = false;
-               peasycap->audio_pages_per_fragment = 4;
+               peasycap->audio_pages_per_fragment = PAGES_PER_AUDIO_FRAGMENT;
        } else {
                SAM("hardware is unidentified:\n");
                SAM("%i=audio_isoc_maxframesize\n", \
@@ -4496,7 +4510,7 @@ case 2: {
        JOM(4, "%6i=audio_buffer_page_many\n", \
                                        peasycap->audio_buffer_page_many);
 
-       peasycap->audio_isoc_framesperdesc = 128;
+       peasycap->audio_isoc_framesperdesc = AUDIO_ISOC_FRAMESPERDESC;
 
        JOM(4, "%i=audio_isoc_framesperdesc\n", \
                                        peasycap->audio_isoc_framesperdesc);
@@ -4548,6 +4562,7 @@ case 2: {
        INIT_LIST_HEAD(&(peasycap->urb_audio_head));
        peasycap->purb_audio_head = &(peasycap->urb_audio_head);
 
+#if !defined(EASYCAP_NEEDS_ALSA)
        JOM(4, "allocating an audio buffer\n");
        JOM(4, ".... scattered over %i pages\n", \
                                        peasycap->audio_buffer_page_many);
@@ -4572,6 +4587,7 @@ case 2: {
        peasycap->audio_fill = 0;
        peasycap->audio_read = 0;
        JOM(4, "allocation of audio buffer done:  %i pages\n", k);
+#endif /*!EASYCAP_NEEDS_ALSA*/
 /*---------------------------------------------------------------------------*/
        JOM(4, "allocating %i isoc audio buffers of size %i\n",  \
                AUDIO_ISOC_BUFFER_MANY, peasycap->audio_isoc_buffer_size);
@@ -4646,7 +4662,11 @@ case 2: {
                                "peasycap->audio_isoc_buffer[.].pgo;\n");
                        JOM(4, "  purb->transfer_buffer_length = %i;\n", \
                                        peasycap->audio_isoc_buffer_size);
-                       JOM(4, "  purb->complete = easysnd_complete;\n");
+#if defined(EASYCAP_NEEDS_ALSA)
+                       JOM(4, "  purb->complete = easycap_alsa_complete;\n");
+#else
+                       JOM(4, "  purb->complete = easyoss_complete;\n");
+#endif /*EASYCAP_NEEDS_ALSA*/
                        JOM(4, "  purb->context = peasycap;\n");
                        JOM(4, "  purb->start_frame = 0;\n");
                        JOM(4, "  purb->number_of_packets = %i;\n", \
@@ -4669,7 +4689,11 @@ case 2: {
                purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
                purb->transfer_buffer_length = \
                                        peasycap->audio_isoc_buffer_size;
-               purb->complete = easysnd_complete;
+#if defined(EASYCAP_NEEDS_ALSA)
+               purb->complete = easycap_alsa_complete;
+#else
+               purb->complete = easyoss_complete;
+#endif /*EASYCAP_NEEDS_ALSA*/
                purb->context = peasycap;
                purb->start_frame = 0;
                purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
@@ -4692,9 +4716,24 @@ case 2: {
  *  THE AUDIO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
  */
 /*---------------------------------------------------------------------------*/
-       rc = usb_register_dev(pusb_interface, &easysnd_class);
+#if defined(EASYCAP_NEEDS_ALSA)
+       JOM(4, "initializing ALSA card\n");
+
+       rc = easycap_alsa_probe(peasycap);
+       if (0 != rc) {
+               err("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);
-       (peasycap->registered_audio)--;
 
+
+       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 @@ default:
 /*---------------------------------------------------------------------------*/
 /*
  *  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
diff --git a/drivers/staging/easycap/easycap_main.h b/drivers/staging/easycap/easycap_main.h
new file mode 100644 (file)
index 0000000..11fcbbc
--- /dev/null
@@ -0,0 +1,43 @@
+/*****************************************************************************
+*                                                                            *
+*  easycap_main.h                                                           *
+*                                                                            *
+*****************************************************************************/
+/*
+ *
+ *  Copyright (C) 2010 R.M. Thomas  <rmthomas@sciolus.org>
+ *
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+/*****************************************************************************/
+#if !defined(EASYCAP_MAIN_H)
+#define EASYCAP_MAIN_H
+
+extern struct easycap_standard easycap_standard[];
+extern struct easycap_format easycap_format[];
+extern struct v4l2_queryctrl easycap_control[];
+extern struct usb_driver easycap_usb_driver;
+#if defined(EASYCAP_NEEDS_ALSA)
+extern struct snd_pcm_ops easycap_alsa_ops;
+extern struct snd_pcm_hardware easycap_pcm_hardware;
+extern struct snd_card *psnd_card;
+#else
+extern struct usb_class_driver easyoss_class;
+extern const struct file_operations easyoss_fops;
+#endif /*EASYCAP_NEEDS_ALSA*/
+
+#endif /*EASYCAP_MAIN_H*/
index df3f17d..0a23e27 100644 (file)
@@ -26,7 +26,7 @@
 /*****************************************************************************/
 
 #include "easycap.h"
-#include "easycap_debug.h"
+#include "easycap_settings.h"
 
 /*---------------------------------------------------------------------------*/
 /*
similarity index 82%
rename from drivers/staging/easycap/easycap_standard.h
rename to drivers/staging/easycap/easycap_settings.h
index cadc8d2..5fe6f07 100644 (file)
@@ -1,6 +1,6 @@
 /*****************************************************************************
 *                                                                            *
-*  easycap_standard.h                                                        *
+*  easycap_settings.h                                                        *
 *                                                                            *
 *****************************************************************************/
 /*
  *
 */
 /*****************************************************************************/
-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*/
index 24d8bb4..0507ea1 100644 (file)
 /*****************************************************************************/
 
 #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,
+};
 /*****************************************************************************/
 /*---------------------------------------------------------------------------*/
 /*
  */
 /*---------------------------------------------------------------------------*/
 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);
+       case -EPERM: {
+               SAM("-EPERM\n");
                break;
        }
+       default: {
+               SAM("unknown error: %i\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");
-                               break;
-                       }
-                       default: {
-                               SAM("0x%08X\n", rc); 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);
+                               "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
index 4912739..82104c8 100644 (file)
  *
 */
 /*****************************************************************************/
+#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*/
index e27dfe9..1089603 100644 (file)
@@ -26,7 +26,7 @@
 /*****************************************************************************/
 
 #include "easycap.h"
-#include "easycap_debug.h"
+#include "easycap_testcard.h"
 
 /*****************************************************************************/
 #define TESTCARD_BYTESPERLINE (2 * 720)
@@ -397,7 +397,7 @@ int tones[2048] = {
 };
 /*****************************************************************************/
 void
-easysnd_testtone(struct easycap *peasycap, int audio_fill)
+easyoss_testtone(struct easycap *peasycap, int audio_fill)
 {
 int i1;
 unsigned char *p2;
diff --git a/drivers/staging/easycap/easycap_testcard.h b/drivers/staging/easycap/easycap_testcard.h
new file mode 100644 (file)
index 0000000..5159127
--- /dev/null
@@ -0,0 +1,34 @@
+/*****************************************************************************
+*                                                                            *
+*  easycap_testcard.h                                                        *
+*                                                                            *
+*****************************************************************************/
+/*
+ *
+ *  Copyright (C) 2010 R.M. Thomas  <rmthomas@sciolus.org>
+ *
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+/*****************************************************************************/
+#if !defined(EASYCAP_TESTCARD_H)
+#define EASYCAP_TESTCARD_H
+
+extern int easycap_debug;
+extern int easycap_gain;
+extern struct easycap_dongle easycapdc60_dongle[];
+
+#endif /*EASYCAP_TESTCARD_H*/