]> git.openfabrics.org - ~shefty/rdma-dev.git/commitdiff
staging: Move media drivers to staging/media
authorMauro Carvalho Chehab <mchehab@redhat.com>
Wed, 2 Nov 2011 00:23:55 +0000 (22:23 -0200)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 3 Nov 2011 09:59:03 +0000 (07:59 -0200)
In practice, it is being hard to distinguish when a patch
should go to staging tree or to the media tree. Better
to distinguish it, by putting the media drivers at a
separate staging directory. Newer staging drivers that include
anything with "dvb*.h", "v4l2*.h" or "videodev2.h" should
go to the drivers/staging/media tree.

Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
160 files changed:
drivers/media/dvb/ddbridge/Makefile
drivers/media/dvb/ngene/Makefile
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/cxd2099/Kconfig [deleted file]
drivers/staging/cxd2099/Makefile [deleted file]
drivers/staging/cxd2099/TODO [deleted file]
drivers/staging/cxd2099/cxd2099.c [deleted file]
drivers/staging/cxd2099/cxd2099.h [deleted file]
drivers/staging/dt3155v4l/Kconfig [deleted file]
drivers/staging/dt3155v4l/Makefile [deleted file]
drivers/staging/dt3155v4l/dt3155v4l.c [deleted file]
drivers/staging/dt3155v4l/dt3155v4l.h [deleted file]
drivers/staging/easycap/Kconfig [deleted file]
drivers/staging/easycap/Makefile [deleted file]
drivers/staging/easycap/README [deleted file]
drivers/staging/easycap/easycap.h [deleted file]
drivers/staging/easycap/easycap_ioctl.c [deleted file]
drivers/staging/easycap/easycap_low.c [deleted file]
drivers/staging/easycap/easycap_main.c [deleted file]
drivers/staging/easycap/easycap_settings.c [deleted file]
drivers/staging/easycap/easycap_sound.c [deleted file]
drivers/staging/easycap/easycap_testcard.c [deleted file]
drivers/staging/go7007/Kconfig [deleted file]
drivers/staging/go7007/Makefile [deleted file]
drivers/staging/go7007/README [deleted file]
drivers/staging/go7007/go7007-driver.c [deleted file]
drivers/staging/go7007/go7007-fw.c [deleted file]
drivers/staging/go7007/go7007-i2c.c [deleted file]
drivers/staging/go7007/go7007-priv.h [deleted file]
drivers/staging/go7007/go7007-usb.c [deleted file]
drivers/staging/go7007/go7007-v4l2.c [deleted file]
drivers/staging/go7007/go7007.h [deleted file]
drivers/staging/go7007/go7007.txt [deleted file]
drivers/staging/go7007/s2250-board.c [deleted file]
drivers/staging/go7007/s2250-loader.c [deleted file]
drivers/staging/go7007/s2250-loader.h [deleted file]
drivers/staging/go7007/saa7134-go7007.c [deleted file]
drivers/staging/go7007/snd-go7007.c [deleted file]
drivers/staging/go7007/wis-i2c.h [deleted file]
drivers/staging/go7007/wis-ov7640.c [deleted file]
drivers/staging/go7007/wis-saa7113.c [deleted file]
drivers/staging/go7007/wis-saa7115.c [deleted file]
drivers/staging/go7007/wis-sony-tuner.c [deleted file]
drivers/staging/go7007/wis-tw2804.c [deleted file]
drivers/staging/go7007/wis-tw9903.c [deleted file]
drivers/staging/go7007/wis-uda1342.c [deleted file]
drivers/staging/lirc/Kconfig [deleted file]
drivers/staging/lirc/Makefile [deleted file]
drivers/staging/lirc/TODO [deleted file]
drivers/staging/lirc/TODO.lirc_zilog [deleted file]
drivers/staging/lirc/lirc_bt829.c [deleted file]
drivers/staging/lirc/lirc_ene0100.h [deleted file]
drivers/staging/lirc/lirc_igorplugusb.c [deleted file]
drivers/staging/lirc/lirc_imon.c [deleted file]
drivers/staging/lirc/lirc_parallel.c [deleted file]
drivers/staging/lirc/lirc_parallel.h [deleted file]
drivers/staging/lirc/lirc_sasem.c [deleted file]
drivers/staging/lirc/lirc_serial.c [deleted file]
drivers/staging/lirc/lirc_sir.c [deleted file]
drivers/staging/lirc/lirc_ttusbir.c [deleted file]
drivers/staging/lirc/lirc_zilog.c [deleted file]
drivers/staging/media/Kconfig [new file with mode: 0644]
drivers/staging/media/Makefile [new file with mode: 0644]
drivers/staging/media/cxd2099/Kconfig [new file with mode: 0644]
drivers/staging/media/cxd2099/Makefile [new file with mode: 0644]
drivers/staging/media/cxd2099/TODO [new file with mode: 0644]
drivers/staging/media/cxd2099/cxd2099.c [new file with mode: 0644]
drivers/staging/media/cxd2099/cxd2099.h [new file with mode: 0644]
drivers/staging/media/dt3155v4l/Kconfig [new file with mode: 0644]
drivers/staging/media/dt3155v4l/Makefile [new file with mode: 0644]
drivers/staging/media/dt3155v4l/dt3155v4l.c [new file with mode: 0644]
drivers/staging/media/dt3155v4l/dt3155v4l.h [new file with mode: 0644]
drivers/staging/media/easycap/Kconfig [new file with mode: 0644]
drivers/staging/media/easycap/Makefile [new file with mode: 0644]
drivers/staging/media/easycap/README [new file with mode: 0644]
drivers/staging/media/easycap/easycap.h [new file with mode: 0644]
drivers/staging/media/easycap/easycap_ioctl.c [new file with mode: 0644]
drivers/staging/media/easycap/easycap_low.c [new file with mode: 0644]
drivers/staging/media/easycap/easycap_main.c [new file with mode: 0644]
drivers/staging/media/easycap/easycap_settings.c [new file with mode: 0644]
drivers/staging/media/easycap/easycap_sound.c [new file with mode: 0644]
drivers/staging/media/easycap/easycap_testcard.c [new file with mode: 0644]
drivers/staging/media/go7007/Kconfig [new file with mode: 0644]
drivers/staging/media/go7007/Makefile [new file with mode: 0644]
drivers/staging/media/go7007/README [new file with mode: 0644]
drivers/staging/media/go7007/go7007-driver.c [new file with mode: 0644]
drivers/staging/media/go7007/go7007-fw.c [new file with mode: 0644]
drivers/staging/media/go7007/go7007-i2c.c [new file with mode: 0644]
drivers/staging/media/go7007/go7007-priv.h [new file with mode: 0644]
drivers/staging/media/go7007/go7007-usb.c [new file with mode: 0644]
drivers/staging/media/go7007/go7007-v4l2.c [new file with mode: 0644]
drivers/staging/media/go7007/go7007.h [new file with mode: 0644]
drivers/staging/media/go7007/go7007.txt [new file with mode: 0644]
drivers/staging/media/go7007/s2250-board.c [new file with mode: 0644]
drivers/staging/media/go7007/s2250-loader.c [new file with mode: 0644]
drivers/staging/media/go7007/s2250-loader.h [new file with mode: 0644]
drivers/staging/media/go7007/saa7134-go7007.c [new file with mode: 0644]
drivers/staging/media/go7007/snd-go7007.c [new file with mode: 0644]
drivers/staging/media/go7007/wis-i2c.h [new file with mode: 0644]
drivers/staging/media/go7007/wis-ov7640.c [new file with mode: 0644]
drivers/staging/media/go7007/wis-saa7113.c [new file with mode: 0644]
drivers/staging/media/go7007/wis-saa7115.c [new file with mode: 0644]
drivers/staging/media/go7007/wis-sony-tuner.c [new file with mode: 0644]
drivers/staging/media/go7007/wis-tw2804.c [new file with mode: 0644]
drivers/staging/media/go7007/wis-tw9903.c [new file with mode: 0644]
drivers/staging/media/go7007/wis-uda1342.c [new file with mode: 0644]
drivers/staging/media/lirc/Kconfig [new file with mode: 0644]
drivers/staging/media/lirc/Makefile [new file with mode: 0644]
drivers/staging/media/lirc/TODO [new file with mode: 0644]
drivers/staging/media/lirc/TODO.lirc_zilog [new file with mode: 0644]
drivers/staging/media/lirc/lirc_bt829.c [new file with mode: 0644]
drivers/staging/media/lirc/lirc_ene0100.h [new file with mode: 0644]
drivers/staging/media/lirc/lirc_igorplugusb.c [new file with mode: 0644]
drivers/staging/media/lirc/lirc_imon.c [new file with mode: 0644]
drivers/staging/media/lirc/lirc_parallel.c [new file with mode: 0644]
drivers/staging/media/lirc/lirc_parallel.h [new file with mode: 0644]
drivers/staging/media/lirc/lirc_sasem.c [new file with mode: 0644]
drivers/staging/media/lirc/lirc_serial.c [new file with mode: 0644]
drivers/staging/media/lirc/lirc_sir.c [new file with mode: 0644]
drivers/staging/media/lirc/lirc_ttusbir.c [new file with mode: 0644]
drivers/staging/media/lirc/lirc_zilog.c [new file with mode: 0644]
drivers/staging/media/solo6x10/Kconfig [new file with mode: 0644]
drivers/staging/media/solo6x10/Makefile [new file with mode: 0644]
drivers/staging/media/solo6x10/TODO [new file with mode: 0644]
drivers/staging/media/solo6x10/core.c [new file with mode: 0644]
drivers/staging/media/solo6x10/disp.c [new file with mode: 0644]
drivers/staging/media/solo6x10/enc.c [new file with mode: 0644]
drivers/staging/media/solo6x10/g723.c [new file with mode: 0644]
drivers/staging/media/solo6x10/gpio.c [new file with mode: 0644]
drivers/staging/media/solo6x10/i2c.c [new file with mode: 0644]
drivers/staging/media/solo6x10/jpeg.h [new file with mode: 0644]
drivers/staging/media/solo6x10/offsets.h [new file with mode: 0644]
drivers/staging/media/solo6x10/osd-font.h [new file with mode: 0644]
drivers/staging/media/solo6x10/p2m.c [new file with mode: 0644]
drivers/staging/media/solo6x10/registers.h [new file with mode: 0644]
drivers/staging/media/solo6x10/solo6x10.h [new file with mode: 0644]
drivers/staging/media/solo6x10/tw28.c [new file with mode: 0644]
drivers/staging/media/solo6x10/tw28.h [new file with mode: 0644]
drivers/staging/media/solo6x10/v4l2-enc.c [new file with mode: 0644]
drivers/staging/media/solo6x10/v4l2.c [new file with mode: 0644]
drivers/staging/solo6x10/Kconfig [deleted file]
drivers/staging/solo6x10/Makefile [deleted file]
drivers/staging/solo6x10/TODO [deleted file]
drivers/staging/solo6x10/core.c [deleted file]
drivers/staging/solo6x10/disp.c [deleted file]
drivers/staging/solo6x10/enc.c [deleted file]
drivers/staging/solo6x10/g723.c [deleted file]
drivers/staging/solo6x10/gpio.c [deleted file]
drivers/staging/solo6x10/i2c.c [deleted file]
drivers/staging/solo6x10/jpeg.h [deleted file]
drivers/staging/solo6x10/offsets.h [deleted file]
drivers/staging/solo6x10/osd-font.h [deleted file]
drivers/staging/solo6x10/p2m.c [deleted file]
drivers/staging/solo6x10/registers.h [deleted file]
drivers/staging/solo6x10/solo6x10.h [deleted file]
drivers/staging/solo6x10/tw28.c [deleted file]
drivers/staging/solo6x10/tw28.h [deleted file]
drivers/staging/solo6x10/v4l2-enc.c [deleted file]
drivers/staging/solo6x10/v4l2.c [deleted file]

index cf7214edf65ffc7fe6a7214d2238224919ee397b..38019bafb862246b992f6026f77314f460cb2c78 100644 (file)
@@ -11,4 +11,4 @@ ccflags-y += -Idrivers/media/dvb/frontends/
 ccflags-y += -Idrivers/media/common/tuners/
 
 # For the staging CI driver cxd2099
-ccflags-y += -Idrivers/staging/cxd2099/
+ccflags-y += -Idrivers/staging/media/cxd2099/
index 89873615e6839f81ebb10729784994b9963a672f..13ebeffb705ffeee530c91e5859ef22e1512b66f 100644 (file)
@@ -11,4 +11,4 @@ ccflags-y += -Idrivers/media/dvb/frontends/
 ccflags-y += -Idrivers/media/common/tuners/
 
 # For the staging CI driver cxd2099
-ccflags-y += -Idrivers/staging/cxd2099/
+ccflags-y += -Idrivers/staging/media/cxd2099/
index 39df8597d310632c77cb95f1bff719b5e2fa6f03..25cdff36a78ac63d981baddd3926d96297760ade 100644 (file)
@@ -30,10 +30,6 @@ source "drivers/staging/et131x/Kconfig"
 
 source "drivers/staging/slicoss/Kconfig"
 
-source "drivers/staging/go7007/Kconfig"
-
-source "drivers/staging/cxd2099/Kconfig"
-
 source "drivers/staging/usbip/Kconfig"
 
 source "drivers/staging/winbond/Kconfig"
@@ -102,20 +98,12 @@ source "drivers/staging/wlags49_h25/Kconfig"
 
 source "drivers/staging/sm7xx/Kconfig"
 
-source "drivers/staging/dt3155v4l/Kconfig"
-
 source "drivers/staging/crystalhd/Kconfig"
 
 source "drivers/staging/cxt1e1/Kconfig"
 
 source "drivers/staging/xgifb/Kconfig"
 
-source "drivers/staging/lirc/Kconfig"
-
-source "drivers/staging/easycap/Kconfig"
-
-source "drivers/staging/solo6x10/Kconfig"
-
 source "drivers/staging/tidspbridge/Kconfig"
 
 source "drivers/staging/quickstart/Kconfig"
@@ -142,6 +130,6 @@ source "drivers/staging/mei/Kconfig"
 
 source "drivers/staging/nvec/Kconfig"
 
-source "drivers/staging/media/as102/Kconfig"
+source "drivers/staging/media/Kconfig"
 
 endif # STAGING
index cd1bcc1f0e661251a9e88df5f9f51a9cb41a3d16..a25f3f26c7ff5899d22aad952c11061b0307ceea 100644 (file)
@@ -4,11 +4,9 @@
 obj-$(CONFIG_STAGING)          += staging.o
 
 obj-y                          += serial/
+obj-y                          += media/
 obj-$(CONFIG_ET131X)           += et131x/
 obj-$(CONFIG_SLICOSS)          += slicoss/
-obj-$(CONFIG_VIDEO_GO7007)     += go7007/
-obj-$(CONFIG_DVB_CXD2099)      += cxd2099/
-obj-$(CONFIG_LIRC_STAGING)     += lirc/
 obj-$(CONFIG_USBIP_CORE)       += usbip/
 obj-$(CONFIG_W35UND)           += winbond/
 obj-$(CONFIG_PRISM2_USB)       += wlan-ng/
@@ -43,12 +41,9 @@ obj-$(CONFIG_ZCACHE)         += zcache/
 obj-$(CONFIG_WLAGS49_H2)       += wlags49_h2/
 obj-$(CONFIG_WLAGS49_H25)      += wlags49_h25/
 obj-$(CONFIG_FB_SM7XX)         += sm7xx/
-obj-$(CONFIG_VIDEO_DT3155)     += dt3155v4l/
 obj-$(CONFIG_CRYSTALHD)                += crystalhd/
 obj-$(CONFIG_CXT1E1)           += cxt1e1/
 obj-$(CONFIG_FB_XGI)           += xgifb/
-obj-$(CONFIG_EASYCAP)          += easycap/
-obj-$(CONFIG_SOLO6X10)         += solo6x10/
 obj-$(CONFIG_TIDSPBRIDGE)      += tidspbridge/
 obj-$(CONFIG_ACPI_QUICKSTART)  += quickstart/
 obj-$(CONFIG_SBE_2T3E3)                += sbe-2t3e3/
@@ -62,4 +57,3 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)  += ste_rmi4/
 obj-$(CONFIG_DRM_PSB)          += gma500/
 obj-$(CONFIG_INTEL_MEI)                += mei/
 obj-$(CONFIG_MFD_NVEC)         += nvec/
-obj-$(CONFIG_DVB_AS102)                += media/as102/
diff --git a/drivers/staging/cxd2099/Kconfig b/drivers/staging/cxd2099/Kconfig
deleted file mode 100644 (file)
index b48aefd..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-config DVB_CXD2099
-       tristate "CXD2099AR Common Interface driver"
-       depends on DVB_CORE && PCI && I2C
-       ---help---
-         Support for the CI module found on cards based on
-         - Micronas ngene PCIe bridge: cineS2 etc.
-         - Digital Devices PCIe bridge: Octopus series
-
-         For now, data is passed through '/dev/dvb/adapterX/sec0':
-           - Encrypted data must be written to 'sec0'.
-           - Decrypted data can be read from 'sec0'.
-           - Setup the CAM using device 'ca0'.
diff --git a/drivers/staging/cxd2099/Makefile b/drivers/staging/cxd2099/Makefile
deleted file mode 100644 (file)
index 64cfc77..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-obj-$(CONFIG_DVB_CXD2099) += cxd2099.o
-
-ccflags-y += -Idrivers/media/dvb/dvb-core/
-ccflags-y += -Idrivers/media/dvb/frontends/
-ccflags-y += -Idrivers/media/common/tuners/
diff --git a/drivers/staging/cxd2099/TODO b/drivers/staging/cxd2099/TODO
deleted file mode 100644 (file)
index 375bb6f..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-For now, data is passed through '/dev/dvb/adapterX/sec0':
- - Encrypted data must be written to 'sec0'.
- - Decrypted data can be read from 'sec0'.
- - Setup the CAM using device 'ca0'.
-
-But this is wrong. There are some discussions about the proper way for
-doing it, as seen at:
-       http://www.mail-archive.com/linux-media@vger.kernel.org/msg22196.html
-
-While there's no proper fix for it, the driver should be kept in staging.
-
-Patches should be submitted to: linux-media@vger.kernel.org.
diff --git a/drivers/staging/cxd2099/cxd2099.c b/drivers/staging/cxd2099/cxd2099.c
deleted file mode 100644 (file)
index 1c04185..0000000
+++ /dev/null
@@ -1,716 +0,0 @@
-/*
- * cxd2099.c: Driver for the CXD2099AR Common Interface Controller
- *
- * Copyright (C) 2010-2011 Digital Devices GmbH
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/io.h>
-
-#include "cxd2099.h"
-
-#define MAX_BUFFER_SIZE 248
-
-struct cxd {
-       struct dvb_ca_en50221 en;
-
-       struct i2c_adapter *i2c;
-       struct cxd2099_cfg cfg;
-
-       u8     regs[0x23];
-       u8     lastaddress;
-       u8     clk_reg_f;
-       u8     clk_reg_b;
-       int    mode;
-       int    ready;
-       int    dr;
-       int    slot_stat;
-
-       u8     amem[1024];
-       int    amem_read;
-
-       int    cammode;
-       struct mutex lock;
-};
-
-static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr,
-                        u8 reg, u8 data)
-{
-       u8 m[2] = {reg, data};
-       struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = 2};
-
-       if (i2c_transfer(adapter, &msg, 1) != 1) {
-               printk(KERN_ERR "Failed to write to I2C register %02x@%02x!\n",
-                      reg, adr);
-               return -1;
-       }
-       return 0;
-}
-
-static int i2c_write(struct i2c_adapter *adapter, u8 adr,
-                    u8 *data, u8 len)
-{
-       struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len};
-
-       if (i2c_transfer(adapter, &msg, 1) != 1) {
-               printk(KERN_ERR "Failed to write to I2C!\n");
-               return -1;
-       }
-       return 0;
-}
-
-static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr,
-                       u8 reg, u8 *val)
-{
-       struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
-                                  .buf = &reg, .len = 1},
-                                 {.addr = adr, .flags = I2C_M_RD,
-                                  .buf = val, .len = 1} };
-
-       if (i2c_transfer(adapter, msgs, 2) != 2) {
-               printk(KERN_ERR "error in i2c_read_reg\n");
-               return -1;
-       }
-       return 0;
-}
-
-static int i2c_read(struct i2c_adapter *adapter, u8 adr,
-                   u8 reg, u8 *data, u8 n)
-{
-       struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
-                                .buf = &reg, .len = 1},
-                               {.addr = adr, .flags = I2C_M_RD,
-                                .buf = data, .len = n} };
-
-       if (i2c_transfer(adapter, msgs, 2) != 2) {
-               printk(KERN_ERR "error in i2c_read\n");
-               return -1;
-       }
-       return 0;
-}
-
-static int read_block(struct cxd *ci, u8 adr, u8 *data, u8 n)
-{
-       int status;
-
-       status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
-       if (!status) {
-               ci->lastaddress = adr;
-               status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, n);
-       }
-       return status;
-}
-
-static int read_reg(struct cxd *ci, u8 reg, u8 *val)
-{
-       return read_block(ci, reg, val, 1);
-}
-
-
-static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
-{
-       int status;
-       u8 addr[3] = {2, address & 0xff, address >> 8};
-
-       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
-       if (!status)
-               status = i2c_read(ci->i2c, ci->cfg.adr, 3, data, n);
-       return status;
-}
-
-static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
-{
-       int status;
-       u8 addr[3] = {2, address & 0xff, address >> 8};
-
-       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
-       if (!status) {
-               u8 buf[256] = {3};
-               memcpy(buf+1, data, n);
-               status = i2c_write(ci->i2c, ci->cfg.adr, buf, n+1);
-       }
-       return status;
-}
-
-static int read_io(struct cxd *ci, u16 address, u8 *val)
-{
-       int status;
-       u8 addr[3] = {2, address & 0xff, address >> 8};
-
-       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
-       if (!status)
-               status = i2c_read(ci->i2c, ci->cfg.adr, 3, val, 1);
-       return status;
-}
-
-static int write_io(struct cxd *ci, u16 address, u8 val)
-{
-       int status;
-       u8 addr[3] = {2, address & 0xff, address >> 8};
-       u8 buf[2] = {3, val};
-
-       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
-       if (!status)
-               status = i2c_write(ci->i2c, ci->cfg.adr, buf, 2);
-       return status;
-}
-
-#if 0
-static int read_io_data(struct cxd *ci, u8 *data, u8 n)
-{
-       int status;
-       u8 addr[3] = { 2, 0, 0 };
-
-       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
-       if (!status)
-               status = i2c_read(ci->i2c, ci->cfg.adr, 3, data, n);
-       return 0;
-}
-
-static int write_io_data(struct cxd *ci, u8 *data, u8 n)
-{
-       int status;
-       u8 addr[3] = {2, 0, 0};
-
-       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
-       if (!status) {
-               u8 buf[256] = {3};
-               memcpy(buf+1, data, n);
-               status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
-       }
-       return 0;
-}
-#endif
-
-static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask)
-{
-       int status;
-
-       status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, reg);
-       if (!status && reg >= 6 && reg <= 8 && mask != 0xff)
-               status = i2c_read_reg(ci->i2c, ci->cfg.adr, 1, &ci->regs[reg]);
-       ci->regs[reg] = (ci->regs[reg] & (~mask)) | val;
-       if (!status) {
-               ci->lastaddress = reg;
-               status = i2c_write_reg(ci->i2c, ci->cfg.adr, 1, ci->regs[reg]);
-       }
-       if (reg == 0x20)
-               ci->regs[reg] &= 0x7f;
-       return status;
-}
-
-static int write_reg(struct cxd *ci, u8 reg, u8 val)
-{
-       return write_regm(ci, reg, val, 0xff);
-}
-
-#ifdef BUFFER_MODE
-static int write_block(struct cxd *ci, u8 adr, u8 *data, int n)
-{
-       int status;
-       u8 buf[256] = {1};
-
-       status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
-       if (!status) {
-               ci->lastaddress = adr;
-               memcpy(buf + 1, data, n);
-               status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
-       }
-       return status;
-}
-#endif
-
-static void set_mode(struct cxd *ci, int mode)
-{
-       if (mode == ci->mode)
-               return;
-
-       switch (mode) {
-       case 0x00: /* IO mem */
-               write_regm(ci, 0x06, 0x00, 0x07);
-               break;
-       case 0x01: /* ATT mem */
-               write_regm(ci, 0x06, 0x02, 0x07);
-               break;
-       default:
-               break;
-       }
-       ci->mode = mode;
-}
-
-static void cam_mode(struct cxd *ci, int mode)
-{
-       if (mode == ci->cammode)
-               return;
-
-       switch (mode) {
-       case 0x00:
-               write_regm(ci, 0x20, 0x80, 0x80);
-               break;
-       case 0x01:
-#ifdef BUFFER_MODE
-               if (!ci->en.read_data)
-                       return;
-               printk(KERN_INFO "enable cam buffer mode\n");
-               /* write_reg(ci, 0x0d, 0x00); */
-               /* write_reg(ci, 0x0e, 0x01); */
-               write_regm(ci, 0x08, 0x40, 0x40);
-               /* read_reg(ci, 0x12, &dummy); */
-               write_regm(ci, 0x08, 0x80, 0x80);
-#endif
-               break;
-       default:
-               break;
-       }
-       ci->cammode = mode;
-}
-
-
-
-static int init(struct cxd *ci)
-{
-       int status;
-
-       mutex_lock(&ci->lock);
-       ci->mode = -1;
-       do {
-               status = write_reg(ci, 0x00, 0x00);
-               if (status < 0)
-                       break;
-               status = write_reg(ci, 0x01, 0x00);
-               if (status < 0)
-                       break;
-               status = write_reg(ci, 0x02, 0x10);
-               if (status < 0)
-                       break;
-               status = write_reg(ci, 0x03, 0x00);
-               if (status < 0)
-                       break;
-               status = write_reg(ci, 0x05, 0xFF);
-               if (status < 0)
-                       break;
-               status = write_reg(ci, 0x06, 0x1F);
-               if (status < 0)
-                       break;
-               status = write_reg(ci, 0x07, 0x1F);
-               if (status < 0)
-                       break;
-               status = write_reg(ci, 0x08, 0x28);
-               if (status < 0)
-                       break;
-               status = write_reg(ci, 0x14, 0x20);
-               if (status < 0)
-                       break;
-
-#if 0
-               status = write_reg(ci, 0x09, 0x4D); /* Input Mode C, BYPass Serial, TIVAL = low, MSB */
-               if (status < 0)
-                       break;
-#endif
-               status = write_reg(ci, 0x0A, 0xA7); /* TOSTRT = 8, Mode B (gated clock), falling Edge, Serial, POL=HIGH, MSB */
-               if (status < 0)
-                       break;
-
-               status = write_reg(ci, 0x0B, 0x33);
-               if (status < 0)
-                       break;
-               status = write_reg(ci, 0x0C, 0x33);
-               if (status < 0)
-                       break;
-
-               status = write_regm(ci, 0x14, 0x00, 0x0F);
-               if (status < 0)
-                       break;
-               status = write_reg(ci, 0x15, ci->clk_reg_b);
-               if (status < 0)
-                       break;
-               status = write_regm(ci, 0x16, 0x00, 0x0F);
-               if (status < 0)
-                       break;
-               status = write_reg(ci, 0x17, ci->clk_reg_f);
-               if (status < 0)
-                       break;
-
-               if (ci->cfg.clock_mode) {
-                       if (ci->cfg.polarity) {
-                               status = write_reg(ci, 0x09, 0x6f);
-                               if (status < 0)
-                                       break;
-                       } else {
-                               status = write_reg(ci, 0x09, 0x6d);
-                               if (status < 0)
-                                       break;
-                       }
-                       status = write_reg(ci, 0x20, 0x68);
-                       if (status < 0)
-                               break;
-                       status = write_reg(ci, 0x21, 0x00);
-                       if (status < 0)
-                               break;
-                       status = write_reg(ci, 0x22, 0x02);
-                       if (status < 0)
-                               break;
-               } else {
-                       if (ci->cfg.polarity) {
-                               status = write_reg(ci, 0x09, 0x4f);
-                               if (status < 0)
-                                       break;
-                       } else {
-                               status = write_reg(ci, 0x09, 0x4d);
-                               if (status < 0)
-                                       break;
-                       }
-
-                       status = write_reg(ci, 0x20, 0x28);
-                       if (status < 0)
-                               break;
-                       status = write_reg(ci, 0x21, 0x00);
-                       if (status < 0)
-                               break;
-                       status = write_reg(ci, 0x22, 0x07);
-                       if (status < 0)
-                               break;
-               }
-
-               status = write_regm(ci, 0x20, 0x80, 0x80);
-               if (status < 0)
-                       break;
-               status = write_regm(ci, 0x03, 0x02, 0x02);
-               if (status < 0)
-                       break;
-               status = write_reg(ci, 0x01, 0x04);
-               if (status < 0)
-                       break;
-               status = write_reg(ci, 0x00, 0x31);
-               if (status < 0)
-                       break;
-
-               /* Put TS in bypass */
-               status = write_regm(ci, 0x09, 0x08, 0x08);
-               if (status < 0)
-                       break;
-               ci->cammode = -1;
-               cam_mode(ci, 0);
-       } while (0);
-       mutex_unlock(&ci->lock);
-
-       return 0;
-}
-
-static int read_attribute_mem(struct dvb_ca_en50221 *ca,
-                             int slot, int address)
-{
-       struct cxd *ci = ca->data;
-#if 0
-       if (ci->amem_read) {
-               if (address <= 0 || address > 1024)
-                       return -EIO;
-               return ci->amem[address];
-       }
-
-       mutex_lock(&ci->lock);
-       write_regm(ci, 0x06, 0x00, 0x05);
-       read_pccard(ci, 0, &ci->amem[0], 128);
-       read_pccard(ci, 128, &ci->amem[0], 128);
-       read_pccard(ci, 256, &ci->amem[0], 128);
-       read_pccard(ci, 384, &ci->amem[0], 128);
-       write_regm(ci, 0x06, 0x05, 0x05);
-       mutex_unlock(&ci->lock);
-       return ci->amem[address];
-#else
-       u8 val;
-       mutex_lock(&ci->lock);
-       set_mode(ci, 1);
-       read_pccard(ci, address, &val, 1);
-       mutex_unlock(&ci->lock);
-       /* printk(KERN_INFO "%02x:%02x\n", address,val); */
-       return val;
-#endif
-}
-
-static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot,
-                              int address, u8 value)
-{
-       struct cxd *ci = ca->data;
-
-       mutex_lock(&ci->lock);
-       set_mode(ci, 1);
-       write_pccard(ci, address, &value, 1);
-       mutex_unlock(&ci->lock);
-       return 0;
-}
-
-static int read_cam_control(struct dvb_ca_en50221 *ca,
-                           int slot, u8 address)
-{
-       struct cxd *ci = ca->data;
-       u8 val;
-
-       mutex_lock(&ci->lock);
-       set_mode(ci, 0);
-       read_io(ci, address, &val);
-       mutex_unlock(&ci->lock);
-       return val;
-}
-
-static int write_cam_control(struct dvb_ca_en50221 *ca, int slot,
-                            u8 address, u8 value)
-{
-       struct cxd *ci = ca->data;
-
-       mutex_lock(&ci->lock);
-       set_mode(ci, 0);
-       write_io(ci, address, value);
-       mutex_unlock(&ci->lock);
-       return 0;
-}
-
-static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
-{
-       struct cxd *ci = ca->data;
-
-       mutex_lock(&ci->lock);
-#if 0
-       write_reg(ci, 0x00, 0x21);
-       write_reg(ci, 0x06, 0x1F);
-       write_reg(ci, 0x00, 0x31);
-#else
-#if 0
-       write_reg(ci, 0x06, 0x1F);
-       write_reg(ci, 0x06, 0x2F);
-#else
-       cam_mode(ci, 0);
-       write_reg(ci, 0x00, 0x21);
-       write_reg(ci, 0x06, 0x1F);
-       write_reg(ci, 0x00, 0x31);
-       write_regm(ci, 0x20, 0x80, 0x80);
-       write_reg(ci, 0x03, 0x02);
-       ci->ready = 0;
-#endif
-#endif
-       ci->mode = -1;
-       {
-               int i;
-#if 0
-               u8 val;
-#endif
-               for (i = 0; i < 100; i++) {
-                       msleep(10);
-#if 0
-                       read_reg(ci, 0x06, &val);
-                       printk(KERN_INFO "%d:%02x\n", i, val);
-                       if (!(val&0x10))
-                               break;
-#else
-                       if (ci->ready)
-                               break;
-#endif
-               }
-       }
-       mutex_unlock(&ci->lock);
-       /* msleep(500); */
-       return 0;
-}
-
-static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
-{
-       struct cxd *ci = ca->data;
-
-       printk(KERN_INFO "slot_shutdown\n");
-       mutex_lock(&ci->lock);
-       write_regm(ci, 0x09, 0x08, 0x08);
-       write_regm(ci, 0x20, 0x80, 0x80); /* Reset CAM Mode */
-       write_regm(ci, 0x06, 0x07, 0x07); /* Clear IO Mode */
-       ci->mode = -1;
-       mutex_unlock(&ci->lock);
-       return 0;
-}
-
-static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
-{
-       struct cxd *ci = ca->data;
-
-       mutex_lock(&ci->lock);
-       write_regm(ci, 0x09, 0x00, 0x08);
-       set_mode(ci, 0);
-#ifdef BUFFER_MODE
-       cam_mode(ci, 1);
-#endif
-       mutex_unlock(&ci->lock);
-       return 0;
-}
-
-
-static int campoll(struct cxd *ci)
-{
-       u8 istat;
-
-       read_reg(ci, 0x04, &istat);
-       if (!istat)
-               return 0;
-       write_reg(ci, 0x05, istat);
-
-       if (istat&0x40) {
-               ci->dr = 1;
-               printk(KERN_INFO "DR\n");
-       }
-       if (istat&0x20)
-               printk(KERN_INFO "WC\n");
-
-       if (istat&2) {
-               u8 slotstat;
-
-               read_reg(ci, 0x01, &slotstat);
-               if (!(2&slotstat)) {
-                       if (!ci->slot_stat) {
-                               ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_PRESENT;
-                               write_regm(ci, 0x03, 0x08, 0x08);
-                       }
-
-               } else {
-                       if (ci->slot_stat) {
-                               ci->slot_stat = 0;
-                               write_regm(ci, 0x03, 0x00, 0x08);
-                               printk(KERN_INFO "NO CAM\n");
-                               ci->ready = 0;
-                       }
-               }
-               if (istat&8 && ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) {
-                       ci->ready = 1;
-                       ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY;
-               }
-       }
-       return 0;
-}
-
-
-static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
-{
-       struct cxd *ci = ca->data;
-       u8 slotstat;
-
-       mutex_lock(&ci->lock);
-       campoll(ci);
-       read_reg(ci, 0x01, &slotstat);
-       mutex_unlock(&ci->lock);
-
-       return ci->slot_stat;
-}
-
-#ifdef BUFFER_MODE
-static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
-{
-       struct cxd *ci = ca->data;
-       u8 msb, lsb;
-       u16 len;
-
-       mutex_lock(&ci->lock);
-       campoll(ci);
-       mutex_unlock(&ci->lock);
-
-       printk(KERN_INFO "read_data\n");
-       if (!ci->dr)
-               return 0;
-
-       mutex_lock(&ci->lock);
-       read_reg(ci, 0x0f, &msb);
-       read_reg(ci, 0x10, &lsb);
-       len = (msb<<8)|lsb;
-       read_block(ci, 0x12, ebuf, len);
-       ci->dr = 0;
-       mutex_unlock(&ci->lock);
-
-       return len;
-}
-
-static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
-{
-       struct cxd *ci = ca->data;
-
-       mutex_lock(&ci->lock);
-       printk(kern_INFO "write_data %d\n", ecount);
-       write_reg(ci, 0x0d, ecount>>8);
-       write_reg(ci, 0x0e, ecount&0xff);
-       write_block(ci, 0x11, ebuf, ecount);
-       mutex_unlock(&ci->lock);
-       return ecount;
-}
-#endif
-
-static struct dvb_ca_en50221 en_templ = {
-       .read_attribute_mem  = read_attribute_mem,
-       .write_attribute_mem = write_attribute_mem,
-       .read_cam_control    = read_cam_control,
-       .write_cam_control   = write_cam_control,
-       .slot_reset          = slot_reset,
-       .slot_shutdown       = slot_shutdown,
-       .slot_ts_enable      = slot_ts_enable,
-       .poll_slot_status    = poll_slot_status,
-#ifdef BUFFER_MODE
-       .read_data           = read_data,
-       .write_data          = write_data,
-#endif
-
-};
-
-struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
-                                     void *priv,
-                                     struct i2c_adapter *i2c)
-{
-       struct cxd *ci = 0;
-       u8 val;
-
-       if (i2c_read_reg(i2c, cfg->adr, 0, &val) < 0) {
-               printk(KERN_INFO "No CXD2099 detected at %02x\n", cfg->adr);
-               return 0;
-       }
-
-       ci = kmalloc(sizeof(struct cxd), GFP_KERNEL);
-       if (!ci)
-               return 0;
-       memset(ci, 0, sizeof(*ci));
-
-       mutex_init(&ci->lock);
-       memcpy(&ci->cfg, cfg, sizeof(struct cxd2099_cfg));
-       ci->i2c = i2c;
-       ci->lastaddress = 0xff;
-       ci->clk_reg_b = 0x4a;
-       ci->clk_reg_f = 0x1b;
-
-       memcpy(&ci->en, &en_templ, sizeof(en_templ));
-       ci->en.data = ci;
-       init(ci);
-       printk(KERN_INFO "Attached CXD2099AR at %02x\n", ci->cfg.adr);
-       return &ci->en;
-}
-EXPORT_SYMBOL(cxd2099_attach);
-
-MODULE_DESCRIPTION("cxd2099");
-MODULE_AUTHOR("Ralph Metzler");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/cxd2099/cxd2099.h b/drivers/staging/cxd2099/cxd2099.h
deleted file mode 100644 (file)
index 19c588a..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * cxd2099.h: Driver for the CXD2099AR Common Interface Controller
- *
- * Copyright (C) 2010-2011 Digital Devices GmbH
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#ifndef _CXD2099_H_
-#define _CXD2099_H_
-
-#include <dvb_ca_en50221.h>
-
-struct cxd2099_cfg {
-       u32 bitrate;
-       u8  adr;
-       u8  polarity:1;
-       u8  clock_mode:1;
-};
-
-#if defined(CONFIG_DVB_CXD2099) || \
-       (defined(CONFIG_DVB_CXD2099_MODULE) && defined(MODULE))
-struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
-                                     void *priv, struct i2c_adapter *i2c);
-#else
-
-static inline struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
-                                       void *priv, struct i2c_adapter *i2c)
-{
-       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-       return NULL;
-}
-#endif
-
-#endif
diff --git a/drivers/staging/dt3155v4l/Kconfig b/drivers/staging/dt3155v4l/Kconfig
deleted file mode 100644 (file)
index 226a1ca..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-config VIDEO_DT3155
-       tristate "DT3155 frame grabber, Video4Linux interface"
-       depends on PCI && VIDEO_DEV && VIDEO_V4L2
-       select VIDEOBUF2_DMA_CONTIG
-       default n
-       ---help---
-         Enables dt3155 device driver for the DataTranslation DT3155 frame grabber.
-         Say Y here if you have this hardware.
-         In doubt, say N.
-
-         To compile this driver as a module, choose M here: the
-         module will be called dt3155v4l.
-
-config DT3155_CCIR
-       bool "Selects CCIR/50Hz vertical refresh"
-       depends on VIDEO_DT3155
-       default y
-       ---help---
-         Select it for CCIR/50Hz (European region),
-         or leave it unselected for RS-170/60Hz (North America).
-
-config DT3155_STREAMING
-       bool "Selects streaming capture method"
-       depends on VIDEO_DT3155
-       default y
-       ---help---
-         Select it if you want to use streaming of memory mapped buffers
-         or leave it unselected if you want to use read method (one copy more).
diff --git a/drivers/staging/dt3155v4l/Makefile b/drivers/staging/dt3155v4l/Makefile
deleted file mode 100644 (file)
index ce7a3ec..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_VIDEO_DT3155)     += dt3155v4l.o
diff --git a/drivers/staging/dt3155v4l/dt3155v4l.c b/drivers/staging/dt3155v4l/dt3155v4l.c
deleted file mode 100644 (file)
index 04e93c4..0000000
+++ /dev/null
@@ -1,993 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2006-2010 by Marin Mitov                                *
- *   mitov@issp.bas.bg                                                     *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/stringify.h>
-#include <linux/delay.h>
-#include <linux/kthread.h>
-#include <linux/slab.h>
-#include <media/v4l2-dev.h>
-#include <media/v4l2-ioctl.h>
-#include <media/videobuf2-dma-contig.h>
-
-#include "dt3155v4l.h"
-
-#define DT3155_VENDOR_ID 0x8086
-#define DT3155_DEVICE_ID 0x1223
-
-/* DT3155_CHUNK_SIZE is 4M (2^22) 8 full size buffers */
-#define DT3155_CHUNK_SIZE (1U << 22)
-
-#define DT3155_COH_FLAGS (GFP_KERNEL | GFP_DMA32 | __GFP_COLD | __GFP_NOWARN)
-
-#define DT3155_BUF_SIZE (768 * 576)
-
-#ifdef CONFIG_DT3155_STREAMING
-#define DT3155_CAPTURE_METHOD V4L2_CAP_STREAMING
-#else
-#define DT3155_CAPTURE_METHOD V4L2_CAP_READWRITE
-#endif
-
-/*  global initializers (for all boards)  */
-#ifdef CONFIG_DT3155_CCIR
-static const u8 csr2_init = VT_50HZ;
-#define DT3155_CURRENT_NORM V4L2_STD_625_50
-static const unsigned int img_width = 768;
-static const unsigned int img_height = 576;
-static const unsigned int frames_per_sec = 25;
-static const struct v4l2_fmtdesc frame_std[] = {
-       {
-       .index = 0,
-       .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-       .flags = 0,
-       .description = "CCIR/50Hz 8 bits gray",
-       .pixelformat = V4L2_PIX_FMT_GREY,
-       },
-};
-#else
-static const u8 csr2_init = VT_60HZ;
-#define DT3155_CURRENT_NORM V4L2_STD_525_60
-static const unsigned int img_width = 640;
-static const unsigned int img_height = 480;
-static const unsigned int frames_per_sec = 30;
-static const struct v4l2_fmtdesc frame_std[] = {
-       {
-       .index = 0,
-       .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-       .flags = 0,
-       .description = "RS-170/60Hz 8 bits gray",
-       .pixelformat = V4L2_PIX_FMT_GREY,
-       },
-};
-#endif
-
-#define NUM_OF_FORMATS ARRAY_SIZE(frame_std)
-
-static u8 config_init = ACQ_MODE_EVEN;
-
-/**
- * read_i2c_reg - reads an internal i2c register
- *
- * @addr:      dt3155 mmio base address
- * @index:     index (internal address) of register to read
- * @data:      pointer to byte the read data will be placed in
- *
- * returns:    zero on success or error code
- *
- * This function starts reading the specified (by index) register
- * and busy waits for the process to finish. The result is placed
- * in a byte pointed by data.
- */
-static int
-read_i2c_reg(void __iomem *addr, u8 index, u8 *data)
-{
-       u32 tmp = index;
-
-       iowrite32((tmp<<17) | IIC_READ, addr + IIC_CSR2);
-       mmiowb();
-       udelay(45); /* wait at least 43 usec for NEW_CYCLE to clear */
-       if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
-               return -EIO; /* error: NEW_CYCLE not cleared */
-       tmp = ioread32(addr + IIC_CSR1);
-       if (tmp & DIRECT_ABORT) {
-               /* reset DIRECT_ABORT bit */
-               iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
-               return -EIO; /* error: DIRECT_ABORT set */
-       }
-       *data = tmp>>24;
-       return 0;
-}
-
-/**
- * write_i2c_reg - writes to an internal i2c register
- *
- * @addr:      dt3155 mmio base address
- * @index:     index (internal address) of register to read
- * @data:      data to be written
- *
- * returns:    zero on success or error code
- *
- * This function starts writting the specified (by index) register
- * and busy waits for the process to finish.
- */
-static int
-write_i2c_reg(void __iomem *addr, u8 index, u8 data)
-{
-       u32 tmp = index;
-
-       iowrite32((tmp<<17) | IIC_WRITE | data, addr + IIC_CSR2);
-       mmiowb();
-       udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */
-       if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
-               return -EIO; /* error: NEW_CYCLE not cleared */
-       if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
-               /* reset DIRECT_ABORT bit */
-               iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
-               return -EIO; /* error: DIRECT_ABORT set */
-       }
-       return 0;
-}
-
-/**
- * write_i2c_reg_nowait - writes to an internal i2c register
- *
- * @addr:      dt3155 mmio base address
- * @index:     index (internal address) of register to read
- * @data:      data to be written
- *
- * This function starts writting the specified (by index) register
- * and then returns.
- */
-static void write_i2c_reg_nowait(void __iomem *addr, u8 index, u8 data)
-{
-       u32 tmp = index;
-
-       iowrite32((tmp<<17) | IIC_WRITE | data, addr + IIC_CSR2);
-       mmiowb();
-}
-
-/**
- * wait_i2c_reg - waits the read/write to finish
- *
- * @addr:      dt3155 mmio base address
- *
- * returns:    zero on success or error code
- *
- * This function waits reading/writting to finish.
- */
-static int wait_i2c_reg(void __iomem *addr)
-{
-       if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
-               udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */
-       if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
-               return -EIO; /* error: NEW_CYCLE not cleared */
-       if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
-               /* reset DIRECT_ABORT bit */
-               iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
-               return -EIO; /* error: DIRECT_ABORT set */
-       }
-       return 0;
-}
-
-static int
-dt3155_start_acq(struct dt3155_priv *pd)
-{
-       struct vb2_buffer *vb = pd->curr_buf;
-       dma_addr_t dma_addr;
-
-       dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
-       iowrite32(dma_addr, pd->regs + EVEN_DMA_START);
-       iowrite32(dma_addr + img_width, pd->regs + ODD_DMA_START);
-       iowrite32(img_width, pd->regs + EVEN_DMA_STRIDE);
-       iowrite32(img_width, pd->regs + ODD_DMA_STRIDE);
-       /* enable interrupts, clear all irq flags */
-       iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
-                       FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR);
-       iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
-                 FLD_DN_ODD | FLD_DN_EVEN | CAP_CONT_EVEN | CAP_CONT_ODD,
-                                                       pd->regs + CSR1);
-       wait_i2c_reg(pd->regs);
-       write_i2c_reg(pd->regs, CONFIG, pd->config);
-       write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE);
-       write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_DONE);
-
-       /*  start the board  */
-       write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | BUSY_ODD);
-       return 0; /* success  */
-}
-
-/*
- *     driver-specific callbacks (vb2_ops)
- */
-static int
-dt3155_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
-                       unsigned int *num_planes, unsigned long sizes[],
-                                               void *alloc_ctxs[])
-{
-       struct dt3155_priv *pd = vb2_get_drv_priv(q);
-       void *ret;
-
-       if (*num_buffers == 0)
-               *num_buffers = 1;
-       *num_planes = 1;
-       sizes[0] = img_width * img_height;
-       if (pd->q->alloc_ctx[0])
-               return 0;
-       ret = vb2_dma_contig_init_ctx(&pd->pdev->dev);
-       if (IS_ERR(ret))
-               return PTR_ERR(ret);
-       pd->q->alloc_ctx[0] = ret;
-       return 0;
-}
-
-static void
-dt3155_wait_prepare(struct vb2_queue *q)
-{
-       struct dt3155_priv *pd = vb2_get_drv_priv(q);
-
-       mutex_unlock(pd->vdev->lock);
-}
-
-static void
-dt3155_wait_finish(struct vb2_queue *q)
-{
-       struct dt3155_priv *pd = vb2_get_drv_priv(q);
-
-       mutex_lock(pd->vdev->lock);
-}
-
-static int
-dt3155_buf_prepare(struct vb2_buffer *vb)
-{
-       vb2_set_plane_payload(vb, 0, img_width * img_height);
-       return 0;
-}
-
-static int
-dt3155_start_streaming(struct vb2_queue *q)
-{
-       return 0;
-}
-
-static int
-dt3155_stop_streaming(struct vb2_queue *q)
-{
-       struct dt3155_priv *pd = vb2_get_drv_priv(q);
-       struct vb2_buffer *vb;
-
-       spin_lock_irq(&pd->lock);
-       while (!list_empty(&pd->dmaq)) {
-               vb = list_first_entry(&pd->dmaq, typeof(*vb), done_entry);
-               list_del(&vb->done_entry);
-               vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
-       }
-       spin_unlock_irq(&pd->lock);
-       msleep(45); /* irq hendler will stop the hardware */
-       return 0;
-}
-
-static void
-dt3155_buf_queue(struct vb2_buffer *vb)
-{
-       struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue);
-
-       /*  pd->q->streaming = 1 when dt3155_buf_queue() is invoked  */
-       spin_lock_irq(&pd->lock);
-       if (pd->curr_buf)
-               list_add_tail(&vb->done_entry, &pd->dmaq);
-       else {
-               pd->curr_buf = vb;
-               dt3155_start_acq(pd);
-       }
-       spin_unlock_irq(&pd->lock);
-}
-/*
- *     end driver-specific callbacks
- */
-
-const struct vb2_ops q_ops = {
-       .queue_setup = dt3155_queue_setup,
-       .wait_prepare = dt3155_wait_prepare,
-       .wait_finish = dt3155_wait_finish,
-       .buf_prepare = dt3155_buf_prepare,
-       .start_streaming = dt3155_start_streaming,
-       .stop_streaming = dt3155_stop_streaming,
-       .buf_queue = dt3155_buf_queue,
-};
-
-static irqreturn_t
-dt3155_irq_handler_even(int irq, void *dev_id)
-{
-       struct dt3155_priv *ipd = dev_id;
-       struct vb2_buffer *ivb;
-       dma_addr_t dma_addr;
-       u32 tmp;
-
-       tmp = ioread32(ipd->regs + INT_CSR) & (FLD_START | FLD_END_ODD);
-       if (!tmp)
-               return IRQ_NONE;  /* not our irq */
-       if ((tmp & FLD_START) && !(tmp & FLD_END_ODD)) {
-               iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START,
-                                                       ipd->regs + INT_CSR);
-               ipd->field_count++;
-               return IRQ_HANDLED; /* start of field irq */
-       }
-       if ((tmp & FLD_START) && (tmp & FLD_END_ODD))
-               ipd->stats.start_before_end++;
-       /*      check for corrupted fields     */
-/*     write_i2c_reg(ipd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE);       */
-/*     write_i2c_reg(ipd->regs, ODD_CSR, CSR_ERROR | CSR_DONE);        */
-       tmp = ioread32(ipd->regs + CSR1) & (FLD_CRPT_EVEN | FLD_CRPT_ODD);
-       if (tmp) {
-               ipd->stats.corrupted_fields++;
-               iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
-                                               FLD_DN_ODD | FLD_DN_EVEN |
-                                               CAP_CONT_EVEN | CAP_CONT_ODD,
-                                                       ipd->regs + CSR1);
-               mmiowb();
-       }
-
-       spin_lock(&ipd->lock);
-       if (ipd->curr_buf) {
-               do_gettimeofday(&ipd->curr_buf->v4l2_buf.timestamp);
-               ipd->curr_buf->v4l2_buf.sequence = (ipd->field_count) >> 1;
-               vb2_buffer_done(ipd->curr_buf, VB2_BUF_STATE_DONE);
-       }
-
-       if (!ipd->q->streaming || list_empty(&ipd->dmaq))
-               goto stop_dma;
-       ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), done_entry);
-       list_del(&ivb->done_entry);
-       ipd->curr_buf = ivb;
-       dma_addr = vb2_dma_contig_plane_dma_addr(ivb, 0);
-       iowrite32(dma_addr, ipd->regs + EVEN_DMA_START);
-       iowrite32(dma_addr + img_width, ipd->regs + ODD_DMA_START);
-       iowrite32(img_width, ipd->regs + EVEN_DMA_STRIDE);
-       iowrite32(img_width, ipd->regs + ODD_DMA_STRIDE);
-       mmiowb();
-       /* enable interrupts, clear all irq flags */
-       iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
-                       FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR);
-       spin_unlock(&ipd->lock);
-       return IRQ_HANDLED;
-
-stop_dma:
-       ipd->curr_buf = NULL;
-       /* stop the board */
-       write_i2c_reg_nowait(ipd->regs, CSR2, ipd->csr2);
-       iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
-                 FLD_DN_ODD | FLD_DN_EVEN, ipd->regs + CSR1);
-       /* disable interrupts, clear all irq flags */
-       iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR);
-       spin_unlock(&ipd->lock);
-       return IRQ_HANDLED;
-}
-
-static int
-dt3155_open(struct file *filp)
-{
-       int ret = 0;
-       struct dt3155_priv *pd = video_drvdata(filp);
-
-       if (!pd->users) {
-               pd->q = kzalloc(sizeof(*pd->q), GFP_KERNEL);
-               if (!pd->q) {
-                       ret = -ENOMEM;
-                       goto err_alloc_queue;
-               }
-               pd->q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               pd->q->io_modes = VB2_READ | VB2_MMAP;
-               pd->q->ops = &q_ops;
-               pd->q->mem_ops = &vb2_dma_contig_memops;
-               pd->q->drv_priv = pd;
-               pd->curr_buf = NULL;
-               pd->field_count = 0;
-               vb2_queue_init(pd->q); /* cannot fail */
-               INIT_LIST_HEAD(&pd->dmaq);
-               spin_lock_init(&pd->lock);
-               /* disable all irqs, clear all irq flags */
-               iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD,
-                                               pd->regs + INT_CSR);
-               ret = request_irq(pd->pdev->irq, dt3155_irq_handler_even,
-                                               IRQF_SHARED, DT3155_NAME, pd);
-               if (ret)
-                       goto err_request_irq;
-       }
-       pd->users++;
-       return 0; /* success */
-err_request_irq:
-       kfree(pd->q);
-       pd->q = NULL;
-err_alloc_queue:
-       return ret;
-}
-
-static int
-dt3155_release(struct file *filp)
-{
-       struct dt3155_priv *pd = video_drvdata(filp);
-
-       pd->users--;
-       BUG_ON(pd->users < 0);
-       if (!pd->users) {
-               vb2_queue_release(pd->q);
-               free_irq(pd->pdev->irq, pd);
-               if (pd->q->alloc_ctx[0])
-                       vb2_dma_contig_cleanup_ctx(pd->q->alloc_ctx[0]);
-               kfree(pd->q);
-               pd->q = NULL;
-       }
-       return 0;
-}
-
-static ssize_t
-dt3155_read(struct file *filp, char __user *user, size_t size, loff_t *loff)
-{
-       struct dt3155_priv *pd = video_drvdata(filp);
-
-       return vb2_read(pd->q, user, size, loff, filp->f_flags & O_NONBLOCK);
-}
-
-static unsigned int
-dt3155_poll(struct file *filp, struct poll_table_struct *polltbl)
-{
-       struct dt3155_priv *pd = video_drvdata(filp);
-
-       return vb2_poll(pd->q, filp, polltbl);
-}
-
-static int
-dt3155_mmap(struct file *filp, struct vm_area_struct *vma)
-{
-       struct dt3155_priv *pd = video_drvdata(filp);
-
-       return vb2_mmap(pd->q, vma);
-}
-
-static const struct v4l2_file_operations dt3155_fops = {
-       .owner = THIS_MODULE,
-       .open = dt3155_open,
-       .release = dt3155_release,
-       .read = dt3155_read,
-       .poll = dt3155_poll,
-       .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
-       .mmap = dt3155_mmap,
-};
-
-static int
-dt3155_ioc_streamon(struct file *filp, void *p, enum v4l2_buf_type type)
-{
-       struct dt3155_priv *pd = video_drvdata(filp);
-
-       return vb2_streamon(pd->q, type);
-}
-
-static int
-dt3155_ioc_streamoff(struct file *filp, void *p, enum v4l2_buf_type type)
-{
-       struct dt3155_priv *pd = video_drvdata(filp);
-
-       return vb2_streamoff(pd->q, type);
-}
-
-static int
-dt3155_ioc_querycap(struct file *filp, void *p, struct v4l2_capability *cap)
-{
-       struct dt3155_priv *pd = video_drvdata(filp);
-
-       strcpy(cap->driver, DT3155_NAME);
-       strcpy(cap->card, DT3155_NAME " frame grabber");
-       sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev));
-       cap->version =
-              KERNEL_VERSION(DT3155_VER_MAJ, DT3155_VER_MIN, DT3155_VER_EXT);
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-                               DT3155_CAPTURE_METHOD;
-       return 0;
-}
-
-static int
-dt3155_ioc_enum_fmt_vid_cap(struct file *filp, void *p, struct v4l2_fmtdesc *f)
-{
-       if (f->index >= NUM_OF_FORMATS)
-               return -EINVAL;
-       *f = frame_std[f->index];
-       return 0;
-}
-
-static int
-dt3155_ioc_g_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
-{
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       f->fmt.pix.width = img_width;
-       f->fmt.pix.height = img_height;
-       f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
-       f->fmt.pix.field = V4L2_FIELD_NONE;
-       f->fmt.pix.bytesperline = f->fmt.pix.width;
-       f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height;
-       f->fmt.pix.colorspace = 0;
-       f->fmt.pix.priv = 0;
-       return 0;
-}
-
-static int
-dt3155_ioc_try_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
-{
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (f->fmt.pix.width == img_width &&
-               f->fmt.pix.height == img_height &&
-               f->fmt.pix.pixelformat == V4L2_PIX_FMT_GREY &&
-               f->fmt.pix.field == V4L2_FIELD_NONE &&
-               f->fmt.pix.bytesperline == f->fmt.pix.width &&
-               f->fmt.pix.sizeimage == f->fmt.pix.width * f->fmt.pix.height)
-                       return 0;
-       else
-               return -EINVAL;
-}
-
-static int
-dt3155_ioc_s_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
-{
-       return dt3155_ioc_g_fmt_vid_cap(filp, p, f);
-}
-
-static int
-dt3155_ioc_reqbufs(struct file *filp, void *p, struct v4l2_requestbuffers *b)
-{
-       struct dt3155_priv *pd = video_drvdata(filp);
-
-       return vb2_reqbufs(pd->q, b);
-}
-
-static int
-dt3155_ioc_querybuf(struct file *filp, void *p, struct v4l2_buffer *b)
-{
-       struct dt3155_priv *pd = video_drvdata(filp);
-
-       return vb2_querybuf(pd->q, b);
-}
-
-static int
-dt3155_ioc_qbuf(struct file *filp, void *p, struct v4l2_buffer *b)
-{
-       struct dt3155_priv *pd = video_drvdata(filp);
-
-       return vb2_qbuf(pd->q, b);
-}
-
-static int
-dt3155_ioc_dqbuf(struct file *filp, void *p, struct v4l2_buffer *b)
-{
-       struct dt3155_priv *pd = video_drvdata(filp);
-
-       return vb2_dqbuf(pd->q, b, filp->f_flags & O_NONBLOCK);
-}
-
-static int
-dt3155_ioc_querystd(struct file *filp, void *p, v4l2_std_id *norm)
-{
-       *norm = DT3155_CURRENT_NORM;
-       return 0;
-}
-
-static int
-dt3155_ioc_g_std(struct file *filp, void *p, v4l2_std_id *norm)
-{
-       *norm = DT3155_CURRENT_NORM;
-       return 0;
-}
-
-static int
-dt3155_ioc_s_std(struct file *filp, void *p, v4l2_std_id *norm)
-{
-       if (*norm & DT3155_CURRENT_NORM)
-               return 0;
-       return -EINVAL;
-}
-
-static int
-dt3155_ioc_enum_input(struct file *filp, void *p, struct v4l2_input *input)
-{
-       if (input->index)
-               return -EINVAL;
-       strcpy(input->name, "Coax in");
-       input->type = V4L2_INPUT_TYPE_CAMERA;
-       /*
-        * FIXME: input->std = 0 according to v4l2 API
-        * VIDIOC_G_STD, VIDIOC_S_STD, VIDIOC_QUERYSTD and VIDIOC_ENUMSTD
-        * should return -EINVAL
-        */
-       input->std = DT3155_CURRENT_NORM;
-       input->status = 0;/* FIXME: add sync detection & V4L2_IN_ST_NO_H_LOCK */
-       return 0;
-}
-
-static int
-dt3155_ioc_g_input(struct file *filp, void *p, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int
-dt3155_ioc_s_input(struct file *filp, void *p, unsigned int i)
-{
-       if (i)
-               return -EINVAL;
-       return 0;
-}
-
-static int
-dt3155_ioc_g_parm(struct file *filp, void *p, struct v4l2_streamparm *parms)
-{
-       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       parms->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-       parms->parm.capture.capturemode = 0;
-       parms->parm.capture.timeperframe.numerator = 1001;
-       parms->parm.capture.timeperframe.denominator = frames_per_sec * 1000;
-       parms->parm.capture.extendedmode = 0;
-       parms->parm.capture.readbuffers = 1; /* FIXME: 2 buffers? */
-       return 0;
-}
-
-static int
-dt3155_ioc_s_parm(struct file *filp, void *p, struct v4l2_streamparm *parms)
-{
-       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       parms->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-       parms->parm.capture.capturemode = 0;
-       parms->parm.capture.timeperframe.numerator = 1001;
-       parms->parm.capture.timeperframe.denominator = frames_per_sec * 1000;
-       parms->parm.capture.extendedmode = 0;
-       parms->parm.capture.readbuffers = 1; /* FIXME: 2 buffers? */
-       return 0;
-}
-
-static const struct v4l2_ioctl_ops dt3155_ioctl_ops = {
-       .vidioc_streamon = dt3155_ioc_streamon,
-       .vidioc_streamoff = dt3155_ioc_streamoff,
-       .vidioc_querycap = dt3155_ioc_querycap,
-/*
-       .vidioc_g_priority = dt3155_ioc_g_priority,
-       .vidioc_s_priority = dt3155_ioc_s_priority,
-*/
-       .vidioc_enum_fmt_vid_cap = dt3155_ioc_enum_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = dt3155_ioc_try_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap = dt3155_ioc_g_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap = dt3155_ioc_s_fmt_vid_cap,
-       .vidioc_reqbufs = dt3155_ioc_reqbufs,
-       .vidioc_querybuf = dt3155_ioc_querybuf,
-       .vidioc_qbuf = dt3155_ioc_qbuf,
-       .vidioc_dqbuf = dt3155_ioc_dqbuf,
-       .vidioc_querystd = dt3155_ioc_querystd,
-       .vidioc_g_std = dt3155_ioc_g_std,
-       .vidioc_s_std = dt3155_ioc_s_std,
-       .vidioc_enum_input = dt3155_ioc_enum_input,
-       .vidioc_g_input = dt3155_ioc_g_input,
-       .vidioc_s_input = dt3155_ioc_s_input,
-/*
-       .vidioc_queryctrl = dt3155_ioc_queryctrl,
-       .vidioc_g_ctrl = dt3155_ioc_g_ctrl,
-       .vidioc_s_ctrl = dt3155_ioc_s_ctrl,
-       .vidioc_querymenu = dt3155_ioc_querymenu,
-       .vidioc_g_ext_ctrls = dt3155_ioc_g_ext_ctrls,
-       .vidioc_s_ext_ctrls = dt3155_ioc_s_ext_ctrls,
-*/
-       .vidioc_g_parm = dt3155_ioc_g_parm,
-       .vidioc_s_parm = dt3155_ioc_s_parm,
-/*
-       .vidioc_cropcap = dt3155_ioc_cropcap,
-       .vidioc_g_crop = dt3155_ioc_g_crop,
-       .vidioc_s_crop = dt3155_ioc_s_crop,
-       .vidioc_enum_framesizes = dt3155_ioc_enum_framesizes,
-       .vidioc_enum_frameintervals = dt3155_ioc_enum_frameintervals,
-*/
-};
-
-static int __devinit
-dt3155_init_board(struct pci_dev *pdev)
-{
-       struct dt3155_priv *pd = pci_get_drvdata(pdev);
-       void *buf_cpu;
-       dma_addr_t buf_dma;
-       int i;
-       u8 tmp;
-
-       pci_set_master(pdev); /* dt3155 needs it */
-
-       /*  resetting the adapter  */
-       iowrite32(FLD_CRPT_ODD | FLD_CRPT_EVEN | FLD_DN_ODD | FLD_DN_EVEN,
-                                                       pd->regs + CSR1);
-       mmiowb();
-       msleep(20);
-
-       /*  initializing adaper registers  */
-       iowrite32(FIFO_EN | SRST, pd->regs + CSR1);
-       mmiowb();
-       iowrite32(0xEEEEEE01, pd->regs + EVEN_PIXEL_FMT);
-       iowrite32(0xEEEEEE01, pd->regs + ODD_PIXEL_FMT);
-       iowrite32(0x00000020, pd->regs + FIFO_TRIGER);
-       iowrite32(0x00000103, pd->regs + XFER_MODE);
-       iowrite32(0, pd->regs + RETRY_WAIT_CNT);
-       iowrite32(0, pd->regs + INT_CSR);
-       iowrite32(1, pd->regs + EVEN_FLD_MASK);
-       iowrite32(1, pd->regs + ODD_FLD_MASK);
-       iowrite32(0, pd->regs + MASK_LENGTH);
-       iowrite32(0x0005007C, pd->regs + FIFO_FLAG_CNT);
-       iowrite32(0x01010101, pd->regs + IIC_CLK_DUR);
-       mmiowb();
-
-       /* verifying that we have a DT3155 board (not just a SAA7116 chip) */
-       read_i2c_reg(pd->regs, DT_ID, &tmp);
-       if (tmp != DT3155_ID)
-               return -ENODEV;
-
-       /* initialize AD LUT */
-       write_i2c_reg(pd->regs, AD_ADDR, 0);
-       for (i = 0; i < 256; i++)
-               write_i2c_reg(pd->regs, AD_LUT, i);
-
-       /* initialize ADC references */
-       /* FIXME: pos_ref & neg_ref depend on VT_50HZ */
-       write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
-       write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
-       write_i2c_reg(pd->regs, AD_ADDR, AD_POS_REF);
-       write_i2c_reg(pd->regs, AD_CMD, 34);
-       write_i2c_reg(pd->regs, AD_ADDR, AD_NEG_REF);
-       write_i2c_reg(pd->regs, AD_CMD, 0);
-
-       /* initialize PM LUT */
-       write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM);
-       for (i = 0; i < 256; i++) {
-               write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
-               write_i2c_reg(pd->regs, PM_LUT_DATA, i);
-       }
-       write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM | PM_LUT_SEL);
-       for (i = 0; i < 256; i++) {
-               write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
-               write_i2c_reg(pd->regs, PM_LUT_DATA, i);
-       }
-       write_i2c_reg(pd->regs, CONFIG, pd->config); /*  ACQ_MODE_EVEN  */
-
-       /* select chanel 1 for input and set sync level */
-       write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
-       write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
-
-       /* allocate memory, and initialize the DMA machine */
-       buf_cpu = dma_alloc_coherent(&pdev->dev, DT3155_BUF_SIZE, &buf_dma,
-                                                               GFP_KERNEL);
-       if (!buf_cpu)
-               return -ENOMEM;
-       iowrite32(buf_dma, pd->regs + EVEN_DMA_START);
-       iowrite32(buf_dma, pd->regs + ODD_DMA_START);
-       iowrite32(0, pd->regs + EVEN_DMA_STRIDE);
-       iowrite32(0, pd->regs + ODD_DMA_STRIDE);
-
-       /*  Perform a pseudo even field acquire    */
-       iowrite32(FIFO_EN | SRST | CAP_CONT_ODD, pd->regs + CSR1);
-       write_i2c_reg(pd->regs, CSR2, pd->csr2 | SYNC_SNTL);
-       write_i2c_reg(pd->regs, CONFIG, pd->config);
-       write_i2c_reg(pd->regs, EVEN_CSR, CSR_SNGL);
-       write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | SYNC_SNTL);
-       msleep(100);
-       read_i2c_reg(pd->regs, CSR2, &tmp);
-       write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_SNGL | CSR_DONE);
-       write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_SNGL | CSR_DONE);
-       write_i2c_reg(pd->regs, CSR2, pd->csr2);
-       iowrite32(FIFO_EN | SRST | FLD_DN_EVEN | FLD_DN_ODD, pd->regs + CSR1);
-
-       /*  deallocate memory  */
-       dma_free_coherent(&pdev->dev, DT3155_BUF_SIZE, buf_cpu, buf_dma);
-       if (tmp & BUSY_EVEN)
-               return -EIO;
-       return 0;
-}
-
-static struct video_device dt3155_vdev = {
-       .name = DT3155_NAME,
-       .fops = &dt3155_fops,
-       .ioctl_ops = &dt3155_ioctl_ops,
-       .minor = -1,
-       .release = video_device_release,
-       .tvnorms = DT3155_CURRENT_NORM,
-       .current_norm = DT3155_CURRENT_NORM,
-};
-
-/* same as in drivers/base/dma-coherent.c */
-struct dma_coherent_mem {
-       void            *virt_base;
-       dma_addr_t      device_base;
-       int             size;
-       int             flags;
-       unsigned long   *bitmap;
-};
-
-static int __devinit
-dt3155_alloc_coherent(struct device *dev, size_t size, int flags)
-{
-       struct dma_coherent_mem *mem;
-       dma_addr_t dev_base;
-       int pages = size >> PAGE_SHIFT;
-       int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
-
-       if ((flags & DMA_MEMORY_MAP) == 0)
-               goto out;
-       if (!size)
-               goto out;
-       if (dev->dma_mem)
-               goto out;
-
-       mem = kzalloc(sizeof(*mem), GFP_KERNEL);
-       if (!mem)
-               goto out;
-       mem->virt_base = dma_alloc_coherent(dev, size, &dev_base,
-                                                       DT3155_COH_FLAGS);
-       if (!mem->virt_base)
-               goto err_alloc_coherent;
-       mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
-       if (!mem->bitmap)
-               goto err_bitmap;
-
-       /* coherent_dma_mask is already set to 32 bits */
-       mem->device_base = dev_base;
-       mem->size = pages;
-       mem->flags = flags;
-       dev->dma_mem = mem;
-       return DMA_MEMORY_MAP;
-
-err_bitmap:
-       dma_free_coherent(dev, size, mem->virt_base, dev_base);
-err_alloc_coherent:
-       kfree(mem);
-out:
-       return 0;
-}
-
-static void __devexit
-dt3155_free_coherent(struct device *dev)
-{
-       struct dma_coherent_mem *mem = dev->dma_mem;
-
-       if (!mem)
-               return;
-       dev->dma_mem = NULL;
-       dma_free_coherent(dev, mem->size << PAGE_SHIFT,
-                                       mem->virt_base, mem->device_base);
-       kfree(mem->bitmap);
-       kfree(mem);
-}
-
-static int __devinit
-dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-       int err;
-       struct dt3155_priv *pd;
-
-       err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
-       if (err)
-               return -ENODEV;
-       err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
-       if (err)
-               return -ENODEV;
-       pd = kzalloc(sizeof(*pd), GFP_KERNEL);
-       if (!pd)
-               return -ENOMEM;
-       pd->vdev = video_device_alloc();
-       if (!pd->vdev)
-               goto err_video_device_alloc;
-       *pd->vdev = dt3155_vdev;
-       pci_set_drvdata(pdev, pd);    /* for use in dt3155_remove() */
-       video_set_drvdata(pd->vdev, pd);  /* for use in video_fops */
-       pd->users = 0;
-       pd->pdev = pdev;
-       INIT_LIST_HEAD(&pd->dmaq);
-       mutex_init(&pd->mux);
-       pd->vdev->lock = &pd->mux; /* for locking v4l2_file_operations */
-       spin_lock_init(&pd->lock);
-       pd->csr2 = csr2_init;
-       pd->config = config_init;
-       err = pci_enable_device(pdev);
-       if (err)
-               goto err_enable_dev;
-       err = pci_request_region(pdev, 0, pci_name(pdev));
-       if (err)
-               goto err_req_region;
-       pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0));
-       if (!pd->regs)
-               err = -ENOMEM;
-               goto err_pci_iomap;
-       err = dt3155_init_board(pdev);
-       if (err)
-               goto err_init_board;
-       err = video_register_device(pd->vdev, VFL_TYPE_GRABBER, -1);
-       if (err)
-               goto err_init_board;
-       if (dt3155_alloc_coherent(&pdev->dev, DT3155_CHUNK_SIZE,
-                                                       DMA_MEMORY_MAP))
-               dev_info(&pdev->dev, "preallocated 8 buffers\n");
-       dev_info(&pdev->dev, "/dev/video%i is ready\n", pd->vdev->minor);
-       return 0;  /*   success   */
-
-err_init_board:
-       pci_iounmap(pdev, pd->regs);
-err_pci_iomap:
-       pci_release_region(pdev, 0);
-err_req_region:
-       pci_disable_device(pdev);
-err_enable_dev:
-       video_device_release(pd->vdev);
-err_video_device_alloc:
-       kfree(pd);
-       return err;
-}
-
-static void __devexit
-dt3155_remove(struct pci_dev *pdev)
-{
-       struct dt3155_priv *pd = pci_get_drvdata(pdev);
-
-       dt3155_free_coherent(&pdev->dev);
-       video_unregister_device(pd->vdev);
-       pci_iounmap(pdev, pd->regs);
-       pci_release_region(pdev, 0);
-       pci_disable_device(pdev);
-       /*
-        * video_device_release() is invoked automatically
-        * see: struct video_device dt3155_vdev
-        */
-       kfree(pd);
-}
-
-static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
-       { PCI_DEVICE(DT3155_VENDOR_ID, DT3155_DEVICE_ID) },
-       { 0, /* zero marks the end */ },
-};
-MODULE_DEVICE_TABLE(pci, pci_ids);
-
-static struct pci_driver pci_driver = {
-       .name = DT3155_NAME,
-       .id_table = pci_ids,
-       .probe = dt3155_probe,
-       .remove = __devexit_p(dt3155_remove),
-};
-
-static int __init
-dt3155_init_module(void)
-{
-       return pci_register_driver(&pci_driver);
-}
-
-static void __exit
-dt3155_exit_module(void)
-{
-       pci_unregister_driver(&pci_driver);
-}
-
-module_init(dt3155_init_module);
-module_exit(dt3155_exit_module);
-
-MODULE_DESCRIPTION("video4linux pci-driver for dt3155 frame grabber");
-MODULE_AUTHOR("Marin Mitov <mitov@issp.bas.bg>");
-MODULE_VERSION(DT3155_VERSION);
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/dt3155v4l/dt3155v4l.h b/drivers/staging/dt3155v4l/dt3155v4l.h
deleted file mode 100644 (file)
index 2e4f89d..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2006-2010 by Marin Mitov                                *
- *   mitov@issp.bas.bg                                                     *
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- *   This program is distributed in the hope that it will be useful,       *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
- *   GNU General Public License for more details.                          *
- *                                                                         *
- *   You should have received a copy of the GNU General Public License     *
- *   along with this program; if not, write to the                         *
- *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
- ***************************************************************************/
-
-/*    DT3155 header file    */
-#ifndef _DT3155_H_
-#define _DT3155_H_
-
-#ifdef __KERNEL__
-
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-
-#define DT3155_NAME "dt3155"
-#define DT3155_VER_MAJ 1
-#define DT3155_VER_MIN 1
-#define DT3155_VER_EXT 0
-#define DT3155_VERSION  __stringify(DT3155_VER_MAJ)    "."             \
-                       __stringify(DT3155_VER_MIN)     "."             \
-                       __stringify(DT3155_VER_EXT)
-
-/* DT3155 Base Register offsets (memory mapped) */
-#define EVEN_DMA_START  0x00
-#define ODD_DMA_START   0x0C
-#define EVEN_DMA_STRIDE  0x18
-#define ODD_DMA_STRIDE  0x24
-#define EVEN_PIXEL_FMT  0x30
-#define ODD_PIXEL_FMT   0x34
-#define FIFO_TRIGER     0x38
-#define XFER_MODE       0x3C
-#define CSR1            0x40
-#define RETRY_WAIT_CNT  0x44
-#define INT_CSR                 0x48
-#define EVEN_FLD_MASK   0x4C
-#define ODD_FLD_MASK    0x50
-#define MASK_LENGTH     0x54
-#define FIFO_FLAG_CNT   0x58
-#define IIC_CLK_DUR     0x5C
-#define IIC_CSR1        0x60
-#define IIC_CSR2        0x64
-
-/*  DT3155 Internal Registers indexes (i2c/IIC mapped) */
-#define CSR2        0x10
-#define EVEN_CSR     0x11
-#define ODD_CSR      0x12
-#define CONFIG      0x13
-#define DT_ID       0x1F
-#define X_CLIP_START 0x20
-#define Y_CLIP_START 0x22
-#define X_CLIP_END   0x24
-#define Y_CLIP_END   0x26
-#define AD_ADDR      0x30
-#define AD_LUT      0x31
-#define AD_CMD      0x32
-#define DIG_OUT      0x40
-#define PM_LUT_ADDR  0x50
-#define PM_LUT_DATA  0x51
-
-/* AD command register values  */
-#define AD_CMD_REG   0x00
-#define AD_POS_REF   0x01
-#define AD_NEG_REF   0x02
-
-/* CSR1 bit masks */
-#define CRPT_DIS       0x00004000
-#define FLD_CRPT_ODD   0x00000200
-#define FLD_CRPT_EVEN  0x00000100
-#define FIFO_EN        0x00000080
-#define SRST          0x00000040
-#define FLD_DN_ODD     0x00000020
-#define FLD_DN_EVEN    0x00000010
-/*   These should not be used.
- *   Use CAP_CONT_ODD/EVEN instead
-#define CAP_SNGL_ODD   0x00000008
-#define CAP_SNGL_EVEN  0x00000004
-*/
-#define CAP_CONT_ODD   0x00000002
-#define CAP_CONT_EVEN  0x00000001
-
-/*  INT_CSR bit masks */
-#define FLD_START_EN    0x00000400
-#define FLD_END_ODD_EN  0x00000200
-#define FLD_END_EVEN_EN  0x00000100
-#define FLD_START       0x00000004
-#define FLD_END_ODD     0x00000002
-#define FLD_END_EVEN    0x00000001
-
-/* IIC_CSR1 bit masks */
-#define DIRECT_ABORT    0x00000200
-
-/* IIC_CSR2 bit masks */
-#define NEW_CYCLE   0x01000000
-#define DIR_RD     0x00010000
-#define IIC_READ    0x01010000
-#define IIC_WRITE   0x01000000
-
-/* CSR2 bit masks */
-#define DISP_PASS     0x40
-#define BUSY_ODD      0x20
-#define BUSY_EVEN     0x10
-#define SYNC_PRESENT  0x08
-#define VT_50HZ       0x04
-#define SYNC_SNTL     0x02
-#define CHROM_FILT    0x01
-#define VT_60HZ       0x00
-
-/* CSR_EVEN/ODD bit masks */
-#define CSR_ERROR      0x04
-#define CSR_SNGL       0x02
-#define CSR_DONE       0x01
-
-/* CONFIG bit masks */
-#define PM_LUT_PGM     0x80
-#define PM_LUT_SEL     0x40
-#define CLIP_EN        0x20
-#define HSCALE_EN      0x10
-#define EXT_TRIG_UP    0x0C
-#define EXT_TRIG_DOWN  0x04
-#define ACQ_MODE_NEXT  0x02
-#define ACQ_MODE_ODD   0x01
-#define ACQ_MODE_EVEN  0x00
-
-/* AD_CMD bit masks */
-#define VIDEO_CNL_1  0x00
-#define VIDEO_CNL_2  0x40
-#define VIDEO_CNL_3  0x80
-#define VIDEO_CNL_4  0xC0
-#define SYNC_CNL_1   0x00
-#define SYNC_CNL_2   0x10
-#define SYNC_CNL_3   0x20
-#define SYNC_CNL_4   0x30
-#define SYNC_LVL_1   0x00
-#define SYNC_LVL_2   0x04
-#define SYNC_LVL_3   0x08
-#define SYNC_LVL_4   0x0C
-
-/* DT3155 identificator */
-#define DT3155_ID   0x20
-
-#ifdef CONFIG_DT3155_CCIR
-#define DMA_STRIDE 768
-#else
-#define DMA_STRIDE 640
-#endif
-
-/**
- * struct dt3155_stats - statistics structure
- *
- * @free_bufs_empty:   no free image buffers
- * @corrupted_fields:  corrupted fields
- * @dma_map_failed:    dma mapping failed
- * @start_before_end:  new started before old ended
- */
-struct dt3155_stats {
-       int free_bufs_empty;
-       int corrupted_fields;
-       int dma_map_failed;
-       int start_before_end;
-};
-
-/*    per board private data structure   */
-/**
- * struct dt3155_priv - private data structure
- *
- * @vdev:              pointer to video_device structure
- * @pdev:              pointer to pci_dev structure
- * @q                  pointer to vb2_queue structure
- * @curr_buf:          pointer to curren buffer
- * @mux:               mutex to protect the instance
- * @dmaq               queue for dma buffers
- * @lock               spinlock for dma queue
- * @field_count                fields counter
- * @stats:             statistics structure
- * @users              open count
- * @regs:              local copy of mmio base register
- * @csr2:              local copy of csr2 register
- * @config:            local copy of config register
- */
-struct dt3155_priv {
-       struct video_device *vdev;
-       struct pci_dev *pdev;
-       struct vb2_queue *q;
-       struct vb2_buffer *curr_buf;
-       struct mutex mux;
-       struct list_head dmaq;
-       spinlock_t lock;
-       unsigned int field_count;
-       struct dt3155_stats stats;
-       void __iomem *regs;
-       int users;
-       u8 csr2, config;
-};
-
-#endif /*  __KERNEL__  */
-
-#endif /*  _DT3155_H_  */
diff --git a/drivers/staging/easycap/Kconfig b/drivers/staging/easycap/Kconfig
deleted file mode 100644 (file)
index a425a6f..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-config EASYCAP
-       tristate "EasyCAP USB ID 05e1:0408 support"
-       depends on USB && VIDEO_DEV && SND
-       select SND_PCM
-
-       ---help---
-         This is an integrated audio/video driver for EasyCAP cards with
-         USB ID 05e1:0408.  It supports two hardware variants:
-
-         *  EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,
-            having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)
-
-         *  EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled
-            1, 2, 3, 4 and an unlabelled input cable for a microphone.
-
-         To compile this driver as a module, choose M here: the
-         module will be called easycap
-
-config EASYCAP_DEBUG
-       bool "Enable EasyCAP driver debugging"
-       depends on EASYCAP
-
-       ---help---
-         This option enables debug printouts
-
-         To enable debug, pass the debug level to the debug module
-          parameter:
-
-          modprobe easycap debug=[0..9]
-
diff --git a/drivers/staging/easycap/Makefile b/drivers/staging/easycap/Makefile
deleted file mode 100644 (file)
index a34e75f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-easycap-objs := easycap_main.o
-easycap-objs += easycap_low.o
-easycap-objs += easycap_ioctl.o
-easycap-objs += easycap_settings.o
-easycap-objs += easycap_testcard.o
-easycap-objs += easycap_sound.o
-obj-$(CONFIG_EASYCAP) += easycap.o
-
-ccflags-y := -Wall
-
diff --git a/drivers/staging/easycap/README b/drivers/staging/easycap/README
deleted file mode 100644 (file)
index 796b032..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-
-        ***********************************************************
-        *   EasyCAP USB 2.0 Video Adapter with Audio, Model DC60  *
-        *                            and                          *
-        *             EasyCAP002 4-Channel USB 2.0 DVR            *
-        ***********************************************************
-                     Mike Thomas  <rmthomas@sciolus.org>
-
-
-
-SUPPORTED HARDWARE
-------------------
-
-This driver is intended for use with hardware having USB ID 05e1:0408.
-Two kinds of EasyCAP have this USB ID, namely:
-
-    *  EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,
-       having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)
-
-    *  EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled
-       1, 2, 3, 4 and an unlabelled input cable for a microphone.
-
-
-BUILD OPTIONS AND DEPENDENCIES
-------------------------------
-
-Unless EASYCAP_DEBUG is defined during compilation it will not be possible
-to select a debug level at the time of module installation.
-
-
-KNOWN RUNTIME ISSUES
---------------------
-
-(1) Intentionally, this driver will not stream material which is unambiguously
-identified by the hardware as copy-protected.  Normal video output will be
-present for about a minute but will then freeze when this situation arises.
-
-(2) The controls for luminance, contrast, saturation, hue and volume may not
-always work properly.
-
-(3) Reduced-resolution S-Video seems to suffer from moire artefacts.
-
-
-INPUT NUMBERING
----------------
-
-For the EasyCAP with S-VIDEO input cable the driver regards a request for
-inputs numbered 0 or 1 as referring to CVBS and a request for input
-numbered 5 as referring to S-VIDEO.
-
-For the EasyCAP with four CVBS inputs the driver expects to be asked for
-any one of inputs numbered 1,2,3,4.  If input 0 is asked for, it is
-interpreted as input 1.
-
-
-MODULE PARAMETERS
------------------
-
-Three module parameters are defined:
-
-debug      the easycap module is configured at diagnostic level n (0 to 9)
-gain       audio gain level n (0 to 31, default is 16)
-bars       whether to display testcard bars when incoming video signal is lost
-           0 => no, 1 => yes (default)
-
-
-SUPPORTED TV STANDARDS AND RESOLUTIONS
---------------------------------------
-
-The following TV standards are natively supported by the hardware and are
-usable as (for example) the "norm=" parameter in the mplayer command:
-
-    PAL_BGHIN,    NTSC_N_443,
-    PAL_Nc,       NTSC_N,
-    SECAM,        NTSC_M,        NTSC_M_JP,
-    PAL_60,       NTSC_443,
-    PAL_M.
-
-In addition, the driver offers "custom" pseudo-standards with a framerate
-which is 20% of the usual framerate.  These pseudo-standards are named:
-
-    PAL_BGHIN_SLOW,    NTSC_N_443_SLOW,
-    PAL_Nc_SLOW,       NTSC_N_SLOW,
-    SECAM_SLOW,        NTSC_M_SLOW,        NTSC_M_JP_SLOW,
-    PAL_60_SLOW,       NTSC_443_SLOW,
-    PAL_M_SLOW.
-
-
-The available picture sizes are:
-
-     at 25 frames per second:   720x576, 704x576, 640x480, 360x288, 320x240;
-     at 30 frames per second:   720x480, 640x480, 360x240, 320x240.
-
-
-WHAT'S TESTED AND WHAT'S NOT
-----------------------------
-
-This driver is known to work with mplayer, mencoder, tvtime, zoneminder,
-xawtv, gstreamer and sufficiently recent versions of vlc.  An interface
-to ffmpeg is implemented, but serious audio-video synchronization problems
-remain.
-
-The driver is designed to support all the TV standards accepted by the
-hardware, but as yet it has actually been tested on only a few of these.
-
-I have been unable to test and calibrate the S-video input myself because I
-do not possess any equipment with S-video output.
-
-
-UDEV RULES
-----------
-
-In order that the special files /dev/easycap0 and /dev/easysnd1 are created
-with conveniently relaxed permissions when the EasyCAP is plugged in, a file
-is preferably to be provided in directory /etc/udev/rules.d with content:
-
-ACTION!="add|change", GOTO="easycap_rules_end"
-ATTRS{idVendor}=="05e1", ATTRS{idProduct}=="0408", \
-       MODE="0666", OWNER="root", GROUP="root"
-LABEL="easycap_rules_end"
-
-
-MODPROBE CONFIGURATION
-----------------------
-
-The easycap module is in competition with the module snd-usb-audio for the
-EasyCAP's audio channel, and its installation can be aided by providing a
-file in directory /etc/modprobe.d with content:
-
-options easycap  gain=16 bars=1
-install easycap /sbin/rmmod snd-usb-audio; /sbin/modprobe --ignore-install easycap
-
-
-ACKNOWLEGEMENTS AND REFERENCES
-------------------------------
-This driver makes use of information contained in the Syntek Semicon DC-1125
-Driver, presently maintained at http://sourceforge.net/projects/syntekdriver/
-by Nicolas Vivien.  Particularly useful has been a patch to the latter driver
-provided by Ivor Hewitt in January 2009.  The NTSC implementation is taken
-from the work of Ben Trask.
-
diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h
deleted file mode 100644 (file)
index 7b256a9..0000000
+++ /dev/null
@@ -1,594 +0,0 @@
-/*****************************************************************************
-*                                                                            *
-*  easycap.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
- *
-*/
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  THE FOLLOWING PARAMETERS ARE UNDEFINED:
- *
- *                EASYCAP_DEBUG
- *
- *  IF REQUIRED THEY MUST BE EXTERNALLY DEFINED, FOR EXAMPLE AS COMPILER
- *  OPTIONS.
- */
-/*---------------------------------------------------------------------------*/
-
-#ifndef __EASYCAP_H__
-#define __EASYCAP_H__
-
-/*---------------------------------------------------------------------------*/
-/*
- *  THESE ARE NORMALLY DEFINED
- */
-/*---------------------------------------------------------------------------*/
-#define  PATIENCE  500
-#define  PERSEVERE
-/*---------------------------------------------------------------------------*/
-/*
- *  THESE ARE FOR MAINTENANCE ONLY - NORMALLY UNDEFINED:
- */
-/*---------------------------------------------------------------------------*/
-#undef  EASYCAP_TESTCARD
-/*---------------------------------------------------------------------------*/
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/kref.h>
-#include <linux/usb.h>
-#include <linux/uaccess.h>
-
-#include <linux/i2c.h>
-#include <linux/workqueue.h>
-#include <linux/poll.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-
-#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>
-#include <media/v4l2-dev.h>
-#include <media/v4l2-device.h>
-#include <linux/videodev2.h>
-#include <linux/soundcard.h>
-
-/*---------------------------------------------------------------------------*/
-/*  VENDOR, PRODUCT:  Syntek Semiconductor Co., Ltd
- *
- *      EITHER        EasyCAP USB 2.0 Video Adapter with Audio, Model No. DC60
- *               with input cabling:  AUDIO(L), AUDIO(R), CVBS, S-VIDEO.
- *
- *          OR        EasyCAP 4CHANNEL USB 2.0 DVR, Model No. EasyCAP002
- *               with input cabling:  MICROPHONE, CVBS1, CVBS2, CVBS3, CVBS4.
- */
-/*---------------------------------------------------------------------------*/
-#define USB_EASYCAP_VENDOR_ID  0x05e1
-#define USB_EASYCAP_PRODUCT_ID 0x0408
-
-#define EASYCAP_DRIVER_VERSION "0.9.01"
-#define EASYCAP_DRIVER_DESCRIPTION "easycapdc60"
-
-#define USB_SKEL_MINOR_BASE     192
-#define DONGLE_MANY 8
-#define INPUT_MANY 6
-/*---------------------------------------------------------------------------*/
-/*
- *  DEFAULT LUMINANCE, CONTRAST, SATURATION AND HUE
- */
-/*---------------------------------------------------------------------------*/
-#define SAA_0A_DEFAULT 0x7F
-#define SAA_0B_DEFAULT 0x3F
-#define SAA_0C_DEFAULT 0x2F
-#define SAA_0D_DEFAULT 0x00
-/*---------------------------------------------------------------------------*/
-/*
- *  VIDEO STREAMING PARAMETERS:
- *  USB 2.0 PROVIDES FOR HIGH-BANDWIDTH ENDPOINTS WITH AN UPPER LIMIT
- *  OF 3072 BYTES PER MICROFRAME for wMaxPacketSize.
- */
-/*---------------------------------------------------------------------------*/
-#define VIDEO_ISOC_BUFFER_MANY 16
-#define VIDEO_ISOC_ORDER 3
-#define VIDEO_ISOC_FRAMESPERDESC ((unsigned int) 1 << VIDEO_ISOC_ORDER)
-#define USB_2_0_MAXPACKETSIZE 3072
-#if (USB_2_0_MAXPACKETSIZE > PAGE_SIZE)
-#error video_isoc_buffer[.] will not be big enough
-#endif
-#define VIDEO_JUNK_TOLERATE VIDEO_ISOC_BUFFER_MANY
-#define VIDEO_LOST_TOLERATE 50
-/*---------------------------------------------------------------------------*/
-/*
- *  VIDEO BUFFERS
- */
-/*---------------------------------------------------------------------------*/
-#define FIELD_BUFFER_SIZE (203 * PAGE_SIZE)
-#define FRAME_BUFFER_SIZE (405 * PAGE_SIZE)
-#define FIELD_BUFFER_MANY 4
-#define FRAME_BUFFER_MANY 6
-/*---------------------------------------------------------------------------*/
-/*
- *  AUDIO STREAMING PARAMETERS
- */
-/*---------------------------------------------------------------------------*/
-#define AUDIO_ISOC_BUFFER_MANY 16
-#define AUDIO_ISOC_ORDER 1
-#define AUDIO_ISOC_FRAMESPERDESC 32
-#define AUDIO_ISOC_BUFFER_SIZE (PAGE_SIZE << AUDIO_ISOC_ORDER)
-/*---------------------------------------------------------------------------*/
-/*
- *  AUDIO BUFFERS
- */
-/*---------------------------------------------------------------------------*/
-#define AUDIO_FRAGMENT_MANY 32
-#define PAGES_PER_AUDIO_FRAGMENT 4
-/*---------------------------------------------------------------------------*/
-/*
- *  IT IS ESSENTIAL THAT EVEN-NUMBERED STANDARDS ARE 25 FRAMES PER SECOND,
- *                        ODD-NUMBERED STANDARDS ARE 30 FRAMES PER SECOND.
- *  THE NUMBERING OF STANDARDS MUST NOT BE CHANGED WITHOUT DUE CARE.  NOT
- *  ONLY MUST THE PARAMETER
- *                             STANDARD_MANY
- *  BE CHANGED TO CORRESPOND TO THE NEW NUMBER OF STANDARDS, BUT ALSO THE
- *  NUMBERING MUST REMAIN AN UNBROKEN ASCENDING SEQUENCE:  DUMMY STANDARDS
- *  MAY NEED TO BE ADDED.   APPROPRIATE CHANGES WILL ALWAYS BE REQUIRED IN
- *  ROUTINE fillin_formats() AND POSSIBLY ELSEWHERE.  BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-#define  PAL_BGHIN      0
-#define  PAL_Nc         2
-#define  SECAM          4
-#define  NTSC_N         6
-#define  NTSC_N_443     8
-#define  NTSC_M         1
-#define  NTSC_443       3
-#define  NTSC_M_JP      5
-#define  PAL_60         7
-#define  PAL_M          9
-#define  PAL_BGHIN_SLOW    10
-#define  PAL_Nc_SLOW       12
-#define  SECAM_SLOW        14
-#define  NTSC_N_SLOW       16
-#define  NTSC_N_443_SLOW   18
-#define  NTSC_M_SLOW       11
-#define  NTSC_443_SLOW     13
-#define  NTSC_M_JP_SLOW    15
-#define  PAL_60_SLOW       17
-#define  PAL_M_SLOW        19
-#define  STANDARD_MANY 20
-/*---------------------------------------------------------------------------*/
-/*
- *  ENUMS
- */
-/*---------------------------------------------------------------------------*/
-enum {
-       AT_720x576,
-       AT_704x576,
-       AT_640x480,
-       AT_720x480,
-       AT_360x288,
-       AT_320x240,
-       AT_360x240,
-       RESOLUTION_MANY
-};
-enum {
-       FMT_UYVY,
-       FMT_YUY2,
-       FMT_RGB24,
-       FMT_RGB32,
-       FMT_BGR24,
-       FMT_BGR32,
-       PIXELFORMAT_MANY
-};
-enum {
-       FIELD_NONE,
-       FIELD_INTERLACED,
-       INTERLACE_MANY
-};
-#define SETTINGS_MANY  (STANDARD_MANY * \
-                       RESOLUTION_MANY * \
-                       2 * \
-                       PIXELFORMAT_MANY * \
-                       INTERLACE_MANY)
-/*---------------------------------------------------------------------------*/
-/*
- *  STRUCTURE DEFINITIONS
- */
-/*---------------------------------------------------------------------------*/
-struct easycap_dongle {
-       struct easycap *peasycap;
-       struct mutex mutex_video;
-       struct mutex mutex_audio;
-};
-/*---------------------------------------------------------------------------*/
-struct data_buffer {
-       struct list_head list_head;
-       void *pgo;
-       void *pto;
-       u16 kount;
-       u16 input;
-};
-/*---------------------------------------------------------------------------*/
-struct data_urb {
-       struct list_head list_head;
-       struct urb *purb;
-       int isbuf;
-       int length;
-};
-/*---------------------------------------------------------------------------*/
-struct easycap_standard {
-       u16 mask;
-struct v4l2_standard v4l2_standard;
-};
-struct easycap_format {
-       u16 mask;
-       char name[128];
-struct v4l2_format v4l2_format;
-};
-struct inputset {
-       int input;
-       int input_ok;
-       int standard_offset;
-       int standard_offset_ok;
-       int format_offset;
-       int format_offset_ok;
-       int brightness;
-       int brightness_ok;
-       int contrast;
-       int contrast_ok;
-       int saturation;
-       int saturation_ok;
-       int hue;
-       int hue_ok;
-};
-/*---------------------------------------------------------------------------*/
-/*
- *   easycap.ilk == 0   =>  CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=256
- *   easycap.ilk == 2   =>  CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=9
- *   easycap.ilk == 3   =>     FOUR-CVBS HARDWARE, AUDIO wMaxPacketSize=9
- */
-/*---------------------------------------------------------------------------*/
-struct easycap {
-       int isdongle;
-       int minor;
-
-       struct video_device video_device;
-       struct v4l2_device v4l2_device;
-
-       int status;
-       unsigned int audio_pages_per_fragment;
-       unsigned int audio_bytes_per_fragment;
-       unsigned int audio_buffer_page_many;
-
-#define UPSAMPLE
-#ifdef UPSAMPLE
-       s16 oldaudio;
-#endif /*UPSAMPLE*/
-
-       int ilk;
-       bool microphone;
-
-       struct usb_device *pusb_device;
-       struct usb_interface *pusb_interface;
-
-       struct kref kref;
-
-       int queued[FRAME_BUFFER_MANY];
-       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;
-       int standard_offset;
-       int format_offset;
-       struct inputset inputset[INPUT_MANY];
-
-       bool ntsc;
-       int fps;
-       int usec;
-       int tolerate;
-       int skip;
-       int skipped;
-       int lost[INPUT_MANY];
-       int merit[180];
-
-       long long int dnbydt;
-
-       int    video_interface;
-       int    video_altsetting_on;
-       int    video_altsetting_off;
-       int    video_endpointnumber;
-       int    video_isoc_maxframesize;
-       int    video_isoc_buffer_size;
-       int    video_isoc_framesperdesc;
-
-       int    video_isoc_streaming;
-       int    video_isoc_sequence;
-       int    video_idle;
-       int    video_eof;
-       int    video_junk;
-
-       struct data_buffer video_isoc_buffer[VIDEO_ISOC_BUFFER_MANY];
-       struct data_buffer field_buffer[FIELD_BUFFER_MANY]
-                                       [(FIELD_BUFFER_SIZE/PAGE_SIZE)];
-       struct data_buffer frame_buffer[FRAME_BUFFER_MANY]
-                                       [(FRAME_BUFFER_SIZE/PAGE_SIZE)];
-
-       struct list_head urb_video_head;
-       struct list_head *purb_video_head;
-
-       u8 cache[8];
-       u8 *pcache;
-       int video_mt;
-       int audio_mt;
-       long long audio_bytes;
-       u32 isequence;
-
-       int vma_many;
-/*---------------------------------------------------------------------------*/
-/*
- *  BUFFER INDICATORS
- */
-/*---------------------------------------------------------------------------*/
-       int field_fill; /* Field buffer being filled by easycap_complete().  */
-                       /*   Bumped only by easycap_complete().              */
-       int field_page; /* Page of field buffer page being filled by         */
-                       /*   easycap_complete().                             */
-       int field_read; /* Field buffer to be read by field2frame().         */
-                       /*   Bumped only by easycap_complete().              */
-       int frame_fill; /* Frame buffer being filled by field2frame().       */
-                       /*   Bumped only by easycap_dqbuf() when             */
-                       /*   field2frame() has created a complete frame.     */
-       int frame_read; /* Frame buffer offered to user by DQBUF.            */
-                       /*   Set only by easycap_dqbuf() to trail frame_fill.*/
-       int frame_lock; /* Flag set to 1 by DQBUF and cleared by QBUF        */
-/*---------------------------------------------------------------------------*/
-/*
- *  IMAGE PROPERTIES
- */
-/*---------------------------------------------------------------------------*/
-       u32                   pixelformat;
-       int                     width;
-       int                     height;
-       int                     bytesperpixel;
-       bool                    byteswaporder;
-       bool                    decimatepixel;
-       bool                    offerfields;
-       int                     frame_buffer_used;
-       int                     frame_buffer_many;
-       int                     videofieldamount;
-
-       int                     brightness;
-       int                     contrast;
-       int                     saturation;
-       int                     hue;
-
-       int allocation_video_urb;
-       int allocation_video_page;
-       int allocation_video_struct;
-       int registered_video;
-/*---------------------------------------------------------------------------*/
-/*
- *  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;
-/*---------------------------------------------------------------------------*/
-/*
- *  SOUND PROPERTIES
- */
-/*---------------------------------------------------------------------------*/
-       int audio_interface;
-       int audio_altsetting_on;
-       int audio_altsetting_off;
-       int audio_endpointnumber;
-       int audio_isoc_maxframesize;
-       int audio_isoc_buffer_size;
-       int audio_isoc_framesperdesc;
-
-       int audio_isoc_streaming;
-       int audio_idle;
-       int audio_eof;
-       int volume;
-       int mute;
-       s8 gain;
-
-       struct data_buffer audio_isoc_buffer[AUDIO_ISOC_BUFFER_MANY];
-
-       struct list_head urb_audio_head;
-       struct list_head *purb_audio_head;
-/*---------------------------------------------------------------------------*/
-/*
- *  BUFFER INDICATORS
- */
-/*---------------------------------------------------------------------------*/
-       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.                                   */
-/*---------------------------------------------------------------------------*/
-/*
- *  SOUND PROPERTIES
- */
-/*---------------------------------------------------------------------------*/
-
-       int audio_buffer_many;
-
-       int allocation_audio_urb;
-       int allocation_audio_page;
-       int allocation_audio_struct;
-       int registered_audio;
-
-       long long int audio_sample;
-       long long int audio_niveau;
-       long long int audio_square;
-
-       struct data_buffer audio_buffer[];
-};
-/*---------------------------------------------------------------------------*/
-/*
- *  VIDEO FUNCTION PROTOTYPES
- */
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-long easycap_unlocked_ioctl(struct file *, unsigned int, unsigned long);
-int              easycap_dqbuf(struct easycap *, int);
-int              submit_video_urbs(struct easycap *);
-int              kill_video_urbs(struct easycap *);
-int              field2frame(struct easycap *);
-int              redaub(struct easycap *, void *, void *,
-                                               int, int, u8, u8, bool);
-void             easycap_testcard(struct easycap *, int);
-int              fillin_formats(void);
-int              newinput(struct easycap *, int);
-int              adjust_standard(struct easycap *, v4l2_std_id);
-int              adjust_format(struct easycap *, u32, u32, u32,
-                                                               int, bool);
-int              adjust_brightness(struct easycap *, int);
-int              adjust_contrast(struct easycap *, int);
-int              adjust_saturation(struct easycap *, int);
-int              adjust_hue(struct easycap *, int);
-int              adjust_volume(struct easycap *, int);
-/*---------------------------------------------------------------------------*/
-/*
- *  AUDIO FUNCTION PROTOTYPES
- */
-/*---------------------------------------------------------------------------*/
-int            easycap_alsa_probe(struct easycap *);
-void            easycap_alsa_complete(struct urb *);
-
-int              easycap_sound_setup(struct easycap *);
-int              submit_audio_urbs(struct easycap *);
-int              kill_audio_urbs(struct easycap *);
-void             easyoss_testtone(struct easycap *, int);
-int              audio_setup(struct easycap *);
-/*---------------------------------------------------------------------------*/
-/*
- *  LOW-LEVEL FUNCTION PROTOTYPES
- */
-/*---------------------------------------------------------------------------*/
-int              audio_gainget(struct usb_device *);
-int              audio_gainset(struct usb_device *, s8);
-
-int              set_interface(struct usb_device *, u16);
-int              wakeup_device(struct usb_device *);
-int              confirm_resolution(struct usb_device *);
-int              confirm_stream(struct usb_device *);
-
-int              setup_stk(struct usb_device *, bool);
-int              setup_saa(struct usb_device *, bool);
-int              setup_vt(struct usb_device *);
-int              check_stk(struct usb_device *, bool);
-int              check_saa(struct usb_device *, bool);
-int              ready_saa(struct usb_device *);
-int              merit_saa(struct usb_device *);
-int              check_vt(struct usb_device *);
-int              select_input(struct usb_device *, int, int);
-int              set_resolution(struct usb_device *,
-                                               u16, u16, u16, u16);
-
-int              read_saa(struct usb_device *, u16);
-int              read_stk(struct usb_device *, u32);
-int              write_saa(struct usb_device *, u16, u16);
-int              write_000(struct usb_device *, u16, u16);
-int              start_100(struct usb_device *);
-int              stop_100(struct usb_device *);
-int              write_300(struct usb_device *);
-int              read_vt(struct usb_device *, u16);
-int              write_vt(struct usb_device *, u16, u16);
-int            isdongle(struct easycap *);
-/*---------------------------------------------------------------------------*/
-
-
-/*---------------------------------------------------------------------------*/
-/*
- *  MACROS SAM(...) AND JOM(...) ALLOW DIAGNOSTIC OUTPUT TO BE TAGGED WITH
- *  THE IDENTITY OF THE DONGLE TO WHICH IT APPLIES, BUT IF INVOKED WHEN THE
- *  POINTER peasycap IS INVALID AN Oops IS LIKELY, AND ITS CAUSE MAY NOT BE
- *  IMMEDIATELY OBVIOUS FROM A CASUAL READING OF THE SOURCE CODE.  BEWARE.
-*/
-/*---------------------------------------------------------------------------*/
-const char *strerror(int err);
-
-#define SAY(format, args...) do { \
-       printk(KERN_DEBUG "easycap:: %s: " \
-                       format, __func__, ##args); \
-} while (0)
-#define SAM(format, args...) do { \
-       printk(KERN_DEBUG "easycap::%i%s: " \
-                       format, peasycap->isdongle, __func__, ##args);\
-} while (0)
-
-#ifdef CONFIG_EASYCAP_DEBUG
-extern int easycap_debug;
-#define JOT(n, format, args...) do { \
-       if (n <= easycap_debug) { \
-               printk(KERN_DEBUG "easycap:: %s: " \
-                       format, __func__, ##args);\
-       } \
-} while (0)
-#define JOM(n, format, args...) do { \
-       if (n <= easycap_debug) { \
-               printk(KERN_DEBUG "easycap::%i%s: " \
-                       format, peasycap->isdongle, __func__, ##args);\
-       } \
-} while (0)
-
-#else
-#define JOT(n, format, args...) do {} while (0)
-#define JOM(n, format, args...) do {} while (0)
-#endif /* CONFIG_EASYCAP_DEBUG */
-
-/*---------------------------------------------------------------------------*/
-
-/*---------------------------------------------------------------------------*/
-/* globals
- */
-/*---------------------------------------------------------------------------*/
-
-extern bool easycap_readback;
-extern const struct easycap_standard easycap_standard[];
-extern struct easycap_format easycap_format[];
-extern struct v4l2_queryctrl easycap_control[];
-extern struct usb_driver easycap_usb_driver;
-extern struct easycap_dongle easycapdc60_dongle[];
-
-#endif /* !__EASYCAP_H__  */
diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c
deleted file mode 100644 (file)
index c99addf..0000000
+++ /dev/null
@@ -1,2450 +0,0 @@
-/******************************************************************************
-*                                                                             *
-*  easycap_ioctl.c                                                            *
-*                                                                             *
-******************************************************************************/
-/*
- *
- *  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
- *
-*/
-/*****************************************************************************/
-
-#include <linux/version.h>
-#include "easycap.h"
-
-/*--------------------------------------------------------------------------*/
-/*
- *  UNLESS THERE IS A PREMATURE ERROR RETURN THIS ROUTINE UPDATES THE
- *  FOLLOWING:
- *          peasycap->standard_offset
- *          peasycap->inputset[peasycap->input].standard_offset
- *          peasycap->fps
- *          peasycap->usec
- *          peasycap->tolerate
- *          peasycap->skip
- */
-/*---------------------------------------------------------------------------*/
-int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id)
-{
-       struct easycap_standard const *peasycap_standard;
-       u16 reg, set;
-       int ir, rc, need, k;
-       unsigned int itwas, isnow;
-       bool resubmit;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       peasycap_standard = &easycap_standard[0];
-       while (0xFFFF != peasycap_standard->mask) {
-               if (std_id == peasycap_standard->v4l2_standard.id)
-                       break;
-               peasycap_standard++;
-       }
-       if (0xFFFF == peasycap_standard->mask) {
-               peasycap_standard = &easycap_standard[0];
-               while (0xFFFF != peasycap_standard->mask) {
-                       if (std_id & peasycap_standard->v4l2_standard.id)
-                               break;
-                       peasycap_standard++;
-               }
-       }
-       if (0xFFFF == peasycap_standard->mask) {
-               SAM("ERROR: 0x%08X=std_id: standard not found\n",
-                   (unsigned int)std_id);
-               return -EINVAL;
-       }
-       SAM("selected standard: %s\n",
-           &(peasycap_standard->v4l2_standard.name[0]));
-       if (peasycap->standard_offset == peasycap_standard - easycap_standard) {
-               SAM("requested standard already in effect\n");
-               return 0;
-       }
-       peasycap->standard_offset = peasycap_standard - easycap_standard;
-       for (k = 0; k < INPUT_MANY;  k++) {
-               if (!peasycap->inputset[k].standard_offset_ok) {
-                       peasycap->inputset[k].standard_offset =
-                               peasycap->standard_offset;
-               }
-       }
-       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
-               peasycap->inputset[peasycap->input].standard_offset =
-                       peasycap->standard_offset;
-               peasycap->inputset[peasycap->input].standard_offset_ok = 1;
-       } else
-               JOM(8, "%i=peasycap->input\n", peasycap->input);
-
-       peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator /
-                       peasycap_standard->v4l2_standard.frameperiod.numerator;
-       switch (peasycap->fps) {
-       case 6:
-       case 30: {
-               peasycap->ntsc = true;
-               break;
-       }
-       case 5:
-       case 25: {
-               peasycap->ntsc = false;
-               break;
-       }
-       default: {
-               SAM("MISTAKE: %i=frames-per-second\n", peasycap->fps);
-               return -ENOENT;
-       }
-       }
-       JOM(8, "%i frames-per-second\n", peasycap->fps);
-       if (0x8000 & peasycap_standard->mask) {
-               peasycap->skip = 5;
-               peasycap->usec = 1000000 / (2 * (5 * peasycap->fps));
-               peasycap->tolerate = 1000 * (25 / (5 * peasycap->fps));
-       } else {
-               peasycap->skip = 0;
-               peasycap->usec = 1000000 / (2 * peasycap->fps);
-               peasycap->tolerate = 1000 * (25 / peasycap->fps);
-       }
-       if (peasycap->video_isoc_streaming) {
-               resubmit = true;
-               kill_video_urbs(peasycap);
-       } else
-               resubmit = false;
-/*--------------------------------------------------------------------------*/
-/*
- *  SAA7113H DATASHEET PAGE 44, TABLE 42
- */
-/*--------------------------------------------------------------------------*/
-       need = 0;
-       itwas = 0;
-       reg = 0x00;
-       set = 0x00;
-       switch (peasycap_standard->mask & 0x000F) {
-       case NTSC_M_JP: {
-               reg = 0x0A;
-               set = 0x95;
-               ir = read_saa(peasycap->pusb_device, reg);
-               if (0 > ir)
-                       SAM("ERROR: cannot read SAA register 0x%02X\n", reg);
-               else
-                       itwas = (unsigned int)ir;
-               rc = write_saa(peasycap->pusb_device, reg, set);
-               if (rc)
-                       SAM("ERROR: failed to set SAA register "
-                           "0x%02X to 0x%02X for JP standard\n", reg, set);
-               else {
-                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
-                       if (0 > ir)
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "to 0x%02X\n", reg, isnow);
-                       else
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
-               }
-
-               reg = 0x0B;
-               set = 0x48;
-               ir = read_saa(peasycap->pusb_device, reg);
-               if (0 > ir)
-                       SAM("ERROR: cannot read SAA register 0x%02X\n", reg);
-               else
-                       itwas = (unsigned int)ir;
-               rc = write_saa(peasycap->pusb_device, reg, set);
-               if (rc)
-                       SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X "
-                           "for JP standard\n", reg, set);
-               else {
-                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
-                       if (0 > ir)
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "to 0x%02X\n", reg, isnow);
-                       else
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
-               }
-/*--------------------------------------------------------------------------*/
-/*
- *  NOTE:  NO break HERE:  RUN ON TO NEXT CASE
- */
-/*--------------------------------------------------------------------------*/
-       }
-       case NTSC_M:
-       case PAL_BGHIN: {
-               reg = 0x0E;
-               set = 0x01;
-               need = 1;
-               break;
-       }
-       case NTSC_N_443:
-       case PAL_60: {
-               reg = 0x0E;
-               set = 0x11;
-               need = 1;
-               break;
-       }
-       case NTSC_443:
-       case PAL_Nc: {
-               reg = 0x0E;
-               set = 0x21;
-               need = 1;
-               break;
-       }
-       case NTSC_N:
-       case PAL_M: {
-               reg = 0x0E;
-               set = 0x31;
-               need = 1;
-               break;
-       }
-       case SECAM: {
-               reg = 0x0E;
-               set = 0x51;
-               need = 1;
-               break;
-       }
-       default:
-               break;
-       }
-/*--------------------------------------------------------------------------*/
-       if (need) {
-               ir = read_saa(peasycap->pusb_device, reg);
-               if (0 > ir)
-                       SAM("ERROR: failed to read SAA register 0x%02X\n", reg);
-               else
-                       itwas = (unsigned int)ir;
-               rc = write_saa(peasycap->pusb_device, reg, set);
-               if (0 != write_saa(peasycap->pusb_device, reg, set)) {
-                       SAM("ERROR: failed to set SAA register "
-                           "0x%02X to 0x%02X for table 42\n", reg, set);
-               } else {
-                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
-                       if (0 > ir)
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "to 0x%02X\n", reg, isnow);
-                       else
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
-               }
-       }
-/*--------------------------------------------------------------------------*/
-/*
-        *  SAA7113H DATASHEET PAGE 41
-        */
-/*--------------------------------------------------------------------------*/
-       reg = 0x08;
-       ir = read_saa(peasycap->pusb_device, reg);
-       if (0 > ir)
-               SAM("ERROR: failed to read SAA register 0x%02X "
-                   "so cannot reset\n", reg);
-       else {
-               itwas = (unsigned int)ir;
-               if (peasycap_standard->mask & 0x0001)
-                       set = itwas | 0x40 ;
-               else
-                       set = itwas & ~0x40 ;
-               rc  = write_saa(peasycap->pusb_device, reg, set);
-               if (rc)
-                       SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
-                           reg, set);
-               else {
-                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
-                       if (0 > ir)
-                               JOM(8, "SAA register 0x%02X changed to 0x%02X\n",
-                                   reg, isnow);
-                       else
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
-               }
-       }
-/*--------------------------------------------------------------------------*/
-/*
- *  SAA7113H DATASHEET PAGE 51, TABLE 57
- */
-/*---------------------------------------------------------------------------*/
-       reg = 0x40;
-       ir = read_saa(peasycap->pusb_device, reg);
-       if (0 > ir)
-               SAM("ERROR: failed to read SAA register 0x%02X "
-                   "so cannot reset\n", reg);
-       else {
-               itwas = (unsigned int)ir;
-               if (peasycap_standard->mask & 0x0001)
-                       set = itwas | 0x80 ;
-               else
-                       set = itwas & ~0x80 ;
-               rc = write_saa(peasycap->pusb_device, reg, set);
-               if (rc)
-                       SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
-                           reg, set);
-               else {
-                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
-                       if (0 > ir)
-                               JOM(8, "SAA register 0x%02X changed to 0x%02X\n",
-                                   reg, isnow);
-                       else
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
-               }
-       }
-/*--------------------------------------------------------------------------*/
-/*
-        *  SAA7113H DATASHEET PAGE 53, TABLE 66
-        */
-/*--------------------------------------------------------------------------*/
-       reg = 0x5A;
-       ir = read_saa(peasycap->pusb_device, reg);
-       if (0 > ir)
-               SAM("ERROR: failed to read SAA register 0x%02X but continuing\n", reg);
-       itwas = (unsigned int)ir;
-       if (peasycap_standard->mask & 0x0001)
-               set = 0x0A ;
-       else
-               set = 0x07 ;
-       if (0 != write_saa(peasycap->pusb_device, reg, set))
-               SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
-                   reg, set);
-       else {
-               isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
-               if (0 > ir)
-                       JOM(8, "SAA register 0x%02X changed "
-                           "to 0x%02X\n", reg, isnow);
-               else
-                       JOM(8, "SAA register 0x%02X changed "
-                           "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
-       }
-       if (resubmit)
-               submit_video_urbs(peasycap);
-       return 0;
-}
-/*****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *  THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL REQUIRES
- *  A VALID VALUE OF peasycap->standard_offset, OTHERWISE -EBUSY IS RETURNED.
- *
- *  PROVIDED THE ARGUMENT try IS false AND THERE IS NO PREMATURE ERROR RETURN
- *  THIS ROUTINE UPDATES THE FOLLOWING:
- *          peasycap->format_offset
- *          peasycap->inputset[peasycap->input].format_offset
- *          peasycap->pixelformat
- *          peasycap->height
- *          peasycap->width
- *          peasycap->bytesperpixel
- *          peasycap->byteswaporder
- *          peasycap->decimatepixel
- *          peasycap->frame_buffer_used
- *          peasycap->videofieldamount
- *          peasycap->offerfields
- *
- *  IF SUCCESSFUL THE FUNCTION RETURNS THE OFFSET IN easycap_format[]
- *  IDENTIFYING THE FORMAT WHICH IS TO RETURNED TO THE USER.
- *  ERRORS RETURN A NEGATIVE NUMBER.
- */
-/*--------------------------------------------------------------------------*/
-int adjust_format(struct easycap *peasycap,
-                 u32 width, u32 height, u32 pixelformat, int field, bool try)
-{
-       struct easycap_format *peasycap_format, *peasycap_best_format;
-       u16 mask;
-       struct usb_device *p;
-       int miss, multiplier, best, k;
-       char bf[5], fo[32], *pc;
-       u32 uc;
-       bool resubmit;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (0 > peasycap->standard_offset) {
-               JOM(8, "%i=peasycap->standard_offset\n", peasycap->standard_offset);
-               return -EBUSY;
-       }
-       p = peasycap->pusb_device;
-       if (!p) {
-               SAM("ERROR: peaycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       pc = &bf[0];
-       uc = pixelformat;
-       memcpy((void *)pc, (void *)(&uc), 4);
-       bf[4] = 0;
-       mask = 0xFF & easycap_standard[peasycap->standard_offset].mask;
-       SAM("sought:    %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n",
-           width, height, pc, pixelformat, field, mask);
-       switch (field) {
-       case V4L2_FIELD_ANY: {
-               strcpy(&fo[0], "V4L2_FIELD_ANY ");
-               break;
-       }
-       case V4L2_FIELD_NONE: {
-               strcpy(&fo[0], "V4L2_FIELD_NONE");
-               break;
-       }
-       case V4L2_FIELD_TOP: {
-               strcpy(&fo[0], "V4L2_FIELD_TOP");
-               break;
-       }
-       case V4L2_FIELD_BOTTOM: {
-               strcpy(&fo[0], "V4L2_FIELD_BOTTOM");
-               break;
-       }
-       case V4L2_FIELD_INTERLACED: {
-               strcpy(&fo[0], "V4L2_FIELD_INTERLACED");
-               break;
-       }
-       case V4L2_FIELD_SEQ_TB: {
-               strcpy(&fo[0], "V4L2_FIELD_SEQ_TB");
-               break;
-       }
-       case V4L2_FIELD_SEQ_BT: {
-               strcpy(&fo[0], "V4L2_FIELD_SEQ_BT");
-               break;
-       }
-       case V4L2_FIELD_ALTERNATE: {
-               strcpy(&fo[0], "V4L2_FIELD_ALTERNATE");
-               break;
-       }
-       case V4L2_FIELD_INTERLACED_TB: {
-               strcpy(&fo[0], "V4L2_FIELD_INTERLACED_TB");
-               break;
-       }
-       case V4L2_FIELD_INTERLACED_BT: {
-               strcpy(&fo[0], "V4L2_FIELD_INTERLACED_BT");
-               break;
-       }
-       default: {
-               strcpy(&fo[0], "V4L2_FIELD_... UNKNOWN  ");
-               break;
-       }
-       }
-       SAM("sought:    %s\n", &fo[0]);
-       if (V4L2_FIELD_ANY == field) {
-               field = V4L2_FIELD_NONE;
-               SAM("prefer:    V4L2_FIELD_NONE=field, was V4L2_FIELD_ANY\n");
-       }
-       peasycap_best_format = NULL;
-       peasycap_format = &easycap_format[0];
-       while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
-               JOM(16, ".> %i %i 0x%08X %ix%i\n",
-                   peasycap_format->mask & 0x01,
-                   peasycap_format->v4l2_format.fmt.pix.field,
-                   peasycap_format->v4l2_format.fmt.pix.pixelformat,
-                   peasycap_format->v4l2_format.fmt.pix.width,
-                   peasycap_format->v4l2_format.fmt.pix.height);
-
-               if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) &&
-                   (peasycap_format->v4l2_format.fmt.pix.field == field) &&
-                   (peasycap_format->v4l2_format.fmt.pix.pixelformat == pixelformat) &&
-                   (peasycap_format->v4l2_format.fmt.pix.width  == width) &&
-                   (peasycap_format->v4l2_format.fmt.pix.height == height)) {
-
-                       peasycap_best_format = peasycap_format;
-                       break;
-               }
-               peasycap_format++;
-       }
-       if (0 == peasycap_format->v4l2_format.fmt.pix.width) {
-               SAM("cannot do: %ix%i with standard mask 0x%02X\n",
-                   width, height, mask);
-               peasycap_format = &easycap_format[0];
-               best = -1;
-               while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
-                       if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) &&
-                           (peasycap_format->v4l2_format.fmt.pix.field == field) &&
-                           (peasycap_format->v4l2_format.fmt.pix.pixelformat == pixelformat)) {
-
-                               miss = abs(peasycap_format->v4l2_format.fmt.pix.width  - width);
-                               if ((best > miss) || (best < 0)) {
-                                       best = miss;
-                                       peasycap_best_format = peasycap_format;
-                                       if (!miss)
-                                               break;
-                               }
-                       }
-                       peasycap_format++;
-               }
-               if (-1 == best) {
-                       SAM("cannot do %ix... with standard mask 0x%02X\n",
-                           width, mask);
-                       SAM("cannot do ...x%i with standard mask 0x%02X\n",
-                           height, mask);
-                       SAM("           %ix%i unmatched\n", width, height);
-                       return peasycap->format_offset;
-               }
-       }
-       if (!peasycap_best_format) {
-               SAM("MISTAKE: peasycap_best_format is NULL");
-               return -EINVAL;
-       }
-       peasycap_format = peasycap_best_format;
-
-/*...........................................................................*/
-       if (try)
-               return peasycap_best_format - easycap_format;
-/*...........................................................................*/
-
-       if (false != try) {
-               SAM("MISTAKE: true==try where is should be false\n");
-               return -EINVAL;
-       }
-       SAM("actioning: %ix%i %s\n",
-           peasycap_format->v4l2_format.fmt.pix.width,
-           peasycap_format->v4l2_format.fmt.pix.height,
-           &peasycap_format->name[0]);
-       peasycap->height        = peasycap_format->v4l2_format.fmt.pix.height;
-       peasycap->width         = peasycap_format->v4l2_format.fmt.pix.width;
-       peasycap->pixelformat   = peasycap_format->v4l2_format.fmt.pix.pixelformat;
-       peasycap->format_offset = peasycap_format - easycap_format;
-
-
-       for (k = 0; k < INPUT_MANY; k++) {
-               if (!peasycap->inputset[k].format_offset_ok) {
-                       peasycap->inputset[k].format_offset =
-                               peasycap->format_offset;
-               }
-       }
-       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
-               peasycap->inputset[peasycap->input].format_offset =
-                       peasycap->format_offset;
-               peasycap->inputset[peasycap->input].format_offset_ok = 1;
-       } else
-               JOM(8, "%i=peasycap->input\n", peasycap->input);
-
-
-
-       peasycap->bytesperpixel = (0x00E0 & peasycap_format->mask) >> 5 ;
-       if (0x0100 & peasycap_format->mask)
-               peasycap->byteswaporder = true;
-       else
-               peasycap->byteswaporder = false;
-       if (0x0200 & peasycap_format->mask)
-               peasycap->skip = 5;
-       else
-               peasycap->skip = 0;
-       if (0x0800 & peasycap_format->mask)
-               peasycap->decimatepixel = true;
-       else
-               peasycap->decimatepixel = false;
-       if (0x1000 & peasycap_format->mask)
-               peasycap->offerfields = true;
-       else
-               peasycap->offerfields = false;
-       if (peasycap->decimatepixel)
-               multiplier = 2;
-       else
-               multiplier = 1;
-       peasycap->videofieldamount =
-               multiplier * peasycap->width * multiplier * peasycap->height;
-       peasycap->frame_buffer_used =
-               peasycap->bytesperpixel * peasycap->width * peasycap->height;
-       if (peasycap->video_isoc_streaming) {
-               resubmit = true;
-               kill_video_urbs(peasycap);
-       } else
-               resubmit = false;
-/*---------------------------------------------------------------------------*/
-/*
-        *  PAL
-        */
-/*---------------------------------------------------------------------------*/
-       if (0 == (0x01 & peasycap_format->mask)) {
-               if (((720 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                    (576 == peasycap_format->v4l2_format.fmt.pix.height)) ||
-                   ((360 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                    (288 == peasycap_format->v4l2_format.fmt.pix.height))) {
-                       if (set_resolution(p, 0x0000, 0x0001, 0x05A0, 0x0121)) {
-                               SAM("ERROR: set_resolution() failed\n");
-                               return -EINVAL;
-                       }
-               } else if ((704 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                          (576 == peasycap_format->v4l2_format.fmt.pix.height)) {
-                       if (set_resolution(p, 0x0004, 0x0001, 0x0584, 0x0121)) {
-                               SAM("ERROR: set_resolution() failed\n");
-                               return -EINVAL;
-                       }
-               } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                           (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
-                          ((320 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                           (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
-                       if (set_resolution(p, 0x0014, 0x0020, 0x0514, 0x0110)) {
-                               SAM("ERROR: set_resolution() failed\n");
-                               return -EINVAL;
-                       }
-               } else {
-                       SAM("MISTAKE: bad format, cannot set resolution\n");
-                       return -EINVAL;
-               }
-/*---------------------------------------------------------------------------*/
-/*
- *  NTSC
- */
-/*---------------------------------------------------------------------------*/
-       } else {
-               if (((720 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                    (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
-                   ((360 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                    (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
-                       if (set_resolution(p, 0x0000, 0x0003, 0x05A0, 0x00F3)) {
-                               SAM("ERROR: set_resolution() failed\n");
-                               return -EINVAL;
-                       }
-               } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                           (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
-                          ((320 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                           (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
-                       if (set_resolution(p, 0x0014, 0x0003, 0x0514, 0x00F3)) {
-                               SAM("ERROR: set_resolution() failed\n");
-                               return -EINVAL;
-                       }
-               } else {
-                       SAM("MISTAKE: bad format, cannot set resolution\n");
-                       return -EINVAL;
-               }
-       }
-/*---------------------------------------------------------------------------*/
-       if (resubmit)
-               submit_video_urbs(peasycap);
-
-       return peasycap_best_format - easycap_format;
-}
-/*****************************************************************************/
-int adjust_brightness(struct easycap *peasycap, int value)
-{
-       unsigned int mood;
-       int i1, k;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       i1 = 0;
-       while (0xFFFFFFFF != easycap_control[i1].id) {
-               if (V4L2_CID_BRIGHTNESS == easycap_control[i1].id) {
-                       if ((easycap_control[i1].minimum > value) ||
-                           (easycap_control[i1].maximum < value))
-                               value = easycap_control[i1].default_value;
-
-                       if ((easycap_control[i1].minimum <= peasycap->brightness) &&
-                           (easycap_control[i1].maximum >= peasycap->brightness)) {
-                               if (peasycap->brightness == value) {
-                                       SAM("unchanged brightness at  0x%02X\n",
-                                           value);
-                                       return 0;
-                               }
-                       }
-                       peasycap->brightness = value;
-                       for (k = 0; k < INPUT_MANY; k++) {
-                               if (!peasycap->inputset[k].brightness_ok)
-                                       peasycap->inputset[k].brightness =
-                                               peasycap->brightness;
-                       }
-                       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
-                               peasycap->inputset[peasycap->input].brightness =
-                                       peasycap->brightness;
-                               peasycap->inputset[peasycap->input].brightness_ok = 1;
-                       } else
-                               JOM(8, "%i=peasycap->input\n", peasycap->input);
-                       mood = 0x00FF & (unsigned int)peasycap->brightness;
-                       if (!write_saa(peasycap->pusb_device, 0x0A, mood)) {
-                               SAM("adjusting brightness to  0x%02X\n", mood);
-                               return 0;
-                       } else {
-                               SAM("WARNING: failed to adjust brightness "
-                                   "to 0x%02X\n", mood);
-                               return -ENOENT;
-                       }
-                       break;
-               }
-               i1++;
-       }
-       SAM("WARNING: failed to adjust brightness: control not found\n");
-       return -ENOENT;
-}
-/*****************************************************************************/
-int adjust_contrast(struct easycap *peasycap, int value)
-{
-       unsigned int mood;
-       int i1, k;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       i1 = 0;
-       while (0xFFFFFFFF != easycap_control[i1].id) {
-               if (V4L2_CID_CONTRAST == easycap_control[i1].id) {
-                       if ((easycap_control[i1].minimum > value) ||
-                           (easycap_control[i1].maximum < value))
-                               value = easycap_control[i1].default_value;
-
-
-                       if ((easycap_control[i1].minimum <= peasycap->contrast) &&
-                           (easycap_control[i1].maximum >= peasycap->contrast)) {
-                               if (peasycap->contrast == value) {
-                                       SAM("unchanged contrast at  0x%02X\n", value);
-                                       return 0;
-                               }
-                       }
-                       peasycap->contrast = value;
-                       for (k = 0; k < INPUT_MANY; k++) {
-                               if (!peasycap->inputset[k].contrast_ok)
-                                       peasycap->inputset[k].contrast = peasycap->contrast;
-                       }
-
-                       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
-                               peasycap->inputset[peasycap->input].contrast =
-                                               peasycap->contrast;
-                               peasycap->inputset[peasycap->input].contrast_ok = 1;
-                       } else
-                               JOM(8, "%i=peasycap->input\n", peasycap->input);
-
-                       mood = 0x00FF & (unsigned int) (peasycap->contrast - 128);
-                       if (!write_saa(peasycap->pusb_device, 0x0B, mood)) {
-                               SAM("adjusting contrast to  0x%02X\n", mood);
-                               return 0;
-                       } else {
-                               SAM("WARNING: failed to adjust contrast to "
-                                   "0x%02X\n", mood);
-                               return -ENOENT;
-                       }
-                       break;
-               }
-               i1++;
-       }
-       SAM("WARNING: failed to adjust contrast: control not found\n");
-       return -ENOENT;
-}
-/*****************************************************************************/
-int adjust_saturation(struct easycap *peasycap, int value)
-{
-       unsigned int mood;
-       int i1, k;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       i1 = 0;
-       while (0xFFFFFFFF != easycap_control[i1].id) {
-               if (V4L2_CID_SATURATION == easycap_control[i1].id) {
-                       if ((easycap_control[i1].minimum > value) ||
-                           (easycap_control[i1].maximum < value))
-                               value = easycap_control[i1].default_value;
-
-
-                       if ((easycap_control[i1].minimum <= peasycap->saturation) &&
-                           (easycap_control[i1].maximum >= peasycap->saturation)) {
-                               if (peasycap->saturation == value) {
-                                       SAM("unchanged saturation at  0x%02X\n",
-                                           value);
-                                       return 0;
-                               }
-                       }
-                       peasycap->saturation = value;
-                       for (k = 0; k < INPUT_MANY; k++) {
-                               if (!peasycap->inputset[k].saturation_ok)
-                                       peasycap->inputset[k].saturation =
-                                               peasycap->saturation;
-                       }
-                       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
-                               peasycap->inputset[peasycap->input].saturation =
-                                       peasycap->saturation;
-                               peasycap->inputset[peasycap->input].saturation_ok = 1;
-                       } else
-                               JOM(8, "%i=peasycap->input\n", peasycap->input);
-                       mood = 0x00FF & (unsigned int) (peasycap->saturation - 128);
-                       if (!write_saa(peasycap->pusb_device, 0x0C, mood)) {
-                               SAM("adjusting saturation to  0x%02X\n", mood);
-                               return 0;
-                       } else {
-                               SAM("WARNING: failed to adjust saturation to "
-                                   "0x%02X\n", mood);
-                               return -ENOENT;
-                       }
-                       break;
-               }
-               i1++;
-       }
-       SAM("WARNING: failed to adjust saturation: control not found\n");
-       return -ENOENT;
-}
-/*****************************************************************************/
-int adjust_hue(struct easycap *peasycap, int value)
-{
-       unsigned int mood;
-       int i1, i2, k;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       i1 = 0;
-       while (0xFFFFFFFF != easycap_control[i1].id) {
-               if (V4L2_CID_HUE == easycap_control[i1].id) {
-                       if ((easycap_control[i1].minimum > value) ||
-                           (easycap_control[i1].maximum < value))
-                               value = easycap_control[i1].default_value;
-
-                       if ((easycap_control[i1].minimum <= peasycap->hue) &&
-                           (easycap_control[i1].maximum >= peasycap->hue)) {
-                               if (peasycap->hue == value) {
-                                       SAM("unchanged hue at  0x%02X\n", value);
-                                       return 0;
-                               }
-                       }
-                       peasycap->hue = value;
-                       for (k = 0; k < INPUT_MANY; k++) {
-                               if (!peasycap->inputset[k].hue_ok)
-                                       peasycap->inputset[k].hue = peasycap->hue;
-                       }
-                       if (0 <= peasycap->input && INPUT_MANY > peasycap->input) {
-                               peasycap->inputset[peasycap->input].hue = peasycap->hue;
-                               peasycap->inputset[peasycap->input].hue_ok = 1;
-                       } else
-                               JOM(8, "%i=peasycap->input\n", peasycap->input);
-                       i2 = peasycap->hue - 128;
-                       mood = 0x00FF & ((int) i2);
-                       if (!write_saa(peasycap->pusb_device, 0x0D, mood)) {
-                               SAM("adjusting hue to  0x%02X\n", mood);
-                               return 0;
-                       } else {
-                               SAM("WARNING: failed to adjust hue to 0x%02X\n", mood);
-                               return -ENOENT;
-                       }
-                       break;
-               }
-               i1++;
-       }
-       SAM("WARNING: failed to adjust hue: control not found\n");
-       return -ENOENT;
-}
-/*****************************************************************************/
-int adjust_volume(struct easycap *peasycap, int value)
-{
-       s8 mood;
-       int i1;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       i1 = 0;
-       while (0xFFFFFFFF != easycap_control[i1].id) {
-               if (V4L2_CID_AUDIO_VOLUME == easycap_control[i1].id) {
-                       if ((easycap_control[i1].minimum > value) ||
-                           (easycap_control[i1].maximum < value))
-                               value = easycap_control[i1].default_value;
-
-                       if ((easycap_control[i1].minimum <= peasycap->volume) &&
-                           (easycap_control[i1].maximum >= peasycap->volume)) {
-                               if (peasycap->volume == value) {
-                                       SAM("unchanged volume at  0x%02X\n", value);
-                                       return 0;
-                               }
-                       }
-                       peasycap->volume = value;
-                       mood = (16 > peasycap->volume) ? 16 :
-                               ((31 < peasycap->volume) ? 31 :
-                                 (s8) peasycap->volume);
-                       if (!audio_gainset(peasycap->pusb_device, mood)) {
-                               SAM("adjusting volume to 0x%02X\n", mood);
-                               return 0;
-                       } else {
-                               SAM("WARNING: failed to adjust volume to "
-                                   "0x%2X\n", mood);
-                               return -ENOENT;
-                       }
-                       break;
-               }
-               i1++;
-       }
-       SAM("WARNING: failed to adjust volume: control not found\n");
-       return -ENOENT;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  AN ALTERNATIVE METHOD OF MUTING MIGHT SEEM TO BE:
- *            usb_set_interface(peasycap->pusb_device,
- *                              peasycap->audio_interface,
- *                              peasycap->audio_altsetting_off);
- *  HOWEVER, AFTER THIS COMMAND IS ISSUED ALL SUBSEQUENT URBS RECEIVE STATUS
- *  -ESHUTDOWN.  THE HANDLER ROUTINE easyxxx_complete() DECLINES TO RESUBMIT
- *  THE URB AND THE PIPELINE COLLAPSES IRRETRIEVABLY.  BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-static int adjust_mute(struct easycap *peasycap, int value)
-{
-       int i1;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       i1 = 0;
-       while (0xFFFFFFFF != easycap_control[i1].id) {
-               if (V4L2_CID_AUDIO_MUTE == easycap_control[i1].id) {
-                       peasycap->mute = value;
-                       switch (peasycap->mute) {
-                       case 1: {
-                               peasycap->audio_idle = 1;
-                               SAM("adjusting mute: %i=peasycap->audio_idle\n",
-                                   peasycap->audio_idle);
-                               return 0;
-                       }
-                       default: {
-                               peasycap->audio_idle = 0;
-                               SAM("adjusting mute: %i=peasycap->audio_idle\n",
-                                   peasycap->audio_idle);
-                               return 0;
-                       }
-                       }
-                       break;
-               }
-               i1++;
-       }
-       SAM("WARNING: failed to adjust mute: control not found\n");
-       return -ENOENT;
-}
-/*---------------------------------------------------------------------------*/
-long easycap_unlocked_ioctl(struct file *file,
-                           unsigned int cmd, unsigned long arg)
-{
-       struct easycap *peasycap;
-       struct usb_device *p;
-       int kd;
-
-       if (!file) {
-               SAY("ERROR:  file is NULL\n");
-               return -ERESTARTSYS;
-       }
-       peasycap = file->private_data;
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               return -1;
-       }
-       p = peasycap->pusb_device;
-       if (!p) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       kd = isdongle(peasycap);
-       if (0 <= kd && DONGLE_MANY > 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 easycapdc60_dongle[%i].mutex_video\n", kd);
-/*---------------------------------------------------------------------------*/
-/*
- *  MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
- *  IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
- *  IF NECESSARY, BAIL OUT.
- */
-/*---------------------------------------------------------------------------*/
-               if (kd != isdongle(peasycap))
-                       return -ERESTARTSYS;
-               if (!file) {
-                       SAY("ERROR:  file is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ERESTARTSYS;
-               }
-               peasycap = file->private_data;
-               if (!peasycap) {
-                       SAY("ERROR:  peasycap is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ERESTARTSYS;
-               }
-               if (!peasycap->pusb_device) {
-                       SAM("ERROR: peasycap->pusb_device is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ERESTARTSYS;
-               }
-       } else {
-/*---------------------------------------------------------------------------*/
-/*
- *  IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
- *  ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED.  BAIL OUT.
- */
-/*---------------------------------------------------------------------------*/
-               return -ERESTARTSYS;
-       }
-/*---------------------------------------------------------------------------*/
-       switch (cmd) {
-       case VIDIOC_QUERYCAP: {
-               struct v4l2_capability v4l2_capability;
-               char version[16], *p1, *p2;
-               int i, rc, k[3];
-               long lng;
-
-               JOM(8, "VIDIOC_QUERYCAP\n");
-
-               if (16 <= strlen(EASYCAP_DRIVER_VERSION)) {
-                       SAM("ERROR: bad driver version string\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               strcpy(&version[0], EASYCAP_DRIVER_VERSION);
-               for (i = 0; i < 3; i++)
-                       k[i] = 0;
-               p2 = &version[0];
-               i = 0;
-               while (*p2) {
-                       p1 = p2;
-                       while (*p2 && ('.' != *p2))
-                               p2++;
-                       if (*p2)
-                               *p2++ = 0;
-                       if (3 > i) {
-                               rc = (int) strict_strtol(p1, 10, &lng);
-                               if (rc) {
-                                       SAM("ERROR: %i=strict_strtol(%s,.,,)\n",
-                                           rc, p1);
-                                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                                       return -EINVAL;
-                               }
-                               k[i] = (int)lng;
-                       }
-                       i++;
-               }
-
-               memset(&v4l2_capability, 0, sizeof(struct v4l2_capability));
-               strlcpy(&v4l2_capability.driver[0],
-                       "easycap", sizeof(v4l2_capability.driver));
-
-               v4l2_capability.capabilities = V4L2_CAP_VIDEO_CAPTURE |
-                                               V4L2_CAP_STREAMING |
-                                               V4L2_CAP_AUDIO |
-                                               V4L2_CAP_READWRITE;
-
-               v4l2_capability.version = KERNEL_VERSION(k[0], k[1], k[2]);
-               JOM(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]);
-
-               strlcpy(&v4l2_capability.card[0],
-                       "EasyCAP DC60", sizeof(v4l2_capability.card));
-
-               if (usb_make_path(peasycap->pusb_device,
-                               &v4l2_capability.bus_info[0],
-                               sizeof(v4l2_capability.bus_info)) < 0) {
-
-                       strlcpy(&v4l2_capability.bus_info[0], "EasyCAP bus_info",
-                               sizeof(v4l2_capability.bus_info));
-                       JOM(8, "%s=v4l2_capability.bus_info\n",
-                               &v4l2_capability.bus_info[0]);
-               }
-               if (copy_to_user((void __user *)arg, &v4l2_capability,
-                               sizeof(struct v4l2_capability))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_ENUMINPUT: {
-               struct v4l2_input v4l2_input;
-               u32 index;
-
-               JOM(8, "VIDIOC_ENUMINPUT\n");
-
-               if (copy_from_user(&v4l2_input, (void __user *)arg,
-                                       sizeof(struct v4l2_input))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               index = v4l2_input.index;
-               memset(&v4l2_input, 0, sizeof(struct v4l2_input));
-
-               switch (index) {
-               case 0: {
-                       v4l2_input.index = index;
-                       strcpy(&v4l2_input.name[0], "CVBS0");
-                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
-                       v4l2_input.audioset = 0x01;
-                       v4l2_input.tuner = 0;
-                       v4l2_input.std = V4L2_STD_PAL |
-                                       V4L2_STD_SECAM |
-                                       V4L2_STD_NTSC ;
-                       v4l2_input.status = 0;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
-                       break;
-               }
-               case 1: {
-                       v4l2_input.index = index;
-                       strcpy(&v4l2_input.name[0], "CVBS1");
-                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
-                       v4l2_input.audioset = 0x01;
-                       v4l2_input.tuner = 0;
-                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
-                                       V4L2_STD_NTSC;
-                       v4l2_input.status = 0;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
-                       break;
-               }
-               case 2: {
-                       v4l2_input.index = index;
-                       strcpy(&v4l2_input.name[0], "CVBS2");
-                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
-                       v4l2_input.audioset = 0x01;
-                       v4l2_input.tuner = 0;
-                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
-                                       V4L2_STD_NTSC ;
-                       v4l2_input.status = 0;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
-                       break;
-               }
-               case 3: {
-                       v4l2_input.index = index;
-                       strcpy(&v4l2_input.name[0], "CVBS3");
-                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
-                       v4l2_input.audioset = 0x01;
-                       v4l2_input.tuner = 0;
-                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
-                                       V4L2_STD_NTSC ;
-                       v4l2_input.status = 0;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
-                       break;
-               }
-               case 4: {
-                       v4l2_input.index = index;
-                       strcpy(&v4l2_input.name[0], "CVBS4");
-                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
-                       v4l2_input.audioset = 0x01;
-                       v4l2_input.tuner = 0;
-                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
-                                       V4L2_STD_NTSC ;
-                       v4l2_input.status = 0;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
-                       break;
-               }
-               case 5: {
-                       v4l2_input.index = index;
-                       strcpy(&v4l2_input.name[0], "S-VIDEO");
-                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
-                       v4l2_input.audioset = 0x01;
-                       v4l2_input.tuner = 0;
-                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
-                                       V4L2_STD_NTSC ;
-                       v4l2_input.status = 0;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
-                       break;
-               }
-               default: {
-                       JOM(8, "%i=index: exhausts inputs\n", index);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               }
-
-               if (copy_to_user((void __user *)arg, &v4l2_input,
-                               sizeof(struct v4l2_input))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_INPUT: {
-               u32 index;
-
-               JOM(8, "VIDIOC_G_INPUT\n");
-               index = (u32)peasycap->input;
-               JOM(8, "user is told: %i\n", index);
-               if (copy_to_user((void __user *)arg, &index, sizeof(u32))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_INPUT:
-       {
-               u32 index;
-               int rc;
-
-               JOM(8, "VIDIOC_S_INPUT\n");
-
-               if (0 != copy_from_user(&index, (void __user *)arg, sizeof(u32))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               JOM(8, "user requests input %i\n", index);
-
-               if ((int)index == peasycap->input) {
-                       SAM("requested input already in effect\n");
-                       break;
-               }
-
-               if ((0 > index) || (INPUT_MANY <= index)) {
-                       JOM(8, "ERROR:  bad requested input: %i\n", index);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-
-               rc = newinput(peasycap, (int)index);
-               if (0 == rc) {
-                       JOM(8, "newinput(.,%i) OK\n", (int)index);
-               } else {
-                       SAM("ERROR: newinput(.,%i) returned %i\n", (int)index, rc);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_ENUMAUDIO: {
-               JOM(8, "VIDIOC_ENUMAUDIO\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_ENUMAUDOUT: {
-               struct v4l2_audioout v4l2_audioout;
-
-               JOM(8, "VIDIOC_ENUMAUDOUT\n");
-
-               if (copy_from_user(&v4l2_audioout, (void __user *)arg,
-                                       sizeof(struct v4l2_audioout))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               if (0 != v4l2_audioout.index) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout));
-               v4l2_audioout.index = 0;
-               strcpy(&v4l2_audioout.name[0], "Soundtrack");
-
-               if (copy_to_user((void __user *)arg, &v4l2_audioout,
-                               sizeof(struct v4l2_audioout))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_QUERYCTRL: {
-               int i1;
-               struct v4l2_queryctrl v4l2_queryctrl;
-
-               JOM(8, "VIDIOC_QUERYCTRL\n");
-
-               if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg,
-                               sizeof(struct v4l2_queryctrl))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               i1 = 0;
-               while (0xFFFFFFFF != easycap_control[i1].id) {
-                       if (easycap_control[i1].id == v4l2_queryctrl.id) {
-                               JOM(8, "VIDIOC_QUERYCTRL  %s=easycap_control[%i]"
-                                   ".name\n", &easycap_control[i1].name[0], i1);
-                               memcpy(&v4l2_queryctrl, &easycap_control[i1],
-                                      sizeof(struct v4l2_queryctrl));
-                               break;
-                       }
-                       i1++;
-               }
-               if (0xFFFFFFFF == easycap_control[i1].id) {
-                       JOM(8, "%i=index: exhausts controls\n", i1);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               if (copy_to_user((void __user *)arg, &v4l2_queryctrl,
-                               sizeof(struct v4l2_queryctrl))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_QUERYMENU: {
-               JOM(8, "VIDIOC_QUERYMENU unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_CTRL: {
-               struct v4l2_control *pv4l2_control;
-
-               JOM(8, "VIDIOC_G_CTRL\n");
-               pv4l2_control = memdup_user((void __user *)arg,
-                                           sizeof(struct v4l2_control));
-               if (IS_ERR(pv4l2_control)) {
-                       SAM("ERROR: copy from user failed\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return PTR_ERR(pv4l2_control);
-               }
-
-               switch (pv4l2_control->id) {
-               case V4L2_CID_BRIGHTNESS: {
-                       pv4l2_control->value = peasycap->brightness;
-                       JOM(8, "user enquires brightness: %i\n", pv4l2_control->value);
-                       break;
-               }
-               case V4L2_CID_CONTRAST: {
-                       pv4l2_control->value = peasycap->contrast;
-                       JOM(8, "user enquires contrast: %i\n", pv4l2_control->value);
-                       break;
-               }
-               case V4L2_CID_SATURATION: {
-                       pv4l2_control->value = peasycap->saturation;
-                       JOM(8, "user enquires saturation: %i\n", pv4l2_control->value);
-                       break;
-               }
-               case V4L2_CID_HUE: {
-                       pv4l2_control->value = peasycap->hue;
-                       JOM(8, "user enquires hue: %i\n", pv4l2_control->value);
-                       break;
-               }
-               case V4L2_CID_AUDIO_VOLUME: {
-                       pv4l2_control->value = peasycap->volume;
-                       JOM(8, "user enquires volume: %i\n", pv4l2_control->value);
-                       break;
-               }
-               case V4L2_CID_AUDIO_MUTE: {
-                       if (1 == peasycap->mute)
-                               pv4l2_control->value = true;
-                       else
-                               pv4l2_control->value = false;
-                       JOM(8, "user enquires mute: %i\n", pv4l2_control->value);
-                       break;
-               }
-               default: {
-                       SAM("ERROR: unknown V4L2 control: 0x%08X=id\n",
-                           pv4l2_control->id);
-                       kfree(pv4l2_control);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               }
-               if (copy_to_user((void __user *)arg, pv4l2_control,
-                               sizeof(struct v4l2_control))) {
-                       kfree(pv4l2_control);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               kfree(pv4l2_control);
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_CTRL: {
-               struct v4l2_control v4l2_control;
-
-               JOM(8, "VIDIOC_S_CTRL\n");
-
-               if (0 != copy_from_user(&v4l2_control, (void __user *)arg,
-                               sizeof(struct v4l2_control))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               switch (v4l2_control.id) {
-               case V4L2_CID_BRIGHTNESS: {
-                       JOM(8, "user requests brightness %i\n", v4l2_control.value);
-                       if (0 != adjust_brightness(peasycap, v4l2_control.value))
-                               ;
-                       break;
-               }
-               case V4L2_CID_CONTRAST: {
-                       JOM(8, "user requests contrast %i\n", v4l2_control.value);
-                       if (0 != adjust_contrast(peasycap, v4l2_control.value))
-                               ;
-                       break;
-               }
-               case V4L2_CID_SATURATION: {
-                       JOM(8, "user requests saturation %i\n", v4l2_control.value);
-                       if (0 != adjust_saturation(peasycap, v4l2_control.value))
-                               ;
-                       break;
-               }
-               case V4L2_CID_HUE: {
-                       JOM(8, "user requests hue %i\n", v4l2_control.value);
-                       if (0 != adjust_hue(peasycap, v4l2_control.value))
-                               ;
-                       break;
-               }
-               case V4L2_CID_AUDIO_VOLUME: {
-                       JOM(8, "user requests volume %i\n", v4l2_control.value);
-                       if (0 != adjust_volume(peasycap, v4l2_control.value))
-                               ;
-                       break;
-               }
-               case V4L2_CID_AUDIO_MUTE: {
-                       int mute;
-
-                       JOM(8, "user requests mute %i\n", v4l2_control.value);
-                       if (v4l2_control.value)
-                               mute = 1;
-                       else
-                               mute = 0;
-
-                       if (0 != adjust_mute(peasycap, mute))
-                               SAM("WARNING: failed to adjust mute to %i\n", mute);
-                       break;
-               }
-               default: {
-                       SAM("ERROR: unknown V4L2 control: 0x%08X=id\n",
-                           v4l2_control.id);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_EXT_CTRLS: {
-               JOM(8, "VIDIOC_S_EXT_CTRLS unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_ENUM_FMT: {
-               u32 index;
-               struct v4l2_fmtdesc v4l2_fmtdesc;
-
-               JOM(8, "VIDIOC_ENUM_FMT\n");
-
-               if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg,
-                               sizeof(struct v4l2_fmtdesc))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               index = v4l2_fmtdesc.index;
-               memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc));
-
-               v4l2_fmtdesc.index = index;
-               v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-               switch (index) {
-               case 0: {
-                       v4l2_fmtdesc.flags = 0;
-                       strcpy(&v4l2_fmtdesc.description[0], "uyvy");
-                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_UYVY;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
-                       break;
-               }
-               case 1: {
-                       v4l2_fmtdesc.flags = 0;
-                       strcpy(&v4l2_fmtdesc.description[0], "yuy2");
-                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_YUYV;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
-                       break;
-               }
-               case 2: {
-                       v4l2_fmtdesc.flags = 0;
-                       strcpy(&v4l2_fmtdesc.description[0], "rgb24");
-                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB24;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
-                       break;
-               }
-               case 3: {
-                       v4l2_fmtdesc.flags = 0;
-                       strcpy(&v4l2_fmtdesc.description[0], "rgb32");
-                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB32;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
-                       break;
-               }
-               case 4: {
-                       v4l2_fmtdesc.flags = 0;
-                       strcpy(&v4l2_fmtdesc.description[0], "bgr24");
-                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR24;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
-                       break;
-               }
-               case 5: {
-                       v4l2_fmtdesc.flags = 0;
-                       strcpy(&v4l2_fmtdesc.description[0], "bgr32");
-                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR32;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
-                       break;
-               }
-               default: {
-                       JOM(8, "%i=index: exhausts formats\n", index);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               }
-               if (copy_to_user((void __user *)arg, &v4l2_fmtdesc,
-                               sizeof(struct v4l2_fmtdesc))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/*
-        *  THE RESPONSE TO VIDIOC_ENUM_FRAMESIZES MUST BE CONDITIONED ON THE
-        *  THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS.  BEWARE.
-       */
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_ENUM_FRAMESIZES: {
-               u32 index;
-               struct v4l2_frmsizeenum v4l2_frmsizeenum;
-
-               JOM(8, "VIDIOC_ENUM_FRAMESIZES\n");
-
-               if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg,
-                               sizeof(struct v4l2_frmsizeenum))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               index = v4l2_frmsizeenum.index;
-
-               v4l2_frmsizeenum.type = (u32) V4L2_FRMSIZE_TYPE_DISCRETE;
-
-               if (peasycap->ntsc) {
-                       switch (index) {
-                       case 0: {
-                               v4l2_frmsizeenum.discrete.width = 640;
-                               v4l2_frmsizeenum.discrete.height = 480;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       case 1: {
-                               v4l2_frmsizeenum.discrete.width = 320;
-                               v4l2_frmsizeenum.discrete.height = 240;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       case 2: {
-                               v4l2_frmsizeenum.discrete.width = 720;
-                               v4l2_frmsizeenum.discrete.height = 480;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       case 3: {
-                               v4l2_frmsizeenum.discrete.width = 360;
-                               v4l2_frmsizeenum.discrete.height = 240;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       default: {
-                               JOM(8, "%i=index: exhausts framesizes\n", index);
-                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                               return -EINVAL;
-                       }
-                       }
-               } else {
-                       switch (index) {
-                       case 0: {
-                               v4l2_frmsizeenum.discrete.width = 640;
-                               v4l2_frmsizeenum.discrete.height = 480;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       case 1: {
-                               v4l2_frmsizeenum.discrete.width = 320;
-                               v4l2_frmsizeenum.discrete.height = 240;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       case 2: {
-                               v4l2_frmsizeenum.discrete.width = 704;
-                               v4l2_frmsizeenum.discrete.height = 576;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       case 3: {
-                               v4l2_frmsizeenum.discrete.width = 720;
-                               v4l2_frmsizeenum.discrete.height = 576;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       case 4: {
-                               v4l2_frmsizeenum.discrete.width = 360;
-                               v4l2_frmsizeenum.discrete.height = 288;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       default: {
-                               JOM(8, "%i=index: exhausts framesizes\n", index);
-                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                               return -EINVAL;
-                       }
-                       }
-               }
-               if (copy_to_user((void __user *)arg, &v4l2_frmsizeenum,
-                               sizeof(struct v4l2_frmsizeenum))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/*
-        *  THE RESPONSE TO VIDIOC_ENUM_FRAMEINTERVALS MUST BE CONDITIONED ON THE
-        *  THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS.  BEWARE.
-       */
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_ENUM_FRAMEINTERVALS: {
-               u32 index;
-               int denominator;
-               struct v4l2_frmivalenum v4l2_frmivalenum;
-
-               JOM(8, "VIDIOC_ENUM_FRAMEINTERVALS\n");
-
-               if (peasycap->fps)
-                       denominator = peasycap->fps;
-               else {
-                       if (peasycap->ntsc)
-                               denominator = 30;
-                       else
-                               denominator = 25;
-               }
-
-               if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg,
-                               sizeof(struct v4l2_frmivalenum))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               index = v4l2_frmivalenum.index;
-
-               v4l2_frmivalenum.type = (u32) V4L2_FRMIVAL_TYPE_DISCRETE;
-
-               switch (index) {
-               case 0: {
-                       v4l2_frmivalenum.discrete.numerator = 1;
-                       v4l2_frmivalenum.discrete.denominator = denominator;
-                       JOM(8, "%i=index: %i/%i\n", index,
-                           (int)(v4l2_frmivalenum.discrete.numerator),
-                           (int)(v4l2_frmivalenum.discrete.denominator));
-                       break;
-               }
-               case 1: {
-                       v4l2_frmivalenum.discrete.numerator = 1;
-                       v4l2_frmivalenum.discrete.denominator = denominator/5;
-                       JOM(8, "%i=index: %i/%i\n", index,
-                           (int)(v4l2_frmivalenum.discrete.numerator),
-                           (int)(v4l2_frmivalenum.discrete.denominator));
-                       break;
-               }
-               default: {
-                       JOM(8, "%i=index: exhausts frameintervals\n", index);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               }
-               if (copy_to_user((void __user *)arg, &v4l2_frmivalenum,
-                                       sizeof(struct v4l2_frmivalenum))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_FMT: {
-               struct v4l2_format *pv4l2_format;
-               struct v4l2_pix_format *pv4l2_pix_format;
-
-               JOM(8, "VIDIOC_G_FMT\n");
-               pv4l2_format = kzalloc(sizeof(struct v4l2_format), GFP_KERNEL);
-               if (!pv4l2_format) {
-                       SAM("ERROR: out of memory\n");
-                       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(&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(&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(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-
-               memset(pv4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
-               pv4l2_format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               memcpy(&pv4l2_format->fmt.pix,
-                      &easycap_format[peasycap->format_offset]
-                      .v4l2_format.fmt.pix, sizeof(struct v4l2_pix_format));
-               JOM(8, "user is told: %s\n",
-                   &easycap_format[peasycap->format_offset].name[0]);
-
-               if (copy_to_user((void __user *)arg, pv4l2_format,
-                                       sizeof(struct v4l2_format))) {
-                       kfree(pv4l2_format);
-                       kfree(pv4l2_pix_format);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               kfree(pv4l2_format);
-               kfree(pv4l2_pix_format);
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_TRY_FMT:
-       case VIDIOC_S_FMT: {
-               struct v4l2_format v4l2_format;
-               struct v4l2_pix_format v4l2_pix_format;
-               bool try;
-               int best_format;
-
-               if (VIDIOC_TRY_FMT == cmd) {
-                       JOM(8, "VIDIOC_TRY_FMT\n");
-                       try = true;
-               } else {
-                       JOM(8, "VIDIOC_S_FMT\n");
-                       try = false;
-               }
-
-               if (0 != copy_from_user(&v4l2_format, (void __user *)arg,
-                                       sizeof(struct v4l2_format))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               best_format = adjust_format(peasycap,
-                                       v4l2_format.fmt.pix.width,
-                                       v4l2_format.fmt.pix.height,
-                                       v4l2_format.fmt.pix.pixelformat,
-                                       v4l2_format.fmt.pix.field,
-                                       try);
-               if (0 > best_format) {
-                       if (-EBUSY == best_format) {
-                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                               return -EBUSY;
-                       }
-                       JOM(8, "WARNING: adjust_format() returned %i\n", best_format);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ENOENT;
-               }
-/*...........................................................................*/
-               memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
-               v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-               memcpy(&(v4l2_format.fmt.pix),
-                       &(easycap_format[best_format].v4l2_format.fmt.pix),
-                       sizeof(v4l2_pix_format));
-               JOM(8, "user is told: %s\n", &easycap_format[best_format].name[0]);
-
-               if (copy_to_user((void __user *)arg, &v4l2_format,
-                                       sizeof(struct v4l2_format))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_CROPCAP: {
-               struct v4l2_cropcap v4l2_cropcap;
-
-               JOM(8, "VIDIOC_CROPCAP\n");
-
-               if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg,
-                                       sizeof(struct v4l2_cropcap))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       JOM(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
-
-               memset(&v4l2_cropcap, 0, sizeof(struct v4l2_cropcap));
-               v4l2_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               v4l2_cropcap.bounds.left      = 0;
-               v4l2_cropcap.bounds.top       = 0;
-               v4l2_cropcap.bounds.width     = peasycap->width;
-               v4l2_cropcap.bounds.height    = peasycap->height;
-               v4l2_cropcap.defrect.left     = 0;
-               v4l2_cropcap.defrect.top      = 0;
-               v4l2_cropcap.defrect.width    = peasycap->width;
-               v4l2_cropcap.defrect.height   = peasycap->height;
-               v4l2_cropcap.pixelaspect.numerator = 1;
-               v4l2_cropcap.pixelaspect.denominator = 1;
-
-               JOM(8, "user is told: %ix%i\n", peasycap->width, peasycap->height);
-
-               if (copy_to_user((void __user *)arg, &v4l2_cropcap,
-                                       sizeof(struct v4l2_cropcap))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_CROP:
-       case VIDIOC_S_CROP: {
-               JOM(8, "VIDIOC_G_CROP|VIDIOC_S_CROP  unsupported\n");
-               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(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-               break;
-       }
-       /*-------------------------------------------------------------------*/
-       /*
-        *  THE MANIPULATIONS INVOLVING last0,last1,last2,last3
-        *  CONSTITUTE A WORKAROUND *  FOR WHAT APPEARS TO BE
-        *  A BUG IN 64-BIT mplayer.
-        *  NOT NEEDED, BUT HOPEFULLY HARMLESS, FOR 32-BIT mplayer.
-        */
-       /*------------------------------------------------------------------*/
-       case VIDIOC_ENUMSTD: {
-               int last0 = -1, last1 = -1, last2 = -1, last3 = -1;
-               struct v4l2_standard v4l2_standard;
-               u32 index;
-               struct easycap_standard const *peasycap_standard;
-
-               JOM(8, "VIDIOC_ENUMSTD\n");
-
-               if (0 != copy_from_user(&v4l2_standard, (void __user *)arg,
-                                       sizeof(struct v4l2_standard))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               index = v4l2_standard.index;
-
-               last3 = last2;
-               last2 = last1;
-               last1 = last0;
-               last0 = index;
-               if ((index == last3) && (index == last2) &&
-                   (index == last1) && (index == last0)) {
-                       index++;
-                       last3 = last2;
-                       last2 = last1;
-                       last1 = last0;
-                       last0 = index;
-               }
-
-               memset(&v4l2_standard, 0, sizeof(struct v4l2_standard));
-
-               peasycap_standard = &easycap_standard[0];
-               while (0xFFFF != peasycap_standard->mask) {
-                       if ((int)(peasycap_standard - &easycap_standard[0]) == index)
-                               break;
-                       peasycap_standard++;
-               }
-               if (0xFFFF == peasycap_standard->mask) {
-                       JOM(8, "%i=index: exhausts standards\n", index);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               JOM(8, "%i=index: %s\n", index,
-                   &(peasycap_standard->v4l2_standard.name[0]));
-               memcpy(&v4l2_standard, &(peasycap_standard->v4l2_standard),
-                      sizeof(struct v4l2_standard));
-
-               v4l2_standard.index = index;
-
-               if (copy_to_user((void __user *)arg, &v4l2_standard,
-                               sizeof(struct v4l2_standard))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_STD: {
-               v4l2_std_id std_id;
-               struct easycap_standard const *peasycap_standard;
-
-               JOM(8, "VIDIOC_G_STD\n");
-
-               if (0 > peasycap->standard_offset) {
-                       JOM(8, "%i=peasycap->standard_offset\n",
-                           peasycap->standard_offset);
-                       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(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               peasycap_standard = &easycap_standard[peasycap->standard_offset];
-               std_id = peasycap_standard->v4l2_standard.id;
-
-               JOM(8, "user is told: %s\n",
-                   &peasycap_standard->v4l2_standard.name[0]);
-
-               if (copy_to_user((void __user *)arg, &std_id,
-                                       sizeof(v4l2_std_id))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_STD: {
-               v4l2_std_id std_id;
-               int rc;
-
-               JOM(8, "VIDIOC_S_STD\n");
-
-               if (0 != copy_from_user(&std_id, (void __user *)arg,
-                                       sizeof(v4l2_std_id))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               JOM(8, "User requests standard: 0x%08X%08X\n",
-                   (int)((std_id & (((v4l2_std_id)0xFFFFFFFF) << 32)) >> 32),
-                   (int)(std_id & ((v4l2_std_id)0xFFFFFFFF)));
-
-               rc = adjust_standard(peasycap, std_id);
-               if (0 > rc) {
-                       JOM(8, "WARNING: adjust_standard() returned %i\n", rc);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ENOENT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_REQBUFS: {
-               int nbuffers;
-               struct v4l2_requestbuffers v4l2_requestbuffers;
-
-               JOM(8, "VIDIOC_REQBUFS\n");
-
-               if (0 != copy_from_user(&v4l2_requestbuffers,
-                                       (void __user *)arg,
-                                       sizeof(struct v4l2_requestbuffers))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               nbuffers = v4l2_requestbuffers.count;
-               JOM(8, "                   User requests %i buffers ...\n", nbuffers);
-               if (nbuffers < 2)
-                       nbuffers = 2;
-               if (nbuffers > FRAME_BUFFER_MANY)
-                       nbuffers = FRAME_BUFFER_MANY;
-               if (v4l2_requestbuffers.count == nbuffers) {
-                       JOM(8, "                   ... agree to  %i buffers\n",
-                           nbuffers);
-               } else {
-                       JOM(8, "                  ... insist on  %i buffers\n",
-                           nbuffers);
-                       v4l2_requestbuffers.count = nbuffers;
-               }
-               peasycap->frame_buffer_many = nbuffers;
-
-               if (copy_to_user((void __user *)arg, &v4l2_requestbuffers,
-                                       sizeof(struct v4l2_requestbuffers))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_QUERYBUF: {
-               u32 index;
-               struct v4l2_buffer v4l2_buffer;
-
-               JOM(8, "VIDIOC_QUERYBUF\n");
-
-               if (peasycap->video_eof) {
-                       JOM(8, "returning -EIO because  %i=video_eof\n",
-                           peasycap->video_eof);
-                       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(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               index = v4l2_buffer.index;
-               if (index < 0 || index >= peasycap->frame_buffer_many)
-                       return -EINVAL;
-               memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer));
-               v4l2_buffer.index = index;
-               v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               v4l2_buffer.bytesused = peasycap->frame_buffer_used;
-               v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED |
-                                       peasycap->done[index] |
-                                       peasycap->queued[index];
-               v4l2_buffer.field = V4L2_FIELD_NONE;
-               v4l2_buffer.memory = V4L2_MEMORY_MMAP;
-               v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE;
-               v4l2_buffer.length = FRAME_BUFFER_SIZE;
-
-               JOM(16, "  %10i=index\n", v4l2_buffer.index);
-               JOM(16, "  0x%08X=type\n", v4l2_buffer.type);
-               JOM(16, "  %10i=bytesused\n", v4l2_buffer.bytesused);
-               JOM(16, "  0x%08X=flags\n", v4l2_buffer.flags);
-               JOM(16, "  %10i=field\n", v4l2_buffer.field);
-               JOM(16, "  %10li=timestamp.tv_usec\n",
-                   (long)v4l2_buffer.timestamp.tv_usec);
-               JOM(16, "  %10i=sequence\n", v4l2_buffer.sequence);
-               JOM(16, "  0x%08X=memory\n", v4l2_buffer.memory);
-               JOM(16, "  %10i=m.offset\n", v4l2_buffer.m.offset);
-               JOM(16, "  %10i=length\n", v4l2_buffer.length);
-
-               if (copy_to_user((void __user *)arg, &v4l2_buffer,
-                                       sizeof(struct v4l2_buffer))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_QBUF: {
-               struct v4l2_buffer v4l2_buffer;
-
-               JOM(8, "VIDIOC_QBUF\n");
-
-               if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg,
-                                       sizeof(struct v4l2_buffer))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               if (v4l2_buffer.index < 0 ||
-                   v4l2_buffer.index >= peasycap->frame_buffer_many) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
-
-               peasycap->done[v4l2_buffer.index]   = 0;
-               peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED;
-
-               if (copy_to_user((void __user *)arg, &v4l2_buffer,
-                                       sizeof(struct v4l2_buffer))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               JOM(8, ".....   user queueing frame buffer %i\n",
-                   (int)v4l2_buffer.index);
-
-               peasycap->frame_lock = 0;
-
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_DQBUF:
-       {
-               struct timeval timeval, timeval2;
-               int i, j;
-               struct v4l2_buffer v4l2_buffer;
-               int rcdq;
-               u16 input;
-
-               JOM(8, "VIDIOC_DQBUF\n");
-
-               if ((peasycap->video_idle) || (peasycap->video_eof)) {
-                       JOM(8, "returning -EIO because  "
-                           "%i=video_idle  %i=video_eof\n",
-                           peasycap->video_idle, peasycap->video_eof);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EIO;
-               }
-
-               if (copy_from_user(&v4l2_buffer, (void __user *)arg,
-                                 sizeof(struct v4l2_buffer))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-
-               if (peasycap->offerfields) {
-                       /*---------------------------------------------------*/
-                       /*
-                        *  IN ITS 50 "fps" MODE tvtime SEEMS ALWAYS TO REQUEST
-                        *  V4L2_FIELD_BOTTOM
-                        */
-                       /*---------------------------------------------------*/
-                       if (V4L2_FIELD_TOP == v4l2_buffer.field)
-                               JOM(8, "user wants V4L2_FIELD_TOP\n");
-                       else if (V4L2_FIELD_BOTTOM == v4l2_buffer.field)
-                               JOM(8, "user wants V4L2_FIELD_BOTTOM\n");
-                       else if (V4L2_FIELD_ANY == v4l2_buffer.field)
-                               JOM(8, "user wants V4L2_FIELD_ANY\n");
-                       else
-                               JOM(8, "user wants V4L2_FIELD_...UNKNOWN: %i\n",
-                                   v4l2_buffer.field);
-               }
-
-               if (!peasycap->video_isoc_streaming) {
-                       JOM(16, "returning -EIO because video urbs not streaming\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EIO;
-               }
-       /*-------------------------------------------------------------------*/
-       /*
-        *  IF THE USER HAS PREVIOUSLY CALLED easycap_poll(),
-        *  AS DETERMINED BY FINDING
-        *  THE FLAG peasycap->polled SET, THERE MUST BE
-        *  NO FURTHER WAIT HERE.  IN THIS
-        *  CASE, JUST CHOOSE THE FRAME INDICATED BY peasycap->frame_read
-        */
-       /*-------------------------------------------------------------------*/
-
-               if (!peasycap->polled) {
-                       do {
-                               rcdq = easycap_dqbuf(peasycap, 0);
-                               if (-EIO == rcdq) {
-                                       JOM(8, "returning -EIO because "
-                                           "dqbuf() returned -EIO\n");
-                                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                                       return -EIO;
-                               }
-                       } while (0 != rcdq);
-               } else {
-                       if (peasycap->video_eof) {
-                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                               return -EIO;
-                       }
-               }
-               if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) {
-                       JOM(8, "V4L2_BUF_FLAG_DONE != 0x%08X\n",
-                           peasycap->done[peasycap->frame_read]);
-               }
-               peasycap->polled = 0;
-
-               if (!(peasycap->isequence % 10)) {
-                       for (i = 0; i < 179; i++)
-                               peasycap->merit[i] = peasycap->merit[i+1];
-                       peasycap->merit[179] = merit_saa(peasycap->pusb_device);
-                       j = 0;
-                       for (i = 0; i < 180; i++)
-                               j += peasycap->merit[i];
-                       if (90 < j) {
-                               SAM("easycap driver shutting down "
-                                   "on condition blue\n");
-                               peasycap->video_eof = 1;
-                               peasycap->audio_eof = 1;
-                       }
-               }
-
-               v4l2_buffer.index = peasycap->frame_read;
-               v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               v4l2_buffer.bytesused = peasycap->frame_buffer_used;
-               v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
-               if (peasycap->offerfields)
-                       v4l2_buffer.field = V4L2_FIELD_BOTTOM;
-               else
-                       v4l2_buffer.field = V4L2_FIELD_NONE;
-               do_gettimeofday(&timeval);
-               timeval2 = timeval;
-
-               v4l2_buffer.timestamp = timeval2;
-               v4l2_buffer.sequence = peasycap->isequence++;
-               v4l2_buffer.memory = V4L2_MEMORY_MMAP;
-               v4l2_buffer.m.offset = v4l2_buffer.index * FRAME_BUFFER_SIZE;
-               v4l2_buffer.length = FRAME_BUFFER_SIZE;
-
-               JOM(16, "  %10i=index\n", v4l2_buffer.index);
-               JOM(16, "  0x%08X=type\n", v4l2_buffer.type);
-               JOM(16, "  %10i=bytesused\n", v4l2_buffer.bytesused);
-               JOM(16, "  0x%08X=flags\n", v4l2_buffer.flags);
-               JOM(16, "  %10i=field\n", v4l2_buffer.field);
-               JOM(16, "  %10li=timestamp.tv_sec\n",
-                   (long)v4l2_buffer.timestamp.tv_sec);
-               JOM(16, "  %10li=timestamp.tv_usec\n",
-                   (long)v4l2_buffer.timestamp.tv_usec);
-               JOM(16, "  %10i=sequence\n", v4l2_buffer.sequence);
-               JOM(16, "  0x%08X=memory\n", v4l2_buffer.memory);
-               JOM(16, "  %10i=m.offset\n", v4l2_buffer.m.offset);
-               JOM(16, "  %10i=length\n", v4l2_buffer.length);
-
-               if (copy_to_user((void __user *)arg, &v4l2_buffer,
-                                       sizeof(struct v4l2_buffer))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               input = peasycap->frame_buffer[peasycap->frame_read][0].input;
-               if (0x08 & input) {
-                       JOM(8, "user is offered frame buffer %i, input %i\n",
-                           peasycap->frame_read, (0x07 & input));
-               } else {
-                       JOM(8, "user is offered frame buffer %i\n",
-                           peasycap->frame_read);
-               }
-               peasycap->frame_lock = 1;
-               JOM(8, "%i=peasycap->frame_fill\n", peasycap->frame_fill);
-               if (peasycap->frame_read == peasycap->frame_fill) {
-                       if (peasycap->frame_lock) {
-                               JOM(8, "WORRY:  filling frame buffer "
-                                   "while offered to user\n");
-                       }
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_STREAMON: {
-               int i;
-
-               JOM(8, "VIDIOC_STREAMON\n");
-
-               peasycap->isequence = 0;
-               for (i = 0; i < 180; i++)
-                       peasycap->merit[i] = 0;
-               if (!peasycap->pusb_device) {
-                       SAM("ERROR: peasycap->pusb_device is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               submit_video_urbs(peasycap);
-               peasycap->video_idle = 0;
-               peasycap->audio_idle = 0;
-               peasycap->video_eof = 0;
-               peasycap->audio_eof = 0;
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_STREAMOFF: {
-               JOM(8, "VIDIOC_STREAMOFF\n");
-
-               if (!peasycap->pusb_device) {
-                       SAM("ERROR: peasycap->pusb_device is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               peasycap->video_idle = 1;
-               peasycap->audio_idle = 1;
-/*---------------------------------------------------------------------------*/
-/*
- *  IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO THE STREAMOFF COMMAND
- *  THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT.   BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-               JOM(8, "calling wake_up on wq_video and wq_audio\n");
-               wake_up_interruptible(&(peasycap->wq_video));
-               if (peasycap->psubstream)
-                       snd_pcm_period_elapsed(peasycap->psubstream);
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_PARM: {
-               struct v4l2_streamparm *pv4l2_streamparm;
-
-               JOM(8, "VIDIOC_G_PARM\n");
-               pv4l2_streamparm = memdup_user((void __user *)arg,
-                                              sizeof(struct v4l2_streamparm));
-               if (IS_ERR(pv4l2_streamparm)) {
-                       SAM("ERROR: copy from user failed\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return PTR_ERR(pv4l2_streamparm);
-               }
-
-               if (pv4l2_streamparm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       kfree(pv4l2_streamparm);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               pv4l2_streamparm->parm.capture.capability = 0;
-               pv4l2_streamparm->parm.capture.capturemode = 0;
-               pv4l2_streamparm->parm.capture.timeperframe.numerator = 1;
-
-               if (peasycap->fps) {
-                       pv4l2_streamparm->parm.capture.timeperframe.
-                       denominator = peasycap->fps;
-               } else {
-                       if (peasycap->ntsc) {
-                               pv4l2_streamparm->parm.capture.timeperframe.
-                               denominator = 30;
-                       } else {
-                               pv4l2_streamparm->parm.capture.timeperframe.
-                               denominator = 25;
-                       }
-               }
-
-               pv4l2_streamparm->parm.capture.readbuffers =
-                       peasycap->frame_buffer_many;
-               pv4l2_streamparm->parm.capture.extendedmode = 0;
-               if (copy_to_user((void __user *)arg,
-                               pv4l2_streamparm,
-                               sizeof(struct v4l2_streamparm))) {
-                       kfree(pv4l2_streamparm);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               kfree(pv4l2_streamparm);
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_PARM: {
-               JOM(8, "VIDIOC_S_PARM unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_AUDIO: {
-               JOM(8, "VIDIOC_G_AUDIO unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_AUDIO: {
-               JOM(8, "VIDIOC_S_AUDIO unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_TUNER: {
-               JOM(8, "VIDIOC_S_TUNER unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       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(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_TUNER: {
-               JOM(8, "VIDIOC_G_TUNER unsupported\n");
-               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(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       default: {
-               JOM(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd);
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -ENOIOCTLCMD;
-       }
-       }
-       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-       JOM(4, "unlocked easycapdc60_dongle[%i].mutex_video\n", kd);
-       return 0;
-}
-/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_low.c b/drivers/staging/easycap/easycap_low.c
deleted file mode 100644 (file)
index 0385735..0000000
+++ /dev/null
@@ -1,1129 +0,0 @@
-/*****************************************************************************
-*                                                                            *
-*                                                                            *
-*  easycap_low.c                                                             *
-*                                                                            *
-*                                                                            *
-*****************************************************************************/
-/*
- *
- *  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
- *
-*/
-/*****************************************************************************/
-/*
- *  ACKNOWLEGEMENTS AND REFERENCES
- *  ------------------------------
- *  This driver makes use of register information contained in the Syntek
- *  Semicon DC-1125 driver hosted at
- *               http://sourceforge.net/projects/syntekdriver/.
- *  Particularly useful has been a patch to the latter driver provided by
- *  Ivor Hewitt in January 2009.  The NTSC implementation is taken from the
- *  work of Ben Trask.
-*/
-/****************************************************************************/
-
-#include "easycap.h"
-
-#define GET(X, Y, Z) do { \
-       int __rc; \
-       *(Z) = (u16)0; \
-       __rc = regget(X, Y, Z, sizeof(u8)); \
-       if (0 > __rc) { \
-               JOT(8, ":-(%i\n", __LINE__);  return __rc; \
-       } \
-} while (0)
-
-#define SET(X, Y, Z) do { \
-       int __rc; \
-       __rc = regset(X, Y, Z); \
-       if (0 > __rc) { \
-               JOT(8, ":-(%i\n", __LINE__);  return __rc; \
-       } \
-} while (0)
-
-/*--------------------------------------------------------------------------*/
-static const struct stk1160config {
-       int reg;
-       int set;
-} stk1160configPAL[256] = {
-               {0x000, 0x0098},
-               {0x002, 0x0093},
-
-               {0x001, 0x0003},
-               {0x003, 0x0080},
-               {0x00D, 0x0000},
-               {0x00F, 0x0002},
-               {0x018, 0x0010},
-               {0x019, 0x0000},
-               {0x01A, 0x0014},
-               {0x01B, 0x000E},
-               {0x01C, 0x0046},
-
-               {0x100, 0x0033},
-               {0x103, 0x0000},
-               {0x104, 0x0000},
-               {0x105, 0x0000},
-               {0x106, 0x0000},
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/*
- *  RESOLUTION 640x480
-*/
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-               {0x110, 0x0008},
-               {0x111, 0x0000},
-               {0x112, 0x0020},
-               {0x113, 0x0000},
-               {0x114, 0x0508},
-               {0x115, 0x0005},
-               {0x116, 0x0110},
-               {0x117, 0x0001},
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
-               {0x202, 0x000F},
-               {0x203, 0x004A},
-               {0x2FF, 0x0000},
-
-               {0xFFF, 0xFFFF}
-};
-/*--------------------------------------------------------------------------*/
-static const struct stk1160config stk1160configNTSC[256] = {
-               {0x000, 0x0098},
-               {0x002, 0x0093},
-
-               {0x001, 0x0003},
-               {0x003, 0x0080},
-               {0x00D, 0x0000},
-               {0x00F, 0x0002},
-               {0x018, 0x0010},
-               {0x019, 0x0000},
-               {0x01A, 0x0014},
-               {0x01B, 0x000E},
-               {0x01C, 0x0046},
-
-               {0x100, 0x0033},
-               {0x103, 0x0000},
-               {0x104, 0x0000},
-               {0x105, 0x0000},
-               {0x106, 0x0000},
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/*
- *  RESOLUTION 640x480
-*/
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-               {0x110, 0x0008},
-               {0x111, 0x0000},
-               {0x112, 0x0003},
-               {0x113, 0x0000},
-               {0x114, 0x0508},
-               {0x115, 0x0005},
-               {0x116, 0x00F3},
-               {0x117, 0x0000},
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
-               {0x202, 0x000F},
-               {0x203, 0x004A},
-               {0x2FF, 0x0000},
-
-               {0xFFF, 0xFFFF}
-};
-/*--------------------------------------------------------------------------*/
-static const struct saa7113config {
-       int reg;
-       int set;
-} saa7113configPAL[256] = {
-               {0x01, 0x08},
-               {0x02, 0x80},
-               {0x03, 0x33},
-               {0x04, 0x00},
-               {0x05, 0x00},
-               {0x06, 0xE9},
-               {0x07, 0x0D},
-               {0x08, 0x38},
-               {0x09, 0x00},
-               {0x0A, SAA_0A_DEFAULT},
-               {0x0B, SAA_0B_DEFAULT},
-               {0x0C, SAA_0C_DEFAULT},
-               {0x0D, SAA_0D_DEFAULT},
-               {0x0E, 0x01},
-               {0x0F, 0x36},
-               {0x10, 0x00},
-               {0x11, 0x0C},
-               {0x12, 0xE7},
-               {0x13, 0x00},
-               {0x15, 0x00},
-               {0x16, 0x00},
-               {0x40, 0x02},
-               {0x41, 0xFF},
-               {0x42, 0xFF},
-               {0x43, 0xFF},
-               {0x44, 0xFF},
-               {0x45, 0xFF},
-               {0x46, 0xFF},
-               {0x47, 0xFF},
-               {0x48, 0xFF},
-               {0x49, 0xFF},
-               {0x4A, 0xFF},
-               {0x4B, 0xFF},
-               {0x4C, 0xFF},
-               {0x4D, 0xFF},
-               {0x4E, 0xFF},
-               {0x4F, 0xFF},
-               {0x50, 0xFF},
-               {0x51, 0xFF},
-               {0x52, 0xFF},
-               {0x53, 0xFF},
-               {0x54, 0xFF},
-               {0x55, 0xFF},
-               {0x56, 0xFF},
-               {0x57, 0xFF},
-               {0x58, 0x40},
-               {0x59, 0x54},
-               {0x5A, 0x07},
-               {0x5B, 0x83},
-
-               {0xFF, 0xFF}
-};
-/*--------------------------------------------------------------------------*/
-static const struct saa7113config saa7113configNTSC[256] = {
-               {0x01, 0x08},
-               {0x02, 0x80},
-               {0x03, 0x33},
-               {0x04, 0x00},
-               {0x05, 0x00},
-               {0x06, 0xE9},
-               {0x07, 0x0D},
-               {0x08, 0x78},
-               {0x09, 0x00},
-               {0x0A, SAA_0A_DEFAULT},
-               {0x0B, SAA_0B_DEFAULT},
-               {0x0C, SAA_0C_DEFAULT},
-               {0x0D, SAA_0D_DEFAULT},
-               {0x0E, 0x01},
-               {0x0F, 0x36},
-               {0x10, 0x00},
-               {0x11, 0x0C},
-               {0x12, 0xE7},
-               {0x13, 0x00},
-               {0x15, 0x00},
-               {0x16, 0x00},
-               {0x40, 0x82},
-               {0x41, 0xFF},
-               {0x42, 0xFF},
-               {0x43, 0xFF},
-               {0x44, 0xFF},
-               {0x45, 0xFF},
-               {0x46, 0xFF},
-               {0x47, 0xFF},
-               {0x48, 0xFF},
-               {0x49, 0xFF},
-               {0x4A, 0xFF},
-               {0x4B, 0xFF},
-               {0x4C, 0xFF},
-               {0x4D, 0xFF},
-               {0x4E, 0xFF},
-               {0x4F, 0xFF},
-               {0x50, 0xFF},
-               {0x51, 0xFF},
-               {0x52, 0xFF},
-               {0x53, 0xFF},
-               {0x54, 0xFF},
-               {0x55, 0xFF},
-               {0x56, 0xFF},
-               {0x57, 0xFF},
-               {0x58, 0x40},
-               {0x59, 0x54},
-               {0x5A, 0x0A},
-               {0x5B, 0x83},
-
-               {0xFF, 0xFF}
-};
-
-static int regget(struct usb_device *pusb_device,
-               u16 index, void *reg, int reg_size)
-{
-       int rc;
-
-       if (!pusb_device)
-               return -ENODEV;
-
-       rc = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0),
-                       0x00,
-                       (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
-                       0x00,
-                       index, reg, reg_size, 50000);
-
-       return rc;
-}
-
-static int regset(struct usb_device *pusb_device, u16 index, u16 value)
-{
-       int rc;
-
-       if (!pusb_device)
-               return -ENODEV;
-
-       rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
-                       0x01,
-                       (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
-                       value, index, NULL, 0, 500);
-
-       if (rc < 0)
-               return rc;
-
-       if (easycap_readback) {
-               u16 igot = 0;
-               rc = regget(pusb_device, index, &igot, sizeof(igot));
-               igot = 0xFF & igot;
-               switch (index) {
-               case 0x000:
-               case 0x500:
-               case 0x502:
-               case 0x503:
-               case 0x504:
-               case 0x506:
-               case 0x507:
-                       break;
-
-               case 0x204:
-               case 0x205:
-               case 0x350:
-               case 0x351:
-                       if (igot)
-                               JOT(8, "unexpected 0x%02X "
-                                       "for STK register 0x%03X\n",
-                                       igot, index);
-                       break;
-
-               default:
-                       if ((0xFF & value) != igot)
-                               JOT(8, "unexpected 0x%02X != 0x%02X "
-                                       "for STK register 0x%03X\n",
-                                               igot, value, index);
-                       break;
-               }
-       }
-
-       return rc;
-}
-/*--------------------------------------------------------------------------*/
-/*
- *  FUNCTION wait_i2c() RETURNS 0 ON SUCCESS
-*/
-/*--------------------------------------------------------------------------*/
-static int wait_i2c(struct usb_device *p)
-{
-       u16 get0;
-       u8 igot;
-       const int max = 2;
-       int k;
-
-       if (!p)
-               return -ENODEV;
-
-       for (k = 0;  k < max;  k++) {
-               GET(p, 0x0201, &igot);  get0 = igot;
-               switch (get0) {
-               case 0x04:
-               case 0x01:
-                       return 0;
-               case 0x00:
-                       msleep(20);
-                       continue;
-               default:
-                       return get0 - 1;
-               }
-       }
-       return -1;
-}
-
-/****************************************************************************/
-int confirm_resolution(struct usb_device *p)
-{
-       u8 get0, get1, get2, get3, get4, get5, get6, get7;
-
-       if (!p)
-               return -ENODEV;
-       GET(p, 0x0110, &get0);
-       GET(p, 0x0111, &get1);
-       GET(p, 0x0112, &get2);
-       GET(p, 0x0113, &get3);
-       GET(p, 0x0114, &get4);
-       GET(p, 0x0115, &get5);
-       GET(p, 0x0116, &get6);
-       GET(p, 0x0117, &get7);
-       JOT(8,  "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X\n",
-               get0, get1, get2, get3, get4, get5, get6, get7);
-       JOT(8,  "....cf PAL_720x526: "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X\n",
-               0x000, 0x000, 0x001, 0x000, 0x5A0, 0x005, 0x121, 0x001);
-       JOT(8,  "....cf PAL_704x526: "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X\n",
-               0x004, 0x000, 0x001, 0x000, 0x584, 0x005, 0x121, 0x001);
-       JOT(8,  "....cf VGA_640x480: "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X, "
-               "0x%03X, 0x%03X\n",
-               0x008, 0x000, 0x020, 0x000, 0x508, 0x005, 0x110, 0x001);
-       return 0;
-}
-/****************************************************************************/
-int confirm_stream(struct usb_device *p)
-{
-       u16 get2;
-       u8 igot;
-
-       if (!p)
-               return -ENODEV;
-       GET(p, 0x0100, &igot);  get2 = 0x80 & igot;
-       if (0x80 == get2)
-               JOT(8, "confirm_stream:  OK\n");
-       else
-               JOT(8, "confirm_stream:  STUCK\n");
-       return 0;
-}
-/****************************************************************************/
-int setup_stk(struct usb_device *p, bool ntsc)
-{
-       int i;
-       const struct stk1160config *cfg;
-       if (!p)
-               return -ENODEV;
-       cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL;
-       for (i = 0; cfg[i].reg != 0xFFF; i++)
-               SET(p, cfg[i].reg, cfg[i].set);
-
-       write_300(p);
-
-       return 0;
-}
-/****************************************************************************/
-int setup_saa(struct usb_device *p, bool ntsc)
-{
-       int i, ir;
-       const struct saa7113config *cfg;
-       if (!p)
-               return -ENODEV;
-       cfg = (ntsc) ?  saa7113configNTSC : saa7113configPAL;
-       for (i = 0; cfg[i].reg != 0xFF; i++)
-               ir = write_saa(p, cfg[i].reg, cfg[i].set);
-       return 0;
-}
-/****************************************************************************/
-int write_000(struct usb_device *p, u16 set2, u16 set0)
-{
-       u8 igot0, igot2;
-
-       if (!p)
-               return -ENODEV;
-       GET(p, 0x0002, &igot2);
-       GET(p, 0x0000, &igot0);
-       SET(p, 0x0002, set2);
-       SET(p, 0x0000, set0);
-       return 0;
-}
-/****************************************************************************/
-int write_saa(struct usb_device *p, u16 reg0, u16 set0)
-{
-       if (!p)
-               return -ENODEV;
-       SET(p, 0x200, 0x00);
-       SET(p, 0x204, reg0);
-       SET(p, 0x205, set0);
-       SET(p, 0x200, 0x01);
-       return wait_i2c(p);
-}
-/****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *  REGISTER 500:  SETTING VALUE TO 0x008B READS FROM VT1612A (?)
- *  REGISTER 500:  SETTING VALUE TO 0x008C WRITES TO  VT1612A
- *  REGISTER 502:  LEAST SIGNIFICANT BYTE OF VALUE TO SET
- *  REGISTER 503:  MOST SIGNIFICANT BYTE OF VALUE TO SET
- *  REGISTER 504:  TARGET ADDRESS ON VT1612A
- */
-/*--------------------------------------------------------------------------*/
-int
-write_vt(struct usb_device *p, u16 reg0, u16 set0)
-{
-       u8 igot;
-       u16 got502, got503;
-       u16 set502, set503;
-
-       if (!p)
-               return -ENODEV;
-       SET(p, 0x0504, reg0);
-       SET(p, 0x0500, 0x008B);
-
-       GET(p, 0x0502, &igot);  got502 = (0xFF & igot);
-       GET(p, 0x0503, &igot);  got503 = (0xFF & igot);
-
-       JOT(16, "write_vt(., 0x%04X, 0x%04X): was 0x%04X\n",
-                               reg0, set0, ((got503 << 8) | got502));
-
-       set502 =  (0x00FF & set0);
-       set503 = ((0xFF00 & set0) >> 8);
-
-       SET(p, 0x0504, reg0);
-       SET(p, 0x0502, set502);
-       SET(p, 0x0503, set503);
-       SET(p, 0x0500, 0x008C);
-
-       return 0;
-}
-/****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *  REGISTER 500:  SETTING VALUE TO 0x008B READS FROM VT1612A (?)
- *  REGISTER 500:  SETTING VALUE TO 0x008C WRITES TO  VT1612A
- *  REGISTER 502:  LEAST SIGNIFICANT BYTE OF VALUE TO GET
- *  REGISTER 503:  MOST SIGNIFICANT BYTE OF VALUE TO GET
- *  REGISTER 504:  TARGET ADDRESS ON VT1612A
- */
-/*--------------------------------------------------------------------------*/
-int read_vt(struct usb_device *p, u16 reg0)
-{
-       u8 igot;
-       u16 got502, got503;
-
-       if (!p)
-               return -ENODEV;
-       SET(p, 0x0504, reg0);
-       SET(p, 0x0500, 0x008B);
-
-       GET(p, 0x0502, &igot);  got502 = (0xFF & igot);
-       GET(p, 0x0503, &igot);  got503 = (0xFF & igot);
-
-       JOT(16, "read_vt(., 0x%04X): has 0x%04X\n",
-                       reg0, ((got503 << 8) | got502));
-
-       return (got503 << 8) | got502;
-}
-/****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *  THESE APPEAR TO HAVE NO EFFECT ON EITHER VIDEO OR AUDIO.
- */
-/*--------------------------------------------------------------------------*/
-int write_300(struct usb_device *p)
-{
-       if (!p)
-               return -ENODEV;
-       SET(p, 0x300, 0x0012);
-       SET(p, 0x350, 0x002D);
-       SET(p, 0x351, 0x0001);
-       SET(p, 0x352, 0x0000);
-       SET(p, 0x353, 0x0000);
-       SET(p, 0x300, 0x0080);
-       return 0;
-}
-/****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *  NOTE: THE FOLLOWING IS NOT CHECKED:
- *  REGISTER 0x0F, WHICH IS INVOLVED IN CHROMINANCE AUTOMATIC GAIN CONTROL.
- */
-/*--------------------------------------------------------------------------*/
-int check_saa(struct usb_device *p, bool ntsc)
-{
-       int i, ir, rc = 0;
-       struct saa7113config const *cfg;
-       if (!p)
-               return -ENODEV;
-
-       cfg = (ntsc) ? saa7113configNTSC : saa7113configPAL;
-       for (i = 0; cfg[i].reg != 0xFF; i++) {
-               if (0x0F == cfg[i].reg)
-                       continue;
-               ir = read_saa(p, cfg[i].reg);
-               if (ir != cfg[i].set) {
-                       SAY("SAA register 0x%02X has 0x%02X, expected 0x%02X\n",
-                               cfg[i].reg, ir, cfg[i].set);
-                               rc--;
-               }
-       }
-
-       return (rc < -8) ? rc : 0;
-}
-/****************************************************************************/
-int merit_saa(struct usb_device *p)
-{
-       int rc;
-
-       if (!p)
-               return -ENODEV;
-       rc = read_saa(p, 0x1F);
-       return ((0 > rc) || (0x02 & rc)) ? 1 : 0;
-}
-/****************************************************************************/
-int ready_saa(struct usb_device *p)
-{
-       int j, rc, rate;
-       const int max = 5, marktime = PATIENCE/5;
-/*--------------------------------------------------------------------------*/
-/*
- *   RETURNS    0     FOR INTERLACED       50 Hz
- *              1     FOR NON-INTERLACED   50 Hz
- *              2     FOR INTERLACED       60 Hz
- *              3     FOR NON-INTERLACED   60 Hz
-*/
-/*--------------------------------------------------------------------------*/
-       if (!p)
-               return -ENODEV;
-       j = 0;
-       while (max > j) {
-               rc = read_saa(p, 0x1F);
-               if (0 <= rc) {
-                       if (0 == (0x40 & rc))
-                               break;
-                       if (1 == (0x01 & rc))
-                               break;
-               }
-               msleep(marktime);
-               j++;
-       }
-       if (max == j)
-               return -1;
-       else {
-               if (0x20 & rc) {
-                       rate = 2;
-                       JOT(8, "hardware detects 60 Hz\n");
-               } else {
-                       rate = 0;
-                       JOT(8, "hardware detects 50 Hz\n");
-               }
-               if (0x80 & rc)
-                       JOT(8, "hardware detects interlacing\n");
-               else {
-                       rate++;
-                       JOT(8, "hardware detects no interlacing\n");
-               }
-       }
-       return 0;
-}
-/****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *  NOTE: THE FOLLOWING ARE NOT CHECKED:
- *  REGISTERS 0x000, 0x002:  FUNCTIONALITY IS NOT KNOWN
- *  REGISTER  0x100:  ACCEPT ALSO (0x80 | stk1160config....[.].set)
- */
-/*--------------------------------------------------------------------------*/
-int check_stk(struct usb_device *p, bool ntsc)
-{
-       int i, ir;
-       const struct stk1160config *cfg;
-
-       if (!p)
-               return -ENODEV;
-       cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL;
-
-       for (i = 0; 0xFFF != cfg[i].reg; i++) {
-               if (0x000 == cfg[i].reg || 0x002 == cfg[i].reg)
-                       continue;
-
-
-               ir = read_stk(p, cfg[i].reg);
-               if (0x100 == cfg[i].reg) {
-                       if ((ir != (0xFF & cfg[i].set)) &&
-                           (ir != (0x80 | (0xFF & cfg[i].set))) &&
-                           (0xFFFF != cfg[i].set)) {
-                               SAY("STK reg[0x%03X]=0x%02X expected 0x%02X\n",
-                                       cfg[i].reg, ir, cfg[i].set);
-                       }
-                       continue;
-               }
-               if ((ir != (0xFF & cfg[i].set)) && (0xFFFF != cfg[i].set))
-                       SAY("STK register 0x%03X has 0x%02X,expected 0x%02X\n",
-                               cfg[i].reg, ir, cfg[i].set);
-       }
-       return 0;
-}
-/****************************************************************************/
-int read_saa(struct usb_device *p, u16 reg0)
-{
-       u8 igot;
-
-       if (!p)
-               return -ENODEV;
-       SET(p, 0x208, reg0);
-       SET(p, 0x200, 0x20);
-       if (0 != wait_i2c(p))
-               return -1;
-       igot = 0;
-       GET(p, 0x0209, &igot);
-       return igot;
-}
-/****************************************************************************/
-int read_stk(struct usb_device *p, u32 reg0)
-{
-       u8 igot;
-
-       if (!p)
-               return -ENODEV;
-       igot = 0;
-       GET(p, reg0, &igot);
-       return igot;
-}
-/****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *    HARDWARE    USERSPACE INPUT NUMBER   PHYSICAL INPUT   DRIVER input VALUE
- *
- *  CVBS+S-VIDEO           0 or 1              CVBS                 1
- *   FOUR-CVBS             0 or 1              CVBS1                1
- *   FOUR-CVBS                2                CVBS2                2
- *   FOUR-CVBS                3                CVBS3                3
- *   FOUR-CVBS                4                CVBS4                4
- *  CVBS+S-VIDEO              5               S-VIDEO               5
- *
- *  WHEN 5==input THE ARGUMENT mode MUST ALSO BE SUPPLIED:
- *
- *     mode  7   => GAIN TO BE SET EXPLICITLY USING REGISTER 0x05 (UNTESTED)
- *     mode  9   => USE AUTOMATIC GAIN CONTROL (DEFAULT)
- *
-*/
-/*---------------------------------------------------------------------------*/
-int
-select_input(struct usb_device *p, int input, int mode)
-{
-       int ir;
-
-       if (!p)
-               return -ENODEV;
-       stop_100(p);
-       switch (input) {
-       case 0:
-       case 1: {
-               if (0 != write_saa(p, 0x02, 0x80))
-                       SAY("ERROR: failed to set SAA register 0x02 "
-                                               "for input %i\n", input);
-
-               SET(p, 0x0000, 0x0098);
-               SET(p, 0x0002, 0x0078);
-               break;
-       }
-       case 2: {
-               if (0 != write_saa(p, 0x02, 0x80))
-                       SAY("ERROR: failed to set SAA register 0x02 "
-                                               "for input %i\n", input);
-
-               SET(p, 0x0000, 0x0090);
-               SET(p, 0x0002, 0x0078);
-               break;
-       }
-       case 3: {
-               if (0 != write_saa(p, 0x02, 0x80))
-                       SAY("ERROR: failed to set SAA register 0x02 "
-                                       " for input %i\n", input);
-
-               SET(p, 0x0000, 0x0088);
-               SET(p, 0x0002, 0x0078);
-               break;
-       }
-       case 4: {
-               if (0 != write_saa(p, 0x02, 0x80)) {
-                       SAY("ERROR: failed to set SAA register 0x02 "
-                                               "for input %i\n", input);
-               }
-               SET(p, 0x0000, 0x0080);
-               SET(p, 0x0002, 0x0078);
-               break;
-       }
-       case 5: {
-               if (9 != mode)
-                       mode = 7;
-               switch (mode) {
-               case 7: {
-                       if (0 != write_saa(p, 0x02, 0x87))
-                               SAY("ERROR: failed to set SAA register 0x02 "
-                                               "for input %i\n", input);
-
-                       if (0 != write_saa(p, 0x05, 0xFF))
-                               SAY("ERROR: failed to set SAA register 0x05 "
-                                               "for input %i\n", input);
-
-                       break;
-               }
-               case 9: {
-                       if (0 != write_saa(p, 0x02, 0x89))
-                               SAY("ERROR: failed to set SAA register 0x02 "
-                                               "for input %i\n", input);
-
-                       if (0 != write_saa(p, 0x05, 0x00))
-                               SAY("ERROR: failed to set SAA register 0x05 "
-                                               "for input %i\n", input);
-
-                       break;
-               }
-               default:
-                       SAY("MISTAKE:  bad mode: %i\n", mode);
-                       return -1;
-               }
-
-               if (0 != write_saa(p, 0x04, 0x00))
-                       SAY("ERROR: failed to set SAA register 0x04 "
-                                       "for input %i\n", input);
-
-               if (0 != write_saa(p, 0x09, 0x80))
-                       SAY("ERROR: failed to set SAA register 0x09 "
-                                               "for input %i\n", input);
-
-               SET(p, 0x0002, 0x0093);
-               break;
-       }
-       default:
-               SAY("ERROR:  bad input: %i\n", input);
-               return -1;
-       }
-
-       ir = read_stk(p, 0x00);
-       JOT(8, "STK register 0x00 has 0x%02X\n", ir);
-       ir = read_saa(p, 0x02);
-       JOT(8, "SAA register 0x02 has 0x%02X\n", ir);
-
-       start_100(p);
-
-       return 0;
-}
-/****************************************************************************/
-int set_resolution(struct usb_device *p,
-                  u16 set0, u16 set1, u16 set2, u16 set3)
-{
-       u16 u0x0111, u0x0113, u0x0115, u0x0117;
-
-       if (!p)
-               return -ENODEV;
-       u0x0111 = ((0xFF00 & set0) >> 8);
-       u0x0113 = ((0xFF00 & set1) >> 8);
-       u0x0115 = ((0xFF00 & set2) >> 8);
-       u0x0117 = ((0xFF00 & set3) >> 8);
-
-       SET(p, 0x0110, (0x00FF & set0));
-       SET(p, 0x0111, u0x0111);
-       SET(p, 0x0112, (0x00FF & set1));
-       SET(p, 0x0113, u0x0113);
-       SET(p, 0x0114, (0x00FF & set2));
-       SET(p, 0x0115, u0x0115);
-       SET(p, 0x0116, (0x00FF & set3));
-       SET(p, 0x0117, u0x0117);
-
-       return 0;
-}
-/****************************************************************************/
-int start_100(struct usb_device *p)
-{
-       u16 get116, get117, get0;
-       u8 igot116, igot117, igot;
-
-       if (!p)
-               return -ENODEV;
-       GET(p, 0x0116, &igot116);
-       get116 = igot116;
-       GET(p, 0x0117, &igot117);
-       get117 = igot117;
-       SET(p, 0x0116, 0x0000);
-       SET(p, 0x0117, 0x0000);
-
-       GET(p, 0x0100, &igot);
-       get0 = igot;
-       SET(p, 0x0100, (0x80 | get0));
-
-       SET(p, 0x0116, get116);
-       SET(p, 0x0117, get117);
-
-       return 0;
-}
-/****************************************************************************/
-int stop_100(struct usb_device *p)
-{
-       u16 get0;
-       u8 igot;
-
-       if (!p)
-               return -ENODEV;
-       GET(p, 0x0100, &igot);
-       get0 = igot;
-       SET(p, 0x0100, (0x7F & get0));
-       return 0;
-}
-/****************************************************************************/
-/****************************************************************************/
-/*****************************************************************************/
-int wakeup_device(struct usb_device *pusb_device)
-{
-       if (!pusb_device)
-               return -ENODEV;
-       return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
-                       USB_REQ_SET_FEATURE,
-                       USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-                       USB_DEVICE_REMOTE_WAKEUP,
-                       0, NULL, 0, 50000);
-}
-/*****************************************************************************/
-int
-audio_setup(struct easycap *peasycap)
-{
-       struct usb_device *pusb_device;
-       u8 buffer[1];
-       int rc, id1, id2;
-/*---------------------------------------------------------------------------*/
-/*
- *                                IMPORTANT:
- *  THE MESSAGE OF TYPE (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
- *  CAUSES MUTING IF THE VALUE 0x0100 IS SENT.
- *  TO ENABLE AUDIO  THE VALUE 0x0200 MUST BE SENT.
- */
-/*---------------------------------------------------------------------------*/
-       const u8 request = 0x01;
-       const u8 requesttype = USB_DIR_OUT |
-                              USB_TYPE_CLASS |
-                              USB_RECIP_INTERFACE;
-       const u16 value_unmute = 0x0200;
-       const u16 index = 0x0301;
-       const u16 length = 1;
-
-       if (!peasycap)
-               return -EFAULT;
-
-       pusb_device = peasycap->pusb_device;
-       if (!pusb_device)
-               return -ENODEV;
-
-       JOM(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n",
-                               requesttype, request,
-                               (0x00FF & value_unmute),
-                               (0xFF00 & value_unmute) >> 8,
-                               (0x00FF & index),
-                               (0xFF00 & index) >> 8,
-                               (0x00FF & length),
-                               (0xFF00 & length) >> 8);
-
-       buffer[0] = 0x01;
-
-       rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
-                               request, requesttype, value_unmute,
-                               index, &buffer[0], length, 50000);
-
-       JOT(8, "0x%02X=buffer\n", buffer[0]);
-       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 ???
- *  REGISTER 506:  ANALOGUE AUDIO ATTENTUATOR ???
- *                 FOR THE CVBS+S-VIDEO HARDWARE:
- *                    SETTING VALUE TO 0x0000 GIVES QUIET SOUND.
- *                    THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
- *                 FOR THE FOUR-CVBS HARDWARE:
- *                    SETTING VALUE TO 0x0000 SEEMS TO HAVE NO EFFECT.
- *  REGISTER 507:  ANALOGUE AUDIO PREAMPLIFIER ON/OFF ???
- *                 FOR THE CVBS-S-VIDEO HARDWARE:
- *                    SETTING VALUE TO 0x0001 GIVES VERY LOUD, DISTORTED SOUND.
- *                    THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
- */
-/*--------------------------------------------------------------------------*/
-       SET(pusb_device, 0x0500, 0x0094);
-       SET(pusb_device, 0x0500, 0x008C);
-       SET(pusb_device, 0x0506, 0x0001);
-       SET(pusb_device, 0x0507, 0x0000);
-       id1 = read_vt(pusb_device, 0x007C);
-       id2 = read_vt(pusb_device, 0x007E);
-       SAM("0x%04X:0x%04X is audio vendor id\n", id1, id2);
-/*---------------------------------------------------------------------------*/
-/*
- *  SELECT AUDIO SOURCE "LINE IN" AND SET THE AUDIO GAIN.
-*/
-/*---------------------------------------------------------------------------*/
-       if (0 != audio_gainset(pusb_device, peasycap->gain))
-               SAY("ERROR: audio_gainset() failed\n");
-       check_vt(pusb_device);
-       return 0;
-}
-/*****************************************************************************/
-int check_vt(struct usb_device *pusb_device)
-{
-       int igot;
-
-       if (!pusb_device)
-               return -ENODEV;
-       igot = read_vt(pusb_device, 0x0002);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x02\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x02);
-
-       igot = read_vt(pusb_device, 0x000E);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x0E\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x0E);
-
-       igot = read_vt(pusb_device, 0x0010);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x10\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x10);
-
-       igot = read_vt(pusb_device, 0x0012);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x12\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x12);
-
-       igot = read_vt(pusb_device, 0x0014);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x14\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x14);
-
-       igot = read_vt(pusb_device, 0x0016);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x16\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x16);
-
-       igot = read_vt(pusb_device, 0x0018);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x18\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x18);
-
-       igot = read_vt(pusb_device, 0x001C);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x1C\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x1C);
-
-       return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*  NOTE:  THIS DOES INCREASE THE VOLUME DRAMATICALLY:
- *                      audio_gainset(pusb_device, 0x000F);
- *
- *       loud        dB  register 0x10      dB register 0x1C    dB total
- *         0               -34.5                   0             -34.5
- *        ..                ....                   .              ....
- *        15                10.5                   0              10.5
- *        16                12.0                   0              12.0
- *        17                12.0                   1.5            13.5
- *        ..                ....                  ....            ....
- *        31                12.0                  22.5            34.5
-*/
-/*---------------------------------------------------------------------------*/
-int audio_gainset(struct usb_device *pusb_device, s8 loud)
-{
-       int igot;
-       u8 tmp;
-       u16 mute;
-
-       if (!pusb_device)
-               return -ENODEV;
-       if (0 > loud)
-               loud = 0;
-       if (31 < loud)
-               loud = 31;
-
-       write_vt(pusb_device, 0x0002, 0x8000);
-/*---------------------------------------------------------------------------*/
-       igot = read_vt(pusb_device, 0x000E);
-       if (0 > igot) {
-               SAY("ERROR: failed to read VT1612A register 0x0E\n");
-               mute = 0x0000;
-       } else
-               mute = 0x8000 & ((unsigned int)igot);
-       mute = 0;
-
-       if (16 > loud)
-               tmp = 0x01 | (0x001F & (((u8)(15 - loud)) << 1));
-       else
-               tmp = 0;
-
-       JOT(8, "0x%04X=(mute|tmp) for VT1612A register 0x0E\n", mute | tmp);
-       write_vt(pusb_device, 0x000E, (mute | tmp));
-/*---------------------------------------------------------------------------*/
-       igot = read_vt(pusb_device, 0x0010);
-       if (0 > igot) {
-               SAY("ERROR: failed to read VT1612A register 0x10\n");
-               mute = 0x0000;
-       } else
-               mute = 0x8000 & ((unsigned int)igot);
-       mute = 0;
-
-       JOT(8, "0x%04X=(mute|tmp|(tmp<<8)) for VT1612A register 0x10,...0x18\n",
-                                               mute | tmp | (tmp << 8));
-       write_vt(pusb_device, 0x0010, (mute | tmp | (tmp << 8)));
-       write_vt(pusb_device, 0x0012, (mute | tmp | (tmp << 8)));
-       write_vt(pusb_device, 0x0014, (mute | tmp | (tmp << 8)));
-       write_vt(pusb_device, 0x0016, (mute | tmp | (tmp << 8)));
-       write_vt(pusb_device, 0x0018, (mute | tmp | (tmp << 8)));
-/*---------------------------------------------------------------------------*/
-       igot = read_vt(pusb_device, 0x001C);
-       if (0 > igot) {
-               SAY("ERROR: failed to read VT1612A register 0x1C\n");
-               mute = 0x0000;
-       } else
-               mute = 0x8000 & ((unsigned int)igot);
-       mute = 0;
-
-       if (16 <= loud)
-               tmp = 0x000F & (u8)(loud - 16);
-       else
-               tmp = 0;
-
-       JOT(8, "0x%04X=(mute|tmp|(tmp<<8)) for VT1612A register 0x1C\n",
-                                               mute | tmp | (tmp << 8));
-       write_vt(pusb_device, 0x001C, (mute | tmp | (tmp << 8)));
-       write_vt(pusb_device, 0x001A, 0x0404);
-       write_vt(pusb_device, 0x0002, 0x0000);
-       return 0;
-}
-/*****************************************************************************/
-int audio_gainget(struct usb_device *pusb_device)
-{
-       int igot;
-
-       if (!pusb_device)
-               return -ENODEV;
-       igot = read_vt(pusb_device, 0x001C);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x1C\n");
-       return igot;
-}
-/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c
deleted file mode 100644 (file)
index a45c0b5..0000000
+++ /dev/null
@@ -1,4253 +0,0 @@
-/******************************************************************************
-*                                                                             *
-*  easycap_main.c                                                             *
-*                                                                             *
-*  Video driver for EasyCAP USB2.0 Video Capture Device DC60                  *
-*                                                                             *
-*                                                                             *
-******************************************************************************/
-/*
- *
- *  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
- *
-*/
-/*****************************************************************************/
-
-#include "easycap.h"
-#include <linux/usb/audio.h>
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("R.M. Thomas <rmthomas@sciolus.org>");
-MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION);
-MODULE_VERSION(EASYCAP_DRIVER_VERSION);
-
-#ifdef CONFIG_EASYCAP_DEBUG
-int easycap_debug;
-module_param_named(debug, easycap_debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0(default),1,2,...,9");
-#endif /* CONFIG_EASYCAP_DEBUG */
-
-bool easycap_readback;
-module_param_named(readback, easycap_readback, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(readback, "read back written registers: (default false)");
-
-static int easycap_bars = 1;
-module_param_named(bars, easycap_bars, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(bars,
-       "Testcard bars on input signal failure: 0=>no, 1=>yes(default)");
-
-static int easycap_gain = 16;
-module_param_named(gain, easycap_gain, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(gain, "Audio gain: 0,...,16(default),...31");
-
-static bool easycap_ntsc;
-module_param_named(ntsc, easycap_ntsc, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(ntsc, "NTSC default encoding (default PAL)");
-
-
-
-struct easycap_dongle easycapdc60_dongle[DONGLE_MANY];
-static struct mutex mutex_dongle;
-static void easycap_complete(struct urb *purb);
-static int reset(struct easycap *peasycap);
-
-const char *strerror(int err)
-{
-#define ERRNOSTR(_e) case _e: return # _e
-       switch (err) {
-       case 0: return "OK";
-       ERRNOSTR(ENOMEM);
-       ERRNOSTR(ENODEV);
-       ERRNOSTR(ENXIO);
-       ERRNOSTR(EINVAL);
-       ERRNOSTR(EAGAIN);
-       ERRNOSTR(EFBIG);
-       ERRNOSTR(EPIPE);
-       ERRNOSTR(EMSGSIZE);
-       ERRNOSTR(ENOSPC);
-       ERRNOSTR(EINPROGRESS);
-       ERRNOSTR(ENOSR);
-       ERRNOSTR(EOVERFLOW);
-       ERRNOSTR(EPROTO);
-       ERRNOSTR(EILSEQ);
-       ERRNOSTR(ETIMEDOUT);
-       ERRNOSTR(EOPNOTSUPP);
-       ERRNOSTR(EPFNOSUPPORT);
-       ERRNOSTR(EAFNOSUPPORT);
-       ERRNOSTR(EADDRINUSE);
-       ERRNOSTR(EADDRNOTAVAIL);
-       ERRNOSTR(ENOBUFS);
-       ERRNOSTR(EISCONN);
-       ERRNOSTR(ENOTCONN);
-       ERRNOSTR(ESHUTDOWN);
-       ERRNOSTR(ENOENT);
-       ERRNOSTR(ECONNRESET);
-       ERRNOSTR(ETIME);
-       ERRNOSTR(ECOMM);
-       ERRNOSTR(EREMOTEIO);
-       ERRNOSTR(EXDEV);
-       ERRNOSTR(EPERM);
-       default: return "unknown";
-       }
-
-#undef ERRNOSTR
-}
-
-/*---------------------------------------------------------------------------*/
-/*
- *  PARAMETERS USED WHEN REGISTERING THE VIDEO INTERFACE
- *
- *  NOTE: SOME KERNELS IGNORE usb_class_driver.minor_base, AS MENTIONED BY
- *        CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGE 253.
- *        THIS IS THE CASE FOR OpenSUSE.
- */
-/*---------------------------------------------------------------------------*/
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-/****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  THIS ROUTINE DOES NOT DETECT DUPLICATE OCCURRENCES OF POINTER peasycap
-*/
-/*---------------------------------------------------------------------------*/
-int isdongle(struct easycap *peasycap)
-{
-       int k;
-       if (!peasycap)
-               return -2;
-       for (k = 0; k < DONGLE_MANY; k++) {
-               if (easycapdc60_dongle[k].peasycap == peasycap) {
-                       peasycap->isdongle = k;
-                       return k;
-               }
-       }
-       return -1;
-}
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-static int easycap_open(struct inode *inode, struct file *file)
-{
-       struct video_device *pvideo_device;
-       struct easycap *peasycap;
-       int rc;
-
-       JOT(4, "\n");
-       SAY("==========OPEN=========\n");
-
-       pvideo_device = video_devdata(file);
-       if (!pvideo_device) {
-               SAY("ERROR: pvideo_device is NULL.\n");
-               return -EFAULT;
-       }
-       peasycap = (struct easycap *)video_get_drvdata(pvideo_device);
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       } else {
-               JOM(16, "peasycap->pusb_device=%p\n", peasycap->pusb_device);
-       }
-       file->private_data = peasycap;
-       rc = wakeup_device(peasycap->pusb_device);
-       if (0 == rc)
-               JOM(8, "wakeup_device() OK\n");
-       else {
-               SAM("ERROR: wakeup_device() rc = %i\n", rc);
-               if (-ENODEV == rc)
-                       SAM("ERROR: wakeup_device() returned -ENODEV\n");
-               else
-                       SAM("ERROR: wakeup_device() rc = %i\n", rc);
-               return rc;
-       }
-       peasycap->input = 0;
-       rc = reset(peasycap);
-       if (rc) {
-               SAM("ERROR: reset() rc = %i\n", rc);
-               return -EFAULT;
-       }
-       return 0;
-}
-
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  RESET THE HARDWARE TO ITS REFERENCE STATE.
- *
- *  THIS ROUTINE MAY BE CALLED REPEATEDLY IF easycap_complete() DETECTS
- *  A BAD VIDEO FRAME SIZE.
-*/
-/*---------------------------------------------------------------------------*/
-static int reset(struct easycap *peasycap)
-{
-       struct easycap_standard const *peasycap_standard;
-       int fmtidx, input, rate;
-       bool ntsc, other;
-       int rc;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       input = peasycap->input;
-
-/*---------------------------------------------------------------------------*/
-/*
- *  IF THE SAA7113H HAS ALREADY ACQUIRED SYNC, USE ITS HARDWARE-DETECTED
- *  FIELD FREQUENCY TO DISTINGUISH NTSC FROM PAL.  THIS IS ESSENTIAL FOR
- *  gstreamer AND OTHER USERSPACE PROGRAMS WHICH MAY NOT ATTEMPT TO INITIATE
- *  A SWITCH BETWEEN PAL AND NTSC.
- *
- *  FUNCTION ready_saa() MAY REQUIRE A SUBSTANTIAL FRACTION OF A SECOND TO
- *  COMPLETE, SO SHOULD NOT BE INVOKED WITHOUT GOOD REASON.
-*/
-/*---------------------------------------------------------------------------*/
-       other = false;
-       JOM(8, "peasycap->ntsc=%d\n", peasycap->ntsc);
-
-       rate = ready_saa(peasycap->pusb_device);
-       if (rate < 0) {
-               JOM(8, "not ready to capture after %i ms ...\n", PATIENCE);
-               ntsc = !peasycap->ntsc;
-               JOM(8, "... trying  %s ..\n", ntsc ? "NTSC" : "PAL");
-               rc = setup_stk(peasycap->pusb_device, ntsc);
-               if (rc) {
-                       SAM("ERROR: setup_stk() rc = %i\n", rc);
-                       return -EFAULT;
-               }
-               rc = setup_saa(peasycap->pusb_device, ntsc);
-               if (rc) {
-                       SAM("ERROR: setup_saa() rc = %i\n", rc);
-                       return -EFAULT;
-               }
-
-               rate = ready_saa(peasycap->pusb_device);
-               if (rate < 0) {
-                       JOM(8, "not ready to capture after %i ms\n", PATIENCE);
-                       JOM(8, "... saa register 0x1F has 0x%02X\n",
-                                       read_saa(peasycap->pusb_device, 0x1F));
-                       ntsc = peasycap->ntsc;
-               } else {
-                       JOM(8, "... success at second try:  %i=rate\n", rate);
-                       ntsc = (0 < (rate/2)) ? true : false ;
-                       other = true;
-               }
-       } else {
-               JOM(8, "... success at first try:  %i=rate\n", rate);
-               ntsc = (0 < rate/2) ? true : false ;
-       }
-       JOM(8, "ntsc=%d\n", ntsc);
-/*---------------------------------------------------------------------------*/
-
-       rc = setup_stk(peasycap->pusb_device, ntsc);
-       if (rc) {
-               SAM("ERROR: setup_stk() rc = %i\n", rc);
-               return -EFAULT;
-       }
-       rc = setup_saa(peasycap->pusb_device, ntsc);
-       if (rc) {
-               SAM("ERROR: setup_saa() rc = %i\n", rc);
-               return -EFAULT;
-       }
-
-       memset(peasycap->merit, 0, sizeof(peasycap->merit));
-
-       peasycap->video_eof = 0;
-       peasycap->audio_eof = 0;
-/*---------------------------------------------------------------------------*/
-/*
- * RESTORE INPUT AND FORCE REFRESH OF STANDARD, FORMAT, ETC.
- *
- * WHILE THIS PROCEDURE IS IN PROGRESS, SOME IOCTL COMMANDS WILL RETURN -EBUSY.
-*/
-/*---------------------------------------------------------------------------*/
-       peasycap->input = -8192;
-       peasycap->standard_offset = -8192;
-       fmtidx = ntsc ? NTSC_M : PAL_BGHIN;
-       if (other) {
-               peasycap_standard = &easycap_standard[0];
-               while (0xFFFF != peasycap_standard->mask) {
-                       if (fmtidx == peasycap_standard->v4l2_standard.index) {
-                               peasycap->inputset[input].standard_offset =
-                                       peasycap_standard - easycap_standard;
-                               break;
-                       }
-                       peasycap_standard++;
-               }
-               if (0xFFFF == peasycap_standard->mask) {
-                       SAM("ERROR: standard not found\n");
-                       return -EINVAL;
-               }
-               JOM(8, "%i=peasycap->inputset[%i].standard_offset\n",
-                       peasycap->inputset[input].standard_offset, input);
-       }
-       peasycap->format_offset = -8192;
-       peasycap->brightness = -8192;
-       peasycap->contrast = -8192;
-       peasycap->saturation = -8192;
-       peasycap->hue = -8192;
-
-       rc = newinput(peasycap, input);
-
-       if (rc) {
-               SAM("ERROR: newinput(.,%i) rc = %i\n", rc, input);
-               return -EFAULT;
-       }
-       JOM(4, "restored input, standard and format\n");
-
-       JOM(8, "true=peasycap->ntsc %d\n", peasycap->ntsc);
-
-       if (0 > peasycap->input) {
-               SAM("MISTAKE:  %i=peasycap->input\n", peasycap->input);
-               return -ENOENT;
-       }
-       if (0 > peasycap->standard_offset) {
-               SAM("MISTAKE:  %i=peasycap->standard_offset\n",
-                               peasycap->standard_offset);
-               return -ENOENT;
-       }
-       if (0 > peasycap->format_offset) {
-               SAM("MISTAKE:  %i=peasycap->format_offset\n",
-                               peasycap->format_offset);
-               return -ENOENT;
-       }
-       if (0 > peasycap->brightness) {
-               SAM("MISTAKE:  %i=peasycap->brightness\n",
-                               peasycap->brightness);
-               return -ENOENT;
-       }
-       if (0 > peasycap->contrast) {
-               SAM("MISTAKE:  %i=peasycap->contrast\n", peasycap->contrast);
-               return -ENOENT;
-       }
-       if (0 > peasycap->saturation) {
-               SAM("MISTAKE:  %i=peasycap->saturation\n",
-                               peasycap->saturation);
-               return -ENOENT;
-       }
-       if (0 > peasycap->hue) {
-               SAM("MISTAKE:  %i=peasycap->hue\n", peasycap->hue);
-               return -ENOENT;
-       }
-       return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  IF THE REQUESTED INPUT IS THE SAME AS THE EXISTING INPUT, DO NOTHING.
- *  OTHERWISE:
- *      KILL URBS, CLEAR FIELD AND FRAME BUFFERS AND RESET THEIR
- *           _read AND _fill POINTERS.
- *      SELECT THE NEW INPUT.
- *      ADJUST THE STANDARD, FORMAT, BRIGHTNESS, CONTRAST, SATURATION AND HUE
- *          ON THE BASIS OF INFORMATION IN STRUCTURE easycap.inputset[input].
- *      RESUBMIT THE URBS IF STREAMING WAS ALREADY IN PROGRESS.
- *
- *  NOTE:
- *      THIS ROUTINE MAY BE CALLED FREQUENTLY BY ZONEMINDER VIA IOCTL,
- *      SO IT SHOULD WRITE ONLY SPARINGLY TO THE LOGFILE.
-*/
-/*---------------------------------------------------------------------------*/
-int
-newinput(struct easycap *peasycap, int input)
-{
-       int rc, k, m, mood, off;
-       int inputnow, video_idlenow, audio_idlenow;
-       bool resubmit;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       JOM(8, "%i=input sought\n", input);
-
-       if (0 > input && INPUT_MANY <= input)
-               return -ENOENT;
-       inputnow = peasycap->input;
-       if (input == inputnow)
-               return 0;
-/*---------------------------------------------------------------------------*/
-/*
- *  IF STREAMING IS IN PROGRESS THE URBS ARE KILLED AT THIS
- *  STAGE AND WILL BE RESUBMITTED PRIOR TO EXIT FROM THE ROUTINE.
- *  IF NO STREAMING IS IN PROGRESS NO URBS WILL BE SUBMITTED BY THE
- *  ROUTINE.
-*/
-/*---------------------------------------------------------------------------*/
-       video_idlenow = peasycap->video_idle;
-       audio_idlenow = peasycap->audio_idle;
-
-       peasycap->video_idle = 1;
-       peasycap->audio_idle = 1;
-       if (peasycap->video_isoc_streaming) {
-               resubmit = true;
-               kill_video_urbs(peasycap);
-       } else {
-               resubmit = false;
-       }
-/*---------------------------------------------------------------------------*/
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -ENODEV;
-       }
-       rc = usb_set_interface(peasycap->pusb_device,
-                               peasycap->video_interface,
-                               peasycap->video_altsetting_off);
-       if (rc) {
-               SAM("ERROR: usb_set_interface() rc = %i\n", rc);
-               return -EFAULT;
-       }
-       rc = stop_100(peasycap->pusb_device);
-       if (rc) {
-               SAM("ERROR: stop_100() rc = %i\n", rc);
-               return -EFAULT;
-       }
-       for (k = 0; k < FIELD_BUFFER_MANY; k++) {
-               for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++)
-                       memset(peasycap->field_buffer[k][m].pgo, 0, PAGE_SIZE);
-       }
-       for (k = 0; k < FRAME_BUFFER_MANY; k++) {
-               for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++)
-                       memset(peasycap->frame_buffer[k][m].pgo, 0, PAGE_SIZE);
-       }
-       peasycap->field_page = 0;
-       peasycap->field_read = 0;
-       peasycap->field_fill = 0;
-
-       peasycap->frame_read = 0;
-       peasycap->frame_fill = 0;
-       for (k = 0; k < peasycap->input; k++) {
-               (peasycap->frame_fill)++;
-               if (peasycap->frame_buffer_many <= peasycap->frame_fill)
-                       peasycap->frame_fill = 0;
-       }
-       peasycap->input = input;
-       select_input(peasycap->pusb_device, peasycap->input, 9);
-/*---------------------------------------------------------------------------*/
-       if (input == peasycap->inputset[input].input) {
-               off = peasycap->inputset[input].standard_offset;
-               if (off != peasycap->standard_offset) {
-                       rc = adjust_standard(peasycap,
-                               easycap_standard[off].v4l2_standard.id);
-                       if (rc) {
-                               SAM("ERROR: adjust_standard() rc = %i\n", rc);
-                               return -EFAULT;
-                       }
-                       JOM(8, "%i=peasycap->standard_offset\n",
-                               peasycap->standard_offset);
-               } else {
-                       JOM(8, "%i=peasycap->standard_offset unchanged\n",
-                                               peasycap->standard_offset);
-               }
-               off = peasycap->inputset[input].format_offset;
-               if (off != peasycap->format_offset) {
-                       struct v4l2_pix_format *pix =
-                               &easycap_format[off].v4l2_format.fmt.pix;
-                       rc = adjust_format(peasycap,
-                               pix->width, pix->height,
-                               pix->pixelformat, pix->field, false);
-                       if (0 > rc) {
-                               SAM("ERROR: adjust_format() rc = %i\n", rc);
-                               return -EFAULT;
-                       }
-                       JOM(8, "%i=peasycap->format_offset\n",
-                                       peasycap->format_offset);
-               } else {
-                       JOM(8, "%i=peasycap->format_offset unchanged\n",
-                                       peasycap->format_offset);
-               }
-               mood = peasycap->inputset[input].brightness;
-               if (mood != peasycap->brightness) {
-                       rc = adjust_brightness(peasycap, mood);
-                       if (rc) {
-                               SAM("ERROR: adjust_brightness rc = %i\n", rc);
-                               return -EFAULT;
-                       }
-                       JOM(8, "%i=peasycap->brightness\n",
-                                       peasycap->brightness);
-               }
-               mood = peasycap->inputset[input].contrast;
-               if (mood != peasycap->contrast) {
-                       rc = adjust_contrast(peasycap, mood);
-                       if (rc) {
-                               SAM("ERROR: adjust_contrast rc = %i\n", rc);
-                               return -EFAULT;
-                       }
-                       JOM(8, "%i=peasycap->contrast\n", peasycap->contrast);
-               }
-               mood = peasycap->inputset[input].saturation;
-               if (mood != peasycap->saturation) {
-                       rc = adjust_saturation(peasycap, mood);
-                       if (rc) {
-                               SAM("ERROR: adjust_saturation rc = %i\n", rc);
-                               return -EFAULT;
-                       }
-                       JOM(8, "%i=peasycap->saturation\n",
-                                       peasycap->saturation);
-               }
-               mood = peasycap->inputset[input].hue;
-               if (mood != peasycap->hue) {
-                       rc = adjust_hue(peasycap, mood);
-                       if (rc) {
-                               SAM("ERROR: adjust_hue rc = %i\n", rc);
-                               return -EFAULT;
-                       }
-                       JOM(8, "%i=peasycap->hue\n", peasycap->hue);
-               }
-       } else {
-               SAM("MISTAKE: easycap.inputset[%i] unpopulated\n", input);
-               return -ENOENT;
-       }
-/*---------------------------------------------------------------------------*/
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -ENODEV;
-       }
-       rc = usb_set_interface(peasycap->pusb_device,
-                               peasycap->video_interface,
-                               peasycap->video_altsetting_on);
-       if (rc) {
-               SAM("ERROR: usb_set_interface() rc = %i\n", rc);
-               return -EFAULT;
-       }
-       rc = start_100(peasycap->pusb_device);
-       if (rc) {
-               SAM("ERROR: start_100() rc = %i\n", rc);
-               return -EFAULT;
-       }
-       if (resubmit)
-               submit_video_urbs(peasycap);
-
-       peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1;
-       peasycap->video_idle = video_idlenow;
-       peasycap->audio_idle = audio_idlenow;
-       peasycap->video_junk = 0;
-
-       return 0;
-}
-/*****************************************************************************/
-int submit_video_urbs(struct easycap *peasycap)
-{
-       struct data_urb *pdata_urb;
-       struct urb *purb;
-       struct list_head *plist_head;
-       int j, isbad, nospc, m, rc;
-       int isbuf;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-
-       if (!peasycap->purb_video_head) {
-               SAY("ERROR: peasycap->urb_video_head uninitialized\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAY("ERROR: peasycap->pusb_device is NULL\n");
-               return -ENODEV;
-       }
-       if (!peasycap->video_isoc_streaming) {
-               JOM(4, "submission of all video urbs\n");
-               isbad = 0;  nospc = 0;  m = 0;
-               list_for_each(plist_head, (peasycap->purb_video_head)) {
-                       pdata_urb = list_entry(plist_head,
-                                               struct data_urb, list_head);
-                       if (pdata_urb && pdata_urb->purb) {
-                               purb = pdata_urb->purb;
-                               isbuf = pdata_urb->isbuf;
-                               purb->interval = 1;
-                               purb->dev = peasycap->pusb_device;
-                               purb->pipe =
-                                       usb_rcvisocpipe(peasycap->pusb_device,
-                                       peasycap->video_endpointnumber);
-                               purb->transfer_flags = URB_ISO_ASAP;
-                               purb->transfer_buffer =
-                                       peasycap->video_isoc_buffer[isbuf].pgo;
-                               purb->transfer_buffer_length =
-                                       peasycap->video_isoc_buffer_size;
-                               purb->complete = easycap_complete;
-                               purb->context = peasycap;
-                               purb->start_frame = 0;
-                               purb->number_of_packets =
-                                       peasycap->video_isoc_framesperdesc;
-
-                               for (j = 0;  j < peasycap->video_isoc_framesperdesc; j++) {
-                                       purb->iso_frame_desc[j]. offset =
-                                               j * peasycap->video_isoc_maxframesize;
-                                       purb->iso_frame_desc[j]. length =
-                                               peasycap->video_isoc_maxframesize;
-                               }
-
-                               rc = usb_submit_urb(purb, GFP_KERNEL);
-                               if (rc) {
-                                       isbad++;
-                                       SAM("ERROR: usb_submit_urb() failed "
-                                               "for urb with rc:-%s\n",
-                                                       strerror(rc));
-                                       if (rc == -ENOSPC)
-                                               nospc++;
-                               } else {
-                                       m++;
-                               }
-                       } else {
-                               isbad++;
-                       }
-               }
-               if (nospc) {
-                       SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
-                       SAM(".....  possibly inadequate USB bandwidth\n");
-                       peasycap->video_eof = 1;
-               }
-
-               if (isbad) {
-                       JOM(4, "attempting cleanup instead of submitting\n");
-                       list_for_each(plist_head, (peasycap->purb_video_head)) {
-                               pdata_urb = list_entry(plist_head,
-                                               struct data_urb, list_head);
-                               if (pdata_urb) {
-                                       purb = pdata_urb->purb;
-                                       if (purb)
-                                               usb_kill_urb(purb);
-                               }
-                       }
-                       peasycap->video_isoc_streaming = 0;
-               } else {
-                       peasycap->video_isoc_streaming = 1;
-                       JOM(4, "submitted %i video urbs\n", m);
-               }
-       } else {
-               JOM(4, "already streaming video urbs\n");
-       }
-       return 0;
-}
-/*****************************************************************************/
-int kill_video_urbs(struct easycap *peasycap)
-{
-       int m;
-       struct list_head *plist_head;
-       struct data_urb *pdata_urb;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->video_isoc_streaming) {
-               JOM(8, "%i=video_isoc_streaming, no video urbs killed\n",
-                       peasycap->video_isoc_streaming);
-               return 0;
-       }
-       if (!peasycap->purb_video_head) {
-               SAM("ERROR: peasycap->purb_video_head is NULL\n");
-               return -EFAULT;
-       }
-
-       peasycap->video_isoc_streaming = 0;
-       JOM(4, "killing video urbs\n");
-       m = 0;
-       list_for_each(plist_head, (peasycap->purb_video_head)) {
-               pdata_urb = list_entry(plist_head, struct data_urb, list_head);
-               if (pdata_urb && pdata_urb->purb) {
-                       usb_kill_urb(pdata_urb->purb);
-                       m++;
-               }
-       }
-       JOM(4, "%i video urbs killed\n", m);
-
-       return 0;
-}
-/****************************************************************************/
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-/*--------------------------------------------------------------------------*/
-static int easycap_open_noinode(struct file *file)
-{
-       return easycap_open(NULL, file);
-}
-
-static int videodev_release(struct video_device *pvideo_device)
-{
-       struct easycap *peasycap;
-
-       peasycap = video_get_drvdata(pvideo_device);
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               SAY("ending unsuccessfully\n");
-               return -EFAULT;
-       }
-       if (0 != kill_video_urbs(peasycap)) {
-               SAM("ERROR: kill_video_urbs() failed\n");
-               return -EFAULT;
-       }
-       JOM(4, "ending successfully\n");
-       return 0;
-}
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-/*****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *  THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect() AND IS
- *  PROTECTED BY SEMAPHORES SET AND CLEARED BY easycap_usb_disconnect().
- *
- *  BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED, SO
- *  peasycap->pusb_device IS NO LONGER VALID.
- */
-/*---------------------------------------------------------------------------*/
-static void easycap_delete(struct kref *pkref)
-{
-       struct easycap *peasycap;
-       struct data_urb *pdata_urb;
-       struct list_head *plist_head, *plist_next;
-       int k, m, gone, kd;
-       int allocation_video_urb;
-       int allocation_video_page;
-       int allocation_video_struct;
-       int allocation_audio_urb;
-       int allocation_audio_page;
-       int allocation_audio_struct;
-       int registered_video, registered_audio;
-
-       peasycap = container_of(pkref, struct easycap, kref);
-       if (!peasycap) {
-               SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
-               return;
-       }
-       kd = isdongle(peasycap);
-/*---------------------------------------------------------------------------*/
-/*
- *  FREE VIDEO.
- */
-/*---------------------------------------------------------------------------*/
-       if (peasycap->purb_video_head) {
-               JOM(4, "freeing video urbs\n");
-               m = 0;
-               list_for_each(plist_head, (peasycap->purb_video_head)) {
-                       pdata_urb = list_entry(plist_head,
-                                               struct data_urb, list_head);
-                       if (!pdata_urb) {
-                               JOM(4, "ERROR: pdata_urb is NULL\n");
-                       } else {
-                               if (pdata_urb->purb) {
-                                       usb_free_urb(pdata_urb->purb);
-                                       pdata_urb->purb = NULL;
-                                       peasycap->allocation_video_urb -= 1;
-                                       m++;
-                               }
-                       }
-               }
-
-               JOM(4, "%i video urbs freed\n", m);
-/*---------------------------------------------------------------------------*/
-               JOM(4, "freeing video data_urb structures.\n");
-               m = 0;
-               list_for_each_safe(plist_head, plist_next,
-                                       peasycap->purb_video_head) {
-                       pdata_urb = list_entry(plist_head,
-                                               struct data_urb, list_head);
-                       if (pdata_urb) {
-                               peasycap->allocation_video_struct -=
-                                               sizeof(struct data_urb);
-                               kfree(pdata_urb);
-                               pdata_urb = NULL;
-                               m++;
-                       }
-               }
-               JOM(4, "%i video data_urb structures freed\n", m);
-               JOM(4, "setting peasycap->purb_video_head=NULL\n");
-               peasycap->purb_video_head = NULL;
-       }
-/*---------------------------------------------------------------------------*/
-       JOM(4, "freeing video isoc buffers.\n");
-       m = 0;
-       for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY;  k++) {
-               if (peasycap->video_isoc_buffer[k].pgo) {
-                       free_pages((unsigned long)
-                                  peasycap->video_isoc_buffer[k].pgo,
-                                       VIDEO_ISOC_ORDER);
-                       peasycap->video_isoc_buffer[k].pgo = NULL;
-                       peasycap->allocation_video_page -=
-                                               BIT(VIDEO_ISOC_ORDER);
-                       m++;
-               }
-       }
-       JOM(4, "isoc video buffers freed: %i pages\n",
-                       m * (0x01 << VIDEO_ISOC_ORDER));
-/*---------------------------------------------------------------------------*/
-       JOM(4, "freeing video field buffers.\n");
-       gone = 0;
-       for (k = 0;  k < FIELD_BUFFER_MANY;  k++) {
-               for (m = 0;  m < FIELD_BUFFER_SIZE/PAGE_SIZE;  m++) {
-                       if (peasycap->field_buffer[k][m].pgo) {
-                               free_page((unsigned long)
-                                         peasycap->field_buffer[k][m].pgo);
-                               peasycap->field_buffer[k][m].pgo = NULL;
-                               peasycap->allocation_video_page -= 1;
-                               gone++;
-                       }
-               }
-       }
-       JOM(4, "video field buffers freed: %i pages\n", gone);
-/*---------------------------------------------------------------------------*/
-       JOM(4, "freeing video frame buffers.\n");
-       gone = 0;
-       for (k = 0;  k < FRAME_BUFFER_MANY;  k++) {
-               for (m = 0;  m < FRAME_BUFFER_SIZE/PAGE_SIZE;  m++) {
-                       if (peasycap->frame_buffer[k][m].pgo) {
-                               free_page((unsigned long)
-                                         peasycap->frame_buffer[k][m].pgo);
-                               peasycap->frame_buffer[k][m].pgo = NULL;
-                               peasycap->allocation_video_page -= 1;
-                               gone++;
-                       }
-               }
-       }
-       JOM(4, "video frame buffers freed: %i pages\n", gone);
-/*---------------------------------------------------------------------------*/
-/*
- *  FREE AUDIO.
- */
-/*---------------------------------------------------------------------------*/
-       if (peasycap->purb_audio_head) {
-               JOM(4, "freeing audio urbs\n");
-               m = 0;
-               list_for_each(plist_head, (peasycap->purb_audio_head)) {
-                       pdata_urb = list_entry(plist_head,
-                                       struct data_urb, list_head);
-                       if (!pdata_urb)
-                               JOM(4, "ERROR: pdata_urb is NULL\n");
-                       else {
-                               if (pdata_urb->purb) {
-                                       usb_free_urb(pdata_urb->purb);
-                                       pdata_urb->purb = NULL;
-                                       peasycap->allocation_audio_urb -= 1;
-                                       m++;
-                               }
-                       }
-               }
-               JOM(4, "%i audio urbs freed\n", m);
-/*---------------------------------------------------------------------------*/
-               JOM(4, "freeing audio data_urb structures.\n");
-               m = 0;
-               list_for_each_safe(plist_head, plist_next,
-                                       peasycap->purb_audio_head) {
-                       pdata_urb = list_entry(plist_head,
-                                       struct data_urb, list_head);
-                       if (pdata_urb) {
-                               peasycap->allocation_audio_struct -=
-                                                       sizeof(struct data_urb);
-                               kfree(pdata_urb);
-                               pdata_urb = NULL;
-                               m++;
-                       }
-               }
-               JOM(4, "%i audio data_urb structures freed\n", m);
-               JOM(4, "setting peasycap->purb_audio_head=NULL\n");
-               peasycap->purb_audio_head = NULL;
-       }
-/*---------------------------------------------------------------------------*/
-       JOM(4, "freeing audio isoc buffers.\n");
-       m = 0;
-       for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY;  k++) {
-               if (peasycap->audio_isoc_buffer[k].pgo) {
-                       free_pages((unsigned long)
-                                       (peasycap->audio_isoc_buffer[k].pgo),
-                                       AUDIO_ISOC_ORDER);
-                       peasycap->audio_isoc_buffer[k].pgo = NULL;
-                       peasycap->allocation_audio_page -=
-                                       BIT(AUDIO_ISOC_ORDER);
-                       m++;
-               }
-       }
-       JOM(4, "easyoss_delete(): isoc audio buffers freed: %i pages\n",
-                                       m * (0x01 << AUDIO_ISOC_ORDER));
-/*---------------------------------------------------------------------------*/
-       JOM(4, "freeing easycap structure.\n");
-       allocation_video_urb    = peasycap->allocation_video_urb;
-       allocation_video_page   = peasycap->allocation_video_page;
-       allocation_video_struct = peasycap->allocation_video_struct;
-       registered_video        = peasycap->registered_video;
-       allocation_audio_urb    = peasycap->allocation_audio_urb;
-       allocation_audio_page   = peasycap->allocation_audio_page;
-       allocation_audio_struct = peasycap->allocation_audio_struct;
-       registered_audio        = peasycap->registered_audio;
-
-       if (0 <= kd && DONGLE_MANY > kd) {
-               if (mutex_lock_interruptible(&mutex_dongle)) {
-                       SAY("ERROR: cannot down mutex_dongle\n");
-               } else {
-                       JOM(4, "locked mutex_dongle\n");
-                       easycapdc60_dongle[kd].peasycap = NULL;
-                       mutex_unlock(&mutex_dongle);
-                       JOM(4, "unlocked mutex_dongle\n");
-                       JOT(4, "   null-->dongle[%i].peasycap\n", kd);
-                       allocation_video_struct -= sizeof(struct easycap);
-               }
-       } else {
-               SAY("ERROR: cannot purge dongle[].peasycap");
-       }
-
-       kfree(peasycap);
-
-/*---------------------------------------------------------------------------*/
-       SAY("%8i=video urbs    after all deletions\n", allocation_video_urb);
-       SAY("%8i=video pages   after all deletions\n", allocation_video_page);
-       SAY("%8i=video structs after all deletions\n", allocation_video_struct);
-       SAY("%8i=video devices after all deletions\n", registered_video);
-       SAY("%8i=audio urbs    after all deletions\n", allocation_audio_urb);
-       SAY("%8i=audio pages   after all deletions\n", allocation_audio_page);
-       SAY("%8i=audio structs after all deletions\n", allocation_audio_struct);
-       SAY("%8i=audio devices after all deletions\n", registered_audio);
-
-       JOT(4, "ending.\n");
-       return;
-}
-/*****************************************************************************/
-static unsigned int easycap_poll(struct file *file, poll_table *wait)
-{
-       struct easycap *peasycap;
-       int rc, kd;
-
-       JOT(8, "\n");
-
-       if (NULL == ((poll_table *)wait))
-               JOT(8, "WARNING:  poll table pointer is NULL ... continuing\n");
-       if (!file) {
-               SAY("ERROR:  file pointer is NULL\n");
-               return -ERESTARTSYS;
-       }
-       peasycap = file->private_data;
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAY("ERROR:  peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-/*---------------------------------------------------------------------------*/
-       kd = isdongle(peasycap);
-       if (0 <= kd && DONGLE_MANY > kd) {
-               if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
-                       SAY("ERROR: cannot down dongle[%i].mutex_video\n", kd);
-                       return -ERESTARTSYS;
-               }
-               JOM(4, "locked dongle[%i].mutex_video\n", kd);
-       /*
-        *  MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER
-        *  peasycap, IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
-        *  IF NECESSARY, BAIL OUT.
-        */
-               if (kd != isdongle(peasycap)) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ERESTARTSYS;
-               }
-               if (!file) {
-                       SAY("ERROR:  file is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ERESTARTSYS;
-               }
-               peasycap = file->private_data;
-               if (!peasycap) {
-                       SAY("ERROR:  peasycap is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ERESTARTSYS;
-               }
-               if (!peasycap->pusb_device) {
-                       SAM("ERROR: peasycap->pusb_device is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ERESTARTSYS;
-               }
-       } else
-       /*
-        *  IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap
-        *  BEFORE THE ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL
-        *  HAVE FAILED.  BAIL OUT.
-       */
-               return -ERESTARTSYS;
-/*---------------------------------------------------------------------------*/
-       rc = easycap_dqbuf(peasycap, 0);
-       peasycap->polled = 1;
-       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-       if (0 == rc)
-               return POLLIN | POLLRDNORM;
-       else
-               return POLLERR;
-       }
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  IF mode IS NONZERO THIS ROUTINE RETURNS -EAGAIN RATHER THAN BLOCKING.
- */
-/*---------------------------------------------------------------------------*/
-int easycap_dqbuf(struct easycap *peasycap, int mode)
-{
-       int input, ifield, miss, rc;
-
-
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAY("ERROR:  peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       ifield = 0;
-       JOM(8, "%i=ifield\n", ifield);
-/*---------------------------------------------------------------------------*/
-/*
- *  CHECK FOR LOST INPUT SIGNAL.
- *
- *  FOR THE FOUR-CVBS EasyCAP, THIS DOES NOT WORK AS EXPECTED.
- *  IF INPUT 0 IS PRESENT AND SYNC ACQUIRED, UNPLUGGING INPUT 4 DOES NOT
- *  RESULT IN SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE
- *  IS FLYWHEELING ON INPUT 0.  THE UPSHOT IS:
- *
- *    INPUT 0   PLUGGED, INPUT 4   PLUGGED => SCREEN 0 OK,   SCREEN 4 OK
- *    INPUT 0   PLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 OK,   SCREEN 4 BLACK
- *    INPUT 0 UNPLUGGED, INPUT 4   PLUGGED => SCREEN 0 BARS, SCREEN 4 OK
- *    INPUT 0 UNPLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 BARS, SCREEN 4 BARS
-*/
-/*---------------------------------------------------------------------------*/
-       input = peasycap->input;
-       if (0 <= input && INPUT_MANY > input) {
-               rc = read_saa(peasycap->pusb_device, 0x1F);
-               if (0 <= rc) {
-                       if (rc & 0x40)
-                               peasycap->lost[input] += 1;
-                       else
-                               peasycap->lost[input] -= 2;
-
-               if (0 > peasycap->lost[input])
-                       peasycap->lost[input] = 0;
-               else if ((2 * VIDEO_LOST_TOLERATE) < peasycap->lost[input])
-                       peasycap->lost[input] = (2 * VIDEO_LOST_TOLERATE);
-               }
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  WAIT FOR FIELD ifield  (0 => TOP, 1 => BOTTOM)
- */
-/*---------------------------------------------------------------------------*/
-       miss = 0;
-       while ((peasycap->field_read == peasycap->field_fill) ||
-              (0 != (0xFF00 & peasycap->field_buffer
-                                       [peasycap->field_read][0].kount)) ||
-             (ifield != (0x00FF & peasycap->field_buffer
-                                       [peasycap->field_read][0].kount))) {
-               if (mode)
-                       return -EAGAIN;
-
-               JOM(8, "first wait  on wq_video, %i=field_read %i=field_fill\n",
-                               peasycap->field_read, peasycap->field_fill);
-
-               if (0 != (wait_event_interruptible(peasycap->wq_video,
-                               (peasycap->video_idle || peasycap->video_eof  ||
-                               ((peasycap->field_read != peasycap->field_fill) &&
-                               (0 == (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) &&
-                               (ifield == (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))))))) {
-                       SAM("aborted by signal\n");
-                       return -EIO;
-               }
-               if (peasycap->video_idle) {
-                       JOM(8, "%i=peasycap->video_idle returning -EAGAIN\n",
-                                                       peasycap->video_idle);
-                       return -EAGAIN;
-               }
-               if (peasycap->video_eof) {
-                       JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
-                       #if defined(PERSEVERE)
-                       if (1 == peasycap->status) {
-                               JOM(8, "persevering ...\n");
-                               peasycap->video_eof = 0;
-                               peasycap->audio_eof = 0;
-                               if (0 != reset(peasycap)) {
-                                       JOM(8, " ... failed  returning -EIO\n");
-                                       peasycap->video_eof = 1;
-                                       peasycap->audio_eof = 1;
-                                       kill_video_urbs(peasycap);
-                                       return -EIO;
-                               }
-                               peasycap->status = 0;
-                               JOM(8, " ... OK  returning -EAGAIN\n");
-                               return -EAGAIN;
-                       }
-                       #endif /*PERSEVERE*/
-                       peasycap->video_eof = 1;
-                       peasycap->audio_eof = 1;
-                       kill_video_urbs(peasycap);
-                       JOM(8, "returning -EIO\n");
-                       return -EIO;
-               }
-               miss++;
-       }
-       JOM(8, "first awakening on wq_video after %i waits\n", miss);
-
-       rc = field2frame(peasycap);
-       if (rc)
-               SAM("ERROR: field2frame() rc = %i\n", rc);
-/*---------------------------------------------------------------------------*/
-/*
- *  WAIT FOR THE OTHER FIELD
- */
-/*---------------------------------------------------------------------------*/
-       if (ifield)
-               ifield = 0;
-       else
-               ifield = 1;
-       miss = 0;
-       while ((peasycap->field_read == peasycap->field_fill) ||
-              (0 != (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) ||
-              (ifield != (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))) {
-               if (mode)
-                       return -EAGAIN;
-
-               JOM(8, "second wait on wq_video %i=field_read  %i=field_fill\n",
-                               peasycap->field_read, peasycap->field_fill);
-               if (0 != (wait_event_interruptible(peasycap->wq_video,
-                       (peasycap->video_idle || peasycap->video_eof  ||
-                       ((peasycap->field_read != peasycap->field_fill) &&
-                        (0 == (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) &&
-                        (ifield == (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))))))) {
-                       SAM("aborted by signal\n");
-                       return -EIO;
-               }
-               if (peasycap->video_idle) {
-                       JOM(8, "%i=peasycap->video_idle returning -EAGAIN\n",
-                                                       peasycap->video_idle);
-                       return -EAGAIN;
-               }
-               if (peasycap->video_eof) {
-                       JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
-#if defined(PERSEVERE)
-                       if (1 == peasycap->status) {
-                               JOM(8, "persevering ...\n");
-                               peasycap->video_eof = 0;
-                               peasycap->audio_eof = 0;
-                               if (0 != reset(peasycap)) {
-                                       JOM(8, " ... failed returning -EIO\n");
-                                       peasycap->video_eof = 1;
-                                       peasycap->audio_eof = 1;
-                                       kill_video_urbs(peasycap);
-                                       return -EIO;
-                               }
-                               peasycap->status = 0;
-                               JOM(8, " ... OK ... returning -EAGAIN\n");
-                               return -EAGAIN;
-                       }
-#endif /*PERSEVERE*/
-                       peasycap->video_eof = 1;
-                       peasycap->audio_eof = 1;
-                       kill_video_urbs(peasycap);
-                       JOM(8, "returning -EIO\n");
-                       return -EIO;
-               }
-               miss++;
-       }
-       JOM(8, "second awakening on wq_video after %i waits\n", miss);
-
-       rc = field2frame(peasycap);
-       if (rc)
-               SAM("ERROR: field2frame() rc = %i\n", rc);
-/*---------------------------------------------------------------------------*/
-/*
- *  WASTE THIS FRAME
-*/
-/*---------------------------------------------------------------------------*/
-       if (peasycap->skip) {
-               peasycap->skipped++;
-               if (peasycap->skip != peasycap->skipped)
-                       return peasycap->skip - peasycap->skipped;
-               else
-                       peasycap->skipped = 0;
-       }
-/*---------------------------------------------------------------------------*/
-       peasycap->frame_read = peasycap->frame_fill;
-       peasycap->queued[peasycap->frame_read] = 0;
-       peasycap->done[peasycap->frame_read]   = V4L2_BUF_FLAG_DONE;
-
-       peasycap->frame_fill++;
-       if (peasycap->frame_buffer_many <= peasycap->frame_fill)
-               peasycap->frame_fill = 0;
-
-       if (0x01 & easycap_standard[peasycap->standard_offset].mask)
-               peasycap->frame_buffer[peasycap->frame_read][0].kount =
-                                                       V4L2_FIELD_TOP;
-       else
-               peasycap->frame_buffer[peasycap->frame_read][0].kount =
-                                                       V4L2_FIELD_BOTTOM;
-
-
-       JOM(8, "setting:    %i=peasycap->frame_read\n", peasycap->frame_read);
-       JOM(8, "bumped to:  %i=peasycap->frame_fill\n", peasycap->frame_fill);
-
-       return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  BY DEFINITION, odd IS true  FOR THE FIELD OCCUPYING LINES 1,3,5,...,479
- *                 odd IS false FOR THE FIELD OCCUPYING LINES 0,2,4,...,478
- *
- *  WHEN BOOLEAN PARAMETER decimatepixel IS true, ONLY THE FIELD FOR WHICH
- *  odd==false IS TRANSFERRED TO THE FRAME BUFFER.
- *
- *  THE BOOLEAN PARAMETER offerfields IS true ONLY WHEN THE USER PROGRAM
- *  CHOOSES THE OPTION V4L2_FIELD_INTERLACED.
- */
-/*---------------------------------------------------------------------------*/
-int
-field2frame(struct easycap *peasycap)
-{
-
-       void *pex, *pad;
-       int kex, kad, mex, mad, rex, rad, rad2;
-       int c2, c3, w2, w3, cz, wz;
-       int rc, bytesperpixel, multiplier;
-       int  much, more, over, rump, caches, input;
-       u8 mask, margin;
-       bool odd, isuy, decimatepixel, offerfields, badinput;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-
-       badinput = false;
-       input = 0x07 & peasycap->field_buffer[peasycap->field_read][0].input;
-
-       JOM(8, "=====  parity %i, input 0x%02X, field buffer %i --> "
-                                                       "frame buffer %i\n",
-                       peasycap->field_buffer[peasycap->field_read][0].kount,
-                       peasycap->field_buffer[peasycap->field_read][0].input,
-                       peasycap->field_read, peasycap->frame_fill);
-       JOM(8, "=====  %i=bytesperpixel\n", peasycap->bytesperpixel);
-       if (peasycap->offerfields)
-               JOM(8, "===== offerfields\n");
-
-/*---------------------------------------------------------------------------*/
-/*
- *  REJECT OR CLEAN BAD FIELDS
- */
-/*---------------------------------------------------------------------------*/
-       if (peasycap->field_read == peasycap->field_fill) {
-               SAM("ERROR: on entry, still filling field buffer %i\n",
-                                               peasycap->field_read);
-               return 0;
-       }
-#ifdef EASYCAP_TESTCARD
-       easycap_testcard(peasycap, peasycap->field_read);
-#else
-       if (0 <= input && INPUT_MANY > input) {
-               if (easycap_bars && VIDEO_LOST_TOLERATE <= peasycap->lost[input])
-                       easycap_testcard(peasycap, peasycap->field_read);
-       }
-#endif /*EASYCAP_TESTCARD*/
-/*---------------------------------------------------------------------------*/
-
-       offerfields = peasycap->offerfields;
-       bytesperpixel = peasycap->bytesperpixel;
-       decimatepixel = peasycap->decimatepixel;
-
-       if ((2 != bytesperpixel) &&
-           (3 != bytesperpixel) &&
-           (4 != bytesperpixel)) {
-               SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
-               return -EFAULT;
-       }
-       if (decimatepixel)
-               multiplier = 2;
-       else
-               multiplier = 1;
-
-       w2 = 2 * multiplier * (peasycap->width);
-       w3 = bytesperpixel * multiplier * (peasycap->width);
-       wz = multiplier * (peasycap->height) *
-               multiplier * (peasycap->width);
-
-       kex = peasycap->field_read;  mex = 0;
-       kad = peasycap->frame_fill;  mad = 0;
-
-       pex = peasycap->field_buffer[kex][0].pgo;  rex = PAGE_SIZE;
-       pad = peasycap->frame_buffer[kad][0].pgo;  rad = PAGE_SIZE;
-       odd = !!(peasycap->field_buffer[kex][0].kount);
-
-       if (odd && (!decimatepixel)) {
-               JOM(8, "initial skipping %4i bytes p.%4i\n",
-                                       w3/multiplier, mad);
-               pad += (w3 / multiplier); rad -= (w3 / multiplier);
-       }
-       isuy = true;
-       mask = 0;  rump = 0;  caches = 0;
-
-       cz = 0;
-       while (cz < wz) {
-               /*
-                *  PROCESS ONE LINE OF FRAME AT FULL RESOLUTION:
-                *  READ   w2   BYTES FROM FIELD BUFFER,
-                *  WRITE  w3   BYTES TO FRAME BUFFER
-                */
-               if (!decimatepixel) {
-                       over = w2;
-                       do {
-                               much = over;  more = 0;
-                               margin = 0;  mask = 0x00;
-                               if (rex < much)
-                                       much = rex;
-                               rump = 0;
-
-                               if (much % 2) {
-                                       SAM("MISTAKE: much is odd\n");
-                                       return -EFAULT;
-                               }
-
-                               more = (bytesperpixel *
-                                               much) / 2;
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-                               if (1 < bytesperpixel) {
-                                       if (rad * 2 < much * bytesperpixel) {
-                                               /*
-                                                * INJUDICIOUS ALTERATION OF
-                                                * THIS STATEMENT BLOCK WILL
-                                                * CAUSE BREAKAGE.  BEWARE.
-                                                */
-                                               rad2 = rad + bytesperpixel - 1;
-                                               much = ((((2 * rad2)/bytesperpixel)/2) * 2);
-                                               rump = ((bytesperpixel * much) / 2) - rad;
-                                               more = rad;
-                                       }
-                                       mask = (u8)rump;
-                                       margin = 0;
-                                       if (much == rex) {
-                                               mask |= 0x04;
-                                               if ((mex + 1) < FIELD_BUFFER_SIZE / PAGE_SIZE)
-                                                       margin = *((u8 *)(peasycap->field_buffer[kex][mex + 1].pgo));
-                                               else
-                                                       mask |= 0x08;
-                                       }
-                               } else {
-                                       SAM("MISTAKE: %i=bytesperpixel\n",
-                                                       bytesperpixel);
-                                       return -EFAULT;
-                               }
-                               if (rump)
-                                       caches++;
-                                       if (badinput) {
-                                               JOM(8, "ERROR: 0x%02X=->field_buffer"
-                                                       "[%i][%i].input, "
-                                                       "0x%02X=(0x08|->input)\n",
-                                                       peasycap->field_buffer
-                                                       [kex][mex].input, kex, mex,
-                                                       (0x08|peasycap->input));
-                                       }
-                               rc = redaub(peasycap, pad, pex, much, more,
-                                                               mask, margin, isuy);
-                               if (0 > rc) {
-                                       SAM("ERROR: redaub() failed\n");
-                                       return -EFAULT;
-                               }
-                               if (much % 4)
-                                       isuy = !isuy;
-
-                               over -= much;   cz += much;
-                               pex  += much;  rex -= much;
-                               if (!rex) {
-                                       mex++;
-                                       pex = peasycap->field_buffer[kex][mex].pgo;
-                                       rex = PAGE_SIZE;
-                                       if (peasycap->field_buffer[kex][mex].input != (0x08|peasycap->input))
-                                               badinput = true;
-                               }
-                               pad  += more;
-                               rad -= more;
-                               if (!rad) {
-                                       mad++;
-                                       pad = peasycap->frame_buffer[kad][mad].pgo;
-                                       rad = PAGE_SIZE;
-                                       if (rump) {
-                                               pad += rump;
-                                               rad -= rump;
-                                       }
-                               }
-                       } while (over);
-/*---------------------------------------------------------------------------*/
-/*
- *  SKIP  w3 BYTES IN TARGET FRAME BUFFER,
- *  UNLESS IT IS THE LAST LINE OF AN ODD FRAME
- */
-/*---------------------------------------------------------------------------*/
-                       if (!odd || (cz != wz)) {
-                               over = w3;
-                               do {
-                                       if (!rad) {
-                                               mad++;
-                                               pad = peasycap->frame_buffer
-                                                       [kad][mad].pgo;
-                                               rad = PAGE_SIZE;
-                                       }
-                                       more = over;
-                                       if (rad < more)
-                                               more = rad;
-                                       over -= more;
-                                       pad  += more;
-                                       rad  -= more;
-                               } while (over);
-                       }
-/*---------------------------------------------------------------------------*/
-/*
- *  PROCESS ONE LINE OF FRAME AT REDUCED RESOLUTION:
- *  ONLY IF false==odd,
- *  READ   w2   BYTES FROM FIELD BUFFER,
- *  WRITE  w3 / 2  BYTES TO FRAME BUFFER
- */
-/*---------------------------------------------------------------------------*/
-               } else if (!odd) {
-                       over = w2;
-                       do {
-                               much = over;  more = 0;  margin = 0;  mask = 0x00;
-                               if (rex < much)
-                                       much = rex;
-                               rump = 0;
-
-                               if (much % 2) {
-                                       SAM("MISTAKE: much is odd\n");
-                                       return -EFAULT;
-                               }
-
-                               more = (bytesperpixel * much) / 4;
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-                               if (1 < bytesperpixel) {
-                                       if (rad * 4 < much * bytesperpixel) {
-                                               /*
-                                                * INJUDICIOUS ALTERATION OF
-                                                * THIS STATEMENT BLOCK
-                                                * WILL CAUSE BREAKAGE.
-                                                * BEWARE.
-                                                */
-                                               rad2 = rad + bytesperpixel - 1;
-                                               much = ((((2 * rad2) / bytesperpixel) / 2) * 4);
-                                               rump = ((bytesperpixel * much) / 4) - rad;
-                                               more = rad;
-                                       }
-                                       mask = (u8)rump;
-                                       margin = 0;
-                                       if (much == rex) {
-                                               mask |= 0x04;
-                                               if ((mex + 1) < FIELD_BUFFER_SIZE / PAGE_SIZE)
-                                                       margin = *((u8 *)(peasycap->field_buffer[kex][mex + 1].pgo));
-                                               else
-                                                       mask |= 0x08;
-                                       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-                               } else {
-                                       SAM("MISTAKE: %i=bytesperpixel\n",
-                                               bytesperpixel);
-                                       return -EFAULT;
-                               }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-                               if (rump)
-                                       caches++;
-
-                                       if (badinput) {
-                                               JOM(8, "ERROR: 0x%02X=->field_buffer"
-                                                       "[%i][%i].input, "
-                                                       "0x%02X=(0x08|->input)\n",
-                                                       peasycap->field_buffer
-                                                       [kex][mex].input, kex, mex,
-                                                       (0x08|peasycap->input));
-                                       }
-                               rc = redaub(peasycap, pad, pex, much, more,
-                                                       mask, margin, isuy);
-                               if (0 > rc) {
-                                       SAM("ERROR: redaub() failed\n");
-                                       return -EFAULT;
-                               }
-                               over -= much;   cz += much;
-                               pex  += much;  rex -= much;
-                               if (!rex) {
-                                       mex++;
-                                       pex = peasycap->field_buffer[kex][mex].pgo;
-                                       rex = PAGE_SIZE;
-                                       if (peasycap->field_buffer[kex][mex].input !=
-                                                       (0x08|peasycap->input))
-                                               badinput = true;
-                               }
-                               pad  += more;
-                               rad -= more;
-                               if (!rad) {
-                                       mad++;
-                                       pad = peasycap->frame_buffer[kad][mad].pgo;
-                                       rad = PAGE_SIZE;
-                                       if (rump) {
-                                               pad += rump;
-                                               rad -= rump;
-                                       }
-                               }
-                       } while (over);
-/*---------------------------------------------------------------------------*/
-/*
- *  OTHERWISE JUST
- *  READ   w2   BYTES FROM FIELD BUFFER AND DISCARD THEM
- */
-/*---------------------------------------------------------------------------*/
-               } else {
-                       over = w2;
-                       do {
-                               if (!rex) {
-                                       mex++;
-                                       pex = peasycap->field_buffer[kex][mex].pgo;
-                                       rex = PAGE_SIZE;
-                                       if (peasycap->field_buffer[kex][mex].input !=
-                                                       (0x08|peasycap->input)) {
-                                               JOM(8, "ERROR: 0x%02X=->field_buffer"
-                                                       "[%i][%i].input, "
-                                                       "0x%02X=(0x08|->input)\n",
-                                                       peasycap->field_buffer
-                                                       [kex][mex].input, kex, mex,
-                                                       (0x08|peasycap->input));
-                                               badinput = true;
-                                       }
-                               }
-                               much = over;
-                               if (rex < much)
-                                       much = rex;
-                               over -= much;
-                               cz += much;
-                               pex  += much;
-                               rex -= much;
-                       } while (over);
-               }
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  SANITY CHECKS
- */
-/*---------------------------------------------------------------------------*/
-       c2 = (mex + 1)*PAGE_SIZE - rex;
-       if (cz != c2)
-               SAM("ERROR: discrepancy %i in bytes read\n", c2 - cz);
-       c3 = (mad + 1)*PAGE_SIZE - rad;
-
-       if (!decimatepixel) {
-               if (bytesperpixel * cz != c3)
-                       SAM("ERROR: discrepancy %i in bytes written\n",
-                                       c3 - (bytesperpixel * cz));
-       } else {
-               if (!odd) {
-                       if (bytesperpixel *
-                               cz != (4 * c3))
-                               SAM("ERROR: discrepancy %i in bytes written\n",
-                                       (2*c3)-(bytesperpixel * cz));
-                       } else {
-                               if (0 != c3)
-                                       SAM("ERROR: discrepancy %i "
-                                           "in bytes written\n", c3);
-                       }
-       }
-       if (rump)
-               SAM("WORRY: undischarged cache at end of line in frame buffer\n");
-
-       JOM(8, "===== field2frame(): %i bytes --> %i bytes (incl skip)\n", c2, c3);
-       JOM(8, "===== field2frame(): %i=mad  %i=rad\n", mad, rad);
-
-       if (odd)
-               JOM(8, "+++++ field2frame():  frame buffer %i is full\n", kad);
-
-       if (peasycap->field_read == peasycap->field_fill)
-               SAM("WARNING: on exit, filling field buffer %i\n",
-                                               peasycap->field_read);
-
-       if (caches)
-               JOM(8, "%i=caches\n", caches);
-       return 0;
-}
-/*---------------------------------------------------------------------------*/
-/*
- *  DECIMATION AND COLOURSPACE CONVERSION.
- *
- *  THIS ROUTINE REQUIRES THAT ALL THE DATA TO BE READ RESIDES ON ONE PAGE
- *  AND THAT ALL THE DATA TO BE WRITTEN RESIDES ON ONE (DIFFERENT) PAGE.
- *  THE CALLING ROUTINE MUST ENSURE THAT THIS REQUIREMENT IS MET, AND MUST
- *  ALSO ENSURE THAT much IS EVEN.
- *
- *  much BYTES ARE READ, AT LEAST (bytesperpixel * much)/2 BYTES ARE WRITTEN
- *  IF THERE IS NO DECIMATION, HALF THIS AMOUNT IF THERE IS DECIMATION.
- *
- *  mask IS ZERO WHEN NO SPECIAL BEHAVIOUR REQUIRED. OTHERWISE IT IS SET THUS:
- *     0x03 & mask =  number of bytes to be written to cache instead of to
- *                    frame buffer
- *     0x04 & mask => use argument margin to set the chrominance for last pixel
- *     0x08 & mask => do not set the chrominance for last pixel
- *
- *  YUV to RGB CONVERSION IS (OR SHOULD BE) ITU-R BT 601.
- *
- *  THERE IS A LOT OF CODE REPETITION IN THIS ROUTINE IN ORDER TO AVOID
- *  INEFFICIENT SWITCHING INSIDE INNER LOOPS.  REARRANGING THE LOGIC TO
- *  REDUCE CODE LENGTH WILL GENERALLY IMPAIR RUNTIME PERFORMANCE.  BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-int
-redaub(struct easycap *peasycap, void *pad, void *pex, int much, int more,
-                                       u8 mask, u8 margin, bool isuy)
-{
-       static s32 ay[256], bu[256], rv[256], gu[256], gv[256];
-       u8 *pcache;
-       u8 r, g, b, y, u, v, c, *p2, *p3, *pz, *pr;
-       int  bytesperpixel;
-       bool byteswaporder, decimatepixel, last;
-       int j, rump;
-       s32 tmp;
-
-       if (much % 2) {
-               SAM("MISTAKE: much is odd\n");
-               return -EFAULT;
-       }
-       bytesperpixel = peasycap->bytesperpixel;
-       byteswaporder = peasycap->byteswaporder;
-       decimatepixel = peasycap->decimatepixel;
-
-/*---------------------------------------------------------------------------*/
-       if (!bu[255]) {
-               for (j = 0; j < 112; j++) {
-                       tmp = (0xFF00 & (453 * j)) >> 8;
-                       bu[j + 128] =  tmp; bu[127 - j] = -tmp;
-                       tmp = (0xFF00 & (359 * j)) >> 8;
-                       rv[j + 128] =  tmp; rv[127 - j] = -tmp;
-                       tmp = (0xFF00 & (88 * j)) >> 8;
-                       gu[j + 128] =  tmp; gu[127 - j] = -tmp;
-                       tmp = (0xFF00 & (183 * j)) >> 8;
-                       gv[j + 128] =  tmp; gv[127 - j] = -tmp;
-               }
-               for (j = 0; j < 16; j++) {
-                       bu[j] = bu[16]; rv[j] = rv[16];
-                       gu[j] = gu[16]; gv[j] = gv[16];
-               }
-               for (j = 240; j < 256; j++) {
-                       bu[j] = bu[239]; rv[j] = rv[239];
-                       gu[j] = gu[239]; gv[j] = gv[239];
-               }
-               for (j =  16; j < 236; j++)
-                       ay[j] = j;
-               for (j =   0; j <  16; j++)
-                       ay[j] = ay[16];
-               for (j = 236; j < 256; j++)
-                       ay[j] = ay[235];
-               JOM(8, "lookup tables are prepared\n");
-       }
-       pcache = peasycap->pcache;
-       if (!pcache)
-               pcache = &peasycap->cache[0];
-/*---------------------------------------------------------------------------*/
-/*
- *  TRANSFER CONTENTS OF CACHE TO THE FRAME BUFFER
- */
-/*---------------------------------------------------------------------------*/
-       if (!pcache) {
-               SAM("MISTAKE: pcache is NULL\n");
-               return -EFAULT;
-       }
-
-       if (pcache != &peasycap->cache[0])
-               JOM(16, "cache has %i bytes\n", (int)(pcache - &peasycap->cache[0]));
-       p2 = &peasycap->cache[0];
-       p3 = (u8 *)pad - (int)(pcache - &peasycap->cache[0]);
-       while (p2 < pcache) {
-               *p3++ = *p2;  p2++;
-       }
-       pcache = &peasycap->cache[0];
-       if (p3 != pad) {
-               SAM("MISTAKE: pointer misalignment\n");
-               return -EFAULT;
-       }
-/*---------------------------------------------------------------------------*/
-       rump = (int)(0x03 & mask);
-       u = 0; v = 0;
-       p2 = (u8 *)pex;  pz = p2 + much;  pr = p3 + more;  last = false;
-       p2++;
-
-       if (isuy)
-               u = *(p2 - 1);
-       else
-               v = *(p2 - 1);
-
-       if (rump)
-               JOM(16, "%4i=much  %4i=more  %i=rump\n", much, more, rump);
-
-/*---------------------------------------------------------------------------*/
-       switch (bytesperpixel) {
-       case 2: {
-               if (!decimatepixel) {
-                       memcpy(pad, pex, (size_t)much);
-                       if (!byteswaporder) {
-                               /* UYVY */
-                               return 0;
-                       } else {
-                               /* YUYV */
-                               p3 = (u8 *)pad;  pz = p3 + much;
-                               while  (pz > p3) {
-                                       c = *p3;
-                                       *p3 = *(p3 + 1);
-                                       *(p3 + 1) = c;
-                                       p3 += 2;
-                               }
-                               return 0;
-                       }
-               } else {
-                       if (!byteswaporder) {
-                               /*  UYVY DECIMATED */
-                               p2 = (u8 *)pex;  p3 = (u8 *)pad;  pz = p2 + much;
-                               while (pz > p2) {
-                                       *p3 = *p2;
-                                       *(p3 + 1) = *(p2 + 1);
-                                       *(p3 + 2) = *(p2 + 2);
-                                       *(p3 + 3) = *(p2 + 3);
-                                       p3 += 4;  p2 += 8;
-                               }
-                               return 0;
-                       } else {
-                               /* YUYV DECIMATED */
-                               p2 = (u8 *)pex;  p3 = (u8 *)pad;  pz = p2 + much;
-                               while (pz > p2) {
-                                       *p3 = *(p2 + 1);
-                                       *(p3 + 1) = *p2;
-                                       *(p3 + 2) = *(p2 + 3);
-                                       *(p3 + 3) = *(p2 + 2);
-                                       p3 += 4;  p2 += 8;
-                               }
-                               return 0;
-                       }
-               }
-               break;
-               }
-       case 3:
-               {
-               if (!decimatepixel) {
-                       if (!byteswaporder) {
-                               /* RGB */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               } else
-                                                       if (0x08 & mask)
-                                                               ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       tmp = ay[(int)y] + rv[(int)v];
-                                       r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                               0 : (u8)tmp);
-                                       tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
-                                       g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                               0 : (u8)tmp);
-                                       tmp = ay[(int)y] + bu[(int)u];
-                                       b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                               0 : (u8)tmp);
-
-                                       if (last && rump) {
-                                               pcache = &peasycap->cache[0];
-                                               switch (bytesperpixel - rump) {
-                                               case 1: {
-                                                       *p3 = r;
-                                                       *pcache++ = g;
-                                                       *pcache++ = b;
-                                                       break;
-                                               }
-                                               case 2: {
-                                                       *p3 = r;
-                                                       *(p3 + 1) = g;
-                                                       *pcache++ = b;
-                                                       break;
-                                               }
-                                               default: {
-                                                       SAM("MISTAKE: %i=rump\n",
-                                                               bytesperpixel - rump);
-                                                       return -EFAULT;
-                                               }
-                                               }
-                                       } else {
-                                               *p3 = r;
-                                               *(p3 + 1) = g;
-                                               *(p3 + 2) = b;
-                                       }
-                                       p2 += 2;
-                                       if (isuy)
-                                               isuy = false;
-                                       else
-                                               isuy = true;
-                                       p3 += bytesperpixel;
-                               }
-                               return 0;
-                       } else {
-                               /* BGR */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               }
-                                       else
-                                               if (0x08 & mask)
-                                                       ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       tmp = ay[(int)y] + rv[(int)v];
-                                       r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                       tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
-                                       g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                       tmp = ay[(int)y] + bu[(int)u];
-                                       b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-
-                                       if (last && rump) {
-                                               pcache = &peasycap->cache[0];
-                                               switch (bytesperpixel - rump) {
-                                               case 1: {
-                                                       *p3 = b;
-                                                       *pcache++ = g;
-                                                       *pcache++ = r;
-                                                       break;
-                                               }
-                                               case 2: {
-                                                       *p3 = b;
-                                                       *(p3 + 1) = g;
-                                                       *pcache++ = r;
-                                                       break;
-                                               }
-                                               default: {
-                                                       SAM("MISTAKE: %i=rump\n",
-                                                               bytesperpixel - rump);
-                                                       return -EFAULT;
-                                               }
-                                               }
-                                       } else {
-                                               *p3 = b;
-                                               *(p3 + 1) = g;
-                                               *(p3 + 2) = r;
-                                               }
-                                       p2 += 2;
-                                       if (isuy)
-                                               isuy = false;
-                                       else
-                                               isuy = true;
-                                       p3 += bytesperpixel;
-                                       }
-                               }
-                       return 0;
-               } else {
-                       if (!byteswaporder) {
-                               /*  RGB DECIMATED */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               } else
-                                                       if (0x08 & mask)
-                                                               ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       if (isuy) {
-                                               tmp = ay[(int)y] + rv[(int)v];
-                                               r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] - gu[(int)u] -
-                                                                       gv[(int)v];
-                                               g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] + bu[(int)u];
-                                               b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-
-                                               if (last && rump) {
-                                                       pcache = &peasycap->cache[0];
-                                                       switch (bytesperpixel - rump) {
-                                                       case 1: {
-                                                               *p3 = r;
-                                                               *pcache++ = g;
-                                                               *pcache++ = b;
-                                                               break;
-                                                       }
-                                                       case 2: {
-                                                               *p3 = r;
-                                                               *(p3 + 1) = g;
-                                                               *pcache++ = b;
-                                                               break;
-                                                       }
-                                                       default: {
-                                                               SAM("MISTAKE: "
-                                                               "%i=rump\n",
-                                                               bytesperpixel - rump);
-                                                               return -EFAULT;
-                                                       }
-                                                       }
-                                               } else {
-                                                       *p3 = r;
-                                                       *(p3 + 1) = g;
-                                                       *(p3 + 2) = b;
-                                               }
-                                               isuy = false;
-                                               p3 += bytesperpixel;
-                                       } else {
-                                               isuy = true;
-                                       }
-                                       p2 += 2;
-                               }
-                               return 0;
-                       } else {
-                               /* BGR DECIMATED */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               } else
-                                                       if (0x08 & mask)
-                                                               ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       if (isuy) {
-
-                                               tmp = ay[(int)y] + rv[(int)v];
-                                               r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] - gu[(int)u] -
-                                                                       gv[(int)v];
-                                               g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] + bu[(int)u];
-                                               b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-
-                                               if (last && rump) {
-                                                       pcache = &peasycap->cache[0];
-                                                       switch (bytesperpixel - rump) {
-                                                       case 1: {
-                                                               *p3 = b;
-                                                               *pcache++ = g;
-                                                               *pcache++ = r;
-                                                               break;
-                                                       }
-                                                       case 2: {
-                                                               *p3 = b;
-                                                               *(p3 + 1) = g;
-                                                               *pcache++ = r;
-                                                               break;
-                                                       }
-                                                       default: {
-                                                               SAM("MISTAKE: "
-                                                               "%i=rump\n",
-                                                               bytesperpixel - rump);
-                                                               return -EFAULT;
-                                                       }
-                                                       }
-                                               } else {
-                                                       *p3 = b;
-                                                       *(p3 + 1) = g;
-                                                       *(p3 + 2) = r;
-                                                       }
-                                               isuy = false;
-                                               p3 += bytesperpixel;
-                                               }
-                                       else
-                                               isuy = true;
-                                       p2 += 2;
-                                       }
-                               return 0;
-                               }
-                       }
-               break;
-               }
-       case 4:
-               {
-               if (!decimatepixel) {
-                       if (!byteswaporder) {
-                               /* RGBA */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               } else
-                                                        if (0x08 & mask)
-                                                               ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       tmp = ay[(int)y] + rv[(int)v];
-                                       r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                       tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
-                                       g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                       tmp = ay[(int)y] + bu[(int)u];
-                                       b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-
-                                       if (last && rump) {
-                                               pcache = &peasycap->cache[0];
-                                               switch (bytesperpixel - rump) {
-                                               case 1: {
-                                                       *p3 = r;
-                                                       *pcache++ = g;
-                                                       *pcache++ = b;
-                                                       *pcache++ = 0;
-                                                       break;
-                                               }
-                                               case 2: {
-                                                       *p3 = r;
-                                                       *(p3 + 1) = g;
-                                                       *pcache++ = b;
-                                                       *pcache++ = 0;
-                                                       break;
-                                               }
-                                               case 3: {
-                                                       *p3 = r;
-                                                       *(p3 + 1) = g;
-                                                       *(p3 + 2) = b;
-                                                       *pcache++ = 0;
-                                                       break;
-                                               }
-                                               default: {
-                                                       SAM("MISTAKE: %i=rump\n",
-                                                               bytesperpixel - rump);
-                                                       return -EFAULT;
-                                               }
-                                               }
-                                       } else {
-                                               *p3 = r;
-                                               *(p3 + 1) = g;
-                                               *(p3 + 2) = b;
-                                               *(p3 + 3) = 0;
-                                       }
-                                       p2 += 2;
-                                       if (isuy)
-                                               isuy = false;
-                                       else
-                                               isuy = true;
-                                       p3 += bytesperpixel;
-                               }
-                               return 0;
-                       } else {
-                               /*
-                                *  BGRA
-                                */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               } else
-                                                        if (0x08 & mask)
-                                                               ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       tmp = ay[(int)y] + rv[(int)v];
-                                       r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                       tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
-                                       g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                       tmp = ay[(int)y] + bu[(int)u];
-                                       b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-
-                                       if (last && rump) {
-                                               pcache = &peasycap->cache[0];
-                                               switch (bytesperpixel - rump) {
-                                               case 1: {
-                                                       *p3 = b;
-                                                       *pcache++ = g;
-                                                       *pcache++ = r;
-                                                       *pcache++ = 0;
-                                                       break;
-                                               }
-                                               case 2: {
-                                                       *p3 = b;
-                                                       *(p3 + 1) = g;
-                                                       *pcache++ = r;
-                                                       *pcache++ = 0;
-                                                       break;
-                                               }
-                                               case 3: {
-                                                       *p3 = b;
-                                                       *(p3 + 1) = g;
-                                                       *(p3 + 2) = r;
-                                                       *pcache++ = 0;
-                                                       break;
-                                               }
-                                               default:
-                                                       SAM("MISTAKE: %i=rump\n",
-                                                               bytesperpixel - rump);
-                                                       return -EFAULT;
-                                               }
-                                       } else {
-                                               *p3 = b;
-                                               *(p3 + 1) = g;
-                                               *(p3 + 2) = r;
-                                               *(p3 + 3) = 0;
-                                       }
-                                       p2 += 2;
-                                       if (isuy)
-                                               isuy = false;
-                                       else
-                                               isuy = true;
-                                       p3 += bytesperpixel;
-                               }
-                       }
-                       return 0;
-               } else {
-                       if (!byteswaporder) {
-                               /*
-                                *  RGBA DECIMATED
-                                */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               } else
-                                                       if (0x08 & mask)
-                                                               ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       if (isuy) {
-
-                                               tmp = ay[(int)y] + rv[(int)v];
-                                               r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] - gu[(int)u] -
-                                                                       gv[(int)v];
-                                               g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] + bu[(int)u];
-                                               b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-
-                                               if (last && rump) {
-                                                       pcache = &peasycap->cache[0];
-                                                       switch (bytesperpixel - rump) {
-                                                       case 1: {
-                                                               *p3 = r;
-                                                               *pcache++ = g;
-                                                               *pcache++ = b;
-                                                               *pcache++ = 0;
-                                                               break;
-                                                       }
-                                                       case 2: {
-                                                               *p3 = r;
-                                                               *(p3 + 1) = g;
-                                                               *pcache++ = b;
-                                                               *pcache++ = 0;
-                                                               break;
-                                                       }
-                                                       case 3: {
-                                                               *p3 = r;
-                                                               *(p3 + 1) = g;
-                                                               *(p3 + 2) = b;
-                                                               *pcache++ = 0;
-                                                               break;
-                                                       }
-                                                       default: {
-                                                               SAM("MISTAKE: "
-                                                               "%i=rump\n",
-                                                               bytesperpixel -
-                                                               rump);
-                                                               return -EFAULT;
-                                                               }
-                                                       }
-                                               } else {
-                                                       *p3 = r;
-                                                       *(p3 + 1) = g;
-                                                       *(p3 + 2) = b;
-                                                       *(p3 + 3) = 0;
-                                                       }
-                                               isuy = false;
-                                               p3 += bytesperpixel;
-                                       } else
-                                               isuy = true;
-                                       p2 += 2;
-                               }
-                               return 0;
-                       } else {
-                               /*
-                                *  BGRA DECIMATED
-                                */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               } else
-                                                       if (0x08 & mask)
-                                                               ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       if (isuy) {
-                                               tmp = ay[(int)y] + rv[(int)v];
-                                               r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] - gu[(int)u] -
-                                                                       gv[(int)v];
-                                               g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] + bu[(int)u];
-                                               b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-
-                                               if (last && rump) {
-                                                       pcache = &peasycap->cache[0];
-                                                       switch (bytesperpixel - rump) {
-                                                       case 1: {
-                                                               *p3 = b;
-                                                               *pcache++ = g;
-                                                               *pcache++ = r;
-                                                               *pcache++ = 0;
-                                                               break;
-                                                       }
-                                                       case 2: {
-                                                               *p3 = b;
-                                                               *(p3 + 1) = g;
-                                                               *pcache++ = r;
-                                                               *pcache++ = 0;
-                                                               break;
-                                                       }
-                                                       case 3: {
-                                                               *p3 = b;
-                                                               *(p3 + 1) = g;
-                                                               *(p3 + 2) = r;
-                                                               *pcache++ = 0;
-                                                               break;
-                                                       }
-                                                       default: {
-                                                               SAM("MISTAKE: "
-                                                               "%i=rump\n",
-                                                               bytesperpixel - rump);
-                                                               return -EFAULT;
-                                                       }
-                                                       }
-                                               } else {
-                                                       *p3 = b;
-                                                       *(p3 + 1) = g;
-                                                       *(p3 + 2) = r;
-                                                       *(p3 + 3) = 0;
-                                               }
-                                               isuy = false;
-                                               p3 += bytesperpixel;
-                                       } else
-                                               isuy = true;
-                                               p2 += 2;
-                                       }
-                                       return 0;
-                               }
-                       }
-               break;
-               }
-       default: {
-               SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
-               return -EFAULT;
-               }
-       }
-       return 0;
-}
-/*****************************************************************************/
-/*
- *  SEE CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGES 430-434
- */
-/*****************************************************************************/
-static void easycap_vma_open(struct vm_area_struct *pvma)
-{
-       struct easycap *peasycap;
-
-       peasycap = pvma->vm_private_data;
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return;
-       }
-       peasycap->vma_many++;
-       JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
-       return;
-}
-/*****************************************************************************/
-static void easycap_vma_close(struct vm_area_struct *pvma)
-{
-       struct easycap *peasycap;
-
-       peasycap = pvma->vm_private_data;
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return;
-       }
-       peasycap->vma_many--;
-       JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
-       return;
-}
-/*****************************************************************************/
-static int easycap_vma_fault(struct vm_area_struct *pvma, struct vm_fault *pvmf)
-{
-       int k, m, retcode;
-       void *pbuf;
-       struct page *page;
-       struct easycap *peasycap;
-
-       retcode = VM_FAULT_NOPAGE;
-
-       if (!pvma) {
-               SAY("pvma is NULL\n");
-               return retcode;
-       }
-       if (!pvmf) {
-               SAY("pvmf is NULL\n");
-               return retcode;
-       }
-
-       k = (pvmf->pgoff) / (FRAME_BUFFER_SIZE/PAGE_SIZE);
-       m = (pvmf->pgoff) % (FRAME_BUFFER_SIZE/PAGE_SIZE);
-
-       if (!m)
-               JOT(4, "%4i=k, %4i=m\n", k, m);
-       else
-               JOT(16, "%4i=k, %4i=m\n", k, m);
-
-       if ((0 > k) || (FRAME_BUFFER_MANY <= k)) {
-               SAY("ERROR: buffer index %i out of range\n", k);
-               return retcode;
-       }
-       if ((0 > m) || (FRAME_BUFFER_SIZE/PAGE_SIZE <= m)) {
-               SAY("ERROR: page number  %i out of range\n", m);
-               return retcode;
-       }
-       peasycap = pvma->vm_private_data;
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return retcode;
-       }
-/*---------------------------------------------------------------------------*/
-       pbuf = peasycap->frame_buffer[k][m].pgo;
-       if (!pbuf) {
-               SAM("ERROR:  pbuf is NULL\n");
-               return retcode;
-       }
-       page = virt_to_page(pbuf);
-       if (!page) {
-               SAM("ERROR:  page is NULL\n");
-               return retcode;
-       }
-       get_page(page);
-/*---------------------------------------------------------------------------*/
-       if (!page) {
-               SAM("ERROR:  page is NULL after get_page(page)\n");
-       } else {
-               pvmf->page = page;
-               retcode = VM_FAULT_MINOR;
-       }
-       return retcode;
-}
-
-static const struct vm_operations_struct easycap_vm_ops = {
-       .open  = easycap_vma_open,
-       .close = easycap_vma_close,
-       .fault = easycap_vma_fault,
-};
-
-static int easycap_mmap(struct file *file, struct vm_area_struct *pvma)
-{
-       JOT(8, "\n");
-
-       pvma->vm_ops = &easycap_vm_ops;
-       pvma->vm_flags |= VM_RESERVED;
-       if (file)
-               pvma->vm_private_data = file->private_data;
-       easycap_vma_open(pvma);
-       return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  ON COMPLETION OF A VIDEO URB ITS DATA IS COPIED TO THE FIELD BUFFERS
- *  PROVIDED peasycap->video_idle IS ZERO.  REGARDLESS OF THIS BEING TRUE,
- *  IT IS RESUBMITTED PROVIDED peasycap->video_isoc_streaming IS NOT ZERO.
- *
- *  THIS FUNCTION IS AN INTERRUPT SERVICE ROUTINE AND MUST NOT SLEEP.
- *
- *  INFORMATION ABOUT THE VALIDITY OF THE CONTENTS OF THE FIELD BUFFER ARE
- *  STORED IN THE TWO-BYTE STATUS PARAMETER
- *        peasycap->field_buffer[peasycap->field_fill][0].kount
- *  NOTICE THAT THE INFORMATION IS STORED ONLY WITH PAGE 0 OF THE FIELD BUFFER.
- *
- *  THE LOWER BYTE CONTAINS THE FIELD PARITY BYTE FURNISHED BY THE SAA7113H
- *  CHIP.
- *
- *  THE UPPER BYTE IS ZERO IF NO PROBLEMS, OTHERWISE:
- *      0 != (kount & 0x8000)   => AT LEAST ONE URB COMPLETED WITH ERRORS
- *      0 != (kount & 0x4000)   => BUFFER HAS TOO MUCH DATA
- *      0 != (kount & 0x2000)   => BUFFER HAS NOT ENOUGH DATA
- *      0 != (kount & 0x1000)   => BUFFER HAS DATA FROM DISPARATE INPUTS
- *      0 != (kount & 0x0400)   => RESERVED
- *      0 != (kount & 0x0200)   => FIELD BUFFER NOT YET CHECKED
- *      0 != (kount & 0x0100)   => BUFFER HAS TWO EXTRA BYTES - WHY?
- */
-/*---------------------------------------------------------------------------*/
-static void easycap_complete(struct urb *purb)
-{
-       struct easycap *peasycap;
-       struct data_buffer *pfield_buffer;
-       char errbuf[16];
-       int i, more, much, leap, rc, last;
-       int videofieldamount;
-       unsigned int override, bad;
-       int framestatus, framelength, frameactual, frameoffset;
-       u8 *pu;
-
-       if (!purb) {
-               SAY("ERROR: easycap_complete(): purb is NULL\n");
-               return;
-       }
-       peasycap = purb->context;
-       if (!peasycap) {
-               SAY("ERROR: easycap_complete(): peasycap is NULL\n");
-               return;
-       }
-       if (peasycap->video_eof)
-               return;
-       for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++)
-               if (purb->transfer_buffer == peasycap->video_isoc_buffer[i].pgo)
-                       break;
-       JOM(16, "%2i=urb\n", i);
-       last = peasycap->video_isoc_sequence;
-       if ((((VIDEO_ISOC_BUFFER_MANY - 1) == last) && (0 != i)) ||
-            (((VIDEO_ISOC_BUFFER_MANY - 1) != last) && ((last + 1) != i))) {
-               JOM(16, "ERROR: out-of-order urbs %i,%i ... continuing\n",
-                                               last, i);
-       }
-       peasycap->video_isoc_sequence = i;
-
-       if (peasycap->video_idle) {
-               JOM(16, "%i=video_idle  %i=video_isoc_streaming\n",
-                               peasycap->video_idle, peasycap->video_isoc_streaming);
-               if (peasycap->video_isoc_streaming) {
-                       rc = usb_submit_urb(purb, GFP_ATOMIC);
-                       if (rc) {
-                               SAM("%s:%d ENOMEM\n", strerror(rc), rc);
-                               if (-ENODEV != rc)
-                                       SAM("ERROR: while %i=video_idle, "
-                                                               "usb_submit_urb() "
-                                                               "failed with rc:\n",
-                                                               peasycap->video_idle);
-                       }
-               }
-       return;
-       }
-       override = 0;
-/*---------------------------------------------------------------------------*/
-       if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
-               SAM("ERROR: bad peasycap->field_fill\n");
-               return;
-       }
-       if (purb->status) {
-               if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
-                       JOM(8, "urb status -ESHUTDOWN or -ENOENT\n");
-                       return;
-               }
-
-               (peasycap->field_buffer[peasycap->field_fill][0].kount) |= 0x8000 ;
-               SAM("ERROR: bad urb status -%s: %d\n",
-                               strerror(purb->status), purb->status);
-/*---------------------------------------------------------------------------*/
-       } else {
-               for (i = 0;  i < purb->number_of_packets; i++) {
-                       if (0 != purb->iso_frame_desc[i].status) {
-                               (peasycap->field_buffer
-                                       [peasycap->field_fill][0].kount) |= 0x8000 ;
-                               /* FIXME: 1. missing '-' check boundaries */
-                               strcpy(&errbuf[0],
-                                       strerror(purb->iso_frame_desc[i].status));
-                       }
-                       framestatus = purb->iso_frame_desc[i].status;
-                       framelength = purb->iso_frame_desc[i].length;
-                       frameactual = purb->iso_frame_desc[i].actual_length;
-                       frameoffset = purb->iso_frame_desc[i].offset;
-
-                       JOM(16, "frame[%2i]:"
-                                       "%4i=status "
-                                       "%4i=actual "
-                                       "%4i=length "
-                                       "%5i=offset\n",
-                               i, framestatus, frameactual, framelength, frameoffset);
-                       if (!purb->iso_frame_desc[i].status) {
-                               more = purb->iso_frame_desc[i].actual_length;
-                               pfield_buffer = &peasycap->field_buffer
-                                         [peasycap->field_fill][peasycap->field_page];
-                               videofieldamount = (peasycap->field_page *
-                                       PAGE_SIZE) +
-                                       (int)(pfield_buffer->pto - pfield_buffer->pgo);
-                       if (4 == more)
-                               peasycap->video_mt++;
-                       if (4 < more) {
-                               if (peasycap->video_mt) {
-                                       JOM(8, "%4i empty video urb frames\n",
-                                                               peasycap->video_mt);
-                                       peasycap->video_mt = 0;
-                               }
-                               if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
-                                       SAM("ERROR: bad peasycap->field_fill\n");
-                                       return;
-                               }
-                               if (FIELD_BUFFER_SIZE/PAGE_SIZE <=
-                                                               peasycap->field_page) {
-                                       SAM("ERROR: bad peasycap->field_page\n");
-                                       return;
-                               }
-                               pfield_buffer = &peasycap->field_buffer
-                                       [peasycap->field_fill][peasycap->field_page];
-                               pu = (u8 *)(purb->transfer_buffer +
-                                               purb->iso_frame_desc[i].offset);
-                               if (0x80 & *pu)
-                                       leap = 8;
-                               else
-                                       leap = 4;
-/*--------------------------------------------------------------------------*/
-/*
- *  EIGHT-BYTE END-OF-VIDEOFIELD MARKER.
- *  NOTE:  A SUCCESSION OF URB FRAMES FOLLOWING THIS ARE EMPTY,
- *         CORRESPONDING TO THE FIELD FLYBACK (VERTICAL BLANKING) PERIOD.
- *
- *  PROVIDED THE FIELD BUFFER CONTAINS GOOD DATA AS INDICATED BY A ZERO UPPER
- *  BYTE OF
- *        peasycap->field_buffer[peasycap->field_fill][0].kount
- *  THE CONTENTS OF THE FIELD BUFFER ARE OFFERED TO dqbuf(), field_read IS
- *  UPDATED AND field_fill IS BUMPED.  IF THE FIELD BUFFER CONTAINS BAD DATA
- *  NOTHING IS OFFERED TO dqbuf().
- *
- *  THE DECISION ON WHETHER THE PARITY OF THE OFFERED FIELD BUFFER IS RIGHT
- *  RESTS WITH dqbuf().
- */
-/*---------------------------------------------------------------------------*/
-                               if ((8 == more) || override) {
-                                       if (videofieldamount >
-                                                       peasycap->videofieldamount) {
-                                               if (2 == videofieldamount -
-                                                               peasycap->
-                                                               videofieldamount) {
-                                                       (peasycap->field_buffer
-                                                       [peasycap->field_fill]
-                                                               [0].kount) |= 0x0100;
-                                                       peasycap->video_junk += (1 +
-                                                               VIDEO_JUNK_TOLERATE);
-                                               } else
-                                                       (peasycap->field_buffer
-                                                       [peasycap->field_fill]
-                                                               [0].kount) |= 0x4000;
-                                               } else if (videofieldamount <
-                                                               peasycap->
-                                                               videofieldamount) {
-                                                       (peasycap->field_buffer
-                                                       [peasycap->field_fill]
-                                                               [0].kount) |= 0x2000;
-                                               }
-                                               bad = 0xFF00 & peasycap->field_buffer
-                                                       [peasycap->field_fill]
-                                                       [0].kount;
-                                               if (!bad) {
-                                                       (peasycap->video_junk)--;
-                                                       if (-VIDEO_JUNK_TOLERATE >
-                                                               peasycap->video_junk)
-                                                               peasycap->video_junk =
-                                                               -VIDEO_JUNK_TOLERATE;
-                                                       peasycap->field_read =
-                                                               (peasycap->
-                                                                       field_fill)++;
-                                                       if (FIELD_BUFFER_MANY <=
-                                                                       peasycap->
-                                                                       field_fill)
-                                                               peasycap->
-                                                                       field_fill = 0;
-                                                       peasycap->field_page = 0;
-                                                       pfield_buffer = &peasycap->
-                                                               field_buffer
-                                                               [peasycap->
-                                                               field_fill]
-                                                               [peasycap->
-                                                               field_page];
-                                                       pfield_buffer->pto =
-                                                               pfield_buffer->pgo;
-                                                       JOM(8, "bumped to: %i="
-                                                               "peasycap->"
-                                                               "field_fill  %i="
-                                                               "parity\n",
-                                                               peasycap->field_fill,
-                                                               0x00FF &
-                                                               pfield_buffer->kount);
-                                                       JOM(8, "field buffer %i has "
-                                                               "%i bytes fit to be "
-                                                               "read\n",
-                                                               peasycap->field_read,
-                                                               videofieldamount);
-                                                       JOM(8, "wakeup call to "
-                                                               "wq_video, "
-                                                               "%i=field_read "
-                                                               "%i=field_fill "
-                                                               "%i=parity\n",
-                                                               peasycap->field_read,
-                                                               peasycap->field_fill,
-                                                               0x00FF & peasycap->
-                                                               field_buffer
-                                                               [peasycap->
-                                                               field_read][0].kount);
-                                                       wake_up_interruptible
-                                                               (&(peasycap->
-                                                                        wq_video));
-                                               } else {
-                                               peasycap->video_junk++;
-                                               if (bad & 0x0010)
-                                                       peasycap->video_junk +=
-                                                       (1 + VIDEO_JUNK_TOLERATE/2);
-                                               JOM(8, "field buffer %i had %i "
-                                                       "bytes, now discarded: "
-                                                       "0x%04X\n",
-                                                       peasycap->field_fill,
-                                                       videofieldamount,
-                                                       (0xFF00 &
-                                                       peasycap->field_buffer
-                                                       [peasycap->field_fill][0].
-                                                       kount));
-                                               (peasycap->field_fill)++;
-
-                                               if (FIELD_BUFFER_MANY <=
-                                                               peasycap->field_fill)
-                                                       peasycap->field_fill = 0;
-                                               peasycap->field_page = 0;
-                                               pfield_buffer =
-                                                       &peasycap->field_buffer
-                                                       [peasycap->field_fill]
-                                                       [peasycap->field_page];
-                                               pfield_buffer->pto =
-                                                               pfield_buffer->pgo;
-
-                                               JOM(8, "bumped to: %i=peasycap->"
-                                                       "field_fill  %i=parity\n",
-                                                       peasycap->field_fill,
-                                                       0x00FF & pfield_buffer->kount);
-                                       }
-                                       if (8 == more) {
-                                               JOM(8, "end-of-field: received "
-                                                       "parity byte 0x%02X\n",
-                                                       (0xFF & *pu));
-                                               if (0x40 & *pu)
-                                                       pfield_buffer->kount = 0x0000;
-                                               else
-                                                       pfield_buffer->kount = 0x0001;
-                                               pfield_buffer->input = 0x08 |
-                                                       (0x07 & peasycap->input);
-                                               JOM(8, "end-of-field: 0x%02X=kount\n",
-                                                       0xFF & pfield_buffer->kount);
-                                       }
-                               }
-/*---------------------------------------------------------------------------*/
-/*
- *  COPY more BYTES FROM ISOC BUFFER TO FIELD BUFFER
- */
-/*---------------------------------------------------------------------------*/
-                               pu += leap;
-                               more -= leap;
-
-                               if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
-                                       SAM("ERROR: bad peasycap->field_fill\n");
-                                       return;
-                               }
-                               if (FIELD_BUFFER_SIZE/PAGE_SIZE <= peasycap->field_page) {
-                                       SAM("ERROR: bad peasycap->field_page\n");
-                                       return;
-                               }
-                               pfield_buffer = &peasycap->field_buffer
-                                       [peasycap->field_fill][peasycap->field_page];
-                               while (more) {
-                                       pfield_buffer = &peasycap->field_buffer
-                                                       [peasycap->field_fill]
-                                                       [peasycap->field_page];
-                                       if (PAGE_SIZE < (pfield_buffer->pto -
-                                                               pfield_buffer->pgo)) {
-                                               SAM("ERROR: bad pfield_buffer->pto\n");
-                                               return;
-                                       }
-                                       if (PAGE_SIZE == (pfield_buffer->pto -
-                                                               pfield_buffer->pgo)) {
-                                               (peasycap->field_page)++;
-                                               if (FIELD_BUFFER_SIZE/PAGE_SIZE <=
-                                                               peasycap->field_page) {
-                                                       JOM(16, "wrapping peasycap->"
-                                                               "field_page\n");
-                                                       peasycap->field_page = 0;
-                                               }
-                                               pfield_buffer = &peasycap->
-                                                               field_buffer
-                                                               [peasycap->field_fill]
-                                                               [peasycap->field_page];
-                                               pfield_buffer->pto = pfield_buffer->pgo;
-                                               pfield_buffer->input = 0x08 |
-                                                       (0x07 & peasycap->input);
-                                               if ((peasycap->field_buffer[peasycap->
-                                                               field_fill][0]).
-                                                                       input !=
-                                                               pfield_buffer->input)
-                                                       (peasycap->field_buffer
-                                                               [peasycap->field_fill]
-                                                               [0]).kount |= 0x1000;
-                                       }
-
-                                       much = PAGE_SIZE -
-                                               (int)(pfield_buffer->pto -
-                                                       pfield_buffer->pgo);
-
-                                       if (much > more)
-                                               much = more;
-                                       memcpy(pfield_buffer->pto, pu, much);
-                                       pu += much;
-                                       (pfield_buffer->pto) += much;
-                                       more -= much;
-                                       }
-                               }
-                       }
-               }
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  RESUBMIT THIS URB, UNLESS A SEVERE PERSISTENT ERROR CONDITION EXISTS.
- *
- *  IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO AN ERROR CONDITION
- *  THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT.   BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-       if (VIDEO_ISOC_BUFFER_MANY <= peasycap->video_junk) {
-               SAM("easycap driver shutting down on condition green\n");
-               peasycap->status = 1;
-               peasycap->video_eof = 1;
-               peasycap->video_junk = 0;
-               wake_up_interruptible(&peasycap->wq_video);
-#if !defined(PERSEVERE)
-               peasycap->audio_eof = 1;
-               wake_up_interruptible(&peasycap->wq_audio);
-#endif /*PERSEVERE*/
-               return;
-       }
-       if (peasycap->video_isoc_streaming) {
-               rc = usb_submit_urb(purb, GFP_ATOMIC);
-               if (rc) {
-                       SAM("%s: %d\n", strerror(rc), rc);
-                       if (-ENODEV != rc)
-                               SAM("ERROR: while %i=video_idle, "
-                                       "usb_submit_urb() "
-                                       "failed with rc:\n",
-                                       peasycap->video_idle);
-               }
-       }
-       return;
-}
-static const struct file_operations easycap_fops = {
-       .owner          = THIS_MODULE,
-       .open           = easycap_open,
-       .unlocked_ioctl = easycap_unlocked_ioctl,
-       .poll           = easycap_poll,
-       .mmap           = easycap_mmap,
-       .llseek         = no_llseek,
-};
-static const struct usb_class_driver easycap_class = {
-       .name = "usb/easycap%d",
-       .fops = &easycap_fops,
-       .minor_base = USB_SKEL_MINOR_BASE,
-};
-/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
-static const struct v4l2_file_operations v4l2_fops = {
-       .owner          = THIS_MODULE,
-       .open           = easycap_open_noinode,
-       .unlocked_ioctl = easycap_unlocked_ioctl,
-       .poll           = easycap_poll,
-       .mmap           = easycap_mmap,
-};
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  WHEN THE EasyCAP IS PHYSICALLY PLUGGED IN, THIS FUNCTION IS CALLED THREE
- *  TIMES, ONCE FOR EACH OF THE THREE INTERFACES.  BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-static int easycap_usb_probe(struct usb_interface *intf,
-                           const struct usb_device_id *id)
-{
-       struct usb_device *usbdev;
-       struct usb_host_interface *alt;
-       struct usb_endpoint_descriptor *ep;
-       struct usb_interface_descriptor *interface;
-       struct urb *purb;
-       struct easycap *peasycap;
-       int ndong;
-       struct data_urb *pdata_urb;
-       int i, j, k, m, rc;
-       u8 bInterfaceNumber;
-       u8 bInterfaceClass;
-       u8 bInterfaceSubClass;
-       void *pbuf;
-       int okalt[8], isokalt;
-       int okepn[8];
-       int okmps[8];
-       int maxpacketsize;
-       u16 mask;
-       s32 value;
-       struct easycap_format *peasycap_format;
-       int fmtidx;
-       struct inputset *inputset;
-
-       usbdev = interface_to_usbdev(intf);
-
-/*---------------------------------------------------------------------------*/
-       alt = usb_altnum_to_altsetting(intf, 0);
-       if (!alt) {
-               SAY("ERROR: usb_host_interface not found\n");
-               return -EFAULT;
-       }
-       interface = &alt->desc;
-       if (!interface) {
-               SAY("ERROR: intf_descriptor is NULL\n");
-               return -EFAULT;
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  GET PROPERTIES OF PROBED INTERFACE
- */
-/*---------------------------------------------------------------------------*/
-       bInterfaceNumber = interface->bInterfaceNumber;
-       bInterfaceClass = interface->bInterfaceClass;
-       bInterfaceSubClass = interface->bInterfaceSubClass;
-
-       JOT(4, "intf[%i]: num_altsetting=%i\n",
-                       bInterfaceNumber, intf->num_altsetting);
-       JOT(4, "intf[%i]: cur_altsetting - altsetting=%li\n",
-               bInterfaceNumber,
-               (long int)(intf->cur_altsetting - intf->altsetting));
-       JOT(4, "intf[%i]: bInterfaceClass=0x%02X bInterfaceSubClass=0x%02X\n",
-                       bInterfaceNumber, bInterfaceClass, bInterfaceSubClass);
-/*---------------------------------------------------------------------------*/
-/*
- *  A NEW struct easycap IS ALWAYS ALLOCATED WHEN INTERFACE 0 IS PROBED.
- *  IT IS NOT POSSIBLE HERE TO FREE ANY EXISTING struct easycap.  THIS
- *  SHOULD HAVE BEEN DONE BY easycap_delete() WHEN THE EasyCAP WAS
- *  PHYSICALLY UNPLUGGED.
- *
- *  THE POINTER peasycap TO THE struct easycap IS REMEMBERED WHEN
- *  INTERFACES 1 AND 2 ARE PROBED.
-*/
-/*---------------------------------------------------------------------------*/
-       if (0 == bInterfaceNumber) {
-               peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
-               if (!peasycap) {
-                       SAY("ERROR: Could not allocate peasycap\n");
-                       return -ENOMEM;
-               }
-/*---------------------------------------------------------------------------*/
-/*
- *  PERFORM URGENT INTIALIZATIONS ...
-*/
-/*---------------------------------------------------------------------------*/
-               peasycap->minor = -1;
-               kref_init(&peasycap->kref);
-               JOM(8, "intf[%i]: after kref_init(..._video) "
-                               "%i=peasycap->kref.refcount.counter\n",
-                               bInterfaceNumber, peasycap->kref.refcount.counter);
-
-               /* module params */
-               peasycap->gain = (s8)clamp(easycap_gain, 0, 31);
-
-               init_waitqueue_head(&peasycap->wq_video);
-               init_waitqueue_head(&peasycap->wq_audio);
-               init_waitqueue_head(&peasycap->wq_trigger);
-
-               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 ((!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, ndong);
-                                       break;
-                               }
-                       }
-                       if (DONGLE_MANY <= ndong) {
-                               SAM("ERROR: too many dongles\n");
-                               mutex_unlock(&mutex_dongle);
-                               return -ENOMEM;
-                       }
-                       mutex_unlock(&mutex_dongle);
-               }
-               peasycap->allocation_video_struct = sizeof(struct easycap);
-               peasycap->allocation_video_page = 0;
-               peasycap->allocation_video_urb = 0;
-               peasycap->allocation_audio_struct = 0;
-               peasycap->allocation_audio_page = 0;
-               peasycap->allocation_audio_urb = 0;
-
-/*---------------------------------------------------------------------------*/
-/*
- *  ... AND FURTHER INITIALIZE THE STRUCTURE
-*/
-/*---------------------------------------------------------------------------*/
-               peasycap->pusb_device = usbdev;
-               peasycap->pusb_interface = intf;
-
-               peasycap->ilk = 0;
-               peasycap->microphone = false;
-
-               peasycap->video_interface = -1;
-               peasycap->video_altsetting_on = -1;
-               peasycap->video_altsetting_off = -1;
-               peasycap->video_endpointnumber = -1;
-               peasycap->video_isoc_maxframesize = -1;
-               peasycap->video_isoc_buffer_size = -1;
-
-               peasycap->audio_interface = -1;
-               peasycap->audio_altsetting_on = -1;
-               peasycap->audio_altsetting_off = -1;
-               peasycap->audio_endpointnumber = -1;
-               peasycap->audio_isoc_maxframesize = -1;
-               peasycap->audio_isoc_buffer_size = -1;
-
-               peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
-
-               for (k = 0; k < INPUT_MANY; k++)
-                       peasycap->lost[k] = 0;
-               peasycap->skip = 0;
-               peasycap->skipped = 0;
-               peasycap->offerfields = 0;
-/*---------------------------------------------------------------------------*/
-/*
- *  DYNAMICALLY FILL IN THE AVAILABLE FORMATS ...
- */
-/*---------------------------------------------------------------------------*/
-               rc = fillin_formats();
-               if (0 > rc) {
-                       SAM("ERROR: fillin_formats() rc = %i\n", rc);
-                       return -EFAULT;
-               }
-               JOM(4, "%i formats available\n", rc);
-/*---------------------------------------------------------------------------*/
-/*
- *  ... AND POPULATE easycap.inputset[]
-*/
-/*---------------------------------------------------------------------------*/
-               /* FIXME: maybe we just use memset 0 */
-               inputset = peasycap->inputset;
-               for (k = 0; k < INPUT_MANY; k++) {
-                       inputset[k].input_ok = 0;
-                       inputset[k].standard_offset_ok = 0;
-                       inputset[k].format_offset_ok = 0;
-                       inputset[k].brightness_ok = 0;
-                       inputset[k].contrast_ok = 0;
-                       inputset[k].saturation_ok = 0;
-                       inputset[k].hue_ok = 0;
-               }
-
-               fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN;
-               m = 0;
-               mask = 0;
-               for (i = 0; 0xFFFF != easycap_standard[i].mask; i++) {
-                       if (fmtidx == easycap_standard[i].v4l2_standard.index) {
-                               m++;
-                               for (k = 0; k < INPUT_MANY; k++)
-                                       inputset[k].standard_offset = i;
-
-                               mask = easycap_standard[i].mask;
-                       }
-               }
-
-               if (1 != m) {
-                       SAM("ERROR: "
-                           "inputset->standard_offset unpopulated, %i=m\n", m);
-                       return -ENOENT;
-               }
-
-               peasycap_format = &easycap_format[0];
-               m = 0;
-               for (i = 0; peasycap_format->v4l2_format.fmt.pix.width; i++) {
-                       struct v4l2_pix_format *pix =
-                               &peasycap_format->v4l2_format.fmt.pix;
-                       if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) &&
-                           pix->field == V4L2_FIELD_NONE &&
-                           pix->pixelformat == V4L2_PIX_FMT_UYVY &&
-                           pix->width  == 640 && pix->height == 480) {
-                               m++;
-                               for (k = 0; k < INPUT_MANY; k++)
-                                       inputset[k].format_offset = i;
-                               break;
-                       }
-                       peasycap_format++;
-               }
-               if (1 != m) {
-                       SAM("ERROR: inputset[]->format_offset unpopulated\n");
-                       return -ENOENT;
-               }
-
-               m = 0;
-               for (i = 0; 0xFFFFFFFF != easycap_control[i].id; i++) {
-                       value = easycap_control[i].default_value;
-                       if (V4L2_CID_BRIGHTNESS == easycap_control[i].id) {
-                               m++;
-                               for (k = 0; k < INPUT_MANY; k++)
-                                       inputset[k].brightness = value;
-                       } else if (V4L2_CID_CONTRAST == easycap_control[i].id) {
-                               m++;
-                               for (k = 0; k < INPUT_MANY; k++)
-                                       inputset[k].contrast = value;
-                       } else if (V4L2_CID_SATURATION == easycap_control[i].id) {
-                               m++;
-                               for (k = 0; k < INPUT_MANY; k++)
-                                       inputset[k].saturation = value;
-                       } else if (V4L2_CID_HUE == easycap_control[i].id) {
-                               m++;
-                               for (k = 0; k < INPUT_MANY; k++)
-                                       inputset[k].hue = value;
-                       }
-               }
-
-               if (4 != m) {
-                       SAM("ERROR: inputset[]->brightness underpopulated\n");
-                       return -ENOENT;
-               }
-               for (k = 0; k < INPUT_MANY; k++)
-                       inputset[k].input = k;
-               JOM(4, "populated inputset[]\n");
-               JOM(4, "finished initialization\n");
-       } else {
-/*---------------------------------------------------------------------------*/
-/*
- *                                 FIXME
- *
- *  IDENTIFY THE APPROPRIATE POINTER peasycap FOR INTERFACES 1 AND 2.
- *  THE ADDRESS OF peasycap->pusb_device IS RELUCTANTLY USED FOR THIS PURPOSE.
- */
-/*---------------------------------------------------------------------------*/
-               for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
-                       if (usbdev == easycapdc60_dongle[ndong].peasycap->
-                                                                       pusb_device) {
-                               peasycap = easycapdc60_dongle[ndong].peasycap;
-                               JOT(8, "intf[%i]: dongle[%i].peasycap\n",
-                                               bInterfaceNumber, ndong);
-                               break;
-                       }
-               }
-               if (DONGLE_MANY <= ndong) {
-                       SAY("ERROR: peasycap is unknown when probing interface %i\n",
-                                                               bInterfaceNumber);
-                       return -ENODEV;
-               }
-               if (!peasycap) {
-                       SAY("ERROR: peasycap is NULL when probing interface %i\n",
-                                                               bInterfaceNumber);
-                       return -ENODEV;
-               }
-       }
-/*---------------------------------------------------------------------------*/
-       if ((USB_CLASS_VIDEO == bInterfaceClass) ||
-           (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
-               if (-1 == peasycap->video_interface) {
-                       peasycap->video_interface = bInterfaceNumber;
-                       JOM(4, "setting peasycap->video_interface=%i\n",
-                                                       peasycap->video_interface);
-               } else {
-                       if (peasycap->video_interface != bInterfaceNumber) {
-                               SAM("ERROR: attempting to reset "
-                                               "peasycap->video_interface\n");
-                               SAM("...... continuing with "
-                                               "%i=peasycap->video_interface\n",
-                                               peasycap->video_interface);
-                       }
-               }
-       } else if ((USB_CLASS_AUDIO == bInterfaceClass) &&
-                  (USB_SUBCLASS_AUDIOSTREAMING == bInterfaceSubClass)) {
-               if (-1 == peasycap->audio_interface) {
-                       peasycap->audio_interface = bInterfaceNumber;
-                       JOM(4, "setting peasycap->audio_interface=%i\n",
-                                                        peasycap->audio_interface);
-               } else {
-                       if (peasycap->audio_interface != bInterfaceNumber) {
-                               SAM("ERROR: attempting to reset "
-                                               "peasycap->audio_interface\n");
-                               SAM("...... continuing with "
-                                               "%i=peasycap->audio_interface\n",
-                                               peasycap->audio_interface);
-                       }
-               }
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  INVESTIGATE ALL ALTSETTINGS.
- *  DONE IN DETAIL BECAUSE USB DEVICE 05e1:0408 HAS DISPARATE INCARNATIONS.
- */
-/*---------------------------------------------------------------------------*/
-       isokalt = 0;
-
-       for (i = 0; i < intf->num_altsetting; i++) {
-               alt = usb_altnum_to_altsetting(intf, i);
-               if (!alt) {
-                       SAM("ERROR: alt is NULL\n");
-                       return -EFAULT;
-               }
-               interface = &alt->desc;
-               if (!interface) {
-                       SAM("ERROR: intf_descriptor is NULL\n");
-                       return -EFAULT;
-               }
-
-               if (0 == interface->bNumEndpoints)
-                       JOM(4, "intf[%i]alt[%i] has no endpoints\n",
-                                               bInterfaceNumber, i);
-/*---------------------------------------------------------------------------*/
-               for (j = 0; j < interface->bNumEndpoints; j++) {
-                       ep = &alt->endpoint[j].desc;
-                       if (!ep) {
-                               SAM("ERROR:  ep is NULL.\n");
-                               SAM("...... skipping\n");
-                               continue;
-                       }
-
-                       if (!usb_endpoint_is_isoc_in(ep)) {
-                               JOM(4, "intf[%i]alt[%i]end[%i] is a %d endpoint\n",
-                                               bInterfaceNumber,
-                                               i, j, ep->bmAttributes);
-                               if (usb_endpoint_dir_out(ep)) {
-                                       SAM("ERROR: OUT endpoint unexpected\n");
-                                       SAM("...... continuing\n");
-                               }
-                               continue;
-                       }
-                       switch (bInterfaceClass) {
-                       case USB_CLASS_VIDEO:
-                       case USB_CLASS_VENDOR_SPEC: {
-                               if (ep->wMaxPacketSize) {
-                                       if (8 > isokalt) {
-                                               okalt[isokalt] = i;
-                                               JOM(4,
-                                               "%i=okalt[%i]\n",
-                                               okalt[isokalt],
-                                               isokalt);
-                                               okepn[isokalt] =
-                                               ep->
-                                               bEndpointAddress &
-                                               0x0F;
-                                               JOM(4,
-                                               "%i=okepn[%i]\n",
-                                               okepn[isokalt],
-                                               isokalt);
-                                               okmps[isokalt] =
-                                               le16_to_cpu(ep->
-                                               wMaxPacketSize);
-                                               JOM(4,
-                                               "%i=okmps[%i]\n",
-                                               okmps[isokalt],
-                                               isokalt);
-                                               isokalt++;
-                                       }
-                               } else {
-                                       if (-1 == peasycap->
-                                               video_altsetting_off) {
-                                               peasycap->
-                                               video_altsetting_off =
-                                                                i;
-                                               JOM(4, "%i=video_"
-                                               "altsetting_off "
-                                                       "<====\n",
-                                               peasycap->
-                                               video_altsetting_off);
-                                       } else {
-                                               SAM("ERROR: peasycap"
-                                               "->video_altsetting_"
-                                               "off already set\n");
-                                               SAM("...... "
-                                               "continuing with "
-                                               "%i=peasycap->video_"
-                                               "altsetting_off\n",
-                                               peasycap->
-                                               video_altsetting_off);
-                                       }
-                               }
-                               break;
-                       }
-                       case USB_CLASS_AUDIO: {
-                               if (bInterfaceSubClass !=
-                                   USB_SUBCLASS_AUDIOSTREAMING)
-                                       break;
-                               if (!peasycap) {
-                                       SAM("MISTAKE: "
-                                       "peasycap is NULL\n");
-                                       return -EFAULT;
-                               }
-                               if (ep->wMaxPacketSize) {
-                                       if (8 > isokalt) {
-                                               okalt[isokalt] = i ;
-                                               JOM(4,
-                                               "%i=okalt[%i]\n",
-                                               okalt[isokalt],
-                                               isokalt);
-                                               okepn[isokalt] =
-                                               ep->
-                                               bEndpointAddress &
-                                               0x0F;
-                                               JOM(4,
-                                               "%i=okepn[%i]\n",
-                                               okepn[isokalt],
-                                               isokalt);
-                                               okmps[isokalt] =
-                                               le16_to_cpu(ep->
-                                               wMaxPacketSize);
-                                               JOM(4,
-                                               "%i=okmps[%i]\n",
-                                               okmps[isokalt],
-                                               isokalt);
-                                               isokalt++;
-                                       }
-                               } else {
-                                       if (-1 == peasycap->
-                                               audio_altsetting_off) {
-                                               peasycap->
-                                               audio_altsetting_off =
-                                                                i;
-                                               JOM(4, "%i=audio_"
-                                               "altsetting_off "
-                                               "<====\n",
-                                               peasycap->
-                                               audio_altsetting_off);
-                                       } else {
-                                               SAM("ERROR: peasycap"
-                                               "->audio_altsetting_"
-                                               "off already set\n");
-                                               SAM("...... "
-                                               "continuing with "
-                                               "%i=peasycap->"
-                                               "audio_altsetting_"
-                                               "off\n",
-                                               peasycap->
-                                               audio_altsetting_off);
-                                       }
-                               }
-                       break;
-                       }
-                       default:
-                               break;
-                       }
-                       if (0 == ep->wMaxPacketSize) {
-                               JOM(4, "intf[%i]alt[%i]end[%i] "
-                                                       "has zero packet size\n",
-                                                       bInterfaceNumber, i, j);
-                       }
-               }
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  PERFORM INITIALIZATION OF THE PROBED INTERFACE
- */
-/*---------------------------------------------------------------------------*/
-       JOM(4, "initialization begins for interface %i\n",
-               interface->bInterfaceNumber);
-       switch (bInterfaceNumber) {
-/*---------------------------------------------------------------------------*/
-/*
- *  INTERFACE 0 IS THE VIDEO INTERFACE
- */
-/*---------------------------------------------------------------------------*/
-       case 0: {
-               if (!peasycap) {
-                       SAM("MISTAKE: peasycap is NULL\n");
-                       return -EFAULT;
-               }
-               if (!isokalt) {
-                       SAM("ERROR:  no viable video_altsetting_on\n");
-                       return -ENOENT;
-               } else {
-                       peasycap->video_altsetting_on = okalt[isokalt - 1];
-                       JOM(4, "%i=video_altsetting_on <====\n",
-                                               peasycap->video_altsetting_on);
-               }
-/*---------------------------------------------------------------------------*/
-/*
- *  DECIDE THE VIDEO STREAMING PARAMETERS
- */
-/*---------------------------------------------------------------------------*/
-               peasycap->video_endpointnumber = okepn[isokalt - 1];
-               JOM(4, "%i=video_endpointnumber\n", peasycap->video_endpointnumber);
-               maxpacketsize = okmps[isokalt - 1];
-
-               peasycap->video_isoc_maxframesize =
-                               min(maxpacketsize, USB_2_0_MAXPACKETSIZE);
-               if (0 >= peasycap->video_isoc_maxframesize) {
-                       SAM("ERROR:  bad video_isoc_maxframesize\n");
-                       SAM("        possibly because port is USB 1.1\n");
-                       return -ENOENT;
-               }
-               JOM(4, "%i=video_isoc_maxframesize\n",
-                                       peasycap->video_isoc_maxframesize);
-
-               peasycap->video_isoc_framesperdesc = VIDEO_ISOC_FRAMESPERDESC;
-               JOM(4, "%i=video_isoc_framesperdesc\n",
-                                       peasycap->video_isoc_framesperdesc);
-               if (0 >= peasycap->video_isoc_framesperdesc) {
-                       SAM("ERROR:  bad video_isoc_framesperdesc\n");
-                       return -ENOENT;
-               }
-               peasycap->video_isoc_buffer_size =
-                                       peasycap->video_isoc_maxframesize *
-                                       peasycap->video_isoc_framesperdesc;
-               JOM(4, "%i=video_isoc_buffer_size\n",
-                                       peasycap->video_isoc_buffer_size);
-               if ((PAGE_SIZE << VIDEO_ISOC_ORDER) <
-                                       peasycap->video_isoc_buffer_size) {
-                       SAM("MISTAKE: peasycap->video_isoc_buffer_size too big\n");
-                       return -EFAULT;
-               }
-/*---------------------------------------------------------------------------*/
-               if (-1 == peasycap->video_interface) {
-                       SAM("MISTAKE:  video_interface is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->video_altsetting_on) {
-                       SAM("MISTAKE:  video_altsetting_on is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->video_altsetting_off) {
-                       SAM("MISTAKE:  video_interface_off is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->video_endpointnumber) {
-                       SAM("MISTAKE:  video_endpointnumber is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->video_isoc_maxframesize) {
-                       SAM("MISTAKE:  video_isoc_maxframesize is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->video_isoc_buffer_size) {
-                       SAM("MISTAKE:  video_isoc_buffer_size is unset\n");
-                       return -EFAULT;
-               }
-/*---------------------------------------------------------------------------*/
-/*
- *  ALLOCATE MEMORY FOR VIDEO BUFFERS.  LISTS MUST BE INITIALIZED FIRST.
- */
-/*---------------------------------------------------------------------------*/
-               INIT_LIST_HEAD(&(peasycap->urb_video_head));
-               peasycap->purb_video_head = &(peasycap->urb_video_head);
-/*---------------------------------------------------------------------------*/
-               JOM(4, "allocating %i frame buffers of size %li\n",
-                               FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
-               JOM(4, ".... each scattered over %li pages\n",
-                                                       FRAME_BUFFER_SIZE/PAGE_SIZE);
-
-               for (k = 0;  k < FRAME_BUFFER_MANY;  k++) {
-                       for (m = 0;  m < FRAME_BUFFER_SIZE/PAGE_SIZE;  m++) {
-                               if (peasycap->frame_buffer[k][m].pgo)
-                                       SAM("attempting to reallocate frame "
-                                                                       " buffers\n");
-                               else {
-                                       pbuf = (void *)__get_free_page(GFP_KERNEL);
-                                       if (!pbuf) {
-                                               SAM("ERROR: Could not allocate frame "
-                                                       "buffer %i page %i\n", k, m);
-                                               return -ENOMEM;
-                                       } else
-                                               peasycap->allocation_video_page += 1;
-                                       peasycap->frame_buffer[k][m].pgo = pbuf;
-                               }
-                               peasycap->frame_buffer[k][m].pto =
-                                               peasycap->frame_buffer[k][m].pgo;
-                       }
-               }
-
-               peasycap->frame_fill = 0;
-               peasycap->frame_read = 0;
-               JOM(4, "allocation of frame buffers done:  %i pages\n", k *
-                                                                       m);
-/*---------------------------------------------------------------------------*/
-               JOM(4, "allocating %i field buffers of size %li\n",
-                               FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
-               JOM(4, ".... each scattered over %li pages\n",
-                                               FIELD_BUFFER_SIZE/PAGE_SIZE);
-
-               for (k = 0;  k < FIELD_BUFFER_MANY;  k++) {
-                       for (m = 0;  m < FIELD_BUFFER_SIZE/PAGE_SIZE;  m++) {
-                               if (peasycap->field_buffer[k][m].pgo) {
-                                       SAM("ERROR: attempting to reallocate "
-                                                               "field buffers\n");
-                               } else {
-                                       pbuf = (void *) __get_free_page(GFP_KERNEL);
-                                       if (!pbuf) {
-                                               SAM("ERROR: Could not allocate field"
-                                                       " buffer %i page %i\n", k, m);
-                                               return -ENOMEM;
-                                               }
-                                       else
-                                               peasycap->allocation_video_page += 1;
-                                       peasycap->field_buffer[k][m].pgo = pbuf;
-                                       }
-                               peasycap->field_buffer[k][m].pto =
-                                               peasycap->field_buffer[k][m].pgo;
-                       }
-                       peasycap->field_buffer[k][0].kount = 0x0200;
-               }
-               peasycap->field_fill = 0;
-               peasycap->field_page = 0;
-               peasycap->field_read = 0;
-               JOM(4, "allocation of field buffers done:  %i pages\n", k *
-                                                                       m);
-/*---------------------------------------------------------------------------*/
-               JOM(4, "allocating %i isoc video buffers of size %i\n",
-                                               VIDEO_ISOC_BUFFER_MANY,
-                                               peasycap->video_isoc_buffer_size);
-               JOM(4, ".... each occupying contiguous memory pages\n");
-
-               for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY; k++) {
-                       pbuf = (void *)__get_free_pages(GFP_KERNEL,
-                                                       VIDEO_ISOC_ORDER);
-                       if (!pbuf) {
-                               SAM("ERROR: Could not allocate isoc video buffer "
-                                                                       "%i\n", k);
-                               return -ENOMEM;
-                       } else
-                               peasycap->allocation_video_page +=
-                                       BIT(VIDEO_ISOC_ORDER);
-
-                       peasycap->video_isoc_buffer[k].pgo = pbuf;
-                       peasycap->video_isoc_buffer[k].pto =
-                               pbuf + peasycap->video_isoc_buffer_size;
-                       peasycap->video_isoc_buffer[k].kount = k;
-               }
-               JOM(4, "allocation of isoc video buffers done: %i pages\n",
-                                               k * (0x01 << VIDEO_ISOC_ORDER));
-/*---------------------------------------------------------------------------*/
-/*
- *  ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
- */
-/*---------------------------------------------------------------------------*/
-               JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
-               JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n",
-                                               peasycap->video_isoc_framesperdesc);
-               JOM(4, "using %i=peasycap->video_isoc_maxframesize\n",
-                                               peasycap->video_isoc_maxframesize);
-               JOM(4, "using %i=peasycap->video_isoc_buffer_sizen",
-                                               peasycap->video_isoc_buffer_size);
-
-               for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY; k++) {
-                       purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc,
-                                                                       GFP_KERNEL);
-                       if (!purb) {
-                               SAM("ERROR: usb_alloc_urb returned NULL for buffer "
-                                                                       "%i\n", k);
-                               return -ENOMEM;
-                       } else
-                               peasycap->allocation_video_urb += 1;
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-                       pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
-                       if (!pdata_urb) {
-                               SAM("ERROR: Could not allocate struct data_urb.\n");
-                               return -ENOMEM;
-                       } else
-                               peasycap->allocation_video_struct +=
-                                                       sizeof(struct data_urb);
-
-                       pdata_urb->purb = purb;
-                       pdata_urb->isbuf = k;
-                       pdata_urb->length = 0;
-                       list_add_tail(&(pdata_urb->list_head),
-                                                       peasycap->purb_video_head);
-/*---------------------------------------------------------------------------*/
-/*
- *  ... AND INITIALIZE THEM
- */
-/*---------------------------------------------------------------------------*/
-                       if (!k) {
-                               JOM(4, "initializing video urbs thus:\n");
-                               JOM(4, "  purb->interval = 1;\n");
-                               JOM(4, "  purb->dev = peasycap->pusb_device;\n");
-                               JOM(4, "  purb->pipe = usb_rcvisocpipe"
-                                               "(peasycap->pusb_device,%i);\n",
-                                               peasycap->video_endpointnumber);
-                               JOM(4, "  purb->transfer_flags = URB_ISO_ASAP;\n");
-                               JOM(4, "  purb->transfer_buffer = peasycap->"
-                                               "video_isoc_buffer[.].pgo;\n");
-                               JOM(4, "  purb->transfer_buffer_length = %i;\n",
-                                               peasycap->video_isoc_buffer_size);
-                               JOM(4, "  purb->complete = easycap_complete;\n");
-                               JOM(4, "  purb->context = peasycap;\n");
-                               JOM(4, "  purb->start_frame = 0;\n");
-                               JOM(4, "  purb->number_of_packets = %i;\n",
-                                               peasycap->video_isoc_framesperdesc);
-                               JOM(4, "  for (j = 0; j < %i; j++)\n",
-                                               peasycap->video_isoc_framesperdesc);
-                               JOM(4, "    {\n");
-                               JOM(4, "    purb->iso_frame_desc[j].offset = j*%i;\n",
-                                               peasycap->video_isoc_maxframesize);
-                               JOM(4, "    purb->iso_frame_desc[j].length = %i;\n",
-                                               peasycap->video_isoc_maxframesize);
-                               JOM(4, "    }\n");
-                       }
-
-                       purb->interval = 1;
-                       purb->dev = peasycap->pusb_device;
-                       purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
-                                               peasycap->video_endpointnumber);
-                       purb->transfer_flags = URB_ISO_ASAP;
-                       purb->transfer_buffer = peasycap->video_isoc_buffer[k].pgo;
-                       purb->transfer_buffer_length =
-                                               peasycap->video_isoc_buffer_size;
-                       purb->complete = easycap_complete;
-                       purb->context = peasycap;
-                       purb->start_frame = 0;
-                       purb->number_of_packets = peasycap->video_isoc_framesperdesc;
-                       for (j = 0;  j < peasycap->video_isoc_framesperdesc; j++) {
-                               purb->iso_frame_desc[j].offset = j *
-                                               peasycap->video_isoc_maxframesize;
-                               purb->iso_frame_desc[j].length =
-                                               peasycap->video_isoc_maxframesize;
-                       }
-               }
-               JOM(4, "allocation of %i struct urb done.\n", k);
-/*--------------------------------------------------------------------------*/
-/*
- *  SAVE POINTER peasycap IN THIS INTERFACE.
- */
-/*--------------------------------------------------------------------------*/
-               usb_set_intfdata(intf, peasycap);
-/*---------------------------------------------------------------------------*/
-/*
- *  IT IS ESSENTIAL TO INITIALIZE THE HARDWARE BEFORE, RATHER THAN AFTER,
- *  THE DEVICE IS REGISTERED, BECAUSE SOME VERSIONS OF THE videodev MODULE
- *  CALL easycap_open() IMMEDIATELY AFTER REGISTRATION, CAUSING A CLASH.
- *  BEWARE.
-*/
-/*---------------------------------------------------------------------------*/
-               peasycap->ntsc = easycap_ntsc;
-               JOM(8, "defaulting initially to %s\n",
-                       easycap_ntsc ? "NTSC" : "PAL");
-               rc = reset(peasycap);
-               if (rc) {
-                       SAM("ERROR: reset() rc = %i\n", rc);
-                       return -EFAULT;
-               }
-/*--------------------------------------------------------------------------*/
-/*
- *  THE VIDEO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
- */
-/*--------------------------------------------------------------------------*/
-               if (v4l2_device_register(&intf->dev, &peasycap->v4l2_device)) {
-                       SAM("v4l2_device_register() failed\n");
-                       return -ENODEV;
-               }
-               JOM(4, "registered device instance: %s\n",
-                       peasycap->v4l2_device.name);
-/*---------------------------------------------------------------------------*/
-/*
- *                                 FIXME
- *
- *
- *  THIS IS BELIEVED TO BE HARMLESS, BUT MAY WELL BE UNNECESSARY OR WRONG:
-*/
-/*---------------------------------------------------------------------------*/
-               peasycap->video_device.v4l2_dev = NULL;
-/*---------------------------------------------------------------------------*/
-
-
-               strcpy(&peasycap->video_device.name[0], "easycapdc60");
-               peasycap->video_device.fops = &v4l2_fops;
-               peasycap->video_device.minor = -1;
-               peasycap->video_device.release = (void *)(&videodev_release);
-
-               video_set_drvdata(&(peasycap->video_device), (void *)peasycap);
-
-               if (0 != (video_register_device(&(peasycap->video_device),
-                                                       VFL_TYPE_GRABBER, -1))) {
-                       err("Not able to register with videodev");
-                       videodev_release(&(peasycap->video_device));
-                       return -ENODEV;
-               } else {
-                       (peasycap->registered_video)++;
-                       SAM("registered with videodev: %i=minor\n",
-                                                       peasycap->video_device.minor);
-                       peasycap->minor = peasycap->video_device.minor;
-               }
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-
-               break;
-       }
-/*--------------------------------------------------------------------------*/
-/*
- *  INTERFACE 1 IS THE AUDIO CONTROL INTERFACE
- *  INTERFACE 2 IS THE AUDIO STREAMING INTERFACE
- */
-/*--------------------------------------------------------------------------*/
-       case 1: {
-               if (!peasycap) {
-                       SAM("MISTAKE: peasycap is NULL\n");
-                       return -EFAULT;
-               }
-/*--------------------------------------------------------------------------*/
-/*
- *  SAVE POINTER peasycap IN INTERFACE 1
- */
-/*--------------------------------------------------------------------------*/
-               usb_set_intfdata(intf, peasycap);
-               JOM(4, "no initialization required for interface %i\n",
-                                       interface->bInterfaceNumber);
-               break;
-       }
-/*--------------------------------------------------------------------------*/
-       case 2: {
-               if (!peasycap) {
-                       SAM("MISTAKE: peasycap is NULL\n");
-                       return -EFAULT;
-               }
-               if (!isokalt) {
-                       SAM("ERROR:  no viable audio_altsetting_on\n");
-                       return -ENOENT;
-               } else {
-                       peasycap->audio_altsetting_on = okalt[isokalt - 1];
-                       JOM(4, "%i=audio_altsetting_on <====\n",
-                                                       peasycap->audio_altsetting_on);
-               }
-
-               peasycap->audio_endpointnumber = okepn[isokalt - 1];
-               JOM(4, "%i=audio_endpointnumber\n", peasycap->audio_endpointnumber);
-
-               peasycap->audio_isoc_maxframesize = okmps[isokalt - 1];
-               JOM(4, "%i=audio_isoc_maxframesize\n",
-                                               peasycap->audio_isoc_maxframesize);
-               if (0 >= peasycap->audio_isoc_maxframesize) {
-                       SAM("ERROR:  bad audio_isoc_maxframesize\n");
-                       return -ENOENT;
-               }
-               if (9 == peasycap->audio_isoc_maxframesize) {
-                       peasycap->ilk |= 0x02;
-                       SAM("audio hardware is microphone\n");
-                       peasycap->microphone = true;
-                       peasycap->audio_pages_per_fragment =
-                                       PAGES_PER_AUDIO_FRAGMENT;
-               } else if (256 == peasycap->audio_isoc_maxframesize) {
-                       peasycap->ilk &= ~0x02;
-                       SAM("audio hardware is AC'97\n");
-                       peasycap->microphone = false;
-                       peasycap->audio_pages_per_fragment =
-                                       PAGES_PER_AUDIO_FRAGMENT;
-               } else {
-                       SAM("hardware is unidentified:\n");
-                       SAM("%i=audio_isoc_maxframesize\n",
-                               peasycap->audio_isoc_maxframesize);
-                       return -ENOENT;
-               }
-
-               peasycap->audio_bytes_per_fragment =
-                               peasycap->audio_pages_per_fragment * PAGE_SIZE;
-               peasycap->audio_buffer_page_many = (AUDIO_FRAGMENT_MANY *
-                               peasycap->audio_pages_per_fragment);
-
-               JOM(4, "%6i=AUDIO_FRAGMENT_MANY\n", AUDIO_FRAGMENT_MANY);
-               JOM(4, "%6i=audio_pages_per_fragment\n",
-                                               peasycap->audio_pages_per_fragment);
-               JOM(4, "%6i=audio_bytes_per_fragment\n",
-                                               peasycap->audio_bytes_per_fragment);
-               JOM(4, "%6i=audio_buffer_page_many\n",
-                                               peasycap->audio_buffer_page_many);
-
-               peasycap->audio_isoc_framesperdesc = AUDIO_ISOC_FRAMESPERDESC;
-
-               JOM(4, "%i=audio_isoc_framesperdesc\n",
-                                               peasycap->audio_isoc_framesperdesc);
-               if (0 >= peasycap->audio_isoc_framesperdesc) {
-                       SAM("ERROR:  bad audio_isoc_framesperdesc\n");
-                       return -ENOENT;
-               }
-
-               peasycap->audio_isoc_buffer_size =
-                                       peasycap->audio_isoc_maxframesize *
-                                       peasycap->audio_isoc_framesperdesc;
-               JOM(4, "%i=audio_isoc_buffer_size\n",
-                                               peasycap->audio_isoc_buffer_size);
-               if (AUDIO_ISOC_BUFFER_SIZE < peasycap->audio_isoc_buffer_size) {
-                               SAM("MISTAKE:  audio_isoc_buffer_size bigger "
-                               "than %li=AUDIO_ISOC_BUFFER_SIZE\n",
-                                                       AUDIO_ISOC_BUFFER_SIZE);
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->audio_interface) {
-                       SAM("MISTAKE:  audio_interface is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->audio_altsetting_on) {
-                       SAM("MISTAKE:  audio_altsetting_on is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->audio_altsetting_off) {
-                       SAM("MISTAKE:  audio_interface_off is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->audio_endpointnumber) {
-                       SAM("MISTAKE:  audio_endpointnumber is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->audio_isoc_maxframesize) {
-                       SAM("MISTAKE:  audio_isoc_maxframesize is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->audio_isoc_buffer_size) {
-                       SAM("MISTAKE:  audio_isoc_buffer_size is unset\n");
-                       return -EFAULT;
-               }
-/*---------------------------------------------------------------------------*/
-/*
- *  ALLOCATE MEMORY FOR AUDIO BUFFERS.  LISTS MUST BE INITIALIZED FIRST.
- */
-/*---------------------------------------------------------------------------*/
-               INIT_LIST_HEAD(&(peasycap->urb_audio_head));
-               peasycap->purb_audio_head = &(peasycap->urb_audio_head);
-
-/*---------------------------------------------------------------------------*/
-               JOM(4, "allocating %i isoc audio buffers of size %i\n",
-                       AUDIO_ISOC_BUFFER_MANY,
-                       peasycap->audio_isoc_buffer_size);
-               JOM(4, ".... each occupying contiguous memory pages\n");
-
-               for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY;  k++) {
-                       pbuf = (void *)__get_free_pages(GFP_KERNEL,
-                                                       AUDIO_ISOC_ORDER);
-                       if (!pbuf) {
-                               SAM("ERROR: Could not allocate isoc audio buffer "
-                                                               "%i\n", k);
-                               return -ENOMEM;
-                       } else
-                               peasycap->allocation_audio_page +=
-                                               BIT(AUDIO_ISOC_ORDER);
-
-                       peasycap->audio_isoc_buffer[k].pgo = pbuf;
-                       peasycap->audio_isoc_buffer[k].pto = pbuf +
-                       peasycap->audio_isoc_buffer_size;
-                       peasycap->audio_isoc_buffer[k].kount = k;
-               }
-               JOM(4, "allocation of isoc audio buffers done.\n");
-/*---------------------------------------------------------------------------*/
-/*
- *  ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
- */
-/*---------------------------------------------------------------------------*/
-               JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
-               JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n",
-                                       peasycap->audio_isoc_framesperdesc);
-               JOM(4, "using %i=peasycap->audio_isoc_maxframesize\n",
-                                       peasycap->audio_isoc_maxframesize);
-               JOM(4, "using %i=peasycap->audio_isoc_buffer_size\n",
-                                       peasycap->audio_isoc_buffer_size);
-
-               for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY; k++) {
-                       purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc,
-                                                               GFP_KERNEL);
-                       if (!purb) {
-                               SAM("ERROR: usb_alloc_urb returned NULL for buffer "
-                                                               "%i\n", k);
-                               return -ENOMEM;
-                       }
-                       peasycap->allocation_audio_urb += 1 ;
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-                       pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
-                       if (!pdata_urb) {
-                               SAM("ERROR: Could not allocate struct data_urb.\n");
-                               return -ENOMEM;
-                       }
-                       peasycap->allocation_audio_struct +=
-                                               sizeof(struct data_urb);
-
-                       pdata_urb->purb = purb;
-                       pdata_urb->isbuf = k;
-                       pdata_urb->length = 0;
-                       list_add_tail(&(pdata_urb->list_head),
-                                                       peasycap->purb_audio_head);
-/*---------------------------------------------------------------------------*/
-/*
- *  ... AND INITIALIZE THEM
- */
-/*---------------------------------------------------------------------------*/
-                       if (!k) {
-                               JOM(4, "initializing audio urbs thus:\n");
-                               JOM(4, "  purb->interval = 1;\n");
-                               JOM(4, "  purb->dev = peasycap->pusb_device;\n");
-                               JOM(4, "  purb->pipe = usb_rcvisocpipe(peasycap->"
-                                               "pusb_device,%i);\n",
-                                               peasycap->audio_endpointnumber);
-                               JOM(4, "  purb->transfer_flags = URB_ISO_ASAP;\n");
-                               JOM(4, "  purb->transfer_buffer = "
-                                       "peasycap->audio_isoc_buffer[.].pgo;\n");
-                               JOM(4, "  purb->transfer_buffer_length = %i;\n",
-                                       peasycap->audio_isoc_buffer_size);
-                               JOM(4, "  purb->complete = easycap_alsa_complete;\n");
-                               JOM(4, "  purb->context = peasycap;\n");
-                               JOM(4, "  purb->start_frame = 0;\n");
-                               JOM(4, "  purb->number_of_packets = %i;\n",
-                                               peasycap->audio_isoc_framesperdesc);
-                               JOM(4, "  for (j = 0; j < %i; j++)\n",
-                                               peasycap->audio_isoc_framesperdesc);
-                               JOM(4, "    {\n");
-                               JOM(4, "    purb->iso_frame_desc[j].offset = j*%i;\n",
-                                       peasycap->audio_isoc_maxframesize);
-                               JOM(4, "    purb->iso_frame_desc[j].length = %i;\n",
-                                       peasycap->audio_isoc_maxframesize);
-                               JOM(4, "    }\n");
-                       }
-
-                       purb->interval = 1;
-                       purb->dev = peasycap->pusb_device;
-                       purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
-                                               peasycap->audio_endpointnumber);
-                       purb->transfer_flags = URB_ISO_ASAP;
-                       purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
-                       purb->transfer_buffer_length =
-                                               peasycap->audio_isoc_buffer_size;
-                       purb->complete = easycap_alsa_complete;
-                       purb->context = peasycap;
-                       purb->start_frame = 0;
-                       purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
-                       for (j = 0;  j < peasycap->audio_isoc_framesperdesc; j++) {
-                               purb->iso_frame_desc[j].offset = j *
-                                               peasycap->audio_isoc_maxframesize;
-                               purb->iso_frame_desc[j].length =
-                                               peasycap->audio_isoc_maxframesize;
-                       }
-               }
-               JOM(4, "allocation of %i struct urb done.\n", k);
-/*---------------------------------------------------------------------------*/
-/*
- *  SAVE POINTER peasycap IN THIS INTERFACE.
- */
-/*---------------------------------------------------------------------------*/
-               usb_set_intfdata(intf, peasycap);
-/*---------------------------------------------------------------------------*/
-/*
- *  THE AUDIO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
- */
-/*---------------------------------------------------------------------------*/
-               JOM(4, "initializing ALSA card\n");
-
-               rc = easycap_alsa_probe(peasycap);
-               if (rc) {
-                       err("easycap_alsa_probe() rc = %i\n", rc);
-                       return -ENODEV;
-               }
-
-
-               JOM(8, "kref_get() with %i=kref.refcount.counter\n",
-                               peasycap->kref.refcount.counter);
-               kref_get(&peasycap->kref);
-               peasycap->registered_audio++;
-               break;
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  INTERFACES OTHER THAN 0, 1 AND 2 ARE UNEXPECTED
- */
-/*---------------------------------------------------------------------------*/
-       default:
-               JOM(4, "ERROR: unexpected interface %i\n", bInterfaceNumber);
-               return -EINVAL;
-       }
-       SAM("ends successfully for interface %i\n", bInterfaceNumber);
-       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 ALSA.  BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
-{
-       struct usb_host_interface *pusb_host_interface;
-       struct usb_interface_descriptor *pusb_interface_descriptor;
-       u8 bInterfaceNumber;
-       struct easycap *peasycap;
-
-       struct list_head *plist_head;
-       struct data_urb *pdata_urb;
-       int minor, m, kd;
-
-       JOT(4, "\n");
-
-       pusb_host_interface = pusb_interface->cur_altsetting;
-       if (!pusb_host_interface) {
-               JOT(4, "ERROR: pusb_host_interface is NULL\n");
-               return;
-       }
-       pusb_interface_descriptor = &(pusb_host_interface->desc);
-       if (!pusb_interface_descriptor) {
-               JOT(4, "ERROR: pusb_interface_descriptor is NULL\n");
-               return;
-       }
-       bInterfaceNumber = pusb_interface_descriptor->bInterfaceNumber;
-       minor = pusb_interface->minor;
-       JOT(4, "intf[%i]: minor=%i\n", bInterfaceNumber, minor);
-
-       if (1 == bInterfaceNumber)
-               return;
-
-       peasycap = usb_get_intfdata(pusb_interface);
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return;
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  IF THE WAIT QUEUES ARE NOT CLEARED A DEADLOCK IS POSSIBLE.  BEWARE.
-*/
-/*---------------------------------------------------------------------------*/
-       peasycap->video_eof = 1;
-       peasycap->audio_eof = 1;
-       wake_up_interruptible(&(peasycap->wq_video));
-       wake_up_interruptible(&(peasycap->wq_audio));
-/*---------------------------------------------------------------------------*/
-       switch (bInterfaceNumber) {
-       case 0: {
-               if (peasycap->purb_video_head) {
-                       JOM(4, "killing video urbs\n");
-                       m = 0;
-                       list_for_each(plist_head, peasycap->purb_video_head) {
-                               pdata_urb = list_entry(plist_head,
-                                               struct data_urb, list_head);
-                               if (pdata_urb) {
-                                       if (pdata_urb->purb) {
-                                               usb_kill_urb(pdata_urb->purb);
-                                               m++;
-                                       }
-                               }
-                       }
-                       JOM(4, "%i video urbs killed\n", m);
-               }
-               break;
-       }
-/*---------------------------------------------------------------------------*/
-       case 2: {
-               if (peasycap->purb_audio_head) {
-                       JOM(4, "killing audio urbs\n");
-                       m = 0;
-                       list_for_each(plist_head, peasycap->purb_audio_head) {
-                               pdata_urb = list_entry(plist_head,
-                                               struct data_urb, list_head);
-                               if (pdata_urb) {
-                                       if (pdata_urb->purb) {
-                                               usb_kill_urb(pdata_urb->purb);
-                                               m++;
-                                       }
-                               }
-                       }
-                       JOM(4, "%i audio urbs killed\n", m);
-               }
-               break;
-       }
-       default:
-               break;
-       }
-/*--------------------------------------------------------------------------*/
-/*
- *  DEREGISTER
- *
- *  THIS PROCEDURE WILL BLOCK UNTIL easycap_poll(), VIDEO IOCTL AND AUDIO
- *  IOCTL ARE ALL UNLOCKED.  IF THIS IS NOT DONE AN Oops CAN OCCUR WHEN
- *  AN EasyCAP IS UNPLUGGED WHILE THE URBS ARE RUNNING.  BEWARE.
- */
-/*--------------------------------------------------------------------------*/
-       kd = isdongle(peasycap);
-       switch (bInterfaceNumber) {
-       case 0: {
-               if (0 <= kd && DONGLE_MANY > kd) {
-                       wake_up_interruptible(&peasycap->wq_video);
-                       JOM(4, "about to lock dongle[%i].mutex_video\n", kd);
-                       if (mutex_lock_interruptible(&easycapdc60_dongle[kd].
-                                                               mutex_video)) {
-                               SAY("ERROR: "
-                                   "cannot lock dongle[%i].mutex_video\n", kd);
-                               return;
-                       }
-                       JOM(4, "locked dongle[%i].mutex_video\n", kd);
-               } else {
-                       SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
-               }
-/*---------------------------------------------------------------------------*/
-               if (!peasycap->v4l2_device.name[0]) {
-                       SAM("ERROR: peasycap->v4l2_device.name is empty\n");
-                       if (0 <= kd && DONGLE_MANY > kd)
-                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return;
-               }
-               v4l2_device_disconnect(&peasycap->v4l2_device);
-               JOM(4, "v4l2_device_disconnect() OK\n");
-               v4l2_device_unregister(&peasycap->v4l2_device);
-               JOM(4, "v4l2_device_unregister() OK\n");
-
-               video_unregister_device(&peasycap->video_device);
-               JOM(4, "intf[%i]: video_unregister_device() minor=%i\n",
-                               bInterfaceNumber, minor);
-               peasycap->registered_video--;
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-
-               if (0 <= kd && DONGLE_MANY > kd) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       JOM(4, "unlocked 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 dongle[%i].mutex_audio\n", kd);
-                       if (mutex_lock_interruptible(&easycapdc60_dongle[kd].
-                                                               mutex_audio)) {
-                               SAY("ERROR: "
-                                   "cannot lock dongle[%i].mutex_audio\n", kd);
-                               return;
-                       }
-                       JOM(4, "locked dongle[%i].mutex_audio\n", kd);
-               } else
-                       SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
-               if (0 != snd_card_free(peasycap->psnd_card)) {
-                       SAY("ERROR: snd_card_free() failed\n");
-               } else {
-                       peasycap->psnd_card = NULL;
-                       (peasycap->registered_audio)--;
-               }
-               if (0 <= kd && DONGLE_MANY > kd) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
-                       JOM(4, "unlocked dongle[%i].mutex_audio\n", kd);
-               }
-               break;
-       }
-       default:
-               break;
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap
- *  (ALSO WHEN ALSA HAS BEEN IN USE)
- */
-/*---------------------------------------------------------------------------*/
-       if (!peasycap->kref.refcount.counter) {
-               SAM("ERROR: peasycap->kref.refcount.counter is zero "
-                                                       "so cannot call kref_put()\n");
-               SAM("ending unsuccessfully: may cause memory leak\n");
-               return;
-       }
-       if (0 <= kd && DONGLE_MANY > kd) {
-               JOM(4, "about to lock dongle[%i].mutex_video\n", kd);
-               if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
-                       SAY("ERROR: cannot lock dongle[%i].mutex_video\n", kd);
-                       SAM("ending unsuccessfully: may cause memory leak\n");
-                       return;
-               }
-               JOM(4, "locked dongle[%i].mutex_video\n", kd);
-               JOM(4, "about to lock dongle[%i].mutex_audio\n", kd);
-               if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_audio)) {
-                       SAY("ERROR: cannot lock dongle[%i].mutex_audio\n", kd);
-                       mutex_unlock(&(easycapdc60_dongle[kd].mutex_video));
-                       JOM(4, "unlocked dongle[%i].mutex_video\n", kd);
-                       SAM("ending unsuccessfully: may cause memory leak\n");
-                       return;
-               }
-               JOM(4, "locked 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(&(easycapdc60_dongle[kd].mutex_audio));
-               JOT(4, "unlocked dongle[%i].mutex_audio\n", kd);
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               JOT(4, "unlocked dongle[%i].mutex_video\n", kd);
-       }
-/*---------------------------------------------------------------------------*/
-       JOM(4, "ends\n");
-       return;
-}
-/*****************************************************************************/
-
-/*---------------------------------------------------------------------------*/
-/*
- *  PARAMETERS APPLICABLE TO ENTIRE DRIVER, I.E. BOTH VIDEO AND AUDIO
- */
-/*---------------------------------------------------------------------------*/
-static struct usb_device_id easycap_usb_device_id_table[] = {
-       {USB_DEVICE(USB_EASYCAP_VENDOR_ID, USB_EASYCAP_PRODUCT_ID)},
-       { }
-};
-
-MODULE_DEVICE_TABLE(usb, easycap_usb_device_id_table);
-struct usb_driver easycap_usb_driver = {
-       .name = "easycap",
-       .id_table = easycap_usb_device_id_table,
-       .probe = easycap_usb_probe,
-       .disconnect = easycap_usb_disconnect,
-};
-
-static int __init easycap_module_init(void)
-{
-       int k, rc;
-
-       printk(KERN_INFO "Easycap version: "EASYCAP_DRIVER_VERSION "\n");
-
-       JOT(4, "begins.  %i=debug %i=bars %i=gain\n",
-               easycap_debug, easycap_bars, easycap_gain);
-
-       mutex_init(&mutex_dongle);
-       for (k = 0; k < DONGLE_MANY; k++) {
-               easycapdc60_dongle[k].peasycap = NULL;
-               mutex_init(&easycapdc60_dongle[k].mutex_video);
-               mutex_init(&easycapdc60_dongle[k].mutex_audio);
-       }
-       rc = usb_register(&easycap_usb_driver);
-       if (rc)
-               printk(KERN_ERR "Easycap: usb_register failed rc=%d\n", rc);
-
-       return rc;
-}
-/*****************************************************************************/
-static void __exit easycap_module_exit(void)
-{
-       usb_deregister(&easycap_usb_driver);
-}
-/*****************************************************************************/
-
-module_init(easycap_module_init);
-module_exit(easycap_module_exit);
-
-/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_settings.c b/drivers/staging/easycap/easycap_settings.c
deleted file mode 100644 (file)
index 70f59b1..0000000
+++ /dev/null
@@ -1,696 +0,0 @@
-/******************************************************************************
-*                                                                             *
-*  easycap_settings.c                                                         *
-*                                                                             *
-******************************************************************************/
-/*
- *
- *  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
- *
-*/
-/*****************************************************************************/
-
-#include "easycap.h"
-
-/*---------------------------------------------------------------------------*/
-/*
- *  THE LEAST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
- *                         0 => 25 fps
- *                         1 => 30 fps
- *
- *  THE MOST  SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
- *                         0 => full framerate
- *                         1 => 20%  framerate
- */
-/*---------------------------------------------------------------------------*/
-const struct easycap_standard easycap_standard[] = {
-       {
-               .mask = 0x00FF & PAL_BGHIN ,
-               .v4l2_standard = {
-                       .index = PAL_BGHIN,
-                       .id = (V4L2_STD_PAL_B |
-                               V4L2_STD_PAL_G | V4L2_STD_PAL_H |
-                               V4L2_STD_PAL_I | V4L2_STD_PAL_N),
-                       .name = "PAL_BGHIN",
-                       .frameperiod = {1, 25},
-                       .framelines = 625,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & NTSC_N_443 ,
-               .v4l2_standard = {
-                       .index = NTSC_N_443,
-                       .id = V4L2_STD_UNKNOWN,
-                       .name = "NTSC_N_443",
-                       .frameperiod = {1, 25},
-                       .framelines = 480,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & PAL_Nc ,
-               .v4l2_standard = {
-                       .index = PAL_Nc,
-                       .id = V4L2_STD_PAL_Nc,
-                       .name = "PAL_Nc",
-                       .frameperiod = {1, 25},
-                       .framelines = 625,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & NTSC_N ,
-               .v4l2_standard = {
-                       .index = NTSC_N,
-                       .id = V4L2_STD_UNKNOWN,
-                       .name = "NTSC_N",
-                       .frameperiod = {1, 25},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & SECAM ,
-               .v4l2_standard = {
-                       .index = SECAM,
-                       .id = V4L2_STD_SECAM,
-                       .name = "SECAM",
-                       .frameperiod = {1, 25},
-                       .framelines = 625,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & NTSC_M ,
-               .v4l2_standard = {
-                       .index = NTSC_M,
-                       .id = V4L2_STD_NTSC_M,
-                       .name = "NTSC_M",
-                       .frameperiod = {1, 30},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & NTSC_M_JP ,
-               .v4l2_standard = {
-                       .index = NTSC_M_JP,
-                       .id = V4L2_STD_NTSC_M_JP,
-                       .name = "NTSC_M_JP",
-                       .frameperiod = {1, 30},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & PAL_60 ,
-               .v4l2_standard = {
-                       .index = PAL_60,
-                       .id = V4L2_STD_PAL_60,
-                       .name = "PAL_60",
-                       .frameperiod = {1, 30},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & NTSC_443 ,
-               .v4l2_standard = {
-                       .index = NTSC_443,
-                       .id = V4L2_STD_NTSC_443,
-                       .name = "NTSC_443",
-                       .frameperiod = {1, 30},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & PAL_M ,
-               .v4l2_standard = {
-                       .index = PAL_M,
-                       .id = V4L2_STD_PAL_M,
-                       .name = "PAL_M",
-                       .frameperiod = {1, 30},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & PAL_BGHIN_SLOW),
-               .v4l2_standard = {
-                       .index = PAL_BGHIN_SLOW,
-                       .id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G |
-                               V4L2_STD_PAL_H |
-                               V4L2_STD_PAL_I | V4L2_STD_PAL_N |
-                               (((v4l2_std_id)0x01) << 32)),
-                       .name = "PAL_BGHIN_SLOW",
-                       .frameperiod = {1, 5},
-                       .framelines = 625,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & NTSC_N_443_SLOW),
-               .v4l2_standard = {
-                       .index = NTSC_N_443_SLOW,
-                       .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x11) << 32)),
-                       .name = "NTSC_N_443_SLOW",
-                       .frameperiod = {1, 5},
-                       .framelines = 480,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & PAL_Nc_SLOW),
-               .v4l2_standard = {
-                       .index = PAL_Nc_SLOW,
-                       .id = (V4L2_STD_PAL_Nc | (((v4l2_std_id)0x01) << 32)),
-                       .name = "PAL_Nc_SLOW",
-                       .frameperiod = {1, 5},
-                       .framelines = 625,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & NTSC_N_SLOW),
-               .v4l2_standard = {
-                       .index = NTSC_N_SLOW,
-                       .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x21) << 32)),
-                       .name = "NTSC_N_SLOW",
-                       .frameperiod = {1, 5},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & SECAM_SLOW),
-               .v4l2_standard = {
-                       .index = SECAM_SLOW,
-                       .id = (V4L2_STD_SECAM | (((v4l2_std_id)0x01) << 32)),
-                       .name = "SECAM_SLOW",
-                       .frameperiod = {1, 5},
-                       .framelines = 625,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & NTSC_M_SLOW),
-               .v4l2_standard = {
-                       .index = NTSC_M_SLOW,
-                       .id = (V4L2_STD_NTSC_M | (((v4l2_std_id)0x01) << 32)),
-                       .name = "NTSC_M_SLOW",
-                       .frameperiod = {1, 6},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & NTSC_M_JP_SLOW),
-               .v4l2_standard = {
-                       .index = NTSC_M_JP_SLOW,
-                       .id = (V4L2_STD_NTSC_M_JP |
-                               (((v4l2_std_id)0x01) << 32)),
-                       .name = "NTSC_M_JP_SLOW",
-                       .frameperiod = {1, 6},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & PAL_60_SLOW),
-               .v4l2_standard = {
-                       .index = PAL_60_SLOW,
-                       .id = (V4L2_STD_PAL_60 | (((v4l2_std_id)0x01) << 32)),
-                       .name = "PAL_60_SLOW",
-                       .frameperiod = {1, 6},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & NTSC_443_SLOW),
-               .v4l2_standard = {
-                       .index = NTSC_443_SLOW,
-                       .id = (V4L2_STD_NTSC_443 | (((v4l2_std_id)0x01) << 32)),
-                       .name = "NTSC_443_SLOW",
-                       .frameperiod = {1, 6},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & PAL_M_SLOW),
-               .v4l2_standard = {
-                       .index = PAL_M_SLOW,
-                       .id = (V4L2_STD_PAL_M | (((v4l2_std_id)0x01) << 32)),
-                       .name = "PAL_M_SLOW",
-                       .frameperiod = {1, 6},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0xFFFF
-       }
-};
-/*---------------------------------------------------------------------------*/
-/*
- *  THE 16-BIT easycap_format.mask HAS MEANING:
- *    (least significant) BIT  0:     0 => PAL, 25 FPS;   1 => NTSC, 30 FPS
- *                        BITS 2-4:   RESERVED FOR DIFFERENTIATING STANDARDS
- *                        BITS 5-7:   NUMBER OF BYTES PER PIXEL
- *                        BIT  8:     0 => NATIVE BYTE ORDER;  1 => SWAPPED
- *                        BITS 9-10:  RESERVED FOR OTHER BYTE PERMUTATIONS
- *                        BIT 11:     0 => UNDECIMATED;    1 => DECIMATED
- *                        BIT 12:     0 => OFFER FRAMES;   1 => OFFER FIELDS
- *                        BIT 13:     0 => FULL FRAMERATE; 1 => REDUCED
- *     (most significant) BITS 14-15: RESERVED FOR OTHER FIELD/FRAME OPTIONS
- *  IT FOLLOWS THAT:
- *     bytesperpixel IS         ((0x00E0 & easycap_format.mask) >> 5)
- *     byteswaporder IS true IF (0 != (0x0100 & easycap_format.mask))
- *
- *     decimatepixel IS true IF (0 != (0x0800 & easycap_format.mask))
- *
- *       offerfields IS true IF (0 != (0x1000 & easycap_format.mask))
- */
-/*---------------------------------------------------------------------------*/
-
-struct easycap_format easycap_format[1 + SETTINGS_MANY];
-
-int fillin_formats(void)
-{
-       const char *name1, *name2, *name3, *name4;
-       struct v4l2_format *fmt;
-       int i, j, k, m, n;
-       u32 width, height, pixelformat, bytesperline, sizeimage;
-       u16 mask1, mask2, mask3, mask4;
-       enum v4l2_field field;
-       enum v4l2_colorspace colorspace;
-
-       for (i = 0, n = 0; i < STANDARD_MANY; i++) {
-               mask1 = 0x0000;
-               switch (i) {
-               case PAL_BGHIN: {
-                       mask1 = 0x1F & PAL_BGHIN;
-                       name1 = "PAL_BGHIN";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case SECAM: {
-                       mask1 = 0x1F & SECAM;
-                       name1 = "SECAM";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case PAL_Nc: {
-                       mask1 = 0x1F & PAL_Nc;
-                       name1 = "PAL_Nc";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case PAL_60: {
-                       mask1 = 0x1F & PAL_60;
-                       name1 = "PAL_60";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case PAL_M: {
-                       mask1 = 0x1F & PAL_M;
-                       name1 = "PAL_M";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case NTSC_M: {
-                       mask1 = 0x1F & NTSC_M;
-                       name1 = "NTSC_M";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_443: {
-                       mask1 = 0x1F & NTSC_443;
-                       name1 = "NTSC_443";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_M_JP: {
-                       mask1 = 0x1F & NTSC_M_JP;
-                       name1 = "NTSC_M_JP";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_N: {
-                       mask1 = 0x1F & NTSC_M;
-                       name1 = "NTSC_N";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_N_443: {
-                       mask1 = 0x1F & NTSC_N_443;
-                       name1 = "NTSC_N_443";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case PAL_BGHIN_SLOW: {
-                       mask1 = 0x001F & PAL_BGHIN_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "PAL_BGHIN_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case SECAM_SLOW: {
-                       mask1 = 0x001F & SECAM_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "SECAM_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case PAL_Nc_SLOW: {
-                       mask1 = 0x001F & PAL_Nc_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "PAL_Nc_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case PAL_60_SLOW: {
-                       mask1 = 0x001F & PAL_60_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "PAL_60_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case PAL_M_SLOW: {
-                       mask1 = 0x001F & PAL_M_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "PAL_M_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case NTSC_M_SLOW: {
-                       mask1 = 0x001F & NTSC_M_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "NTSC_M_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_443_SLOW: {
-                       mask1 = 0x001F & NTSC_443_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "NTSC_443_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_M_JP_SLOW: {
-                       mask1 = 0x001F & NTSC_M_JP_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "NTSC_M_JP_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_N_SLOW: {
-                       mask1 = 0x001F & NTSC_N_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "NTSC_N_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_N_443_SLOW: {
-                       mask1 = 0x001F & NTSC_N_443_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "NTSC_N_443_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               default:
-                       return -1;
-               }
-
-               for (j = 0; j < RESOLUTION_MANY; j++) {
-                       mask2 = 0x0000;
-                       switch (j) {
-                       case AT_720x576: {
-                               if (0x1 & mask1)
-                                       continue;
-                               name2 = "_AT_720x576";
-                               width = 720;
-                               height = 576;
-                               break;
-                       }
-                       case AT_704x576: {
-                               if (0x1 & mask1)
-                                       continue;
-                               name2 = "_AT_704x576";
-                               width = 704;
-                               height = 576;
-                               break;
-                       }
-                       case AT_640x480: {
-                               name2 = "_AT_640x480";
-                               width = 640;
-                               height = 480;
-                               break;
-                       }
-                       case AT_720x480: {
-                               if (!(0x1 & mask1))
-                                       continue;
-                               name2 = "_AT_720x480";
-                               width = 720;
-                               height = 480;
-                               break;
-                       }
-                       case AT_360x288: {
-                               if (0x1 & mask1)
-                                       continue;
-                               name2 = "_AT_360x288";
-                               width = 360;
-                               height = 288;
-                               mask2 = 0x0800;
-                               break;
-                       }
-                       case AT_320x240: {
-                               name2 = "_AT_320x240";
-                               width = 320;
-                               height = 240;
-                               mask2 = 0x0800;
-                               break;
-                       }
-                       case AT_360x240: {
-                               if (!(0x1 & mask1))
-                                       continue;
-                               name2 = "_AT_360x240";
-                               width = 360;
-                               height = 240;
-                               mask2 = 0x0800;
-                               break;
-                       }
-                       default:
-                               return -2;
-                       }
-
-                       for (k = 0; k < PIXELFORMAT_MANY; k++) {
-                               mask3 = 0x0000;
-                               switch (k) {
-                               case FMT_UYVY: {
-                                       name3 = __stringify(FMT_UYVY);
-                                       pixelformat = V4L2_PIX_FMT_UYVY;
-                                       mask3 |= (0x02 << 5);
-                                       break;
-                               }
-                               case FMT_YUY2: {
-                                       name3 = __stringify(FMT_YUY2);
-                                       pixelformat = V4L2_PIX_FMT_YUYV;
-                                       mask3 |= (0x02 << 5);
-                                       mask3 |= 0x0100;
-                                       break;
-                               }
-                               case FMT_RGB24: {
-                                       name3 = __stringify(FMT_RGB24);
-                                       pixelformat = V4L2_PIX_FMT_RGB24;
-                                       mask3 |= (0x03 << 5);
-                                       break;
-                               }
-                               case FMT_RGB32: {
-                                       name3 = __stringify(FMT_RGB32);
-                                       pixelformat = V4L2_PIX_FMT_RGB32;
-                                       mask3 |= (0x04 << 5);
-                                       break;
-                               }
-                               case FMT_BGR24: {
-                                       name3 = __stringify(FMT_BGR24);
-                                       pixelformat = V4L2_PIX_FMT_BGR24;
-                                       mask3 |= (0x03 << 5);
-                                       mask3 |= 0x0100;
-                                       break;
-                               }
-                               case FMT_BGR32: {
-                                       name3 = __stringify(FMT_BGR32);
-                                       pixelformat = V4L2_PIX_FMT_BGR32;
-                                       mask3 |= (0x04 << 5);
-                                       mask3 |= 0x0100;
-                                       break;
-                               }
-                               default:
-                                       return -3;
-                               }
-                               bytesperline = width * ((mask3 & 0x00E0) >> 5);
-                               sizeimage =  bytesperline * height;
-
-                               for (m = 0; m < INTERLACE_MANY; m++) {
-                                       mask4 = 0x0000;
-                                       switch (m) {
-                                       case FIELD_NONE: {
-                                               name4 = "-n";
-                                               field = V4L2_FIELD_NONE;
-                                               break;
-                                       }
-                                       case FIELD_INTERLACED: {
-                                               name4 = "-i";
-                                               mask4 |= 0x1000;
-                                               field = V4L2_FIELD_INTERLACED;
-                                               break;
-                                       }
-                                       default:
-                                               return -4;
-                                       }
-                                       if (SETTINGS_MANY <= n)
-                                               return -5;
-
-                                       strcpy(easycap_format[n].name, name1);
-                                       strcat(easycap_format[n].name, name2);
-                                       strcat(easycap_format[n].name, "_");
-                                       strcat(easycap_format[n].name, name3);
-                                       strcat(easycap_format[n].name, name4);
-                                       easycap_format[n].mask =
-                                               mask1 | mask2 | mask3 | mask4;
-                                       fmt = &easycap_format[n].v4l2_format;
-
-                                       fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                                       fmt->fmt.pix.width = width;
-                                       fmt->fmt.pix.height = height;
-                                       fmt->fmt.pix.pixelformat = pixelformat;
-                                       fmt->fmt.pix.field = field;
-                                       fmt->fmt.pix.bytesperline = bytesperline;
-                                       fmt->fmt.pix.sizeimage = sizeimage;
-                                       fmt->fmt.pix.colorspace = colorspace;
-                                       fmt->fmt.pix.priv = 0;
-                                       n++;
-                               }
-                       }
-               }
-       }
-       if ((1 + SETTINGS_MANY) <= n)
-               return -6;
-       easycap_format[n].mask = 0xFFFF;
-       return n;
-}
-/*---------------------------------------------------------------------------*/
-struct v4l2_queryctrl easycap_control[] = {
-       {
-               .id       = V4L2_CID_BRIGHTNESS,
-               .type     = V4L2_CTRL_TYPE_INTEGER,
-               .name     = "Brightness",
-               .minimum  = 0,
-               .maximum  = 255,
-               .step     =  1,
-               .default_value = SAA_0A_DEFAULT,
-               .flags    = 0,
-               .reserved = {0, 0}
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .id       = V4L2_CID_CONTRAST,
-               .type     = V4L2_CTRL_TYPE_INTEGER,
-               .name     = "Contrast",
-               .minimum  = 0,
-               .maximum  = 255,
-               .step     =   1,
-               .default_value = SAA_0B_DEFAULT + 128,
-               .flags    = 0,
-               .reserved = {0, 0}
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .id       = V4L2_CID_SATURATION,
-               .type     = V4L2_CTRL_TYPE_INTEGER,
-               .name     = "Saturation",
-               .minimum  = 0,
-               .maximum  = 255,
-               .step     =   1,
-               .default_value = SAA_0C_DEFAULT + 128,
-               .flags    = 0,
-               .reserved = {0, 0}
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .id       = V4L2_CID_HUE,
-               .type     = V4L2_CTRL_TYPE_INTEGER,
-               .name     = "Hue",
-               .minimum  = 0,
-               .maximum  = 255,
-               .step     =   1,
-               .default_value = SAA_0D_DEFAULT + 128,
-               .flags    = 0,
-               .reserved = {0, 0}
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .id       = V4L2_CID_AUDIO_VOLUME,
-               .type     = V4L2_CTRL_TYPE_INTEGER,
-               .name     = "Volume",
-               .minimum  = 0,
-               .maximum  = 31,
-               .step     =   1,
-               .default_value = 16,
-               .flags    = 0,
-               .reserved = {0, 0}
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .id       = V4L2_CID_AUDIO_MUTE,
-               .type     = V4L2_CTRL_TYPE_BOOLEAN,
-               .name     = "Mute",
-               .default_value = true,
-               .flags    = 0,
-               .reserved = {0, 0}
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .id = 0xFFFFFFFF
-       }
-};
-/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_sound.c b/drivers/staging/easycap/easycap_sound.c
deleted file mode 100644 (file)
index b22bb39..0000000
+++ /dev/null
@@ -1,816 +0,0 @@
-/******************************************************************************
-*                                                                             *
-*  easycap_sound.c                                                            *
-*                                                                             *
-*  Audio driver for EasyCAP USB2.0 Video Capture Device DC60                  *
-*                                                                             *
-*                                                                             *
-******************************************************************************/
-/*
- *
- *  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
- *
-*/
-/*****************************************************************************/
-
-#include "easycap.h"
-
-/*--------------------------------------------------------------------------*/
-/*
- *  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,
-};
-
-
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  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 tmp;
-       int i, j, more, much, rc;
-#ifdef UPSAMPLE
-       int k;
-       s16 oldaudio, newaudio, delta;
-#endif /*UPSAMPLE*/
-
-       JOT(16, "\n");
-
-       if (!purb) {
-               SAY("ERROR: purb is NULL\n");
-               return;
-       }
-       peasycap = purb->context;
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\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 (!pss)
-               goto resubmit;
-       prt = pss->runtime;
-       if (!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: -%s: %d\n",
-                   strerror(purb->status), purb->status);
-               goto resubmit;
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  PROCEED HERE WHEN NO ERROR
- */
-/*---------------------------------------------------------------------------*/
-
-#ifdef UPSAMPLE
-       oldaudio = peasycap->oldaudio;
-#endif /*UPSAMPLE*/
-
-       for (i = 0;  i < purb->number_of_packets; i++) {
-               if (purb->iso_frame_desc[i].status < 0) {
-                       SAM("-%s: %d\n",
-                           strerror(purb->iso_frame_desc[i].status),
-                           purb->iso_frame_desc[i].status);
-               }
-               if (purb->iso_frame_desc[i].status) {
-                       JOM(12, "discarding audio samples because "
-                           "%i=purb->iso_frame_desc[i].status\n",
-                           purb->iso_frame_desc[i].status);
-                       continue;
-               }
-               more = purb->iso_frame_desc[i].actual_length;
-               if (more == 0) {
-                       peasycap->audio_mt++;
-                       continue;
-               }
-               if (0 > more) {
-                       SAM("MISTAKE: more is negative\n");
-                       return;
-               }
-
-               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) {
-                       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 (!peasycap->microphone) {
-                               if (much > more)
-                                       much = more;
-                               memcpy(prt->dma_area + peasycap->dma_fill,
-                                       p1, much);
-                               p1 += much;
-                               more -= much;
-                       } else {
-#ifdef 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;
-                                       tmp = oldaudio + delta;
-
-                                       for (k = 0;  k < 4;  k++) {
-                                               *p2 = (0x00FF & tmp);
-                                               *(p2 + 1) = (0xFF00 & tmp) >> 8;
-                                               p2 += 2;
-                                               *p2 = (0x00FF & tmp);
-                                               *(p2 + 1) = (0xFF00 & tmp) >> 8;
-                                               p2 += 2;
-                                               tmp += delta;
-                                       }
-                                       p1++;
-                                       more--;
-                                       oldaudio = tmp;
-                               }
-#else /*!UPSAMPLE*/
-                               if (much > (2 * more))
-                                       much = 2 * more;
-                               p2 = (u8 *)(prt->dma_area + peasycap->dma_fill);
-
-                               for (j = 0;  j < (much / 2);  j++) {
-                                       tmp = ((int) *p1) - 128;
-                                       tmp = 128 * tmp;
-                                       *p2 = (0x00FF & tmp);
-                                       *(p2 + 1) = (0xFF00 & tmp) >> 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_elapsed(), %i="
-                                           "isfragment\n", isfragment);
-                                       snd_pcm_period_elapsed(pss);
-                               }
-                       }
-               }
-
-#ifdef UPSAMPLE
-               peasycap->oldaudio = oldaudio;
-#endif /*UPSAMPLE*/
-
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  RESUBMIT THIS URB
- */
-/*---------------------------------------------------------------------------*/
-resubmit:
-       if (peasycap->audio_isoc_streaming == 0)
-               return;
-
-       rc = usb_submit_urb(purb, GFP_ATOMIC);
-       if (rc) {
-               if ((-ENODEV != rc) && (-ENOENT != rc)) {
-                       SAM("ERROR: while %i=audio_idle, usb_submit_urb failed "
-                           "with rc: -%s :%d\n",
-                               peasycap->audio_idle, strerror(rc), rc);
-               }
-               if (0 < peasycap->audio_isoc_streaming)
-                       peasycap->audio_isoc_streaming--;
-       }
-       return;
-}
-/*****************************************************************************/
-static 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 (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       psnd_pcm = pss->pcm;
-       if (!psnd_pcm) {
-               SAY("ERROR:  psnd_pcm is NULL\n");
-               return -EFAULT;
-       }
-       psnd_card = psnd_pcm->card;
-       if (!psnd_card) {
-               SAY("ERROR:  psnd_card is NULL\n");
-               return -EFAULT;
-       }
-
-       peasycap = psnd_card->private_data;
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (peasycap->psnd_card != psnd_card) {
-               SAM("ERROR: bad peasycap->psnd_card\n");
-               return -EFAULT;
-       }
-       if (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;
-}
-/*****************************************************************************/
-static int easycap_alsa_close(struct snd_pcm_substream *pss)
-{
-       struct easycap *peasycap;
-
-       JOT(4, "\n");
-       if (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       peasycap = snd_pcm_substream_chip(pss);
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               return -EFAULT;
-       }
-       pss->private_data = NULL;
-       peasycap->psubstream = NULL;
-       JOT(4, "ending successfully\n");
-       return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_vmalloc(struct snd_pcm_substream *pss, size_t sz)
-{
-       struct snd_pcm_runtime *prt;
-       JOT(4, "\n");
-
-       if (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       prt = pss->runtime;
-       if (!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 (!prt->dma_area)
-               return -ENOMEM;
-       prt->dma_bytes = sz;
-       return 0;
-}
-/*****************************************************************************/
-static 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 (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       rc = easycap_alsa_vmalloc(pss, params_buffer_bytes(phw));
-       if (rc)
-               return rc;
-       return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_hw_free(struct snd_pcm_substream *pss)
-{
-       struct snd_pcm_runtime *prt;
-       JOT(4, "\n");
-
-       if (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       prt = pss->runtime;
-       if (!prt) {
-               SAY("ERROR: substream.runtime is NULL\n");
-               return -EFAULT;
-       }
-       if (prt->dma_area) {
-               JOT(8, "prt->dma_area = %p\n", prt->dma_area);
-               vfree(prt->dma_area);
-               prt->dma_area = NULL;
-       } else
-               JOT(8, "dma_area already freed\n");
-       return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_prepare(struct snd_pcm_substream *pss)
-{
-       struct easycap *peasycap;
-       struct snd_pcm_runtime *prt;
-
-       JOT(4, "\n");
-       if (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       prt = pss->runtime;
-       peasycap = snd_pcm_substream_chip(pss);
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               return -EFAULT;
-       }
-
-       JOM(16, "ALSA decides %8i Hz=rate\n", pss->runtime->rate);
-       JOM(16, "ALSA decides %8ld =period_size\n", pss->runtime->period_size);
-       JOM(16, "ALSA decides %8i =periods\n", pss->runtime->periods);
-       JOM(16, "ALSA decides %8ld =buffer_size\n", pss->runtime->buffer_size);
-       JOM(16, "ALSA decides %8zd =dma_bytes\n", pss->runtime->dma_bytes);
-       JOM(16, "ALSA decides %8ld =boundary\n", pss->runtime->boundary);
-       JOM(16, "ALSA decides %8i =period_step\n", pss->runtime->period_step);
-       JOM(16, "ALSA decides %8i =sample_bits\n", pss->runtime->sample_bits);
-       JOM(16, "ALSA decides %8i =frame_bits\n", pss->runtime->frame_bits);
-       JOM(16, "ALSA decides %8ld =min_align\n", pss->runtime->min_align);
-       JOM(12, "ALSA decides %8ld =hw_ptr_base\n", pss->runtime->hw_ptr_base);
-       JOM(12, "ALSA decides %8ld =hw_ptr_interrupt\n",
-               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;
-}
-/*****************************************************************************/
-static int easycap_alsa_ack(struct snd_pcm_substream *pss)
-{
-       return 0;
-}
-/*****************************************************************************/
-static 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 (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       peasycap = snd_pcm_substream_chip(pss);
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\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;
-}
-/*****************************************************************************/
-static snd_pcm_uframes_t easycap_alsa_pointer(struct snd_pcm_substream *pss)
-{
-       struct easycap *peasycap;
-       snd_pcm_uframes_t offset;
-
-       JOT(16, "\n");
-       if (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       peasycap = snd_pcm_substream_chip(pss);
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\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;
-}
-/*****************************************************************************/
-static struct page *
-easycap_alsa_page(struct snd_pcm_substream *pss, unsigned long offset)
-{
-       return vmalloc_to_page(pss->runtime->dma_area + offset);
-}
-/*****************************************************************************/
-
-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 (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -ENODEV;
-       }
-       if (0 > peasycap->minor) {
-               SAY("ERROR: no minor\n");
-               return -ENODEV;
-       }
-
-       peasycap->alsa_hardware = alsa_hardware;
-       if (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 (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;
-       }
-
-       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 (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 = NULL;
-
-       rc = snd_card_register(psnd_card);
-       if (rc) {
-               SAM("ERROR: Cannot do ALSA snd_card_register()\n");
-               snd_card_free(psnd_card);
-               return -EFAULT;
-       }
-
-       SAM("registered %s\n", &psnd_card->id[0]);
-       return 0;
-}
-
-/*****************************************************************************/
-/*****************************************************************************/
-/*****************************************************************************/
-/*****************************************************************************/
-/*****************************************************************************/
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  COMMON AUDIO INITIALIZATION
- */
-/*---------------------------------------------------------------------------*/
-int
-easycap_sound_setup(struct easycap *peasycap)
-{
-       int rc;
-
-       JOM(4, "starting initialization\n");
-
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL.\n");
-               return -EFAULT;
-       }
-       if (!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 (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device has become NULL\n");
-               return -ENODEV;
-       }
-/*---------------------------------------------------------------------------*/
-       if (!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;
-
-       submit_audio_urbs(peasycap);
-
-       JOM(4, "finished initialization\n");
-       return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  SUBMIT ALL AUDIO URBS.
- */
-/*---------------------------------------------------------------------------*/
-int
-submit_audio_urbs(struct easycap *peasycap)
-{
-       struct data_urb *pdata_urb;
-       struct urb *purb;
-       struct list_head *plist_head;
-       int j, isbad, nospc, m, rc;
-       int isbuf;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->purb_audio_head) {
-               SAM("ERROR: peasycap->urb_audio_head uninitialized\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-
-       if (peasycap->audio_isoc_streaming) {
-               JOM(4, "already streaming audio urbs\n");
-               return 0;
-       }
-
-       JOM(4, "initial submission of all audio urbs\n");
-       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);
-
-       isbad = 0;
-       nospc = 0;
-       m = 0;
-       list_for_each(plist_head, peasycap->purb_audio_head) {
-               pdata_urb = list_entry(plist_head, struct data_urb, list_head);
-               if (pdata_urb && pdata_urb->purb) {
-                       purb = pdata_urb->purb;
-                       isbuf = pdata_urb->isbuf;
-
-                       purb->interval = 1;
-                       purb->dev = peasycap->pusb_device;
-                       purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
-                                       peasycap->audio_endpointnumber);
-                       purb->transfer_flags = URB_ISO_ASAP;
-                       purb->transfer_buffer = peasycap->audio_isoc_buffer[isbuf].pgo;
-                       purb->transfer_buffer_length = peasycap->audio_isoc_buffer_size;
-                       purb->complete = easycap_alsa_complete;
-                       purb->context = peasycap;
-                       purb->start_frame = 0;
-                       purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
-                       for (j = 0;  j < peasycap->audio_isoc_framesperdesc; j++) {
-                               purb->iso_frame_desc[j].offset = j * peasycap->audio_isoc_maxframesize;
-                               purb->iso_frame_desc[j].length = peasycap->audio_isoc_maxframesize;
-                       }
-
-                       rc = usb_submit_urb(purb, GFP_KERNEL);
-                       if (rc) {
-                               isbad++;
-                               SAM("ERROR: usb_submit_urb() failed"
-                                   " for urb with rc: -%s: %d\n",
-                                   strerror(rc), rc);
-                       } else {
-                               m++;
-                       }
-               } else {
-                       isbad++;
-               }
-       }
-       if (nospc) {
-               SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
-               SAM(".....  possibly inadequate USB bandwidth\n");
-               peasycap->audio_eof = 1;
-       }
-       if (isbad) {
-               JOM(4, "attempting cleanup instead of submitting\n");
-               list_for_each(plist_head, (peasycap->purb_audio_head)) {
-                       pdata_urb = list_entry(plist_head, struct data_urb, list_head);
-                       if (pdata_urb && pdata_urb->purb)
-                               usb_kill_urb(pdata_urb->purb);
-               }
-               peasycap->audio_isoc_streaming = 0;
-       } else {
-               peasycap->audio_isoc_streaming = m;
-               JOM(4, "submitted %i audio urbs\n", m);
-       }
-
-       return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  KILL ALL AUDIO URBS.
- */
-/*---------------------------------------------------------------------------*/
-int
-kill_audio_urbs(struct easycap *peasycap)
-{
-       int m;
-       struct list_head *plist_head;
-       struct data_urb *pdata_urb;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-
-       if (!peasycap->audio_isoc_streaming) {
-               JOM(8, "%i=audio_isoc_streaming, no audio urbs killed\n",
-                   peasycap->audio_isoc_streaming);
-               return 0;
-       }
-
-       if (!peasycap->purb_audio_head) {
-               SAM("ERROR: peasycap->purb_audio_head is NULL\n");
-               return -EFAULT;
-       }
-
-       peasycap->audio_isoc_streaming = 0;
-       JOM(4, "killing audio urbs\n");
-       m = 0;
-       list_for_each(plist_head, (peasycap->purb_audio_head)) {
-               pdata_urb = list_entry(plist_head, struct data_urb, list_head);
-               if (pdata_urb && pdata_urb->purb) {
-                       usb_kill_urb(pdata_urb->purb);
-                       m++;
-               }
-       }
-       JOM(4, "%i audio urbs killed\n", m);
-
-       return 0;
-}
-/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_testcard.c b/drivers/staging/easycap/easycap_testcard.c
deleted file mode 100644 (file)
index 0f71470..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/******************************************************************************
-*                                                                             *
-*  easycap_testcard.c                                                         *
-*                                                                             *
-******************************************************************************/
-/*
- *
- *  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
- *
-*/
-/*****************************************************************************/
-
-#include "easycap.h"
-
-/*****************************************************************************/
-#define TESTCARD_BYTESPERLINE (2 * 720)
-void
-easycap_testcard(struct easycap *peasycap, int field)
-{
-       int total;
-       int y, u, v, r, g, b;
-       unsigned char uyvy[4];
-       int i1, line, k, m, n, more, much, barwidth, barheight;
-       unsigned char bfbar[TESTCARD_BYTESPERLINE / 8], *p1, *p2;
-       struct data_buffer *pfield_buffer;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return;
-       }
-       JOM(8, "%i=field\n", field);
-       switch (peasycap->width) {
-       case 720:
-       case 360: {
-               barwidth = (2 * 720) / 8;
-               break;
-       }
-       case 704:
-       case 352: {
-               barwidth = (2 * 704) / 8;
-               break;
-       }
-       case 640:
-       case 320: {
-               barwidth = (2 * 640) / 8;
-               break;
-       }
-       default: {
-               SAM("ERROR:  cannot set barwidth\n");
-               return;
-       }
-       }
-       if (TESTCARD_BYTESPERLINE < barwidth) {
-               SAM("ERROR: barwidth is too large\n");
-               return;
-       }
-       switch (peasycap->height) {
-       case 576:
-       case 288: {
-               barheight = 576;
-               break;
-       }
-       case 480:
-       case 240: {
-               barheight = 480;
-               break;
-       }
-       default: {
-               SAM("ERROR: cannot set barheight\n");
-               return;
-       }
-       }
-       total = 0;
-       k = field;
-       m = 0;
-       n = 0;
-
-       for (line = 0;  line < (barheight / 2);  line++) {
-               for (i1 = 0;  i1 < 8;  i1++) {
-                       r = (i1 * 256)/8;
-                       g = (i1 * 256)/8;
-                       b = (i1 * 256)/8;
-
-                       y =  299*r/1000 + 587*g/1000 + 114*b/1000 ;
-                       u = -147*r/1000 - 289*g/1000 + 436*b/1000 ;
-                       u = u + 128;
-                       v =  615*r/1000 - 515*g/1000 - 100*b/1000 ;
-                       v = v + 128;
-
-                       uyvy[0] =  0xFF & u ;
-                       uyvy[1] =  0xFF & y ;
-                       uyvy[2] =  0xFF & v ;
-                       uyvy[3] =  0xFF & y ;
-
-                       p1 = &bfbar[0];
-                       while (p1 < &bfbar[barwidth]) {
-                               *p1++ = uyvy[0] ;
-                               *p1++ = uyvy[1] ;
-                               *p1++ = uyvy[2] ;
-                               *p1++ = uyvy[3] ;
-                               total += 4;
-                       }
-
-                       p1 = &bfbar[0];
-                       more = barwidth;
-
-                       while (more) {
-                               if ((FIELD_BUFFER_SIZE/PAGE_SIZE) <= m) {
-                                       SAM("ERROR:  bad m reached\n");
-                                       return;
-                               }
-                               if (PAGE_SIZE < n) {
-                                       SAM("ERROR:  bad n reached\n");
-                                       return;
-                               }
-
-                               if (0 > more) {
-                                       SAM("ERROR:  internal fault\n");
-                                       return;
-                               }
-
-                               much = PAGE_SIZE - n;
-                               if (much > more)
-                                       much = more;
-                               pfield_buffer = &peasycap->field_buffer[k][m];
-                               p2 = pfield_buffer->pgo + n;
-                               memcpy(p2, p1, much);
-
-                               p1 += much;
-                               n += much;
-                               more -= much;
-                               if (PAGE_SIZE == n) {
-                                       m++;
-                                       n = 0;
-                               }
-                       }
-               }
-       }
-       return;
-}
diff --git a/drivers/staging/go7007/Kconfig b/drivers/staging/go7007/Kconfig
deleted file mode 100644 (file)
index 7dfb281..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-config VIDEO_GO7007
-       tristate "WIS GO7007 MPEG encoder support"
-       depends on VIDEO_DEV && PCI && I2C
-       depends on SND
-       select VIDEOBUF_DMA_SG
-       depends on RC_CORE
-       select VIDEO_TUNER
-       select VIDEO_TVEEPROM
-       select SND_PCM
-       select CRC32
-       default N
-       ---help---
-         This is a video4linux driver for the WIS GO7007 MPEG
-         encoder chip.
-
-         To compile this driver as a module, choose M here: the
-         module will be called go7007
-
-config VIDEO_GO7007_USB
-       tristate "WIS GO7007 USB support"
-       depends on VIDEO_GO7007 && USB
-       default N
-       ---help---
-         This is a video4linux driver for the WIS GO7007 MPEG
-         encoder chip over USB.
-
-         To compile this driver as a module, choose M here: the
-         module will be called go7007-usb
-
-config VIDEO_GO7007_USB_S2250_BOARD
-       tristate "Sensoray 2250/2251 support"
-       depends on VIDEO_GO7007_USB && DVB_USB
-       default N
-       ---help---
-         This is a video4linux driver for the Sensoray 2250/2251 device.
-
-         To compile this driver as a module, choose M here: the
-         module will be called s2250
-
-config VIDEO_GO7007_OV7640
-       tristate "OV7640 subdev support"
-       depends on VIDEO_GO7007
-       default N
-       ---help---
-         This is a video4linux driver for the OV7640 sub-device.
-
-         To compile this driver as a module, choose M here: the
-         module will be called wis-ov7640
-
-config VIDEO_GO7007_SAA7113
-       tristate "SAA7113 subdev support"
-       depends on VIDEO_GO7007
-       default N
-       ---help---
-         This is a video4linux driver for the SAA7113 sub-device.
-
-         To compile this driver as a module, choose M here: the
-         module will be called wis-saa7113
-
-config VIDEO_GO7007_SAA7115
-       tristate "SAA7115 subdev support"
-       depends on VIDEO_GO7007
-       default N
-       ---help---
-         This is a video4linux driver for the SAA7115 sub-device.
-
-         To compile this driver as a module, choose M here: the
-         module will be called wis-saa7115
-
-config VIDEO_GO7007_TW9903
-       tristate "TW9903 subdev support"
-       depends on VIDEO_GO7007
-       default N
-       ---help---
-         This is a video4linux driver for the TW9903 sub-device.
-
-         To compile this driver as a module, choose M here: the
-         module will be called wis-tw9903
-
-config VIDEO_GO7007_UDA1342
-       tristate "UDA1342 subdev support"
-       depends on VIDEO_GO7007
-       default N
-       ---help---
-         This is a video4linux driver for the UDA1342 sub-device.
-
-         To compile this driver as a module, choose M here: the
-         module will be called wis-uda1342
-
-config VIDEO_GO7007_SONY_TUNER
-       tristate "Sony tuner subdev support"
-       depends on VIDEO_GO7007
-       default N
-       ---help---
-         This is a video4linux driver for the Sony Tuner sub-device.
-
-         To compile this driver as a module, choose M here: the
-         module will be called wis-sony-tuner
-
-config VIDEO_GO7007_TW2804
-       tristate "TW2804 subdev support"
-       depends on VIDEO_GO7007
-       default N
-       ---help---
-         This is a video4linux driver for the TW2804 sub-device.
-
-         To compile this driver as a module, choose M here: the
-         module will be called wis-tw2804
-
diff --git a/drivers/staging/go7007/Makefile b/drivers/staging/go7007/Makefile
deleted file mode 100644 (file)
index 6ee837c..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#obj-m += go7007.o go7007-usb.o snd-go7007.o wis-saa7115.o wis-tw9903.o \
-               wis-uda1342.o wis-sony-tuner.o wis-saa7113.o wis-ov7640.o \
-               wis-tw2804.o
-
-
-obj-$(CONFIG_VIDEO_GO7007) += go7007.o
-obj-$(CONFIG_VIDEO_GO7007_USB) += go7007-usb.o
-obj-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD) += s2250.o s2250-loader.o
-obj-$(CONFIG_VIDEO_GO7007_SAA7113) += wis-saa7113.o
-obj-$(CONFIG_VIDEO_GO7007_OV7640) += wis-ov7640.o
-obj-$(CONFIG_VIDEO_GO7007_SAA7115) += wis-saa7115.o
-obj-$(CONFIG_VIDEO_GO7007_TW9903) += wis-tw9903.o
-obj-$(CONFIG_VIDEO_GO7007_UDA1342) += wis-uda1342.o
-obj-$(CONFIG_VIDEO_GO7007_SONY_TUNER) += wis-sony-tuner.o
-obj-$(CONFIG_VIDEO_GO7007_TW2804) += wis-tw2804.o
-
-go7007-y := go7007-v4l2.o go7007-driver.o go7007-i2c.o go7007-fw.o \
-               snd-go7007.o
-
-s2250-y := s2250-board.o
-
-# Uncomment when the saa7134 patches get into upstream
-#obj-$(CONFIG_VIDEO_SAA7134) += saa7134-go7007.o
-#ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/video/saa7134 -DSAA7134_MPEG_GO7007=3
-
-# S2250 needs cypress ezusb loader from dvb-usb
-ccflags-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD:m=y) += -Idrivers/media/dvb/dvb-usb
-
-ccflags-y += -Idrivers/media/dvb/frontends
-ccflags-y += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/staging/go7007/README b/drivers/staging/go7007/README
deleted file mode 100644 (file)
index 48f4476..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-Todo:
-       - checkpatch.pl cleanups
-       - sparse cleanups
-       - lots of little modules, should be merged together
-         and added to the build.
-       - testing?
-       - handle churn in v4l layer.
-
-Please send patchs to Greg Kroah-Hartman <greg@kroah.com> and Cc: Ross
-Cohen <rcohen@snurgle.org> as well.
-
diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c
deleted file mode 100644 (file)
index 6c9279a..0000000
+++ /dev/null
@@ -1,659 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/unistd.h>
-#include <linux/time.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/device.h>
-#include <linux/i2c.h>
-#include <linux/firmware.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <linux/slab.h>
-#include <asm/system.h>
-#include <linux/videodev2.h>
-#include <media/tuner.h>
-#include <media/v4l2-common.h>
-
-#include "go7007-priv.h"
-#include "wis-i2c.h"
-
-/*
- * Wait for an interrupt to be delivered from the GO7007SB and return
- * the associated value and data.
- *
- * Must be called with the hw_lock held.
- */
-int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data)
-{
-       go->interrupt_available = 0;
-       go->hpi_ops->read_interrupt(go);
-       if (wait_event_timeout(go->interrupt_waitq,
-                               go->interrupt_available, 5*HZ) < 0) {
-               v4l2_err(&go->v4l2_dev, "timeout waiting for read interrupt\n");
-               return -1;
-       }
-       if (!go->interrupt_available)
-               return -1;
-       go->interrupt_available = 0;
-       *value = go->interrupt_value & 0xfffe;
-       *data = go->interrupt_data;
-       return 0;
-}
-EXPORT_SYMBOL(go7007_read_interrupt);
-
-/*
- * Read a register/address on the GO7007SB.
- *
- * Must be called with the hw_lock held.
- */
-int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data)
-{
-       int count = 100;
-       u16 value;
-
-       if (go7007_write_interrupt(go, 0x0010, addr) < 0)
-               return -EIO;
-       while (count-- > 0) {
-               if (go7007_read_interrupt(go, &value, data) == 0 &&
-                               value == 0xa000)
-                       return 0;
-       }
-       return -EIO;
-}
-EXPORT_SYMBOL(go7007_read_addr);
-
-/*
- * Send the boot firmware to the encoder, which just wakes it up and lets
- * us talk to the GPIO pins and on-board I2C adapter.
- *
- * Must be called with the hw_lock held.
- */
-static int go7007_load_encoder(struct go7007 *go)
-{
-       const struct firmware *fw_entry;
-       char fw_name[] = "go7007fw.bin";
-       void *bounce;
-       int fw_len, rv = 0;
-       u16 intr_val, intr_data;
-
-       if (request_firmware(&fw_entry, fw_name, go->dev)) {
-               v4l2_err(go, "unable to load firmware from file "
-                       "\"%s\"\n", fw_name);
-               return -1;
-       }
-       if (fw_entry->size < 16 || memcmp(fw_entry->data, "WISGO7007FW", 11)) {
-               v4l2_err(go, "file \"%s\" does not appear to be "
-                               "go7007 firmware\n", fw_name);
-               release_firmware(fw_entry);
-               return -1;
-       }
-       fw_len = fw_entry->size - 16;
-       bounce = kmalloc(fw_len, GFP_KERNEL);
-       if (bounce == NULL) {
-               v4l2_err(go, "unable to allocate %d bytes for "
-                               "firmware transfer\n", fw_len);
-               release_firmware(fw_entry);
-               return -1;
-       }
-       memcpy(bounce, fw_entry->data + 16, fw_len);
-       release_firmware(fw_entry);
-       if (go7007_interface_reset(go) < 0 ||
-                       go7007_send_firmware(go, bounce, fw_len) < 0 ||
-                       go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
-                       (intr_val & ~0x1) != 0x5a5a) {
-               v4l2_err(go, "error transferring firmware\n");
-               rv = -1;
-       }
-       kfree(bounce);
-       return rv;
-}
-
-MODULE_FIRMWARE("go7007fw.bin");
-
-/*
- * Boot the encoder and register the I2C adapter if requested.  Do the
- * minimum initialization necessary, since the board-specific code may
- * still need to probe the board ID.
- *
- * Must NOT be called with the hw_lock held.
- */
-int go7007_boot_encoder(struct go7007 *go, int init_i2c)
-{
-       int ret;
-
-       mutex_lock(&go->hw_lock);
-       ret = go7007_load_encoder(go);
-       mutex_unlock(&go->hw_lock);
-       if (ret < 0)
-               return -1;
-       if (!init_i2c)
-               return 0;
-       if (go7007_i2c_init(go) < 0)
-               return -1;
-       go->i2c_adapter_online = 1;
-       return 0;
-}
-EXPORT_SYMBOL(go7007_boot_encoder);
-
-/*
- * Configure any hardware-related registers in the GO7007, such as GPIO
- * pins and bus parameters, which are board-specific.  This assumes
- * the boot firmware has already been downloaded.
- *
- * Must be called with the hw_lock held.
- */
-static int go7007_init_encoder(struct go7007 *go)
-{
-       if (go->board_info->audio_flags & GO7007_AUDIO_I2S_MASTER) {
-               go7007_write_addr(go, 0x1000, 0x0811);
-               go7007_write_addr(go, 0x1000, 0x0c11);
-       }
-       if (go->board_id == GO7007_BOARDID_MATRIX_REV) {
-               /* Set GPIO pin 0 to be an output (audio clock control) */
-               go7007_write_addr(go, 0x3c82, 0x0001);
-               go7007_write_addr(go, 0x3c80, 0x00fe);
-       }
-       return 0;
-}
-
-/*
- * Send the boot firmware to the GO7007 and configure the registers.  This
- * is the only way to stop the encoder once it has started streaming video.
- *
- * Must be called with the hw_lock held.
- */
-int go7007_reset_encoder(struct go7007 *go)
-{
-       if (go7007_load_encoder(go) < 0)
-               return -1;
-       return go7007_init_encoder(go);
-}
-
-/*
- * Attempt to instantiate an I2C client by ID, probably loading a module.
- */
-static int init_i2c_module(struct i2c_adapter *adapter, const char *type,
-                          int addr)
-{
-       struct go7007 *go = i2c_get_adapdata(adapter);
-       struct v4l2_device *v4l2_dev = &go->v4l2_dev;
-
-       if (v4l2_i2c_new_subdev(v4l2_dev, adapter, type, addr, NULL))
-               return 0;
-
-       printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", type);
-       return -1;
-}
-
-/*
- * Finalize the GO7007 hardware setup, register the on-board I2C adapter
- * (if used on this board), load the I2C client driver for the sensor
- * (SAA7115 or whatever) and other devices, and register the ALSA and V4L2
- * interfaces.
- *
- * Must NOT be called with the hw_lock held.
- */
-int go7007_register_encoder(struct go7007 *go)
-{
-       int i, ret;
-
-       printk(KERN_INFO "go7007: registering new %s\n", go->name);
-
-       mutex_lock(&go->hw_lock);
-       ret = go7007_init_encoder(go);
-       mutex_unlock(&go->hw_lock);
-       if (ret < 0)
-               return -1;
-
-       /* v4l2 init must happen before i2c subdevs */
-       ret = go7007_v4l2_init(go);
-       if (ret < 0)
-               return ret;
-
-       if (!go->i2c_adapter_online &&
-                       go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) {
-               if (go7007_i2c_init(go) < 0)
-                       return -1;
-               go->i2c_adapter_online = 1;
-       }
-       if (go->i2c_adapter_online) {
-               for (i = 0; i < go->board_info->num_i2c_devs; ++i)
-                       init_i2c_module(&go->i2c_adapter,
-                                       go->board_info->i2c_devs[i].type,
-                                       go->board_info->i2c_devs[i].addr);
-               if (go->board_id == GO7007_BOARDID_ADLINK_MPG24)
-                       i2c_clients_command(&go->i2c_adapter,
-                               DECODER_SET_CHANNEL, &go->channel_number);
-       }
-       if (go->board_info->flags & GO7007_BOARD_HAS_AUDIO) {
-               go->audio_enabled = 1;
-               go7007_snd_init(go);
-       }
-       return 0;
-}
-EXPORT_SYMBOL(go7007_register_encoder);
-
-/*
- * Send the encode firmware to the encoder, which will cause it
- * to immediately start delivering the video and audio streams.
- *
- * Must be called with the hw_lock held.
- */
-int go7007_start_encoder(struct go7007 *go)
-{
-       u8 *fw;
-       int fw_len, rv = 0, i;
-       u16 intr_val, intr_data;
-
-       go->modet_enable = 0;
-       if (!go->dvd_mode)
-               for (i = 0; i < 4; ++i) {
-                       if (go->modet[i].enable) {
-                               go->modet_enable = 1;
-                               continue;
-                       }
-                       go->modet[i].pixel_threshold = 32767;
-                       go->modet[i].motion_threshold = 32767;
-                       go->modet[i].mb_threshold = 32767;
-               }
-
-       if (go7007_construct_fw_image(go, &fw, &fw_len) < 0)
-               return -1;
-
-       if (go7007_send_firmware(go, fw, fw_len) < 0 ||
-                       go7007_read_interrupt(go, &intr_val, &intr_data) < 0) {
-               v4l2_err(&go->v4l2_dev, "error transferring firmware\n");
-               rv = -1;
-               goto start_error;
-       }
-
-       go->state = STATE_DATA;
-       go->parse_length = 0;
-       go->seen_frame = 0;
-       if (go7007_stream_start(go) < 0) {
-               v4l2_err(&go->v4l2_dev, "error starting stream transfer\n");
-               rv = -1;
-               goto start_error;
-       }
-
-start_error:
-       kfree(fw);
-       return rv;
-}
-
-/*
- * Store a byte in the current video buffer, if there is one.
- */
-static inline void store_byte(struct go7007_buffer *gobuf, u8 byte)
-{
-       if (gobuf != NULL && gobuf->bytesused < GO7007_BUF_SIZE) {
-               unsigned int pgidx = gobuf->offset >> PAGE_SHIFT;
-               unsigned int pgoff = gobuf->offset & ~PAGE_MASK;
-
-               *((u8 *)page_address(gobuf->pages[pgidx]) + pgoff) = byte;
-               ++gobuf->offset;
-               ++gobuf->bytesused;
-       }
-}
-
-/*
- * Deliver the last video buffer and get a new one to start writing to.
- */
-static void frame_boundary(struct go7007 *go)
-{
-       struct go7007_buffer *gobuf;
-       int i;
-
-       if (go->active_buf) {
-               if (go->active_buf->modet_active) {
-                       if (go->active_buf->bytesused + 216 < GO7007_BUF_SIZE) {
-                               for (i = 0; i < 216; ++i)
-                                       store_byte(go->active_buf,
-                                                       go->active_map[i]);
-                               go->active_buf->bytesused -= 216;
-                       } else
-                               go->active_buf->modet_active = 0;
-               }
-               go->active_buf->state = BUF_STATE_DONE;
-               wake_up_interruptible(&go->frame_waitq);
-               go->active_buf = NULL;
-       }
-       list_for_each_entry(gobuf, &go->stream, stream)
-               if (gobuf->state == BUF_STATE_QUEUED) {
-                       gobuf->seq = go->next_seq;
-                       do_gettimeofday(&gobuf->timestamp);
-                       go->active_buf = gobuf;
-                       break;
-               }
-       ++go->next_seq;
-}
-
-static void write_bitmap_word(struct go7007 *go)
-{
-       int x, y, i, stride = ((go->width >> 4) + 7) >> 3;
-
-       for (i = 0; i < 16; ++i) {
-               y = (((go->parse_length - 1) << 3) + i) / (go->width >> 4);
-               x = (((go->parse_length - 1) << 3) + i) % (go->width >> 4);
-               if (stride * y + (x >> 3) < sizeof(go->active_map))
-                       go->active_map[stride * y + (x >> 3)] |=
-                                       (go->modet_word & 1) << (x & 0x7);
-               go->modet_word >>= 1;
-       }
-}
-
-/*
- * Parse a chunk of the video stream into frames.  The frames are not
- * delimited by the hardware, so we have to parse the frame boundaries
- * based on the type of video stream we're receiving.
- */
-void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
-{
-       int i, seq_start_code = -1, frame_start_code = -1;
-
-       spin_lock(&go->spinlock);
-
-       switch (go->format) {
-       case GO7007_FORMAT_MPEG4:
-               seq_start_code = 0xB0;
-               frame_start_code = 0xB6;
-               break;
-       case GO7007_FORMAT_MPEG1:
-       case GO7007_FORMAT_MPEG2:
-               seq_start_code = 0xB3;
-               frame_start_code = 0x00;
-               break;
-       }
-
-       for (i = 0; i < length; ++i) {
-               if (go->active_buf != NULL &&
-                           go->active_buf->bytesused >= GO7007_BUF_SIZE - 3) {
-                       v4l2_info(&go->v4l2_dev, "dropping oversized frame\n");
-                       go->active_buf->offset -= go->active_buf->bytesused;
-                       go->active_buf->bytesused = 0;
-                       go->active_buf->modet_active = 0;
-                       go->active_buf = NULL;
-               }
-
-               switch (go->state) {
-               case STATE_DATA:
-                       switch (buf[i]) {
-                       case 0x00:
-                               go->state = STATE_00;
-                               break;
-                       case 0xFF:
-                               go->state = STATE_FF;
-                               break;
-                       default:
-                               store_byte(go->active_buf, buf[i]);
-                               break;
-                       }
-                       break;
-               case STATE_00:
-                       switch (buf[i]) {
-                       case 0x00:
-                               go->state = STATE_00_00;
-                               break;
-                       case 0xFF:
-                               store_byte(go->active_buf, 0x00);
-                               go->state = STATE_FF;
-                               break;
-                       default:
-                               store_byte(go->active_buf, 0x00);
-                               store_byte(go->active_buf, buf[i]);
-                               go->state = STATE_DATA;
-                               break;
-                       }
-                       break;
-               case STATE_00_00:
-                       switch (buf[i]) {
-                       case 0x00:
-                               store_byte(go->active_buf, 0x00);
-                               /* go->state remains STATE_00_00 */
-                               break;
-                       case 0x01:
-                               go->state = STATE_00_00_01;
-                               break;
-                       case 0xFF:
-                               store_byte(go->active_buf, 0x00);
-                               store_byte(go->active_buf, 0x00);
-                               go->state = STATE_FF;
-                               break;
-                       default:
-                               store_byte(go->active_buf, 0x00);
-                               store_byte(go->active_buf, 0x00);
-                               store_byte(go->active_buf, buf[i]);
-                               go->state = STATE_DATA;
-                               break;
-                       }
-                       break;
-               case STATE_00_00_01:
-                       if (buf[i] == 0xF8 && go->modet_enable == 0) {
-                               /* MODET start code, but MODET not enabled */
-                               store_byte(go->active_buf, 0x00);
-                               store_byte(go->active_buf, 0x00);
-                               store_byte(go->active_buf, 0x01);
-                               store_byte(go->active_buf, 0xF8);
-                               go->state = STATE_DATA;
-                               break;
-                       }
-                       /* If this is the start of a new MPEG frame,
-                        * get a new buffer */
-                       if ((go->format == GO7007_FORMAT_MPEG1 ||
-                                       go->format == GO7007_FORMAT_MPEG2 ||
-                                       go->format == GO7007_FORMAT_MPEG4) &&
-                                       (buf[i] == seq_start_code ||
-                                               buf[i] == 0xB8 || /* GOP code */
-                                               buf[i] == frame_start_code)) {
-                               if (go->active_buf == NULL || go->seen_frame)
-                                       frame_boundary(go);
-                               if (buf[i] == frame_start_code) {
-                                       if (go->active_buf != NULL)
-                                               go->active_buf->frame_offset =
-                                                       go->active_buf->offset;
-                                       go->seen_frame = 1;
-                               } else {
-                                       go->seen_frame = 0;
-                               }
-                       }
-                       /* Handle any special chunk types, or just write the
-                        * start code to the (potentially new) buffer */
-                       switch (buf[i]) {
-                       case 0xF5: /* timestamp */
-                               go->parse_length = 12;
-                               go->state = STATE_UNPARSED;
-                               break;
-                       case 0xF6: /* vbi */
-                               go->state = STATE_VBI_LEN_A;
-                               break;
-                       case 0xF8: /* MD map */
-                               go->parse_length = 0;
-                               memset(go->active_map, 0,
-                                               sizeof(go->active_map));
-                               go->state = STATE_MODET_MAP;
-                               break;
-                       case 0xFF: /* Potential JPEG start code */
-                               store_byte(go->active_buf, 0x00);
-                               store_byte(go->active_buf, 0x00);
-                               store_byte(go->active_buf, 0x01);
-                               go->state = STATE_FF;
-                               break;
-                       default:
-                               store_byte(go->active_buf, 0x00);
-                               store_byte(go->active_buf, 0x00);
-                               store_byte(go->active_buf, 0x01);
-                               store_byte(go->active_buf, buf[i]);
-                               go->state = STATE_DATA;
-                               break;
-                       }
-                       break;
-               case STATE_FF:
-                       switch (buf[i]) {
-                       case 0x00:
-                               store_byte(go->active_buf, 0xFF);
-                               go->state = STATE_00;
-                               break;
-                       case 0xFF:
-                               store_byte(go->active_buf, 0xFF);
-                               /* go->state remains STATE_FF */
-                               break;
-                       case 0xD8:
-                               if (go->format == GO7007_FORMAT_MJPEG)
-                                       frame_boundary(go);
-                               /* fall through */
-                       default:
-                               store_byte(go->active_buf, 0xFF);
-                               store_byte(go->active_buf, buf[i]);
-                               go->state = STATE_DATA;
-                               break;
-                       }
-                       break;
-               case STATE_VBI_LEN_A:
-                       go->parse_length = buf[i] << 8;
-                       go->state = STATE_VBI_LEN_B;
-                       break;
-               case STATE_VBI_LEN_B:
-                       go->parse_length |= buf[i];
-                       if (go->parse_length > 0)
-                               go->state = STATE_UNPARSED;
-                       else
-                               go->state = STATE_DATA;
-                       break;
-               case STATE_MODET_MAP:
-                       if (go->parse_length < 204) {
-                               if (go->parse_length & 1) {
-                                       go->modet_word |= buf[i];
-                                       write_bitmap_word(go);
-                               } else
-                                       go->modet_word = buf[i] << 8;
-                       } else if (go->parse_length == 207 && go->active_buf) {
-                               go->active_buf->modet_active = buf[i];
-                       }
-                       if (++go->parse_length == 208)
-                               go->state = STATE_DATA;
-                       break;
-               case STATE_UNPARSED:
-                       if (--go->parse_length == 0)
-                               go->state = STATE_DATA;
-                       break;
-               }
-       }
-
-       spin_unlock(&go->spinlock);
-}
-EXPORT_SYMBOL(go7007_parse_video_stream);
-
-/*
- * Allocate a new go7007 struct.  Used by the hardware-specific probe.
- */
-struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev)
-{
-       struct go7007 *go;
-       int i;
-
-       go = kmalloc(sizeof(struct go7007), GFP_KERNEL);
-       if (go == NULL)
-               return NULL;
-       go->dev = dev;
-       go->board_info = board;
-       go->board_id = 0;
-       go->tuner_type = -1;
-       go->channel_number = 0;
-       go->name[0] = 0;
-       mutex_init(&go->hw_lock);
-       init_waitqueue_head(&go->frame_waitq);
-       spin_lock_init(&go->spinlock);
-       go->video_dev = NULL;
-       go->ref_count = 0;
-       go->status = STATUS_INIT;
-       memset(&go->i2c_adapter, 0, sizeof(go->i2c_adapter));
-       go->i2c_adapter_online = 0;
-       go->interrupt_available = 0;
-       init_waitqueue_head(&go->interrupt_waitq);
-       go->in_use = 0;
-       go->input = 0;
-       if (board->sensor_flags & GO7007_SENSOR_TV) {
-               go->standard = GO7007_STD_NTSC;
-               go->width = 720;
-               go->height = 480;
-               go->sensor_framerate = 30000;
-       } else {
-               go->standard = GO7007_STD_OTHER;
-               go->width = board->sensor_width;
-               go->height = board->sensor_height;
-               go->sensor_framerate = board->sensor_framerate;
-       }
-       go->encoder_v_offset = board->sensor_v_offset;
-       go->encoder_h_offset = board->sensor_h_offset;
-       go->encoder_h_halve = 0;
-       go->encoder_v_halve = 0;
-       go->encoder_subsample = 0;
-       go->streaming = 0;
-       go->format = GO7007_FORMAT_MJPEG;
-       go->bitrate = 1500000;
-       go->fps_scale = 1;
-       go->pali = 0;
-       go->aspect_ratio = GO7007_RATIO_1_1;
-       go->gop_size = 0;
-       go->ipb = 0;
-       go->closed_gop = 0;
-       go->repeat_seqhead = 0;
-       go->seq_header_enable = 0;
-       go->gop_header_enable = 0;
-       go->dvd_mode = 0;
-       go->interlace_coding = 0;
-       for (i = 0; i < 4; ++i)
-               go->modet[i].enable = 0;
-       for (i = 0; i < 1624; ++i)
-               go->modet_map[i] = 0;
-       go->audio_deliver = NULL;
-       go->audio_enabled = 0;
-       INIT_LIST_HEAD(&go->stream);
-
-       return go;
-}
-EXPORT_SYMBOL(go7007_alloc);
-
-/*
- * Detach and unregister the encoder.  The go7007 struct won't be freed
- * until v4l2 finishes releasing its resources and all associated fds are
- * closed by applications.
- */
-void go7007_remove(struct go7007 *go)
-{
-       if (go->i2c_adapter_online) {
-               if (i2c_del_adapter(&go->i2c_adapter) == 0)
-                       go->i2c_adapter_online = 0;
-               else
-                       v4l2_err(&go->v4l2_dev,
-                               "error removing I2C adapter!\n");
-       }
-
-       if (go->audio_enabled)
-               go7007_snd_remove(go);
-       go7007_v4l2_remove(go);
-}
-EXPORT_SYMBOL(go7007_remove);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/go7007-fw.c b/drivers/staging/go7007/go7007-fw.c
deleted file mode 100644 (file)
index c9a6409..0000000
+++ /dev/null
@@ -1,1636 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-/*
- * This file contains code to generate a firmware image for the GO7007SB
- * encoder.  Much of the firmware is read verbatim from a file, but some of
- * it concerning bitrate control and other things that can be configured at
- * run-time are generated dynamically.  Note that the format headers
- * generated here do not affect the functioning of the encoder; they are
- * merely parroted back to the host at the start of each frame.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/mm.h>
-#include <linux/device.h>
-#include <linux/i2c.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-
-#include "go7007-priv.h"
-
-/* Constants used in the source firmware image to describe code segments */
-
-#define        FLAG_MODE_MJPEG         (1)
-#define        FLAG_MODE_MPEG1         (1<<1)
-#define        FLAG_MODE_MPEG2         (1<<2)
-#define        FLAG_MODE_MPEG4         (1<<3)
-#define        FLAG_MODE_H263          (1<<4)
-#define FLAG_MODE_ALL          (FLAG_MODE_MJPEG | FLAG_MODE_MPEG1 | \
-                                       FLAG_MODE_MPEG2 | FLAG_MODE_MPEG4 | \
-                                       FLAG_MODE_H263)
-#define FLAG_SPECIAL           (1<<8)
-
-#define SPECIAL_FRM_HEAD       0
-#define SPECIAL_BRC_CTRL       1
-#define SPECIAL_CONFIG         2
-#define SPECIAL_SEQHEAD                3
-#define SPECIAL_AV_SYNC                4
-#define SPECIAL_FINAL          5
-#define SPECIAL_AUDIO          6
-#define SPECIAL_MODET          7
-
-/* Little data class for creating MPEG headers bit-by-bit */
-
-struct code_gen {
-       unsigned char *p; /* destination */
-       u32 a; /* collects bits at the top of the variable */
-       int b; /* bit position of most recently-written bit */
-       int len; /* written out so far */
-};
-
-#define CODE_GEN(name, dest) struct code_gen name = { dest, 0, 32, 0 }
-
-#define CODE_ADD(name, val, length) do { \
-       name.b -= (length); \
-       name.a |= (val) << name.b; \
-       while (name.b <= 24) { \
-               *name.p = name.a >> 24; \
-               ++name.p; \
-               name.a <<= 8; \
-               name.b += 8; \
-               name.len += 8; \
-       } \
-} while (0)
-
-#define CODE_LENGTH(name) (name.len + (32 - name.b))
-
-/* Tables for creating the bitrate control data */
-
-static const s16 converge_speed_ip[101] = {
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-       1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
-       2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
-       3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
-       5, 5, 5, 6, 6, 6, 7, 7, 8, 8,
-       9, 10, 10, 11, 12, 13, 14, 15, 16, 17,
-       19, 20, 22, 23, 25, 27, 30, 32, 35, 38,
-       41, 45, 49, 53, 58, 63, 69, 76, 83, 91,
-       100
-};
-
-static const s16 converge_speed_ipb[101] = {
-       3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-       3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-       3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
-       4, 4, 4, 4, 5, 5, 5, 5, 5, 6,
-       6, 6, 6, 7, 7, 7, 7, 8, 8, 9,
-       9, 9, 10, 10, 11, 12, 12, 13, 14, 14,
-       15, 16, 17, 18, 19, 20, 22, 23, 25, 26,
-       28, 30, 32, 34, 37, 40, 42, 46, 49, 53,
-       57, 61, 66, 71, 77, 83, 90, 97, 106, 115,
-       125, 135, 147, 161, 175, 191, 209, 228, 249, 273,
-       300
-};
-
-static const s16 LAMBDA_table[4][101] = {
-       {       16, 16, 16, 16, 17, 17, 17, 18, 18, 18,
-               19, 19, 19, 20, 20, 20, 21, 21, 22, 22,
-               22, 23, 23, 24, 24, 25, 25, 25, 26, 26,
-               27, 27, 28, 28, 29, 29, 30, 31, 31, 32,
-               32, 33, 33, 34, 35, 35, 36, 37, 37, 38,
-               39, 39, 40, 41, 42, 42, 43, 44, 45, 46,
-               46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
-               56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
-               67, 68, 69, 70, 72, 73, 74, 76, 77, 78,
-               80, 81, 83, 84, 86, 87, 89, 90, 92, 94,
-               96
-       },
-       {
-               20, 20, 20, 21, 21, 21, 22, 22, 23, 23,
-               23, 24, 24, 25, 25, 26, 26, 27, 27, 28,
-               28, 29, 29, 30, 30, 31, 31, 32, 33, 33,
-               34, 34, 35, 36, 36, 37, 38, 38, 39, 40,
-               40, 41, 42, 43, 43, 44, 45, 46, 47, 48,
-               48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
-               58, 59, 60, 61, 62, 64, 65, 66, 67, 68,
-               70, 71, 72, 73, 75, 76, 78, 79, 80, 82,
-               83, 85, 86, 88, 90, 91, 93, 95, 96, 98,
-               100, 102, 103, 105, 107, 109, 111, 113, 115, 117,
-               120
-       },
-       {
-               24, 24, 24, 25, 25, 26, 26, 27, 27, 28,
-               28, 29, 29, 30, 30, 31, 31, 32, 33, 33,
-               34, 34, 35, 36, 36, 37, 38, 38, 39, 40,
-               41, 41, 42, 43, 44, 44, 45, 46, 47, 48,
-               49, 50, 50, 51, 52, 53, 54, 55, 56, 57,
-               58, 59, 60, 62, 63, 64, 65, 66, 67, 69,
-               70, 71, 72, 74, 75, 76, 78, 79, 81, 82,
-               84, 85, 87, 88, 90, 92, 93, 95, 97, 98,
-               100, 102, 104, 106, 108, 110, 112, 114, 116, 118,
-               120, 122, 124, 127, 129, 131, 134, 136, 138, 141,
-               144
-       },
-       {
-               32, 32, 33, 33, 34, 34, 35, 36, 36, 37,
-               38, 38, 39, 40, 41, 41, 42, 43, 44, 44,
-               45, 46, 47, 48, 49, 50, 50, 51, 52, 53,
-               54, 55, 56, 57, 58, 59, 60, 62, 63, 64,
-               65, 66, 67, 69, 70, 71, 72, 74, 75, 76,
-               78, 79, 81, 82, 84, 85, 87, 88, 90, 92,
-               93, 95, 97, 98, 100, 102, 104, 106, 108, 110,
-               112, 114, 116, 118, 120, 122, 124, 127, 129, 131,
-               134, 136, 139, 141, 144, 146, 149, 152, 154, 157,
-               160, 163, 166, 169, 172, 175, 178, 181, 185, 188,
-               192
-       }
-};
-
-/* MPEG blank frame generation tables */
-
-enum mpeg_frame_type {
-       PFRAME,
-       BFRAME_PRE,
-       BFRAME_POST,
-       BFRAME_BIDIR,
-       BFRAME_EMPTY
-};
-
-static const u32 addrinctab[33][2] = {
-       { 0x01, 1 },    { 0x03, 3 },    { 0x02, 3 },    { 0x03, 4 },
-       { 0x02, 4 },    { 0x03, 5 },    { 0x02, 5 },    { 0x07, 7 },
-       { 0x06, 7 },    { 0x0b, 8 },    { 0x0a, 8 },    { 0x09, 8 },
-       { 0x08, 8 },    { 0x07, 8 },    { 0x06, 8 },    { 0x17, 10 },
-       { 0x16, 10 },   { 0x15, 10 },   { 0x14, 10 },   { 0x13, 10 },
-       { 0x12, 10 },   { 0x23, 11 },   { 0x22, 11 },   { 0x21, 11 },
-       { 0x20, 11 },   { 0x1f, 11 },   { 0x1e, 11 },   { 0x1d, 11 },
-       { 0x1c, 11 },   { 0x1b, 11 },   { 0x1a, 11 },   { 0x19, 11 },
-       { 0x18, 11 }
-};
-
-/* Standard JPEG tables */
-
-static const u8 default_intra_quant_table[] = {
-        8, 16, 19, 22, 26, 27, 29, 34,
-       16, 16, 22, 24, 27, 29, 34, 37,
-       19, 22, 26, 27, 29, 34, 34, 38,
-       22, 22, 26, 27, 29, 34, 37, 40,
-       22, 26, 27, 29, 32, 35, 40, 48,
-       26, 27, 29, 32, 35, 40, 48, 58,
-       26, 27, 29, 34, 38, 46, 56, 69,
-       27, 29, 35, 38, 46, 56, 69, 83
-};
-
-static const u8 bits_dc_luminance[] = {
-       0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
-};
-
-static const u8 val_dc_luminance[] = {
-       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
-};
-
-static const u8 bits_dc_chrominance[] = {
-       0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
-};
-
-static const u8 val_dc_chrominance[] = {
-       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
-};
-
-static const u8 bits_ac_luminance[] = {
-       0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
-};
-
-static const u8 val_ac_luminance[] = {
-       0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
-       0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
-       0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
-       0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
-       0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
-       0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
-       0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
-       0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
-       0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
-       0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
-       0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
-       0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
-       0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
-       0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
-       0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
-       0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
-       0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
-       0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
-       0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
-       0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
-       0xf9, 0xfa
-};
-
-static const u8 bits_ac_chrominance[] = {
-       0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
-};
-
-static const u8 val_ac_chrominance[] = {
-       0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
-       0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
-       0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
-       0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
-       0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
-       0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
-       0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
-       0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
-       0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
-       0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
-       0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
-       0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
-       0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
-       0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
-       0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
-       0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
-       0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
-       0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
-       0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
-       0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
-       0xf9, 0xfa
-};
-
-/* Zig-zag mapping for quant table
- *
- * OK, let's do this mapping on the actual table above so it doesn't have
- * to be done on the fly.
- */
-static const int zz[64] = {
-       0,   1,  8, 16,  9,  2,  3, 10, 17, 24, 32, 25, 18, 11,  4,  5,
-       12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13,  6,  7, 14, 21, 28,
-       35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
-       58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
-};
-
-static int copy_packages(__le16 *dest, u16 *src, int pkg_cnt, int space)
-{
-       int i, cnt = pkg_cnt * 32;
-
-       if (space < cnt)
-               return -1;
-
-       for (i = 0; i < cnt; ++i)
-               dest[i] = cpu_to_le16p(src + i);
-
-       return cnt;
-}
-
-static int mjpeg_frame_header(struct go7007 *go, unsigned char *buf, int q)
-{
-       int i, p = 0;
-
-       buf[p++] = 0xff;
-       buf[p++] = 0xd8;
-       buf[p++] = 0xff;
-       buf[p++] = 0xdb;
-       buf[p++] = 0;
-       buf[p++] = 2 + 65;
-       buf[p++] = 0;
-       buf[p++] = default_intra_quant_table[0];
-       for (i = 1; i < 64; ++i)
-               /* buf[p++] = (default_intra_quant_table[i] * q) >> 3; */
-               buf[p++] = (default_intra_quant_table[zz[i]] * q) >> 3;
-       buf[p++] = 0xff;
-       buf[p++] = 0xc0;
-       buf[p++] = 0;
-       buf[p++] = 17;
-       buf[p++] = 8;
-       buf[p++] = go->height >> 8;
-       buf[p++] = go->height & 0xff;
-       buf[p++] = go->width >> 8;
-       buf[p++] = go->width & 0xff;
-       buf[p++] = 3;
-       buf[p++] = 1;
-       buf[p++] = 0x22;
-       buf[p++] = 0;
-       buf[p++] = 2;
-       buf[p++] = 0x11;
-       buf[p++] = 0;
-       buf[p++] = 3;
-       buf[p++] = 0x11;
-       buf[p++] = 0;
-       buf[p++] = 0xff;
-       buf[p++] = 0xc4;
-       buf[p++] = 418 >> 8;
-       buf[p++] = 418 & 0xff;
-       buf[p++] = 0x00;
-       memcpy(buf + p, bits_dc_luminance + 1, 16);
-       p += 16;
-       memcpy(buf + p, val_dc_luminance, sizeof(val_dc_luminance));
-       p += sizeof(val_dc_luminance);
-       buf[p++] = 0x01;
-       memcpy(buf + p, bits_dc_chrominance + 1, 16);
-       p += 16;
-       memcpy(buf + p, val_dc_chrominance, sizeof(val_dc_chrominance));
-       p += sizeof(val_dc_chrominance);
-       buf[p++] = 0x10;
-       memcpy(buf + p, bits_ac_luminance + 1, 16);
-       p += 16;
-       memcpy(buf + p, val_ac_luminance, sizeof(val_ac_luminance));
-       p += sizeof(val_ac_luminance);
-       buf[p++] = 0x11;
-       memcpy(buf + p, bits_ac_chrominance + 1, 16);
-       p += 16;
-       memcpy(buf + p, val_ac_chrominance, sizeof(val_ac_chrominance));
-       p += sizeof(val_ac_chrominance);
-       buf[p++] = 0xff;
-       buf[p++] = 0xda;
-       buf[p++] = 0;
-       buf[p++] = 12;
-       buf[p++] = 3;
-       buf[p++] = 1;
-       buf[p++] = 0x00;
-       buf[p++] = 2;
-       buf[p++] = 0x11;
-       buf[p++] = 3;
-       buf[p++] = 0x11;
-       buf[p++] = 0;
-       buf[p++] = 63;
-       buf[p++] = 0;
-       return p;
-}
-
-static int gen_mjpeghdr_to_package(struct go7007 *go, __le16 *code, int space)
-{
-       u8 *buf;
-       u16 mem = 0x3e00;
-       unsigned int addr = 0x19;
-       int size = 0, i, off = 0, chunk;
-
-       buf = kzalloc(4096, GFP_KERNEL);
-       if (buf == NULL) {
-               printk(KERN_ERR "go7007: unable to allocate 4096 bytes for "
-                               "firmware construction\n");
-               return -1;
-       }
-
-       for (i = 1; i < 32; ++i) {
-               mjpeg_frame_header(go, buf + size, i);
-               size += 80;
-       }
-       chunk = mjpeg_frame_header(go, buf + size, 1);
-       memmove(buf + size, buf + size + 80, chunk - 80);
-       size += chunk - 80;
-
-       for (i = 0; i < size; i += chunk * 2) {
-               if (space - off < 32) {
-                       off = -1;
-                       goto done;
-               }
-
-               code[off + 1] = __cpu_to_le16(0x8000 | mem);
-
-               chunk = 28;
-               if (mem + chunk > 0x4000)
-                       chunk = 0x4000 - mem;
-               if (i + 2 * chunk > size)
-                       chunk = (size - i) / 2;
-
-               if (chunk < 28) {
-                       code[off] = __cpu_to_le16(0x4000 | chunk);
-                       code[off + 31] = __cpu_to_le16(addr++);
-                       mem = 0x3e00;
-               } else {
-                       code[off] = __cpu_to_le16(0x1000 | 28);
-                       code[off + 31] = 0;
-                       mem += 28;
-               }
-
-               memcpy(&code[off + 2], buf + i, chunk * 2);
-               off += 32;
-       }
-done:
-       kfree(buf);
-       return off;
-}
-
-static int mpeg1_frame_header(struct go7007 *go, unsigned char *buf,
-               int modulo, int pict_struct, enum mpeg_frame_type frame)
-{
-       int i, j, mb_code, mb_len;
-       int rows = go->interlace_coding ? go->height / 32 : go->height / 16;
-       CODE_GEN(c, buf + 6);
-
-       switch (frame) {
-       case PFRAME:
-               mb_code = 0x1;
-               mb_len = 3;
-               break;
-       case BFRAME_PRE:
-               mb_code = 0x2;
-               mb_len = 4;
-               break;
-       case BFRAME_POST:
-               mb_code = 0x2;
-               mb_len = 3;
-               break;
-       case BFRAME_BIDIR:
-               mb_code = 0x2;
-               mb_len = 2;
-               break;
-       default: /* keep the compiler happy */
-               mb_code = mb_len = 0;
-               break;
-       }
-
-       CODE_ADD(c, frame == PFRAME ? 0x2 : 0x3, 13);
-       CODE_ADD(c, 0xffff, 16);
-       CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4);
-       if (frame != PFRAME)
-               CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4);
-       else
-               CODE_ADD(c, 0, 4); /* Is this supposed to be here?? */
-       CODE_ADD(c, 0, 3); /* What is this?? */
-       /* Byte-align with zeros */
-       j = 8 - (CODE_LENGTH(c) % 8);
-       if (j != 8)
-               CODE_ADD(c, 0, j);
-
-       if (go->format == GO7007_FORMAT_MPEG2) {
-               CODE_ADD(c, 0x1, 24);
-               CODE_ADD(c, 0xb5, 8);
-               CODE_ADD(c, 0x844, 12);
-               CODE_ADD(c, frame == PFRAME ? 0xff : 0x44, 8);
-               if (go->interlace_coding) {
-                       CODE_ADD(c, pict_struct, 4);
-                       if (go->dvd_mode)
-                               CODE_ADD(c, 0x000, 11);
-                       else
-                               CODE_ADD(c, 0x200, 11);
-               } else {
-                       CODE_ADD(c, 0x3, 4);
-                       CODE_ADD(c, 0x20c, 11);
-               }
-               /* Byte-align with zeros */
-               j = 8 - (CODE_LENGTH(c) % 8);
-               if (j != 8)
-                       CODE_ADD(c, 0, j);
-       }
-
-       for (i = 0; i < rows; ++i) {
-               CODE_ADD(c, 1, 24);
-               CODE_ADD(c, i + 1, 8);
-               CODE_ADD(c, 0x2, 6);
-               CODE_ADD(c, 0x1, 1);
-               CODE_ADD(c, mb_code, mb_len);
-               if (go->interlace_coding) {
-                       CODE_ADD(c, 0x1, 2);
-                       CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1);
-               }
-               if (frame == BFRAME_BIDIR) {
-                       CODE_ADD(c, 0x3, 2);
-                       if (go->interlace_coding)
-                               CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1);
-               }
-               CODE_ADD(c, 0x3, 2);
-               for (j = (go->width >> 4) - 2; j >= 33; j -= 33)
-                       CODE_ADD(c, 0x8, 11);
-               CODE_ADD(c, addrinctab[j][0], addrinctab[j][1]);
-               CODE_ADD(c, mb_code, mb_len);
-               if (go->interlace_coding) {
-                       CODE_ADD(c, 0x1, 2);
-                       CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1);
-               }
-               if (frame == BFRAME_BIDIR) {
-                       CODE_ADD(c, 0x3, 2);
-                       if (go->interlace_coding)
-                               CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1);
-               }
-               CODE_ADD(c, 0x3, 2);
-
-               /* Byte-align with zeros */
-               j = 8 - (CODE_LENGTH(c) % 8);
-               if (j != 8)
-                       CODE_ADD(c, 0, j);
-       }
-
-       i = CODE_LENGTH(c) + 4 * 8;
-       buf[2] = 0x00;
-       buf[3] = 0x00;
-       buf[4] = 0x01;
-       buf[5] = 0x00;
-       return i;
-}
-
-static int mpeg1_sequence_header(struct go7007 *go, unsigned char *buf, int ext)
-{
-       int i, aspect_ratio, picture_rate;
-       CODE_GEN(c, buf + 6);
-
-       if (go->format == GO7007_FORMAT_MPEG1) {
-               switch (go->aspect_ratio) {
-               case GO7007_RATIO_4_3:
-                       aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2;
-                       break;
-               case GO7007_RATIO_16_9:
-                       aspect_ratio = go->standard == GO7007_STD_NTSC ? 5 : 4;
-                       break;
-               default:
-                       aspect_ratio = 1;
-                       break;
-               }
-       } else {
-               switch (go->aspect_ratio) {
-               case GO7007_RATIO_4_3:
-                       aspect_ratio = 2;
-                       break;
-               case GO7007_RATIO_16_9:
-                       aspect_ratio = 3;
-                       break;
-               default:
-                       aspect_ratio = 1;
-                       break;
-               }
-       }
-       switch (go->sensor_framerate) {
-       case 24000:
-               picture_rate = 1;
-               break;
-       case 24024:
-               picture_rate = 2;
-               break;
-       case 25025:
-               picture_rate = go->interlace_coding ? 6 : 3;
-               break;
-       case 30000:
-               picture_rate = go->interlace_coding ? 7 : 4;
-               break;
-       case 30030:
-               picture_rate = go->interlace_coding ? 8 : 5;
-               break;
-       default:
-               picture_rate = 5; /* 30 fps seems like a reasonable default */
-               break;
-       }
-
-       CODE_ADD(c, go->width, 12);
-       CODE_ADD(c, go->height, 12);
-       CODE_ADD(c, aspect_ratio, 4);
-       CODE_ADD(c, picture_rate, 4);
-       CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 20000 : 0x3ffff, 18);
-       CODE_ADD(c, 1, 1);
-       CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 112 : 20, 10);
-       CODE_ADD(c, 0, 3);
-
-       /* Byte-align with zeros */
-       i = 8 - (CODE_LENGTH(c) % 8);
-       if (i != 8)
-               CODE_ADD(c, 0, i);
-
-       if (go->format == GO7007_FORMAT_MPEG2) {
-               CODE_ADD(c, 0x1, 24);
-               CODE_ADD(c, 0xb5, 8);
-               CODE_ADD(c, 0x148, 12);
-               if (go->interlace_coding)
-                       CODE_ADD(c, 0x20001, 20);
-               else
-                       CODE_ADD(c, 0xa0001, 20);
-               CODE_ADD(c, 0, 16);
-
-               /* Byte-align with zeros */
-               i = 8 - (CODE_LENGTH(c) % 8);
-               if (i != 8)
-                       CODE_ADD(c, 0, i);
-
-               if (ext) {
-                       CODE_ADD(c, 0x1, 24);
-                       CODE_ADD(c, 0xb52, 12);
-                       CODE_ADD(c, go->standard == GO7007_STD_NTSC ? 2 : 1, 3);
-                       CODE_ADD(c, 0x105, 9);
-                       CODE_ADD(c, 0x505, 16);
-                       CODE_ADD(c, go->width, 14);
-                       CODE_ADD(c, 1, 1);
-                       CODE_ADD(c, go->height, 14);
-
-                       /* Byte-align with zeros */
-                       i = 8 - (CODE_LENGTH(c) % 8);
-                       if (i != 8)
-                               CODE_ADD(c, 0, i);
-               }
-       }
-
-       i = CODE_LENGTH(c) + 4 * 8;
-       buf[0] = i & 0xff;
-       buf[1] = i >> 8;
-       buf[2] = 0x00;
-       buf[3] = 0x00;
-       buf[4] = 0x01;
-       buf[5] = 0xb3;
-       return i;
-}
-
-static int gen_mpeg1hdr_to_package(struct go7007 *go,
-                                       __le16 *code, int space, int *framelen)
-{
-       u8 *buf;
-       u16 mem = 0x3e00;
-       unsigned int addr = 0x19;
-       int i, off = 0, chunk;
-
-       buf = kzalloc(5120, GFP_KERNEL);
-       if (buf == NULL) {
-               printk(KERN_ERR "go7007: unable to allocate 5120 bytes for "
-                               "firmware construction\n");
-               return -1;
-       }
-       framelen[0] = mpeg1_frame_header(go, buf, 0, 1, PFRAME);
-       if (go->interlace_coding)
-               framelen[0] += mpeg1_frame_header(go, buf + framelen[0] / 8,
-                                                       0, 2, PFRAME);
-       buf[0] = framelen[0] & 0xff;
-       buf[1] = framelen[0] >> 8;
-       i = 368;
-       framelen[1] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_PRE);
-       if (go->interlace_coding)
-               framelen[1] += mpeg1_frame_header(go, buf + i + framelen[1] / 8,
-                                                       0, 2, BFRAME_PRE);
-       buf[i] = framelen[1] & 0xff;
-       buf[i + 1] = framelen[1] >> 8;
-       i += 1632;
-       framelen[2] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_POST);
-       if (go->interlace_coding)
-               framelen[2] += mpeg1_frame_header(go, buf + i + framelen[2] / 8,
-                                                       0, 2, BFRAME_POST);
-       buf[i] = framelen[2] & 0xff;
-       buf[i + 1] = framelen[2] >> 8;
-       i += 1432;
-       framelen[3] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_BIDIR);
-       if (go->interlace_coding)
-               framelen[3] += mpeg1_frame_header(go, buf + i + framelen[3] / 8,
-                                                       0, 2, BFRAME_BIDIR);
-       buf[i] = framelen[3] & 0xff;
-       buf[i + 1] = framelen[3] >> 8;
-       i += 1632 + 16;
-       mpeg1_sequence_header(go, buf + i, 0);
-       i += 40;
-       for (i = 0; i < 5120; i += chunk * 2) {
-               if (space - off < 32) {
-                       off = -1;
-                       goto done;
-               }
-
-               code[off + 1] = __cpu_to_le16(0x8000 | mem);
-
-               chunk = 28;
-               if (mem + chunk > 0x4000)
-                       chunk = 0x4000 - mem;
-               if (i + 2 * chunk > 5120)
-                       chunk = (5120 - i) / 2;
-
-               if (chunk < 28) {
-                       code[off] = __cpu_to_le16(0x4000 | chunk);
-                       code[off + 31] = __cpu_to_le16(addr);
-                       if (mem + chunk == 0x4000) {
-                               mem = 0x3e00;
-                               ++addr;
-                       }
-               } else {
-                       code[off] = __cpu_to_le16(0x1000 | 28);
-                       code[off + 31] = 0;
-                       mem += 28;
-               }
-
-               memcpy(&code[off + 2], buf + i, chunk * 2);
-               off += 32;
-       }
-done:
-       kfree(buf);
-       return off;
-}
-
-static int vti_bitlen(struct go7007 *go)
-{
-       unsigned int i, max_time_incr = go->sensor_framerate / go->fps_scale;
-
-       for (i = 31; (max_time_incr & ((1 << i) - 1)) == max_time_incr; --i);
-       return i + 1;
-}
-
-static int mpeg4_frame_header(struct go7007 *go, unsigned char *buf,
-               int modulo, enum mpeg_frame_type frame)
-{
-       int i;
-       CODE_GEN(c, buf + 6);
-       int mb_count = (go->width >> 4) * (go->height >> 4);
-
-       CODE_ADD(c, frame == PFRAME ? 0x1 : 0x2, 2);
-       if (modulo)
-               CODE_ADD(c, 0x1, 1);
-       CODE_ADD(c, 0x1, 2);
-       CODE_ADD(c, 0, vti_bitlen(go));
-       CODE_ADD(c, 0x3, 2);
-       if (frame == PFRAME)
-               CODE_ADD(c, 0, 1);
-       CODE_ADD(c, 0xc, 11);
-       if (frame != PFRAME)
-               CODE_ADD(c, 0x4, 3);
-       if (frame != BFRAME_EMPTY) {
-               for (i = 0; i < mb_count; ++i) {
-                       switch (frame) {
-                       case PFRAME:
-                               CODE_ADD(c, 0x1, 1);
-                               break;
-                       case BFRAME_PRE:
-                               CODE_ADD(c, 0x47, 8);
-                               break;
-                       case BFRAME_POST:
-                               CODE_ADD(c, 0x27, 7);
-                               break;
-                       case BFRAME_BIDIR:
-                               CODE_ADD(c, 0x5f, 8);
-                               break;
-                       case BFRAME_EMPTY: /* keep compiler quiet */
-                               break;
-                       }
-               }
-       }
-
-       /* Byte-align with a zero followed by ones */
-       i = 8 - (CODE_LENGTH(c) % 8);
-       CODE_ADD(c, 0, 1);
-       CODE_ADD(c, (1 << (i - 1)) - 1, i - 1);
-
-       i = CODE_LENGTH(c) + 4 * 8;
-       buf[0] = i & 0xff;
-       buf[1] = i >> 8;
-       buf[2] = 0x00;
-       buf[3] = 0x00;
-       buf[4] = 0x01;
-       buf[5] = 0xb6;
-       return i;
-}
-
-static int mpeg4_sequence_header(struct go7007 *go, unsigned char *buf, int ext)
-{
-       const unsigned char head[] = { 0x00, 0x00, 0x01, 0xb0, go->pali,
-               0x00, 0x00, 0x01, 0xb5, 0x09,
-               0x00, 0x00, 0x01, 0x00,
-               0x00, 0x00, 0x01, 0x20, };
-       int i, aspect_ratio;
-       int fps = go->sensor_framerate / go->fps_scale;
-       CODE_GEN(c, buf + 2 + sizeof(head));
-
-       switch (go->aspect_ratio) {
-       case GO7007_RATIO_4_3:
-               aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2;
-               break;
-       case GO7007_RATIO_16_9:
-               aspect_ratio = go->standard == GO7007_STD_NTSC ? 5 : 4;
-               break;
-       default:
-               aspect_ratio = 1;
-               break;
-       }
-
-       memcpy(buf + 2, head, sizeof(head));
-       CODE_ADD(c, 0x191, 17);
-       CODE_ADD(c, aspect_ratio, 4);
-       CODE_ADD(c, 0x1, 4);
-       CODE_ADD(c, fps, 16);
-       CODE_ADD(c, 0x3, 2);
-       CODE_ADD(c, 1001, vti_bitlen(go));
-       CODE_ADD(c, 1, 1);
-       CODE_ADD(c, go->width, 13);
-       CODE_ADD(c, 1, 1);
-       CODE_ADD(c, go->height, 13);
-       CODE_ADD(c, 0x2830, 14);
-
-       /* Byte-align */
-       i = 8 - (CODE_LENGTH(c) % 8);
-       CODE_ADD(c, 0, 1);
-       CODE_ADD(c, (1 << (i - 1)) - 1, i - 1);
-
-       i = CODE_LENGTH(c) + sizeof(head) * 8;
-       buf[0] = i & 0xff;
-       buf[1] = i >> 8;
-       return i;
-}
-
-static int gen_mpeg4hdr_to_package(struct go7007 *go,
-                                       __le16 *code, int space, int *framelen)
-{
-       u8 *buf;
-       u16 mem = 0x3e00;
-       unsigned int addr = 0x19;
-       int i, off = 0, chunk;
-
-       buf = kzalloc(5120, GFP_KERNEL);
-       if (buf == NULL) {
-               printk(KERN_ERR "go7007: unable to allocate 5120 bytes for "
-                               "firmware construction\n");
-               return -1;
-       }
-       framelen[0] = mpeg4_frame_header(go, buf, 0, PFRAME);
-       i = 368;
-       framelen[1] = mpeg4_frame_header(go, buf + i, 0, BFRAME_PRE);
-       i += 1632;
-       framelen[2] = mpeg4_frame_header(go, buf + i, 0, BFRAME_POST);
-       i += 1432;
-       framelen[3] = mpeg4_frame_header(go, buf + i, 0, BFRAME_BIDIR);
-       i += 1632;
-       mpeg4_frame_header(go, buf + i, 0, BFRAME_EMPTY);
-       i += 16;
-       mpeg4_sequence_header(go, buf + i, 0);
-       i += 40;
-       for (i = 0; i < 5120; i += chunk * 2) {
-               if (space - off < 32) {
-                       off = -1;
-                       goto done;
-               }
-
-               code[off + 1] = __cpu_to_le16(0x8000 | mem);
-
-               chunk = 28;
-               if (mem + chunk > 0x4000)
-                       chunk = 0x4000 - mem;
-               if (i + 2 * chunk > 5120)
-                       chunk = (5120 - i) / 2;
-
-               if (chunk < 28) {
-                       code[off] = __cpu_to_le16(0x4000 | chunk);
-                       code[off + 31] = __cpu_to_le16(addr);
-                       if (mem + chunk == 0x4000) {
-                               mem = 0x3e00;
-                               ++addr;
-                       }
-               } else {
-                       code[off] = __cpu_to_le16(0x1000 | 28);
-                       code[off + 31] = 0;
-                       mem += 28;
-               }
-
-               memcpy(&code[off + 2], buf + i, chunk * 2);
-               off += 32;
-       }
-       mem = 0x3e00;
-       addr = go->ipb ? 0x14f9 : 0x0af9;
-       memset(buf, 0, 5120);
-       framelen[4] = mpeg4_frame_header(go, buf, 1, PFRAME);
-       i = 368;
-       framelen[5] = mpeg4_frame_header(go, buf + i, 1, BFRAME_PRE);
-       i += 1632;
-       framelen[6] = mpeg4_frame_header(go, buf + i, 1, BFRAME_POST);
-       i += 1432;
-       framelen[7] = mpeg4_frame_header(go, buf + i, 1, BFRAME_BIDIR);
-       i += 1632;
-       mpeg4_frame_header(go, buf + i, 1, BFRAME_EMPTY);
-       i += 16;
-       for (i = 0; i < 5120; i += chunk * 2) {
-               if (space - off < 32) {
-                       off = -1;
-                       goto done;
-               }
-
-               code[off + 1] = __cpu_to_le16(0x8000 | mem);
-
-               chunk = 28;
-               if (mem + chunk > 0x4000)
-                       chunk = 0x4000 - mem;
-               if (i + 2 * chunk > 5120)
-                       chunk = (5120 - i) / 2;
-
-               if (chunk < 28) {
-                       code[off] = __cpu_to_le16(0x4000 | chunk);
-                       code[off + 31] = __cpu_to_le16(addr);
-                       if (mem + chunk == 0x4000) {
-                               mem = 0x3e00;
-                               ++addr;
-                       }
-               } else {
-                       code[off] = __cpu_to_le16(0x1000 | 28);
-                       code[off + 31] = 0;
-                       mem += 28;
-               }
-
-               memcpy(&code[off + 2], buf + i, chunk * 2);
-               off += 32;
-       }
-done:
-       kfree(buf);
-       return off;
-}
-
-static int brctrl_to_package(struct go7007 *go,
-                                       __le16 *code, int space, int *framelen)
-{
-       int converge_speed = 0;
-       int lambda = (go->format == GO7007_FORMAT_MJPEG || go->dvd_mode) ?
-                               100 : 0;
-       int peak_rate = 6 * go->bitrate / 5;
-       int vbv_buffer = go->format == GO7007_FORMAT_MJPEG ?
-                               go->bitrate :
-                               (go->dvd_mode ? 900000 : peak_rate);
-       int fps = go->sensor_framerate / go->fps_scale;
-       int q = 0;
-       /* Bizarre math below depends on rounding errors in division */
-       u32 sgop_expt_addr = go->bitrate / 32 * (go->ipb ? 3 : 1) * 1001 / fps;
-       u32 sgop_peak_addr = peak_rate / 32 * 1001 / fps;
-       u32 total_expt_addr = go->bitrate / 32 * 1000 / fps * (fps / 1000);
-       u32 vbv_alert_addr = vbv_buffer * 3 / (4 * 32);
-       u32 cplx[] = {
-               q > 0 ? sgop_expt_addr * q :
-                       2 * go->width * go->height * (go->ipb ? 6 : 4) / 32,
-               q > 0 ? sgop_expt_addr * q :
-                       2 * go->width * go->height * (go->ipb ? 6 : 4) / 32,
-               q > 0 ? sgop_expt_addr * q :
-                       2 * go->width * go->height * (go->ipb ? 6 : 4) / 32,
-               q > 0 ? sgop_expt_addr * q :
-                       2 * go->width * go->height * (go->ipb ? 6 : 4) / 32,
-       };
-       u32 calc_q = q > 0 ? q : cplx[0] / sgop_expt_addr;
-       u16 pack[] = {
-               0x200e,         0x0000,
-               0xBF20,         go->ipb ? converge_speed_ipb[converge_speed]
-                                       : converge_speed_ip[converge_speed],
-               0xBF21,         go->ipb ? 2 : 0,
-               0xBF22,         go->ipb ? LAMBDA_table[0][lambda / 2 + 50]
-                                       : 32767,
-               0xBF23,         go->ipb ? LAMBDA_table[1][lambda] : 32767,
-               0xBF24,         32767,
-               0xBF25,         lambda > 99 ? 32767 : LAMBDA_table[3][lambda],
-               0xBF26,         sgop_expt_addr & 0x0000FFFF,
-               0xBF27,         sgop_expt_addr >> 16,
-               0xBF28,         sgop_peak_addr & 0x0000FFFF,
-               0xBF29,         sgop_peak_addr >> 16,
-               0xBF2A,         vbv_alert_addr & 0x0000FFFF,
-               0xBF2B,         vbv_alert_addr >> 16,
-               0xBF2C,         0,
-               0xBF2D,         0,
-               0,              0,
-
-               0x200e,         0x0000,
-               0xBF2E,         vbv_alert_addr & 0x0000FFFF,
-               0xBF2F,         vbv_alert_addr >> 16,
-               0xBF30,         cplx[0] & 0x0000FFFF,
-               0xBF31,         cplx[0] >> 16,
-               0xBF32,         cplx[1] & 0x0000FFFF,
-               0xBF33,         cplx[1] >> 16,
-               0xBF34,         cplx[2] & 0x0000FFFF,
-               0xBF35,         cplx[2] >> 16,
-               0xBF36,         cplx[3] & 0x0000FFFF,
-               0xBF37,         cplx[3] >> 16,
-               0xBF38,         0,
-               0xBF39,         0,
-               0xBF3A,         total_expt_addr & 0x0000FFFF,
-               0xBF3B,         total_expt_addr >> 16,
-               0,              0,
-
-               0x200e,         0x0000,
-               0xBF3C,         total_expt_addr & 0x0000FFFF,
-               0xBF3D,         total_expt_addr >> 16,
-               0xBF3E,         0,
-               0xBF3F,         0,
-               0xBF48,         0,
-               0xBF49,         0,
-               0xBF4A,         calc_q < 4 ? 4 : (calc_q > 124 ? 124 : calc_q),
-               0xBF4B,         4,
-               0xBF4C,         0,
-               0xBF4D,         0,
-               0xBF4E,         0,
-               0xBF4F,         0,
-               0xBF50,         0,
-               0xBF51,         0,
-               0,              0,
-
-               0x200e,         0x0000,
-               0xBF40,         sgop_expt_addr & 0x0000FFFF,
-               0xBF41,         sgop_expt_addr >> 16,
-               0xBF42,         0,
-               0xBF43,         0,
-               0xBF44,         0,
-               0xBF45,         0,
-               0xBF46,         (go->width >> 4) * (go->height >> 4),
-               0xBF47,         0,
-               0xBF64,         0,
-               0xBF65,         0,
-               0xBF18,         framelen[4],
-               0xBF19,         framelen[5],
-               0xBF1A,         framelen[6],
-               0xBF1B,         framelen[7],
-               0,              0,
-
-#if 0
-               /* Remove once we don't care about matching */
-               0x200e,         0x0000,
-               0xBF56,         4,
-               0xBF57,         0,
-               0xBF58,         5,
-               0xBF59,         0,
-               0xBF5A,         6,
-               0xBF5B,         0,
-               0xBF5C,         8,
-               0xBF5D,         0,
-               0xBF5E,         1,
-               0xBF5F,         0,
-               0xBF60,         1,
-               0xBF61,         0,
-               0xBF62,         0,
-               0xBF63,         0,
-               0,              0,
-#else
-               0x2008,         0x0000,
-               0xBF56,         4,
-               0xBF57,         0,
-               0xBF58,         5,
-               0xBF59,         0,
-               0xBF5A,         6,
-               0xBF5B,         0,
-               0xBF5C,         8,
-               0xBF5D,         0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-#endif
-
-               0x200e,         0x0000,
-               0xBF10,         0,
-               0xBF11,         0,
-               0xBF12,         0,
-               0xBF13,         0,
-               0xBF14,         0,
-               0xBF15,         0,
-               0xBF16,         0,
-               0xBF17,         0,
-               0xBF7E,         0,
-               0xBF7F,         1,
-               0xBF52,         framelen[0],
-               0xBF53,         framelen[1],
-               0xBF54,         framelen[2],
-               0xBF55,         framelen[3],
-               0,              0,
-       };
-
-       return copy_packages(code, pack, 6, space);
-}
-
-static int config_package(struct go7007 *go, __le16 *code, int space)
-{
-       int fps = go->sensor_framerate / go->fps_scale / 1000;
-       int rows = go->interlace_coding ? go->height / 32 : go->height / 16;
-       int brc_window_size = fps;
-       int q_min = 2, q_max = 31;
-       int THACCoeffSet0 = 0;
-       u16 pack[] = {
-               0x200e,         0x0000,
-               0xc002,         0x14b4,
-               0xc003,         0x28b4,
-               0xc004,         0x3c5a,
-               0xdc05,         0x2a77,
-               0xc6c3,         go->format == GO7007_FORMAT_MPEG4 ? 0 :
-                               (go->format == GO7007_FORMAT_H263 ? 0 : 1),
-               0xc680,         go->format == GO7007_FORMAT_MPEG4 ? 0xf1 :
-                               (go->format == GO7007_FORMAT_H263 ? 0x61 :
-                                                                       0xd3),
-               0xc780,         0x0140,
-               0xe009,         0x0001,
-               0xc60f,         0x0008,
-               0xd4ff,         0x0002,
-               0xe403,         2340,
-               0xe406,         75,
-               0xd411,         0x0001,
-               0xd410,         0xa1d6,
-               0x0001,         0x2801,
-
-               0x200d,         0x0000,
-               0xe402,         0x018b,
-               0xe401,         0x8b01,
-               0xd472,         (go->board_info->sensor_flags &
-                                                       GO7007_SENSOR_TV) &&
-                                               (!go->interlace_coding) ?
-                                       0x01b0 : 0x0170,
-               0xd475,         (go->board_info->sensor_flags &
-                                                       GO7007_SENSOR_TV) &&
-                                               (!go->interlace_coding) ?
-                                       0x0008 : 0x0009,
-               0xc404,         go->interlace_coding ? 0x44 :
-                               (go->format == GO7007_FORMAT_MPEG4 ? 0x11 :
-                               (go->format == GO7007_FORMAT_MPEG1 ? 0x02 :
-                               (go->format == GO7007_FORMAT_MPEG2 ? 0x04 :
-                               (go->format == GO7007_FORMAT_H263  ? 0x08 :
-                                                                    0x20)))),
-               0xbf0a,         (go->format == GO7007_FORMAT_MPEG4 ? 8 :
-                               (go->format == GO7007_FORMAT_MPEG1 ? 1 :
-                               (go->format == GO7007_FORMAT_MPEG2 ? 2 :
-                               (go->format == GO7007_FORMAT_H263 ? 4 : 16)))) |
-                               ((go->repeat_seqhead ? 1 : 0) << 6) |
-                               ((go->dvd_mode ? 1 : 0) << 9) |
-                               ((go->gop_header_enable ? 1 : 0) << 10),
-               0xbf0b,         0,
-               0xdd5a,         go->ipb ? 0x14 : 0x0a,
-               0xbf0c,         0,
-               0xbf0d,         0,
-               0xc683,         THACCoeffSet0,
-               0xc40a,         (go->width << 4) | rows,
-               0xe01a,         go->board_info->hpi_buffer_cap,
-               0,              0,
-               0,              0,
-
-               0x2008,         0,
-               0xe402,         0x88,
-               0xe401,         0x8f01,
-               0xbf6a,         0,
-               0xbf6b,         0,
-               0xbf6c,         0,
-               0xbf6d,         0,
-               0xbf6e,         0,
-               0xbf6f,         0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-
-               0x200e,         0,
-               0xbf66,         brc_window_size,
-               0xbf67,         0,
-               0xbf68,         q_min,
-               0xbf69,         q_max,
-               0xbfe0,         0,
-               0xbfe1,         0,
-               0xbfe2,         0,
-               0xbfe3,         go->ipb ? 3 : 1,
-               0xc031,         go->board_info->sensor_flags &
-                                       GO7007_SENSOR_VBI ? 1 : 0,
-               0xc01c,         0x1f,
-               0xdd8c,         0x15,
-               0xdd94,         0x15,
-               0xdd88,         go->ipb ? 0x1401 : 0x0a01,
-               0xdd90,         go->ipb ? 0x1401 : 0x0a01,
-               0,              0,
-
-               0x200e,         0,
-               0xbfe4,         0,
-               0xbfe5,         0,
-               0xbfe6,         0,
-               0xbfe7,         fps << 8,
-               0xbfe8,         0x3a00,
-               0xbfe9,         0,
-               0xbfea,         0,
-               0xbfeb,         0,
-               0xbfec,         (go->interlace_coding ? 1 << 15 : 0) |
-                                       (go->modet_enable ? 0xa : 0) |
-                                       (go->board_info->sensor_flags &
-                                               GO7007_SENSOR_VBI ? 1 : 0),
-               0xbfed,         0,
-               0xbfee,         0,
-               0xbfef,         0,
-               0xbff0,         go->board_info->sensor_flags &
-                                       GO7007_SENSOR_TV ? 0xf060 : 0xb060,
-               0xbff1,         0,
-               0,              0,
-       };
-
-       return copy_packages(code, pack, 5, space);
-}
-
-static int seqhead_to_package(struct go7007 *go, __le16 *code, int space,
-       int (*sequence_header_func)(struct go7007 *go,
-               unsigned char *buf, int ext))
-{
-       int vop_time_increment_bitlength = vti_bitlen(go);
-       int fps = go->sensor_framerate / go->fps_scale *
-                                       (go->interlace_coding ? 2 : 1);
-       unsigned char buf[40] = { };
-       int len = sequence_header_func(go, buf, 1);
-       u16 pack[] = {
-               0x2006,         0,
-               0xbf08,         fps,
-               0xbf09,         0,
-               0xbff2,         vop_time_increment_bitlength,
-               0xbff3,         (1 << vop_time_increment_bitlength) - 1,
-               0xbfe6,         0,
-               0xbfe7,         (fps / 1000) << 8,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-
-               0x2007,         0,
-               0xc800,         buf[2] << 8 | buf[3],
-               0xc801,         buf[4] << 8 | buf[5],
-               0xc802,         buf[6] << 8 | buf[7],
-               0xc803,         buf[8] << 8 | buf[9],
-               0xc406,         64,
-               0xc407,         len - 64,
-               0xc61b,         1,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-
-               0x200e,         0,
-               0xc808,         buf[10] << 8 | buf[11],
-               0xc809,         buf[12] << 8 | buf[13],
-               0xc80a,         buf[14] << 8 | buf[15],
-               0xc80b,         buf[16] << 8 | buf[17],
-               0xc80c,         buf[18] << 8 | buf[19],
-               0xc80d,         buf[20] << 8 | buf[21],
-               0xc80e,         buf[22] << 8 | buf[23],
-               0xc80f,         buf[24] << 8 | buf[25],
-               0xc810,         buf[26] << 8 | buf[27],
-               0xc811,         buf[28] << 8 | buf[29],
-               0xc812,         buf[30] << 8 | buf[31],
-               0xc813,         buf[32] << 8 | buf[33],
-               0xc814,         buf[34] << 8 | buf[35],
-               0xc815,         buf[36] << 8 | buf[37],
-               0,              0,
-               0,              0,
-               0,              0,
-       };
-
-       return copy_packages(code, pack, 3, space);
-}
-
-static int relative_prime(int big, int little)
-{
-       int remainder;
-
-       while (little != 0) {
-               remainder = big % little;
-               big = little;
-               little = remainder;
-       }
-       return big;
-}
-
-static int avsync_to_package(struct go7007 *go, __le16 *code, int space)
-{
-       int arate = go->board_info->audio_rate * 1001 * go->fps_scale;
-       int ratio = arate / go->sensor_framerate;
-       int adjratio = ratio * 215 / 100;
-       int rprime = relative_prime(go->sensor_framerate,
-                                       arate % go->sensor_framerate);
-       int f1 = (arate % go->sensor_framerate) / rprime;
-       int f2 = (go->sensor_framerate - arate % go->sensor_framerate) / rprime;
-       u16 pack[] = {
-               0x200e,         0,
-               0xbf98,         (u16)((-adjratio) & 0xffff),
-               0xbf99,         (u16)((-adjratio) >> 16),
-               0xbf92,         0,
-               0xbf93,         0,
-               0xbff4,         f1 > f2 ? f1 : f2,
-               0xbff5,         f1 < f2 ? f1 : f2,
-               0xbff6,         f1 < f2 ? ratio : ratio + 1,
-               0xbff7,         f1 > f2 ? ratio : ratio + 1,
-               0xbff8,         0,
-               0xbff9,         0,
-               0xbffa,         adjratio & 0xffff,
-               0xbffb,         adjratio >> 16,
-               0xbf94,         0,
-               0xbf95,         0,
-               0,              0,
-       };
-
-       return copy_packages(code, pack, 1, space);
-}
-
-static int final_package(struct go7007 *go, __le16 *code, int space)
-{
-       int rows = go->interlace_coding ? go->height / 32 : go->height / 16;
-       u16 pack[] = {
-               0x8000,
-               0,
-               0,
-               0,
-               0,
-               0,
-               0,
-               2,
-               ((go->board_info->sensor_flags & GO7007_SENSOR_TV) &&
-                                               (!go->interlace_coding) ?
-                                       (1 << 14) | (1 << 9) : 0) |
-                       ((go->encoder_subsample ? 1 : 0) << 8) |
-                       (go->board_info->sensor_flags &
-                               GO7007_SENSOR_CONFIG_MASK),
-               ((go->encoder_v_halve ? 1 : 0) << 14) |
-                       (go->encoder_v_halve ? rows << 9 : rows << 8) |
-                       (go->encoder_h_halve ? 1 << 6 : 0) |
-                       (go->encoder_h_halve ? go->width >> 3 : go->width >> 4),
-               (1 << 15) | (go->encoder_v_offset << 6) |
-                       (1 << 7) | (go->encoder_h_offset >> 2),
-               (1 << 6),
-               0,
-               0,
-               ((go->fps_scale - 1) << 8) |
-                       (go->board_info->sensor_flags & GO7007_SENSOR_TV ?
-                                               (1 << 7) : 0) |
-                       0x41,
-               go->ipb ? 0xd4c : 0x36b,
-               (rows << 8) | (go->width >> 4),
-               go->format == GO7007_FORMAT_MPEG4 ? 0x0404 : 0,
-               (1 << 15) | ((go->interlace_coding ? 1 : 0) << 13) |
-                       ((go->closed_gop ? 1 : 0) << 12) |
-                       ((go->format == GO7007_FORMAT_MPEG4 ? 1 : 0) << 11) |
-               /*      (1 << 9) |   */
-                       ((go->ipb ? 3 : 0) << 7) |
-                       ((go->modet_enable ? 1 : 0) << 2) |
-                       ((go->dvd_mode ? 1 : 0) << 1) | 1,
-               (go->format == GO7007_FORMAT_MPEG1 ? 0x89a0 :
-                       (go->format == GO7007_FORMAT_MPEG2 ? 0x89a0 :
-                       (go->format == GO7007_FORMAT_MJPEG ? 0x89a0 :
-                       (go->format == GO7007_FORMAT_MPEG4 ? 0x8920 :
-                       (go->format == GO7007_FORMAT_H263 ? 0x8920 : 0))))),
-               go->ipb ? 0x1f15 : 0x1f0b,
-               go->ipb ? 0x0015 : 0x000b,
-               go->ipb ? 0xa800 : 0x5800,
-               0xffff,
-               0x0020 + 0x034b * 0,
-               0x0020 + 0x034b * 1,
-               0x0020 + 0x034b * 2,
-               0x0020 + 0x034b * 3,
-               0x0020 + 0x034b * 4,
-               0x0020 + 0x034b * 5,
-               go->ipb ? (go->gop_size / 3) : go->gop_size,
-               (go->height >> 4) * (go->width >> 4) * 110 / 100,
-       };
-
-       return copy_packages(code, pack, 1, space);
-}
-
-static int audio_to_package(struct go7007 *go, __le16 *code, int space)
-{
-       int clock_config = ((go->board_info->audio_flags &
-                               GO7007_AUDIO_I2S_MASTER ? 1 : 0) << 11) |
-                       ((go->board_info->audio_flags &
-                               GO7007_AUDIO_OKI_MODE ? 1 : 0) << 8) |
-                       (((go->board_info->audio_bclk_div / 4) - 1) << 4) |
-                       (go->board_info->audio_main_div - 1);
-       u16 pack[] = {
-               0x200d,         0,
-               0x9002,         0,
-               0x9002,         0,
-               0x9031,         0,
-               0x9032,         0,
-               0x9033,         0,
-               0x9034,         0,
-               0x9035,         0,
-               0x9036,         0,
-               0x9037,         0,
-               0x9040,         0,
-               0x9000,         clock_config,
-               0x9001,         (go->board_info->audio_flags & 0xffff) |
-                                       (1 << 9),
-               0x9000,         ((go->board_info->audio_flags &
-                                               GO7007_AUDIO_I2S_MASTER ?
-                                               1 : 0) << 10) |
-                                       clock_config,
-               0,              0,
-               0,              0,
-               0x2005,         0,
-               0x9041,         0,
-               0x9042,         256,
-               0x9043,         0,
-               0x9044,         16,
-               0x9045,         16,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-               0,              0,
-       };
-
-       return copy_packages(code, pack, 2, space);
-}
-
-static int modet_to_package(struct go7007 *go, __le16 *code, int space)
-{
-       int ret, mb, i, addr, cnt = 0;
-       u16 pack[32];
-       u16 thresholds[] = {
-               0x200e,         0,
-               0xbf82,         go->modet[0].pixel_threshold,
-               0xbf83,         go->modet[1].pixel_threshold,
-               0xbf84,         go->modet[2].pixel_threshold,
-               0xbf85,         go->modet[3].pixel_threshold,
-               0xbf86,         go->modet[0].motion_threshold,
-               0xbf87,         go->modet[1].motion_threshold,
-               0xbf88,         go->modet[2].motion_threshold,
-               0xbf89,         go->modet[3].motion_threshold,
-               0xbf8a,         go->modet[0].mb_threshold,
-               0xbf8b,         go->modet[1].mb_threshold,
-               0xbf8c,         go->modet[2].mb_threshold,
-               0xbf8d,         go->modet[3].mb_threshold,
-               0xbf8e,         0,
-               0xbf8f,         0,
-               0,              0,
-       };
-
-       ret = copy_packages(code, thresholds, 1, space);
-       if (ret < 0)
-               return -1;
-       cnt += ret;
-
-       addr = 0xbac0;
-       memset(pack, 0, 64);
-       i = 0;
-       for (mb = 0; mb < 1624; ++mb) {
-               pack[i * 2 + 3] <<= 2;
-               pack[i * 2 + 3] |= go->modet_map[mb];
-               if (mb % 8 != 7)
-                       continue;
-               pack[i * 2 + 2] = addr++;
-               ++i;
-               if (i == 10 || mb == 1623) {
-                       pack[0] = 0x2000 | i;
-                       ret = copy_packages(code + cnt, pack, 1, space - cnt);
-                       if (ret < 0)
-                               return -1;
-                       cnt += ret;
-                       i = 0;
-                       memset(pack, 0, 64);
-               }
-               pack[i * 2 + 3] = 0;
-       }
-
-       memset(pack, 0, 64);
-       i = 0;
-       for (addr = 0xbb90; addr < 0xbbfa; ++addr) {
-               pack[i * 2 + 2] = addr;
-               pack[i * 2 + 3] = 0;
-               ++i;
-               if (i == 10 || addr == 0xbbf9) {
-                       pack[0] = 0x2000 | i;
-                       ret = copy_packages(code + cnt, pack, 1, space - cnt);
-                       if (ret < 0)
-                               return -1;
-                       cnt += ret;
-                       i = 0;
-                       memset(pack, 0, 64);
-               }
-       }
-       return cnt;
-}
-
-static int do_special(struct go7007 *go, u16 type, __le16 *code, int space,
-                       int *framelen)
-{
-       switch (type) {
-       case SPECIAL_FRM_HEAD:
-               switch (go->format) {
-               case GO7007_FORMAT_MJPEG:
-                       return gen_mjpeghdr_to_package(go, code, space);
-               case GO7007_FORMAT_MPEG1:
-               case GO7007_FORMAT_MPEG2:
-                       return gen_mpeg1hdr_to_package(go, code, space,
-                                                               framelen);
-               case GO7007_FORMAT_MPEG4:
-                       return gen_mpeg4hdr_to_package(go, code, space,
-                                                               framelen);
-               }
-       case SPECIAL_BRC_CTRL:
-               return brctrl_to_package(go, code, space, framelen);
-       case SPECIAL_CONFIG:
-               return config_package(go, code, space);
-       case SPECIAL_SEQHEAD:
-               switch (go->format) {
-               case GO7007_FORMAT_MPEG1:
-               case GO7007_FORMAT_MPEG2:
-                       return seqhead_to_package(go, code, space,
-                                       mpeg1_sequence_header);
-               case GO7007_FORMAT_MPEG4:
-                       return seqhead_to_package(go, code, space,
-                                       mpeg4_sequence_header);
-               default:
-                       return 0;
-               }
-       case SPECIAL_AV_SYNC:
-               return avsync_to_package(go, code, space);
-       case SPECIAL_FINAL:
-               return final_package(go, code, space);
-       case SPECIAL_AUDIO:
-               return audio_to_package(go, code, space);
-       case SPECIAL_MODET:
-               return modet_to_package(go, code, space);
-       }
-       printk(KERN_ERR
-               "go7007: firmware file contains unsupported feature %04x\n",
-               type);
-       return -1;
-}
-
-int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen)
-{
-       const struct firmware *fw_entry;
-       __le16 *code, *src;
-       int framelen[8] = { }; /* holds the lengths of empty frame templates */
-       int codespace = 64 * 1024, i = 0, srclen, chunk_len, chunk_flags;
-       int mode_flag;
-       int ret;
-
-       switch (go->format) {
-       case GO7007_FORMAT_MJPEG:
-               mode_flag = FLAG_MODE_MJPEG;
-               break;
-       case GO7007_FORMAT_MPEG1:
-               mode_flag = FLAG_MODE_MPEG1;
-               break;
-       case GO7007_FORMAT_MPEG2:
-               mode_flag = FLAG_MODE_MPEG2;
-               break;
-       case GO7007_FORMAT_MPEG4:
-               mode_flag = FLAG_MODE_MPEG4;
-               break;
-       default:
-               return -1;
-       }
-       if (request_firmware(&fw_entry, go->board_info->firmware, go->dev)) {
-               printk(KERN_ERR
-                       "go7007: unable to load firmware from file \"%s\"\n",
-                       go->board_info->firmware);
-               return -1;
-       }
-       code = kzalloc(codespace * 2, GFP_KERNEL);
-       if (code == NULL) {
-               printk(KERN_ERR "go7007: unable to allocate %d bytes for "
-                               "firmware construction\n", codespace * 2);
-               goto fw_failed;
-       }
-       src = (__le16 *)fw_entry->data;
-       srclen = fw_entry->size / 2;
-       while (srclen >= 2) {
-               chunk_flags = __le16_to_cpu(src[0]);
-               chunk_len = __le16_to_cpu(src[1]);
-               if (chunk_len + 2 > srclen) {
-                       printk(KERN_ERR "go7007: firmware file \"%s\" "
-                                       "appears to be corrupted\n",
-                                       go->board_info->firmware);
-                       goto fw_failed;
-               }
-               if (chunk_flags & mode_flag) {
-                       if (chunk_flags & FLAG_SPECIAL) {
-                               ret = do_special(go, __le16_to_cpu(src[2]),
-                                       &code[i], codespace - i, framelen);
-                               if (ret < 0) {
-                                       printk(KERN_ERR "go7007: insufficient "
-                                                       "memory for firmware "
-                                                       "construction\n");
-                                       goto fw_failed;
-                               }
-                               i += ret;
-                       } else {
-                               if (codespace - i < chunk_len) {
-                                       printk(KERN_ERR "go7007: insufficient "
-                                                       "memory for firmware "
-                                                       "construction\n");
-                                       goto fw_failed;
-                               }
-                               memcpy(&code[i], &src[2], chunk_len * 2);
-                               i += chunk_len;
-                       }
-               }
-               srclen -= chunk_len + 2;
-               src += chunk_len + 2;
-       }
-       release_firmware(fw_entry);
-       *fw = (u8 *)code;
-       *fwlen = i * 2;
-       return 0;
-
-fw_failed:
-       kfree(code);
-       release_firmware(fw_entry);
-       return -1;
-}
diff --git a/drivers/staging/go7007/go7007-i2c.c b/drivers/staging/go7007/go7007-i2c.c
deleted file mode 100644 (file)
index b8cfa1a..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/unistd.h>
-#include <linux/time.h>
-#include <linux/device.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <asm/system.h>
-
-#include "go7007-priv.h"
-#include "wis-i2c.h"
-
-/********************* Driver for on-board I2C adapter *********************/
-
-/* #define GO7007_I2C_DEBUG */
-
-#define SPI_I2C_ADDR_BASE              0x1400
-#define STATUS_REG_ADDR                        (SPI_I2C_ADDR_BASE + 0x2)
-#define I2C_CTRL_REG_ADDR              (SPI_I2C_ADDR_BASE + 0x6)
-#define I2C_DEV_UP_ADDR_REG_ADDR       (SPI_I2C_ADDR_BASE + 0x7)
-#define I2C_LO_ADDR_REG_ADDR           (SPI_I2C_ADDR_BASE + 0x8)
-#define I2C_DATA_REG_ADDR              (SPI_I2C_ADDR_BASE + 0x9)
-#define I2C_CLKFREQ_REG_ADDR           (SPI_I2C_ADDR_BASE + 0xa)
-
-#define I2C_STATE_MASK                 0x0007
-#define I2C_READ_READY_MASK            0x0008
-
-/* There is only one I2C port on the TW2804 that feeds all four GO7007 VIPs
- * on the Adlink PCI-MPG24, so access is shared between all of them. */
-static DEFINE_MUTEX(adlink_mpg24_i2c_lock);
-
-static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read,
-               u16 command, int flags, u8 *data)
-{
-       int i, ret = -1;
-       u16 val;
-
-       if (go->status == STATUS_SHUTDOWN)
-               return -1;
-
-#ifdef GO7007_I2C_DEBUG
-       if (read)
-               printk(KERN_DEBUG "go7007-i2c: reading 0x%02x on 0x%02x\n",
-                       command, addr);
-       else
-               printk(KERN_DEBUG
-                       "go7007-i2c: writing 0x%02x to 0x%02x on 0x%02x\n",
-                       *data, command, addr);
-#endif
-
-       mutex_lock(&go->hw_lock);
-
-       if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) {
-               /* Bridge the I2C port on this GO7007 to the shared bus */
-               mutex_lock(&adlink_mpg24_i2c_lock);
-               go7007_write_addr(go, 0x3c82, 0x0020);
-       }
-
-       /* Wait for I2C adapter to be ready */
-       for (i = 0; i < 10; ++i) {
-               if (go7007_read_addr(go, STATUS_REG_ADDR, &val) < 0)
-                       goto i2c_done;
-               if (!(val & I2C_STATE_MASK))
-                       break;
-               msleep(100);
-       }
-       if (i == 10) {
-               printk(KERN_ERR "go7007-i2c: I2C adapter is hung\n");
-               goto i2c_done;
-       }
-
-       /* Set target register (command) */
-       go7007_write_addr(go, I2C_CTRL_REG_ADDR, flags);
-       go7007_write_addr(go, I2C_LO_ADDR_REG_ADDR, command);
-
-       /* If we're writing, send the data and target address and we're done */
-       if (!read) {
-               go7007_write_addr(go, I2C_DATA_REG_ADDR, *data);
-               go7007_write_addr(go, I2C_DEV_UP_ADDR_REG_ADDR,
-                                       (addr << 9) | (command >> 8));
-               ret = 0;
-               goto i2c_done;
-       }
-
-       /* Otherwise, we're reading.  First clear i2c_rx_data_rdy. */
-       if (go7007_read_addr(go, I2C_DATA_REG_ADDR, &val) < 0)
-               goto i2c_done;
-
-       /* Send the target address plus read flag */
-       go7007_write_addr(go, I2C_DEV_UP_ADDR_REG_ADDR,
-                       (addr << 9) | 0x0100 | (command >> 8));
-
-       /* Wait for i2c_rx_data_rdy */
-       for (i = 0; i < 10; ++i) {
-               if (go7007_read_addr(go, STATUS_REG_ADDR, &val) < 0)
-                       goto i2c_done;
-               if (val & I2C_READ_READY_MASK)
-                       break;
-               msleep(100);
-       }
-       if (i == 10) {
-               printk(KERN_ERR "go7007-i2c: I2C adapter is hung\n");
-               goto i2c_done;
-       }
-
-       /* Retrieve the read byte */
-       if (go7007_read_addr(go, I2C_DATA_REG_ADDR, &val) < 0)
-               goto i2c_done;
-       *data = val;
-       ret = 0;
-
-i2c_done:
-       if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) {
-               /* Isolate the I2C port on this GO7007 from the shared bus */
-               go7007_write_addr(go, 0x3c82, 0x0000);
-               mutex_unlock(&adlink_mpg24_i2c_lock);
-       }
-       mutex_unlock(&go->hw_lock);
-       return ret;
-}
-
-static int go7007_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
-               unsigned short flags, char read_write,
-               u8 command, int size, union i2c_smbus_data *data)
-{
-       struct go7007 *go = i2c_get_adapdata(adapter);
-
-       if (size != I2C_SMBUS_BYTE_DATA)
-               return -1;
-       return go7007_i2c_xfer(go, addr, read_write == I2C_SMBUS_READ, command,
-                       flags & I2C_CLIENT_SCCB ? 0x10 : 0x00, &data->byte);
-}
-
-/* VERY LIMITED I2C master xfer function -- only needed because the
- * SMBus functions only support 8-bit commands and the SAA7135 uses
- * 16-bit commands.  The I2C interface on the GO7007, as limited as
- * it is, does support this mode. */
-
-static int go7007_i2c_master_xfer(struct i2c_adapter *adapter,
-                                       struct i2c_msg msgs[], int num)
-{
-       struct go7007 *go = i2c_get_adapdata(adapter);
-       int i;
-
-       for (i = 0; i < num; ++i) {
-               /* We can only do two things here -- write three bytes, or
-                * write two bytes and read one byte. */
-               if (msgs[i].len == 2) {
-                       if (i + 1 == num || msgs[i].addr != msgs[i + 1].addr ||
-                                       (msgs[i].flags & I2C_M_RD) ||
-                                       !(msgs[i + 1].flags & I2C_M_RD) ||
-                                       msgs[i + 1].len != 1)
-                               return -1;
-                       if (go7007_i2c_xfer(go, msgs[i].addr, 1,
-                                       (msgs[i].buf[0] << 8) | msgs[i].buf[1],
-                                       0x01, &msgs[i + 1].buf[0]) < 0)
-                               return -1;
-                       ++i;
-               } else if (msgs[i].len == 3) {
-                       if (msgs[i].flags & I2C_M_RD)
-                               return -1;
-                       if (msgs[i].len != 3)
-                               return -1;
-                       if (go7007_i2c_xfer(go, msgs[i].addr, 0,
-                                       (msgs[i].buf[0] << 8) | msgs[i].buf[1],
-                                       0x01, &msgs[i].buf[2]) < 0)
-                               return -1;
-               } else
-                       return -1;
-       }
-
-       return 0;
-}
-
-static u32 go7007_functionality(struct i2c_adapter *adapter)
-{
-       return I2C_FUNC_SMBUS_BYTE_DATA;
-}
-
-static struct i2c_algorithm go7007_algo = {
-       .smbus_xfer     = go7007_smbus_xfer,
-       .master_xfer    = go7007_i2c_master_xfer,
-       .functionality  = go7007_functionality,
-};
-
-static struct i2c_adapter go7007_adap_templ = {
-       .owner                  = THIS_MODULE,
-       .name                   = "WIS GO7007SB",
-       .algo                   = &go7007_algo,
-};
-
-int go7007_i2c_init(struct go7007 *go)
-{
-       memcpy(&go->i2c_adapter, &go7007_adap_templ,
-                       sizeof(go7007_adap_templ));
-       go->i2c_adapter.dev.parent = go->dev;
-       i2c_set_adapdata(&go->i2c_adapter, go);
-       if (i2c_add_adapter(&go->i2c_adapter) < 0) {
-               printk(KERN_ERR
-                       "go7007-i2c: error: i2c_add_adapter failed\n");
-               return -1;
-       }
-       return 0;
-}
diff --git a/drivers/staging/go7007/go7007-priv.h b/drivers/staging/go7007/go7007-priv.h
deleted file mode 100644 (file)
index b58c394..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-/*
- * This is the private include file for the go7007 driver.  It should not
- * be included by anybody but the driver itself, and especially not by
- * user-space applications.
- */
-
-#include <media/v4l2-device.h>
-
-struct go7007;
-
-/* IDs to activate board-specific support code */
-#define GO7007_BOARDID_MATRIX_II       0
-#define GO7007_BOARDID_MATRIX_RELOAD   1
-#define GO7007_BOARDID_STAR_TREK       2
-#define GO7007_BOARDID_PCI_VOYAGER     3
-#define GO7007_BOARDID_XMEN            4
-#define GO7007_BOARDID_XMEN_II         5
-#define GO7007_BOARDID_XMEN_III                6
-#define GO7007_BOARDID_MATRIX_REV      7
-#define GO7007_BOARDID_PX_M402U                16
-#define GO7007_BOARDID_PX_TV402U_ANY   17 /* need to check tuner model */
-#define GO7007_BOARDID_PX_TV402U_NA    18 /* detected NTSC tuner */
-#define GO7007_BOARDID_PX_TV402U_EU    19 /* detected PAL tuner */
-#define GO7007_BOARDID_PX_TV402U_JP    20 /* detected NTSC-J tuner */
-#define GO7007_BOARDID_LIFEVIEW_LR192  21 /* TV Walker Ultra */
-#define GO7007_BOARDID_ENDURA          22
-#define GO7007_BOARDID_ADLINK_MPG24    23
-#define GO7007_BOARDID_SENSORAY_2250   24 /* Sensoray 2250/2251 */
-
-/* Various characteristics of each board */
-#define GO7007_BOARD_HAS_AUDIO         (1<<0)
-#define GO7007_BOARD_USE_ONBOARD_I2C   (1<<1)
-#define GO7007_BOARD_HAS_TUNER         (1<<2)
-
-/* Characteristics of sensor devices */
-#define GO7007_SENSOR_VALID_POLAR      (1<<0)
-#define GO7007_SENSOR_HREF_POLAR       (1<<1)
-#define GO7007_SENSOR_VREF_POLAR       (1<<2)
-#define GO7007_SENSOR_FIELD_ID_POLAR   (1<<3)
-#define GO7007_SENSOR_BIT_WIDTH                (1<<4)
-#define GO7007_SENSOR_VALID_ENABLE     (1<<5)
-#define GO7007_SENSOR_656              (1<<6)
-#define GO7007_SENSOR_CONFIG_MASK      0x7f
-#define GO7007_SENSOR_TV               (1<<7)
-#define GO7007_SENSOR_VBI              (1<<8)
-#define GO7007_SENSOR_SCALING          (1<<9)
-
-/* Characteristics of audio sensor devices */
-#define GO7007_AUDIO_I2S_MODE_1                (1)
-#define GO7007_AUDIO_I2S_MODE_2                (2)
-#define GO7007_AUDIO_I2S_MODE_3                (3)
-#define GO7007_AUDIO_BCLK_POLAR                (1<<2)
-#define GO7007_AUDIO_WORD_14           (14<<4)
-#define GO7007_AUDIO_WORD_16           (16<<4)
-#define GO7007_AUDIO_ONE_CHANNEL       (1<<11)
-#define GO7007_AUDIO_I2S_MASTER                (1<<16)
-#define GO7007_AUDIO_OKI_MODE          (1<<17)
-
-struct go7007_board_info {
-       char *firmware;
-       unsigned int flags;
-       int hpi_buffer_cap;
-       unsigned int sensor_flags;
-       int sensor_width;
-       int sensor_height;
-       int sensor_framerate;
-       int sensor_h_offset;
-       int sensor_v_offset;
-       unsigned int audio_flags;
-       int audio_rate;
-       int audio_bclk_div;
-       int audio_main_div;
-       int num_i2c_devs;
-       struct {
-               const char *type;
-               int id;
-               int addr;
-       } i2c_devs[4];
-       int num_inputs;
-       struct {
-               int video_input;
-               int audio_input;
-               char *name;
-       } inputs[4];
-};
-
-struct go7007_hpi_ops {
-       int (*interface_reset)(struct go7007 *go);
-       int (*write_interrupt)(struct go7007 *go, int addr, int data);
-       int (*read_interrupt)(struct go7007 *go);
-       int (*stream_start)(struct go7007 *go);
-       int (*stream_stop)(struct go7007 *go);
-       int (*send_firmware)(struct go7007 *go, u8 *data, int len);
-       int (*send_command)(struct go7007 *go, unsigned int cmd, void *arg);
-};
-
-/* The video buffer size must be a multiple of PAGE_SIZE */
-#define        GO7007_BUF_PAGES        (128 * 1024 / PAGE_SIZE)
-#define        GO7007_BUF_SIZE         (GO7007_BUF_PAGES << PAGE_SHIFT)
-
-struct go7007_buffer {
-       struct go7007 *go; /* Reverse reference for VMA ops */
-       int index; /* Reverse reference for DQBUF */
-       enum { BUF_STATE_IDLE, BUF_STATE_QUEUED, BUF_STATE_DONE } state;
-       u32 seq;
-       struct timeval timestamp;
-       struct list_head stream;
-       struct page *pages[GO7007_BUF_PAGES + 1]; /* extra for straddling */
-       unsigned long user_addr;
-       unsigned int page_count;
-       unsigned int offset;
-       unsigned int bytesused;
-       unsigned int frame_offset;
-       u32 modet_active;
-       int mapped;
-};
-
-struct go7007_file {
-       struct go7007 *go;
-       struct mutex lock;
-       int buf_count;
-       struct go7007_buffer *bufs;
-};
-
-#define        GO7007_FORMAT_MJPEG     0
-#define GO7007_FORMAT_MPEG4    1
-#define GO7007_FORMAT_MPEG1    2
-#define GO7007_FORMAT_MPEG2    3
-#define GO7007_FORMAT_H263     4
-
-#define GO7007_RATIO_1_1       0
-#define GO7007_RATIO_4_3       1
-#define GO7007_RATIO_16_9      2
-
-enum go7007_parser_state {
-       STATE_DATA,
-       STATE_00,
-       STATE_00_00,
-       STATE_00_00_01,
-       STATE_FF,
-       STATE_VBI_LEN_A,
-       STATE_VBI_LEN_B,
-       STATE_MODET_MAP,
-       STATE_UNPARSED,
-};
-
-struct go7007 {
-       struct device *dev;
-       struct go7007_board_info *board_info;
-       unsigned int board_id;
-       int tuner_type;
-       int channel_number; /* for multi-channel boards like Adlink PCI-MPG24 */
-       char name[64];
-       struct video_device *video_dev;
-       struct v4l2_device v4l2_dev;
-       int ref_count;
-       enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status;
-       spinlock_t spinlock;
-       struct mutex hw_lock;
-       int streaming;
-       int in_use;
-       int audio_enabled;
-
-       /* Video input */
-       int input;
-       enum { GO7007_STD_NTSC, GO7007_STD_PAL, GO7007_STD_OTHER } standard;
-       int sensor_framerate;
-       int width;
-       int height;
-       int encoder_h_offset;
-       int encoder_v_offset;
-       unsigned int encoder_h_halve:1;
-       unsigned int encoder_v_halve:1;
-       unsigned int encoder_subsample:1;
-
-       /* Encoder config */
-       int format;
-       int bitrate;
-       int fps_scale;
-       int pali;
-       int aspect_ratio;
-       int gop_size;
-       unsigned int ipb:1;
-       unsigned int closed_gop:1;
-       unsigned int repeat_seqhead:1;
-       unsigned int seq_header_enable:1;
-       unsigned int gop_header_enable:1;
-       unsigned int dvd_mode:1;
-       unsigned int interlace_coding:1;
-
-       /* Motion detection */
-       unsigned int modet_enable:1;
-       struct {
-               unsigned int enable:1;
-               int pixel_threshold;
-               int motion_threshold;
-               int mb_threshold;
-       } modet[4];
-       unsigned char modet_map[1624];
-       unsigned char active_map[216];
-
-       /* Video streaming */
-       struct go7007_buffer *active_buf;
-       enum go7007_parser_state state;
-       int parse_length;
-       u16 modet_word;
-       int seen_frame;
-       u32 next_seq;
-       struct list_head stream;
-       wait_queue_head_t frame_waitq;
-
-       /* Audio streaming */
-       void (*audio_deliver)(struct go7007 *go, u8 *buf, int length);
-       void *snd_context;
-
-       /* I2C */
-       int i2c_adapter_online;
-       struct i2c_adapter i2c_adapter;
-
-       /* HPI driver */
-       struct go7007_hpi_ops *hpi_ops;
-       void *hpi_context;
-       int interrupt_available;
-       wait_queue_head_t interrupt_waitq;
-       unsigned short interrupt_value;
-       unsigned short interrupt_data;
-};
-
-static inline struct go7007 *to_go7007(struct v4l2_device *v4l2_dev)
-{
-       return container_of(v4l2_dev, struct go7007, v4l2_dev);
-}
-
-/* All of these must be called with the hpi_lock mutex held! */
-#define go7007_interface_reset(go) \
-                       ((go)->hpi_ops->interface_reset(go))
-#define        go7007_write_interrupt(go, x, y) \
-                       ((go)->hpi_ops->write_interrupt)((go), (x), (y))
-#define go7007_stream_start(go) \
-                       ((go)->hpi_ops->stream_start(go))
-#define go7007_stream_stop(go) \
-                       ((go)->hpi_ops->stream_stop(go))
-#define        go7007_send_firmware(go, x, y) \
-                       ((go)->hpi_ops->send_firmware)((go), (x), (y))
-#define go7007_write_addr(go, x, y) \
-                       ((go)->hpi_ops->write_interrupt)((go), (x)|0x8000, (y))
-
-/* go7007-driver.c */
-int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data);
-int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data);
-int go7007_boot_encoder(struct go7007 *go, int init_i2c);
-int go7007_reset_encoder(struct go7007 *go);
-int go7007_register_encoder(struct go7007 *go);
-int go7007_start_encoder(struct go7007 *go);
-void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length);
-struct go7007 *go7007_alloc(struct go7007_board_info *board,
-                                       struct device *dev);
-void go7007_remove(struct go7007 *go);
-
-/* go7007-fw.c */
-int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen);
-
-/* go7007-i2c.c */
-int go7007_i2c_init(struct go7007 *go);
-int go7007_i2c_remove(struct go7007 *go);
-
-/* go7007-v4l2.c */
-int go7007_v4l2_init(struct go7007 *go);
-void go7007_v4l2_remove(struct go7007 *go);
-
-/* snd-go7007.c */
-int go7007_snd_init(struct go7007 *go);
-int go7007_snd_remove(struct go7007 *go);
diff --git a/drivers/staging/go7007/go7007-usb.c b/drivers/staging/go7007/go7007-usb.c
deleted file mode 100644 (file)
index 3db3b0a..0000000
+++ /dev/null
@@ -1,1288 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/time.h>
-#include <linux/mm.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-#include <asm/byteorder.h>
-#include <media/tvaudio.h>
-
-#include "go7007-priv.h"
-#include "wis-i2c.h"
-
-static unsigned int assume_endura;
-module_param(assume_endura, int, 0644);
-MODULE_PARM_DESC(assume_endura, "when probing fails, "
-                               "hardware is a Pelco Endura");
-
-/* #define GO7007_USB_DEBUG */
-/* #define GO7007_I2C_DEBUG */ /* for debugging the EZ-USB I2C adapter */
-
-#define        HPI_STATUS_ADDR 0xFFF4
-#define        INT_PARAM_ADDR  0xFFF6
-#define        INT_INDEX_ADDR  0xFFF8
-
-/*
- * Pipes on EZ-USB interface:
- *     0 snd - Control
- *     0 rcv - Control
- *     2 snd - Download firmware (control)
- *     4 rcv - Read Interrupt (interrupt)
- *     6 rcv - Read Video (bulk)
- *     8 rcv - Read Audio (bulk)
- */
-
-#define GO7007_USB_EZUSB               (1<<0)
-#define GO7007_USB_EZUSB_I2C           (1<<1)
-
-struct go7007_usb_board {
-       unsigned int flags;
-       struct go7007_board_info main_info;
-};
-
-struct go7007_usb {
-       struct go7007_usb_board *board;
-       struct mutex i2c_lock;
-       struct usb_device *usbdev;
-       struct urb *video_urbs[8];
-       struct urb *audio_urbs[8];
-       struct urb *intr_urb;
-};
-
-/*********************** Product specification data ***********************/
-
-static struct go7007_usb_board board_matrix_ii = {
-       .flags          = GO7007_USB_EZUSB,
-       .main_info      = {
-               .firmware        = "go7007tv.bin",
-               .flags           = GO7007_BOARD_HAS_AUDIO |
-                                       GO7007_BOARD_USE_ONBOARD_I2C,
-               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
-                                       GO7007_AUDIO_WORD_16,
-               .audio_rate      = 48000,
-               .audio_bclk_div  = 8,
-               .audio_main_div  = 2,
-               .hpi_buffer_cap  = 7,
-               .sensor_flags    = GO7007_SENSOR_656 |
-                                       GO7007_SENSOR_VALID_ENABLE |
-                                       GO7007_SENSOR_TV |
-                                       GO7007_SENSOR_VBI |
-                                       GO7007_SENSOR_SCALING,
-               .num_i2c_devs    = 1,
-               .i2c_devs        = {
-                       {
-                               .type   = "wis_saa7115",
-                               .id     = I2C_DRIVERID_WIS_SAA7115,
-                               .addr   = 0x20,
-                       },
-               },
-               .num_inputs      = 2,
-               .inputs          = {
-                       {
-                               .video_input    = 0,
-                               .name           = "Composite",
-                       },
-                       {
-                               .video_input    = 9,
-                               .name           = "S-Video",
-                       },
-               },
-       },
-};
-
-static struct go7007_usb_board board_matrix_reload = {
-       .flags          = GO7007_USB_EZUSB,
-       .main_info      = {
-               .firmware        = "go7007tv.bin",
-               .flags           = GO7007_BOARD_HAS_AUDIO |
-                                       GO7007_BOARD_USE_ONBOARD_I2C,
-               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
-                                       GO7007_AUDIO_I2S_MASTER |
-                                       GO7007_AUDIO_WORD_16,
-               .audio_rate      = 48000,
-               .audio_bclk_div  = 8,
-               .audio_main_div  = 2,
-               .hpi_buffer_cap  = 7,
-               .sensor_flags    = GO7007_SENSOR_656 |
-                                       GO7007_SENSOR_TV,
-               .num_i2c_devs    = 1,
-               .i2c_devs        = {
-                       {
-                               .type   = "wis_saa7113",
-                               .id     = I2C_DRIVERID_WIS_SAA7113,
-                               .addr   = 0x25,
-                       },
-               },
-               .num_inputs      = 2,
-               .inputs          = {
-                       {
-                               .video_input    = 0,
-                               .name           = "Composite",
-                       },
-                       {
-                               .video_input    = 9,
-                               .name           = "S-Video",
-                       },
-               },
-       },
-};
-
-static struct go7007_usb_board board_star_trek = {
-       .flags          = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
-       .main_info      = {
-               .firmware        = "go7007tv.bin",
-               .flags           = GO7007_BOARD_HAS_AUDIO, /* |
-                                       GO7007_BOARD_HAS_TUNER, */
-               .sensor_flags    = GO7007_SENSOR_656 |
-                                       GO7007_SENSOR_VALID_ENABLE |
-                                       GO7007_SENSOR_TV |
-                                       GO7007_SENSOR_VBI |
-                                       GO7007_SENSOR_SCALING,
-               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
-                                       GO7007_AUDIO_WORD_16,
-               .audio_bclk_div  = 8,
-               .audio_main_div  = 2,
-               .hpi_buffer_cap  = 7,
-               .num_i2c_devs    = 1,
-               .i2c_devs        = {
-                       {
-                               .type   = "wis_saa7115",
-                               .id     = I2C_DRIVERID_WIS_SAA7115,
-                               .addr   = 0x20,
-                       },
-               },
-               .num_inputs      = 2,
-               .inputs          = {
-                       {
-                               .video_input    = 1,
-                       /*      .audio_input    = AUDIO_EXTERN, */
-                               .name           = "Composite",
-                       },
-                       {
-                               .video_input    = 8,
-                       /*      .audio_input    = AUDIO_EXTERN, */
-                               .name           = "S-Video",
-                       },
-               /*      {
-                *              .video_input    = 3,
-                *              .audio_input    = AUDIO_TUNER,
-                *              .name           = "Tuner",
-                *      },
-                */
-               },
-       },
-};
-
-static struct go7007_usb_board board_px_tv402u = {
-       .flags          = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
-       .main_info      = {
-               .firmware        = "go7007tv.bin",
-               .flags           = GO7007_BOARD_HAS_AUDIO |
-                                       GO7007_BOARD_HAS_TUNER,
-               .sensor_flags    = GO7007_SENSOR_656 |
-                                       GO7007_SENSOR_VALID_ENABLE |
-                                       GO7007_SENSOR_TV |
-                                       GO7007_SENSOR_VBI |
-                                       GO7007_SENSOR_SCALING,
-               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
-                                       GO7007_AUDIO_WORD_16,
-               .audio_bclk_div  = 8,
-               .audio_main_div  = 2,
-               .hpi_buffer_cap  = 7,
-               .num_i2c_devs    = 3,
-               .i2c_devs        = {
-                       {
-                               .type   = "wis_saa7115",
-                               .id     = I2C_DRIVERID_WIS_SAA7115,
-                               .addr   = 0x20,
-                       },
-                       {
-                               .type   = "wis_uda1342",
-                               .id     = I2C_DRIVERID_WIS_UDA1342,
-                               .addr   = 0x1a,
-                       },
-                       {
-                               .type   = "wis_sony_tuner",
-                               .id     = I2C_DRIVERID_WIS_SONY_TUNER,
-                               .addr   = 0x60,
-                       },
-               },
-               .num_inputs      = 3,
-               .inputs          = {
-                       {
-                               .video_input    = 1,
-                               .audio_input    = TVAUDIO_INPUT_EXTERN,
-                               .name           = "Composite",
-                       },
-                       {
-                               .video_input    = 8,
-                               .audio_input    = TVAUDIO_INPUT_EXTERN,
-                               .name           = "S-Video",
-                       },
-                       {
-                               .video_input    = 3,
-                               .audio_input    = TVAUDIO_INPUT_TUNER,
-                               .name           = "Tuner",
-                       },
-               },
-       },
-};
-
-static struct go7007_usb_board board_xmen = {
-       .flags          = 0,
-       .main_info      = {
-               .firmware         = "go7007tv.bin",
-               .flags            = GO7007_BOARD_USE_ONBOARD_I2C,
-               .hpi_buffer_cap   = 0,
-               .sensor_flags     = GO7007_SENSOR_VREF_POLAR,
-               .sensor_width     = 320,
-               .sensor_height    = 240,
-               .sensor_framerate = 30030,
-               .audio_flags      = GO7007_AUDIO_ONE_CHANNEL |
-                                       GO7007_AUDIO_I2S_MODE_3 |
-                                       GO7007_AUDIO_WORD_14 |
-                                       GO7007_AUDIO_I2S_MASTER |
-                                       GO7007_AUDIO_BCLK_POLAR |
-                                       GO7007_AUDIO_OKI_MODE,
-               .audio_rate       = 8000,
-               .audio_bclk_div   = 48,
-               .audio_main_div   = 1,
-               .num_i2c_devs     = 1,
-               .i2c_devs         = {
-                       {
-                               .type   = "wis_ov7640",
-                               .id     = I2C_DRIVERID_WIS_OV7640,
-                               .addr   = 0x21,
-                       },
-               },
-               .num_inputs       = 1,
-               .inputs           = {
-                       {
-                               .name           = "Camera",
-                       },
-               },
-       },
-};
-
-static struct go7007_usb_board board_matrix_revolution = {
-       .flags          = GO7007_USB_EZUSB,
-       .main_info      = {
-               .firmware        = "go7007tv.bin",
-               .flags           = GO7007_BOARD_HAS_AUDIO |
-                                       GO7007_BOARD_USE_ONBOARD_I2C,
-               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
-                                       GO7007_AUDIO_I2S_MASTER |
-                                       GO7007_AUDIO_WORD_16,
-               .audio_rate      = 48000,
-               .audio_bclk_div  = 8,
-               .audio_main_div  = 2,
-               .hpi_buffer_cap  = 7,
-               .sensor_flags    = GO7007_SENSOR_656 |
-                                       GO7007_SENSOR_TV |
-                                       GO7007_SENSOR_VBI,
-               .num_i2c_devs    = 1,
-               .i2c_devs        = {
-                       {
-                               .type   = "wis_tw9903",
-                               .id     = I2C_DRIVERID_WIS_TW9903,
-                               .addr   = 0x44,
-                       },
-               },
-               .num_inputs      = 2,
-               .inputs          = {
-                       {
-                               .video_input    = 2,
-                               .name           = "Composite",
-                       },
-                       {
-                               .video_input    = 8,
-                               .name           = "S-Video",
-                       },
-               },
-       },
-};
-
-static struct go7007_usb_board board_lifeview_lr192 = {
-       .flags          = GO7007_USB_EZUSB,
-       .main_info      = {
-               .firmware        = "go7007tv.bin",
-               .flags           = GO7007_BOARD_HAS_AUDIO |
-                                       GO7007_BOARD_USE_ONBOARD_I2C,
-               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
-                                       GO7007_AUDIO_WORD_16,
-               .audio_rate      = 48000,
-               .audio_bclk_div  = 8,
-               .audio_main_div  = 2,
-               .hpi_buffer_cap  = 7,
-               .sensor_flags    = GO7007_SENSOR_656 |
-                                       GO7007_SENSOR_VALID_ENABLE |
-                                       GO7007_SENSOR_TV |
-                                       GO7007_SENSOR_VBI |
-                                       GO7007_SENSOR_SCALING,
-               .num_i2c_devs    = 0,
-               .num_inputs      = 1,
-               .inputs          = {
-                       {
-                               .video_input    = 0,
-                               .name           = "Composite",
-                       },
-               },
-       },
-};
-
-static struct go7007_usb_board board_endura = {
-       .flags          = 0,
-       .main_info      = {
-               .firmware        = "go7007tv.bin",
-               .flags           = 0,
-               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
-                                       GO7007_AUDIO_I2S_MASTER |
-                                       GO7007_AUDIO_WORD_16,
-               .audio_rate      = 8000,
-               .audio_bclk_div  = 48,
-               .audio_main_div  = 8,
-               .hpi_buffer_cap  = 0,
-               .sensor_flags    = GO7007_SENSOR_656 |
-                                       GO7007_SENSOR_TV,
-               .sensor_h_offset = 8,
-               .num_i2c_devs    = 0,
-               .num_inputs      = 1,
-               .inputs          = {
-                       {
-                               .name           = "Camera",
-                       },
-               },
-       },
-};
-
-static struct go7007_usb_board board_adlink_mpg24 = {
-       .flags          = 0,
-       .main_info      = {
-               .firmware        = "go7007tv.bin",
-               .flags           = GO7007_BOARD_USE_ONBOARD_I2C,
-               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
-                                       GO7007_AUDIO_I2S_MASTER |
-                                       GO7007_AUDIO_WORD_16,
-               .audio_rate      = 48000,
-               .audio_bclk_div  = 8,
-               .audio_main_div  = 2,
-               .hpi_buffer_cap  = 0,
-               .sensor_flags    = GO7007_SENSOR_656 |
-                                       GO7007_SENSOR_TV |
-                                       GO7007_SENSOR_VBI,
-               .num_i2c_devs    = 1,
-               .i2c_devs        = {
-                       {
-                               .type   = "wis_tw2804",
-                               .id     = I2C_DRIVERID_WIS_TW2804,
-                               .addr   = 0x00, /* yes, really */
-                       },
-               },
-               .num_inputs      = 1,
-               .inputs          = {
-                       {
-                               .name           = "Composite",
-                       },
-               },
-       },
-};
-
-static struct go7007_usb_board board_sensoray_2250 = {
-       .flags          = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
-       .main_info      = {
-               .firmware        = "go7007tv.bin",
-               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
-                                       GO7007_AUDIO_I2S_MASTER |
-                                       GO7007_AUDIO_WORD_16,
-               .flags           = GO7007_BOARD_HAS_AUDIO,
-               .audio_rate      = 48000,
-               .audio_bclk_div  = 8,
-               .audio_main_div  = 2,
-               .hpi_buffer_cap  = 7,
-               .sensor_flags    = GO7007_SENSOR_656 |
-                                       GO7007_SENSOR_TV,
-               .num_i2c_devs    = 1,
-               .i2c_devs        = {
-                       {
-                               .type   = "s2250",
-                               .id     = I2C_DRIVERID_S2250,
-                               .addr   = 0x43,
-                       },
-               },
-               .num_inputs      = 2,
-               .inputs          = {
-                       {
-                               .video_input    = 0,
-                               .name           = "Composite",
-                       },
-                       {
-                               .video_input    = 1,
-                               .name           = "S-Video",
-                       },
-               },
-       },
-};
-
-MODULE_FIRMWARE("go7007tv.bin");
-
-static const struct usb_device_id go7007_usb_id_table[] = {
-       {
-               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
-                                       USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
-               .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
-               .bcdDevice_lo   = 0x200,   /* Revision number of XMen */
-               .bcdDevice_hi   = 0x200,
-               .bInterfaceClass        = 255,
-               .bInterfaceSubClass     = 0,
-               .bInterfaceProtocol     = 255,
-               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_XMEN,
-       },
-       {
-               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
-               .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
-               .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
-               .bcdDevice_lo   = 0x202,   /* Revision number of Matrix II */
-               .bcdDevice_hi   = 0x202,
-               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_MATRIX_II,
-       },
-       {
-               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
-               .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
-               .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
-               .bcdDevice_lo   = 0x204,   /* Revision number of Matrix */
-               .bcdDevice_hi   = 0x204,   /*     Reloaded */
-               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_MATRIX_RELOAD,
-       },
-       {
-               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
-                                       USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
-               .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
-               .bcdDevice_lo   = 0x205,   /* Revision number of XMen-II */
-               .bcdDevice_hi   = 0x205,
-               .bInterfaceClass        = 255,
-               .bInterfaceSubClass     = 0,
-               .bInterfaceProtocol     = 255,
-               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_XMEN_II,
-       },
-       {
-               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
-               .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
-               .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
-               .bcdDevice_lo   = 0x208,   /* Revision number of Star Trek */
-               .bcdDevice_hi   = 0x208,
-               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_STAR_TREK,
-       },
-       {
-               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
-                                       USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
-               .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
-               .bcdDevice_lo   = 0x209,   /* Revision number of XMen-III */
-               .bcdDevice_hi   = 0x209,
-               .bInterfaceClass        = 255,
-               .bInterfaceSubClass     = 0,
-               .bInterfaceProtocol     = 255,
-               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_XMEN_III,
-       },
-       {
-               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
-               .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
-               .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
-               .bcdDevice_lo   = 0x210,   /* Revision number of Matrix */
-               .bcdDevice_hi   = 0x210,   /*     Revolution */
-               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_MATRIX_REV,
-       },
-       {
-               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
-               .idVendor       = 0x093b,  /* Vendor ID of Plextor */
-               .idProduct      = 0xa102,  /* Product ID of M402U */
-               .bcdDevice_lo   = 0x1,     /* revision number of Blueberry */
-               .bcdDevice_hi   = 0x1,
-               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_PX_M402U,
-       },
-       {
-               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
-               .idVendor       = 0x093b,  /* Vendor ID of Plextor */
-               .idProduct      = 0xa104,  /* Product ID of TV402U */
-               .bcdDevice_lo   = 0x1,
-               .bcdDevice_hi   = 0x1,
-               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U_ANY,
-       },
-       {
-               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
-               .idVendor       = 0x10fd,  /* Vendor ID of Anubis Electronics */
-               .idProduct      = 0xde00,  /* Product ID of Lifeview LR192 */
-               .bcdDevice_lo   = 0x1,
-               .bcdDevice_hi   = 0x1,
-               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_LIFEVIEW_LR192,
-       },
-       {
-               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
-               .idVendor       = 0x1943,  /* Vendor ID Sensoray */
-               .idProduct      = 0x2250,  /* Product ID of 2250/2251 */
-               .bcdDevice_lo   = 0x1,
-               .bcdDevice_hi   = 0x1,
-               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_SENSORAY_2250,
-       },
-       { }                                     /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, go7007_usb_id_table);
-
-/********************* Driver for EZ-USB HPI interface *********************/
-
-static int go7007_usb_vendor_request(struct go7007 *go, int request,
-               int value, int index, void *transfer_buffer, int length, int in)
-{
-       struct go7007_usb *usb = go->hpi_context;
-       int timeout = 5000;
-
-       if (in) {
-               return usb_control_msg(usb->usbdev,
-                               usb_rcvctrlpipe(usb->usbdev, 0), request,
-                               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                               value, index, transfer_buffer, length, timeout);
-       } else {
-               return usb_control_msg(usb->usbdev,
-                               usb_sndctrlpipe(usb->usbdev, 0), request,
-                               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               value, index, transfer_buffer, length, timeout);
-       }
-}
-
-static int go7007_usb_interface_reset(struct go7007 *go)
-{
-       struct go7007_usb *usb = go->hpi_context;
-       u16 intr_val, intr_data;
-
-       /* Reset encoder */
-       if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)
-               return -1;
-       msleep(100);
-
-       if (usb->board->flags & GO7007_USB_EZUSB) {
-               /* Reset buffer in EZ-USB */
-#ifdef GO7007_USB_DEBUG
-               printk(KERN_DEBUG "go7007-usb: resetting EZ-USB buffers\n");
-#endif
-               if (go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0 ||
-                   go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0)
-                       return -1;
-
-               /* Reset encoder again */
-               if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)
-                       return -1;
-               msleep(100);
-       }
-
-       /* Wait for an interrupt to indicate successful hardware reset */
-       if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
-                       (intr_val & ~0x1) != 0x55aa) {
-               printk(KERN_ERR
-                       "go7007-usb: unable to reset the USB interface\n");
-               return -1;
-       }
-       return 0;
-}
-
-static int go7007_usb_ezusb_write_interrupt(struct go7007 *go,
-                                               int addr, int data)
-{
-       struct go7007_usb *usb = go->hpi_context;
-       int i, r;
-       u16 status_reg;
-       int timeout = 500;
-
-#ifdef GO7007_USB_DEBUG
-       printk(KERN_DEBUG
-               "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data);
-#endif
-
-       for (i = 0; i < 100; ++i) {
-               r = usb_control_msg(usb->usbdev,
-                               usb_rcvctrlpipe(usb->usbdev, 0), 0x14,
-                               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                               0, HPI_STATUS_ADDR, &status_reg,
-                               sizeof(status_reg), timeout);
-               if (r < 0)
-                       goto write_int_error;
-               __le16_to_cpus(&status_reg);
-               if (!(status_reg & 0x0010))
-                       break;
-               msleep(10);
-       }
-       if (i == 100) {
-               printk(KERN_ERR
-                       "go7007-usb: device is hung, status reg = 0x%04x\n",
-                       status_reg);
-               return -1;
-       }
-       r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), 0x12,
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE, data,
-                       INT_PARAM_ADDR, NULL, 0, timeout);
-       if (r < 0)
-               goto write_int_error;
-       r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0),
-                       0x12, USB_TYPE_VENDOR | USB_RECIP_DEVICE, addr,
-                       INT_INDEX_ADDR, NULL, 0, timeout);
-       if (r < 0)
-               goto write_int_error;
-       return 0;
-
-write_int_error:
-       printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r);
-       return r;
-}
-
-static int go7007_usb_onboard_write_interrupt(struct go7007 *go,
-                                               int addr, int data)
-{
-       struct go7007_usb *usb = go->hpi_context;
-       u8 *tbuf;
-       int r;
-       int timeout = 500;
-
-#ifdef GO7007_USB_DEBUG
-       printk(KERN_DEBUG
-               "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data);
-#endif
-
-       tbuf = kzalloc(8, GFP_KERNEL);
-       if (tbuf == NULL)
-               return -ENOMEM;
-       tbuf[0] = data & 0xff;
-       tbuf[1] = data >> 8;
-       tbuf[2] = addr & 0xff;
-       tbuf[3] = addr >> 8;
-       r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 2), 0x00,
-                       USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x55aa,
-                       0xf0f0, tbuf, 8, timeout);
-       kfree(tbuf);
-       if (r < 0) {
-               printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r);
-               return r;
-       }
-       return 0;
-}
-
-static void go7007_usb_readinterrupt_complete(struct urb *urb)
-{
-       struct go7007 *go = (struct go7007 *)urb->context;
-       u16 *regs = (u16 *)urb->transfer_buffer;
-       int status = urb->status;
-
-       if (status) {
-               if (status != -ESHUTDOWN &&
-                               go->status != STATUS_SHUTDOWN) {
-                       printk(KERN_ERR
-                               "go7007-usb: error in read interrupt: %d\n",
-                               urb->status);
-               } else {
-                       wake_up(&go->interrupt_waitq);
-                       return;
-               }
-       } else if (urb->actual_length != urb->transfer_buffer_length) {
-               printk(KERN_ERR "go7007-usb: short read in interrupt pipe!\n");
-       } else {
-               go->interrupt_available = 1;
-               go->interrupt_data = __le16_to_cpu(regs[0]);
-               go->interrupt_value = __le16_to_cpu(regs[1]);
-#ifdef GO7007_USB_DEBUG
-               printk(KERN_DEBUG "go7007-usb: ReadInterrupt: %04x %04x\n",
-                               go->interrupt_value, go->interrupt_data);
-#endif
-       }
-
-       wake_up(&go->interrupt_waitq);
-}
-
-static int go7007_usb_read_interrupt(struct go7007 *go)
-{
-       struct go7007_usb *usb = go->hpi_context;
-       int r;
-
-       r = usb_submit_urb(usb->intr_urb, GFP_KERNEL);
-       if (r < 0) {
-               printk(KERN_ERR
-                       "go7007-usb: unable to submit interrupt urb: %d\n", r);
-               return r;
-       }
-       return 0;
-}
-
-static void go7007_usb_read_video_pipe_complete(struct urb *urb)
-{
-       struct go7007 *go = (struct go7007 *)urb->context;
-       int r, status = urb->status;
-
-       if (!go->streaming) {
-               wake_up_interruptible(&go->frame_waitq);
-               return;
-       }
-       if (status) {
-               printk(KERN_ERR "go7007-usb: error in video pipe: %d\n",
-                       status);
-               return;
-       }
-       if (urb->actual_length != urb->transfer_buffer_length) {
-               printk(KERN_ERR "go7007-usb: short read in video pipe!\n");
-               return;
-       }
-       go7007_parse_video_stream(go, urb->transfer_buffer, urb->actual_length);
-       r = usb_submit_urb(urb, GFP_ATOMIC);
-       if (r < 0)
-               printk(KERN_ERR "go7007-usb: error in video pipe: %d\n", r);
-}
-
-static void go7007_usb_read_audio_pipe_complete(struct urb *urb)
-{
-       struct go7007 *go = (struct go7007 *)urb->context;
-       int r, status = urb->status;
-
-       if (!go->streaming)
-               return;
-       if (status) {
-               printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n",
-                       status);
-               return;
-       }
-       if (urb->actual_length != urb->transfer_buffer_length) {
-               printk(KERN_ERR "go7007-usb: short read in audio pipe!\n");
-               return;
-       }
-       if (go->audio_deliver != NULL)
-               go->audio_deliver(go, urb->transfer_buffer, urb->actual_length);
-       r = usb_submit_urb(urb, GFP_ATOMIC);
-       if (r < 0)
-               printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", r);
-}
-
-static int go7007_usb_stream_start(struct go7007 *go)
-{
-       struct go7007_usb *usb = go->hpi_context;
-       int i, r;
-
-       for (i = 0; i < 8; ++i) {
-               r = usb_submit_urb(usb->video_urbs[i], GFP_KERNEL);
-               if (r < 0) {
-                       printk(KERN_ERR "go7007-usb: error submitting video "
-                                       "urb %d: %d\n", i, r);
-                       goto video_submit_failed;
-               }
-       }
-       if (!go->audio_enabled)
-               return 0;
-
-       for (i = 0; i < 8; ++i) {
-               r = usb_submit_urb(usb->audio_urbs[i], GFP_KERNEL);
-               if (r < 0) {
-                       printk(KERN_ERR "go7007-usb: error submitting audio "
-                                       "urb %d: %d\n", i, r);
-                       goto audio_submit_failed;
-               }
-       }
-       return 0;
-
-audio_submit_failed:
-       for (i = 0; i < 7; ++i)
-               usb_kill_urb(usb->audio_urbs[i]);
-video_submit_failed:
-       for (i = 0; i < 8; ++i)
-               usb_kill_urb(usb->video_urbs[i]);
-       return -1;
-}
-
-static int go7007_usb_stream_stop(struct go7007 *go)
-{
-       struct go7007_usb *usb = go->hpi_context;
-       int i;
-
-       if (go->status == STATUS_SHUTDOWN)
-               return 0;
-       for (i = 0; i < 8; ++i)
-               usb_kill_urb(usb->video_urbs[i]);
-       if (go->audio_enabled)
-               for (i = 0; i < 8; ++i)
-                       usb_kill_urb(usb->audio_urbs[i]);
-       return 0;
-}
-
-static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len)
-{
-       struct go7007_usb *usb = go->hpi_context;
-       int transferred, pipe;
-       int timeout = 500;
-
-#ifdef GO7007_USB_DEBUG
-       printk(KERN_DEBUG "go7007-usb: DownloadBuffer sending %d bytes\n", len);
-#endif
-
-       if (usb->board->flags & GO7007_USB_EZUSB)
-               pipe = usb_sndbulkpipe(usb->usbdev, 2);
-       else
-               pipe = usb_sndbulkpipe(usb->usbdev, 3);
-
-       return usb_bulk_msg(usb->usbdev, pipe, data, len,
-                                       &transferred, timeout);
-}
-
-static struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = {
-       .interface_reset        = go7007_usb_interface_reset,
-       .write_interrupt        = go7007_usb_ezusb_write_interrupt,
-       .read_interrupt         = go7007_usb_read_interrupt,
-       .stream_start           = go7007_usb_stream_start,
-       .stream_stop            = go7007_usb_stream_stop,
-       .send_firmware          = go7007_usb_send_firmware,
-};
-
-static struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = {
-       .interface_reset        = go7007_usb_interface_reset,
-       .write_interrupt        = go7007_usb_onboard_write_interrupt,
-       .read_interrupt         = go7007_usb_read_interrupt,
-       .stream_start           = go7007_usb_stream_start,
-       .stream_stop            = go7007_usb_stream_stop,
-       .send_firmware          = go7007_usb_send_firmware,
-};
-
-/********************* Driver for EZ-USB I2C adapter *********************/
-
-static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter,
-                                       struct i2c_msg msgs[], int num)
-{
-       struct go7007 *go = i2c_get_adapdata(adapter);
-       struct go7007_usb *usb = go->hpi_context;
-       u8 buf[16];
-       int buf_len, i;
-       int ret = -1;
-
-       if (go->status == STATUS_SHUTDOWN)
-               return -1;
-
-       mutex_lock(&usb->i2c_lock);
-
-       for (i = 0; i < num; ++i) {
-               /* The hardware command is "write some bytes then read some
-                * bytes", so we try to coalesce a write followed by a read
-                * into a single USB transaction */
-               if (i + 1 < num && msgs[i].addr == msgs[i + 1].addr &&
-                               !(msgs[i].flags & I2C_M_RD) &&
-                               (msgs[i + 1].flags & I2C_M_RD)) {
-#ifdef GO7007_I2C_DEBUG
-                       printk(KERN_DEBUG "go7007-usb: i2c write/read %d/%d "
-                                       "bytes on %02x\n", msgs[i].len,
-                                       msgs[i + 1].len, msgs[i].addr);
-#endif
-                       buf[0] = 0x01;
-                       buf[1] = msgs[i].len + 1;
-                       buf[2] = msgs[i].addr << 1;
-                       memcpy(&buf[3], msgs[i].buf, msgs[i].len);
-                       buf_len = msgs[i].len + 3;
-                       buf[buf_len++] = msgs[++i].len;
-               } else if (msgs[i].flags & I2C_M_RD) {
-#ifdef GO7007_I2C_DEBUG
-                       printk(KERN_DEBUG "go7007-usb: i2c read %d "
-                                       "bytes on %02x\n", msgs[i].len,
-                                       msgs[i].addr);
-#endif
-                       buf[0] = 0x01;
-                       buf[1] = 1;
-                       buf[2] = msgs[i].addr << 1;
-                       buf[3] = msgs[i].len;
-                       buf_len = 4;
-               } else {
-#ifdef GO7007_I2C_DEBUG
-                       printk(KERN_DEBUG "go7007-usb: i2c write %d "
-                                       "bytes on %02x\n", msgs[i].len,
-                                       msgs[i].addr);
-#endif
-                       buf[0] = 0x00;
-                       buf[1] = msgs[i].len + 1;
-                       buf[2] = msgs[i].addr << 1;
-                       memcpy(&buf[3], msgs[i].buf, msgs[i].len);
-                       buf_len = msgs[i].len + 3;
-                       buf[buf_len++] = 0;
-               }
-               if (go7007_usb_vendor_request(go, 0x24, 0, 0,
-                                               buf, buf_len, 0) < 0)
-                       goto i2c_done;
-               if (msgs[i].flags & I2C_M_RD) {
-                       memset(buf, 0, sizeof(buf));
-                       if (go7007_usb_vendor_request(go, 0x25, 0, 0, buf,
-                                               msgs[i].len + 1, 1) < 0)
-                               goto i2c_done;
-                       memcpy(msgs[i].buf, buf + 1, msgs[i].len);
-               }
-       }
-       ret = 0;
-
-i2c_done:
-       mutex_unlock(&usb->i2c_lock);
-       return ret;
-}
-
-static u32 go7007_usb_functionality(struct i2c_adapter *adapter)
-{
-       /* No errors are reported by the hardware, so we don't bother
-        * supporting quick writes to avoid confusing probing */
-       return (I2C_FUNC_SMBUS_EMUL) & ~I2C_FUNC_SMBUS_QUICK;
-}
-
-static struct i2c_algorithm go7007_usb_algo = {
-       .master_xfer    = go7007_usb_i2c_master_xfer,
-       .functionality  = go7007_usb_functionality,
-};
-
-static struct i2c_adapter go7007_usb_adap_templ = {
-       .owner                  = THIS_MODULE,
-       .name                   = "WIS GO7007SB EZ-USB",
-       .algo                   = &go7007_usb_algo,
-};
-
-/********************* USB add/remove functions *********************/
-
-static int go7007_usb_probe(struct usb_interface *intf,
-               const struct usb_device_id *id)
-{
-       struct go7007 *go;
-       struct go7007_usb *usb;
-       struct go7007_usb_board *board;
-       struct usb_device *usbdev = interface_to_usbdev(intf);
-       char *name;
-       int video_pipe, i, v_urb_len;
-
-       printk(KERN_DEBUG "go7007-usb: probing new GO7007 USB board\n");
-
-       switch (id->driver_info) {
-       case GO7007_BOARDID_MATRIX_II:
-               name = "WIS Matrix II or compatible";
-               board = &board_matrix_ii;
-               break;
-       case GO7007_BOARDID_MATRIX_RELOAD:
-               name = "WIS Matrix Reloaded or compatible";
-               board = &board_matrix_reload;
-               break;
-       case GO7007_BOARDID_MATRIX_REV:
-               name = "WIS Matrix Revolution or compatible";
-               board = &board_matrix_revolution;
-               break;
-       case GO7007_BOARDID_STAR_TREK:
-               name = "WIS Star Trek or compatible";
-               board = &board_star_trek;
-               break;
-       case GO7007_BOARDID_XMEN:
-               name = "WIS XMen or compatible";
-               board = &board_xmen;
-               break;
-       case GO7007_BOARDID_XMEN_II:
-               name = "WIS XMen II or compatible";
-               board = &board_xmen;
-               break;
-       case GO7007_BOARDID_XMEN_III:
-               name = "WIS XMen III or compatible";
-               board = &board_xmen;
-               break;
-       case GO7007_BOARDID_PX_M402U:
-               name = "Plextor PX-M402U";
-               board = &board_matrix_ii;
-               break;
-       case GO7007_BOARDID_PX_TV402U_ANY:
-               name = "Plextor PX-TV402U (unknown tuner)";
-               board = &board_px_tv402u;
-               break;
-       case GO7007_BOARDID_LIFEVIEW_LR192:
-               printk(KERN_ERR "go7007-usb: The Lifeview TV Walker Ultra "
-                               "is not supported.  Sorry!\n");
-               return 0;
-               name = "Lifeview TV Walker Ultra";
-               board = &board_lifeview_lr192;
-               break;
-       case GO7007_BOARDID_SENSORAY_2250:
-               printk(KERN_INFO "Sensoray 2250 found\n");
-               name = "Sensoray 2250/2251";
-               board = &board_sensoray_2250;
-               break;
-       default:
-               printk(KERN_ERR "go7007-usb: unknown board ID %d!\n",
-                               (unsigned int)id->driver_info);
-               return 0;
-       }
-
-       usb = kzalloc(sizeof(struct go7007_usb), GFP_KERNEL);
-       if (usb == NULL)
-               return -ENOMEM;
-
-       /* Allocate the URB and buffer for receiving incoming interrupts */
-       usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (usb->intr_urb == NULL)
-               goto allocfail;
-       usb->intr_urb->transfer_buffer = kmalloc(2*sizeof(u16), GFP_KERNEL);
-       if (usb->intr_urb->transfer_buffer == NULL)
-               goto allocfail;
-
-       go = go7007_alloc(&board->main_info, &intf->dev);
-       if (go == NULL)
-               goto allocfail;
-       usb->board = board;
-       usb->usbdev = usbdev;
-       go->board_id = id->driver_info;
-       strncpy(go->name, name, sizeof(go->name));
-       if (board->flags & GO7007_USB_EZUSB)
-               go->hpi_ops = &go7007_usb_ezusb_hpi_ops;
-       else
-               go->hpi_ops = &go7007_usb_onboard_hpi_ops;
-       go->hpi_context = usb;
-       usb_fill_int_urb(usb->intr_urb, usb->usbdev,
-                       usb_rcvintpipe(usb->usbdev, 4),
-                       usb->intr_urb->transfer_buffer, 2*sizeof(u16),
-                       go7007_usb_readinterrupt_complete, go, 8);
-       usb_set_intfdata(intf, &go->v4l2_dev);
-
-       /* Boot the GO7007 */
-       if (go7007_boot_encoder(go, go->board_info->flags &
-                                       GO7007_BOARD_USE_ONBOARD_I2C) < 0)
-               goto initfail;
-
-       /* Register the EZ-USB I2C adapter, if we're using it */
-       if (board->flags & GO7007_USB_EZUSB_I2C) {
-               memcpy(&go->i2c_adapter, &go7007_usb_adap_templ,
-                               sizeof(go7007_usb_adap_templ));
-               mutex_init(&usb->i2c_lock);
-               go->i2c_adapter.dev.parent = go->dev;
-               i2c_set_adapdata(&go->i2c_adapter, go);
-               if (i2c_add_adapter(&go->i2c_adapter) < 0) {
-                       printk(KERN_ERR
-                               "go7007-usb: error: i2c_add_adapter failed\n");
-                       goto initfail;
-               }
-               go->i2c_adapter_online = 1;
-       }
-
-       /* Pelco and Adlink reused the XMen and XMen-III vendor and product
-        * IDs for their own incompatible designs.  We can detect XMen boards
-        * by probing the sensor, but there is no way to probe the sensors on
-        * the Pelco and Adlink designs so we default to the Adlink.  If it
-        * is actually a Pelco, the user must set the assume_endura module
-        * parameter. */
-       if ((go->board_id == GO7007_BOARDID_XMEN ||
-                               go->board_id == GO7007_BOARDID_XMEN_III) &&
-                       go->i2c_adapter_online) {
-               union i2c_smbus_data data;
-
-               /* Check to see if register 0x0A is 0x76 */
-               i2c_smbus_xfer(&go->i2c_adapter, 0x21, I2C_CLIENT_SCCB,
-                       I2C_SMBUS_READ, 0x0A, I2C_SMBUS_BYTE_DATA, &data);
-               if (data.byte != 0x76) {
-                       if (assume_endura) {
-                               go->board_id = GO7007_BOARDID_ENDURA;
-                               usb->board = board = &board_endura;
-                               go->board_info = &board->main_info;
-                               strncpy(go->name, "Pelco Endura",
-                                       sizeof(go->name));
-                       } else {
-                               u16 channel;
-
-                               /* set GPIO5 to be an output, currently low */
-                               go7007_write_addr(go, 0x3c82, 0x0000);
-                               go7007_write_addr(go, 0x3c80, 0x00df);
-                               /* read channel number from GPIO[1:0] */
-                               go7007_read_addr(go, 0x3c81, &channel);
-                               channel &= 0x3;
-                               go->board_id = GO7007_BOARDID_ADLINK_MPG24;
-                               usb->board = board = &board_adlink_mpg24;
-                               go->board_info = &board->main_info;
-                               go->channel_number = channel;
-                               snprintf(go->name, sizeof(go->name),
-                                       "Adlink PCI-MPG24, channel #%d",
-                                       channel);
-                       }
-               }
-       }
-
-       /* Probe the tuner model on the TV402U */
-       if (go->board_id == GO7007_BOARDID_PX_TV402U_ANY) {
-               u8 data[3];
-
-               /* Board strapping indicates tuner model */
-               if (go7007_usb_vendor_request(go, 0x41, 0, 0, data, 3, 1) < 0) {
-                       printk(KERN_ERR "go7007-usb: GPIO read failed!\n");
-                       goto initfail;
-               }
-               switch (data[0] >> 6) {
-               case 1:
-                       go->board_id = GO7007_BOARDID_PX_TV402U_EU;
-                       go->tuner_type = TUNER_SONY_BTF_PG472Z;
-                       strncpy(go->name, "Plextor PX-TV402U-EU",
-                                       sizeof(go->name));
-                       break;
-               case 2:
-                       go->board_id = GO7007_BOARDID_PX_TV402U_JP;
-                       go->tuner_type = TUNER_SONY_BTF_PK467Z;
-                       strncpy(go->name, "Plextor PX-TV402U-JP",
-                                       sizeof(go->name));
-                       break;
-               case 3:
-                       go->board_id = GO7007_BOARDID_PX_TV402U_NA;
-                       go->tuner_type = TUNER_SONY_BTF_PB463Z;
-                       strncpy(go->name, "Plextor PX-TV402U-NA",
-                                       sizeof(go->name));
-                       break;
-               default:
-                       printk(KERN_DEBUG "go7007-usb: unable to detect "
-                                               "tuner type!\n");
-                       break;
-               }
-               /* Configure tuner mode selection inputs connected
-                * to the EZ-USB GPIO output pins */
-               if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0,
-                                       NULL, 0, 0) < 0) {
-                       printk(KERN_ERR "go7007-usb: GPIO write failed!\n");
-                       goto initfail;
-               }
-       }
-
-       /* Print a nasty message if the user attempts to use a USB2.0 device in
-        * a USB1.1 port.  There will be silent corruption of the stream. */
-       if ((board->flags & GO7007_USB_EZUSB) &&
-                       usbdev->speed != USB_SPEED_HIGH)
-               printk(KERN_ERR "go7007-usb: *** WARNING ***  This device "
-                               "must be connected to a USB 2.0 port!  "
-                               "Attempting to capture video through a USB 1.1 "
-                               "port will result in stream corruption, even "
-                               "at low bitrates!\n");
-
-       /* Do any final GO7007 initialization, then register the
-        * V4L2 and ALSA interfaces */
-       if (go7007_register_encoder(go) < 0)
-               goto initfail;
-
-       /* Allocate the URBs and buffers for receiving the video stream */
-       if (board->flags & GO7007_USB_EZUSB) {
-               v_urb_len = 1024;
-               video_pipe = usb_rcvbulkpipe(usb->usbdev, 6);
-       } else {
-               v_urb_len = 512;
-               video_pipe = usb_rcvbulkpipe(usb->usbdev, 1);
-       }
-       for (i = 0; i < 8; ++i) {
-               usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
-               if (usb->video_urbs[i] == NULL)
-                       goto initfail;
-               usb->video_urbs[i]->transfer_buffer =
-                                               kmalloc(v_urb_len, GFP_KERNEL);
-               if (usb->video_urbs[i]->transfer_buffer == NULL)
-                       goto initfail;
-               usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe,
-                               usb->video_urbs[i]->transfer_buffer, v_urb_len,
-                               go7007_usb_read_video_pipe_complete, go);
-       }
-
-       /* Allocate the URBs and buffers for receiving the audio stream */
-       if ((board->flags & GO7007_USB_EZUSB) && go->audio_enabled)
-               for (i = 0; i < 8; ++i) {
-                       usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
-                       if (usb->audio_urbs[i] == NULL)
-                               goto initfail;
-                       usb->audio_urbs[i]->transfer_buffer = kmalloc(4096,
-                                                               GFP_KERNEL);
-                       if (usb->audio_urbs[i]->transfer_buffer == NULL)
-                               goto initfail;
-                       usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev,
-                               usb_rcvbulkpipe(usb->usbdev, 8),
-                               usb->audio_urbs[i]->transfer_buffer, 4096,
-                               go7007_usb_read_audio_pipe_complete, go);
-               }
-
-
-       go->status = STATUS_ONLINE;
-       return 0;
-
-initfail:
-       go->status = STATUS_SHUTDOWN;
-       return 0;
-
-allocfail:
-       if (usb->intr_urb) {
-               kfree(usb->intr_urb->transfer_buffer);
-               usb_free_urb(usb->intr_urb);
-       }
-       kfree(usb);
-       return -ENOMEM;
-}
-
-static void go7007_usb_disconnect(struct usb_interface *intf)
-{
-       struct go7007 *go = to_go7007(usb_get_intfdata(intf));
-       struct go7007_usb *usb = go->hpi_context;
-       struct urb *vurb, *aurb;
-       int i;
-
-       go->status = STATUS_SHUTDOWN;
-       usb_kill_urb(usb->intr_urb);
-
-       /* Free USB-related structs */
-       for (i = 0; i < 8; ++i) {
-               vurb = usb->video_urbs[i];
-               if (vurb) {
-                       usb_kill_urb(vurb);
-                       kfree(vurb->transfer_buffer);
-                       usb_free_urb(vurb);
-               }
-               aurb = usb->audio_urbs[i];
-               if (aurb) {
-                       usb_kill_urb(aurb);
-                       kfree(aurb->transfer_buffer);
-                       usb_free_urb(aurb);
-               }
-       }
-       kfree(usb->intr_urb->transfer_buffer);
-       usb_free_urb(usb->intr_urb);
-
-       kfree(go->hpi_context);
-
-       go7007_remove(go);
-}
-
-static struct usb_driver go7007_usb_driver = {
-       .name           = "go7007",
-       .probe          = go7007_usb_probe,
-       .disconnect     = go7007_usb_disconnect,
-       .id_table       = go7007_usb_id_table,
-};
-
-static int __init go7007_usb_init(void)
-{
-       return usb_register(&go7007_usb_driver);
-}
-
-static void __exit go7007_usb_cleanup(void)
-{
-       usb_deregister(&go7007_usb_driver);
-}
-
-module_init(go7007_usb_init);
-module_exit(go7007_usb_cleanup);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/go7007-v4l2.c b/drivers/staging/go7007/go7007-v4l2.c
deleted file mode 100644 (file)
index 2b27d8d..0000000
+++ /dev/null
@@ -1,1839 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/version.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/unistd.h>
-#include <linux/time.h>
-#include <linux/vmalloc.h>
-#include <linux/pagemap.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-subdev.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <asm/system.h>
-
-#include "go7007.h"
-#include "go7007-priv.h"
-#include "wis-i2c.h"
-
-/* Temporary defines until accepted in v4l-dvb */
-#ifndef V4L2_MPEG_STREAM_TYPE_MPEG_ELEM
-#define        V4L2_MPEG_STREAM_TYPE_MPEG_ELEM   6 /* MPEG elementary stream */
-#endif
-#ifndef V4L2_MPEG_VIDEO_ENCODING_MPEG_4
-#define        V4L2_MPEG_VIDEO_ENCODING_MPEG_4   3
-#endif
-
-#define call_all(dev, o, f, args...) \
-       v4l2_device_call_until_err(dev, 0, o, f, ##args)
-
-static void deactivate_buffer(struct go7007_buffer *gobuf)
-{
-       int i;
-
-       if (gobuf->state != BUF_STATE_IDLE) {
-               list_del(&gobuf->stream);
-               gobuf->state = BUF_STATE_IDLE;
-       }
-       if (gobuf->page_count > 0) {
-               for (i = 0; i < gobuf->page_count; ++i)
-                       page_cache_release(gobuf->pages[i]);
-               gobuf->page_count = 0;
-       }
-}
-
-static void abort_queued(struct go7007 *go)
-{
-       struct go7007_buffer *gobuf, *next;
-
-       list_for_each_entry_safe(gobuf, next, &go->stream, stream) {
-               deactivate_buffer(gobuf);
-       }
-}
-
-static int go7007_streamoff(struct go7007 *go)
-{
-       int retval = -EINVAL;
-       unsigned long flags;
-
-       mutex_lock(&go->hw_lock);
-       if (go->streaming) {
-               go->streaming = 0;
-               go7007_stream_stop(go);
-               spin_lock_irqsave(&go->spinlock, flags);
-               abort_queued(go);
-               spin_unlock_irqrestore(&go->spinlock, flags);
-               go7007_reset_encoder(go);
-               retval = 0;
-       }
-       mutex_unlock(&go->hw_lock);
-       return 0;
-}
-
-static int go7007_open(struct file *file)
-{
-       struct go7007 *go = video_get_drvdata(video_devdata(file));
-       struct go7007_file *gofh;
-
-       if (go->status != STATUS_ONLINE)
-               return -EBUSY;
-       gofh = kmalloc(sizeof(struct go7007_file), GFP_KERNEL);
-       if (gofh == NULL)
-               return -ENOMEM;
-       ++go->ref_count;
-       gofh->go = go;
-       mutex_init(&gofh->lock);
-       gofh->buf_count = 0;
-       file->private_data = gofh;
-       return 0;
-}
-
-static int go7007_release(struct file *file)
-{
-       struct go7007_file *gofh = file->private_data;
-       struct go7007 *go = gofh->go;
-
-       if (gofh->buf_count > 0) {
-               go7007_streamoff(go);
-               go->in_use = 0;
-               kfree(gofh->bufs);
-               gofh->buf_count = 0;
-       }
-       kfree(gofh);
-       if (--go->ref_count == 0)
-               kfree(go);
-       file->private_data = NULL;
-       return 0;
-}
-
-static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format)
-{
-       u8 *f = page_address(gobuf->pages[0]);
-
-       switch (format) {
-       case GO7007_FORMAT_MJPEG:
-               return V4L2_BUF_FLAG_KEYFRAME;
-       case GO7007_FORMAT_MPEG4:
-               switch ((f[gobuf->frame_offset + 4] >> 6) & 0x3) {
-               case 0:
-                       return V4L2_BUF_FLAG_KEYFRAME;
-               case 1:
-                       return V4L2_BUF_FLAG_PFRAME;
-               case 2:
-                       return V4L2_BUF_FLAG_BFRAME;
-               default:
-                       return 0;
-               }
-       case GO7007_FORMAT_MPEG1:
-       case GO7007_FORMAT_MPEG2:
-               switch ((f[gobuf->frame_offset + 5] >> 3) & 0x7) {
-               case 1:
-                       return V4L2_BUF_FLAG_KEYFRAME;
-               case 2:
-                       return V4L2_BUF_FLAG_PFRAME;
-               case 3:
-                       return V4L2_BUF_FLAG_BFRAME;
-               default:
-                       return 0;
-               }
-       }
-
-       return 0;
-}
-
-static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
-{
-       int sensor_height = 0, sensor_width = 0;
-       int width, height, i;
-
-       if (fmt != NULL && fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG &&
-                       fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG &&
-                       fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG4)
-               return -EINVAL;
-
-       switch (go->standard) {
-       case GO7007_STD_NTSC:
-               sensor_width = 720;
-               sensor_height = 480;
-               break;
-       case GO7007_STD_PAL:
-               sensor_width = 720;
-               sensor_height = 576;
-               break;
-       case GO7007_STD_OTHER:
-               sensor_width = go->board_info->sensor_width;
-               sensor_height = go->board_info->sensor_height;
-               break;
-       }
-
-       if (fmt == NULL) {
-               width = sensor_width;
-               height = sensor_height;
-       } else if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
-               if (fmt->fmt.pix.width > sensor_width)
-                       width = sensor_width;
-               else if (fmt->fmt.pix.width < 144)
-                       width = 144;
-               else
-                       width = fmt->fmt.pix.width & ~0x0f;
-
-               if (fmt->fmt.pix.height > sensor_height)
-                       height = sensor_height;
-               else if (fmt->fmt.pix.height < 96)
-                       height = 96;
-               else
-                       height = fmt->fmt.pix.height & ~0x0f;
-       } else {
-               int requested_size = fmt->fmt.pix.width * fmt->fmt.pix.height;
-               int sensor_size = sensor_width * sensor_height;
-
-               if (64 * requested_size < 9 * sensor_size) {
-                       width = sensor_width / 4;
-                       height = sensor_height / 4;
-               } else if (64 * requested_size < 36 * sensor_size) {
-                       width = sensor_width / 2;
-                       height = sensor_height / 2;
-               } else {
-                       width = sensor_width;
-                       height = sensor_height;
-               }
-               width &= ~0xf;
-               height &= ~0xf;
-       }
-
-       if (fmt != NULL) {
-               u32 pixelformat = fmt->fmt.pix.pixelformat;
-
-               memset(fmt, 0, sizeof(*fmt));
-               fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               fmt->fmt.pix.width = width;
-               fmt->fmt.pix.height = height;
-               fmt->fmt.pix.pixelformat = pixelformat;
-               fmt->fmt.pix.field = V4L2_FIELD_NONE;
-               fmt->fmt.pix.bytesperline = 0;
-               fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
-               fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* ?? */
-       }
-
-       if (try)
-               return 0;
-
-       go->width = width;
-       go->height = height;
-       go->encoder_h_offset = go->board_info->sensor_h_offset;
-       go->encoder_v_offset = go->board_info->sensor_v_offset;
-       for (i = 0; i < 4; ++i)
-               go->modet[i].enable = 0;
-       for (i = 0; i < 1624; ++i)
-               go->modet_map[i] = 0;
-
-       if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
-               struct v4l2_mbus_framefmt mbus_fmt;
-
-               mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
-               if (fmt != NULL)
-                       mbus_fmt.width = fmt->fmt.pix.width;
-               else
-                       mbus_fmt.width = width;
-
-               if (height > sensor_height / 2) {
-                       mbus_fmt.height = height / 2;
-                       go->encoder_v_halve = 0;
-               } else {
-                       mbus_fmt.height = height;
-                       go->encoder_v_halve = 1;
-               }
-               call_all(&go->v4l2_dev, video, s_mbus_fmt, &mbus_fmt);
-       } else {
-               if (width <= sensor_width / 4) {
-                       go->encoder_h_halve = 1;
-                       go->encoder_v_halve = 1;
-                       go->encoder_subsample = 1;
-               } else if (width <= sensor_width / 2) {
-                       go->encoder_h_halve = 1;
-                       go->encoder_v_halve = 1;
-                       go->encoder_subsample = 0;
-               } else {
-                       go->encoder_h_halve = 0;
-                       go->encoder_v_halve = 0;
-                       go->encoder_subsample = 0;
-               }
-       }
-
-       if (fmt == NULL)
-               return 0;
-
-       switch (fmt->fmt.pix.pixelformat) {
-       case V4L2_PIX_FMT_MPEG:
-               if (go->format == GO7007_FORMAT_MPEG1 ||
-                               go->format == GO7007_FORMAT_MPEG2 ||
-                               go->format == GO7007_FORMAT_MPEG4)
-                       break;
-               go->format = GO7007_FORMAT_MPEG1;
-               go->pali = 0;
-               go->aspect_ratio = GO7007_RATIO_1_1;
-               go->gop_size = go->sensor_framerate / 1000;
-               go->ipb = 0;
-               go->closed_gop = 1;
-               go->repeat_seqhead = 1;
-               go->seq_header_enable = 1;
-               go->gop_header_enable = 1;
-               go->dvd_mode = 0;
-               break;
-       /* Backwards compatibility only! */
-       case V4L2_PIX_FMT_MPEG4:
-               if (go->format == GO7007_FORMAT_MPEG4)
-                       break;
-               go->format = GO7007_FORMAT_MPEG4;
-               go->pali = 0xf5;
-               go->aspect_ratio = GO7007_RATIO_1_1;
-               go->gop_size = go->sensor_framerate / 1000;
-               go->ipb = 0;
-               go->closed_gop = 1;
-               go->repeat_seqhead = 1;
-               go->seq_header_enable = 1;
-               go->gop_header_enable = 1;
-               go->dvd_mode = 0;
-               break;
-       case V4L2_PIX_FMT_MJPEG:
-               go->format = GO7007_FORMAT_MJPEG;
-               go->pali = 0;
-               go->aspect_ratio = GO7007_RATIO_1_1;
-               go->gop_size = 0;
-               go->ipb = 0;
-               go->closed_gop = 0;
-               go->repeat_seqhead = 0;
-               go->seq_header_enable = 0;
-               go->gop_header_enable = 0;
-               go->dvd_mode = 0;
-               break;
-       }
-       return 0;
-}
-
-#if 0
-static int clip_to_modet_map(struct go7007 *go, int region,
-               struct v4l2_clip *clip_list)
-{
-       struct v4l2_clip clip, *clip_ptr;
-       int x, y, mbnum;
-
-       /* Check if coordinates are OK and if any macroblocks are already
-        * used by other regions (besides 0) */
-       clip_ptr = clip_list;
-       while (clip_ptr) {
-               if (copy_from_user(&clip, clip_ptr, sizeof(clip)))
-                       return -EFAULT;
-               if (clip.c.left < 0 || (clip.c.left & 0xF) ||
-                               clip.c.width <= 0 || (clip.c.width & 0xF))
-                       return -EINVAL;
-               if (clip.c.left + clip.c.width > go->width)
-                       return -EINVAL;
-               if (clip.c.top < 0 || (clip.c.top & 0xF) ||
-                               clip.c.height <= 0 || (clip.c.height & 0xF))
-                       return -EINVAL;
-               if (clip.c.top + clip.c.height > go->height)
-                       return -EINVAL;
-               for (y = 0; y < clip.c.height; y += 16)
-                       for (x = 0; x < clip.c.width; x += 16) {
-                               mbnum = (go->width >> 4) *
-                                               ((clip.c.top + y) >> 4) +
-                                       ((clip.c.left + x) >> 4);
-                               if (go->modet_map[mbnum] != 0 &&
-                                               go->modet_map[mbnum] != region)
-                                       return -EBUSY;
-                       }
-               clip_ptr = clip.next;
-       }
-
-       /* Clear old region macroblocks */
-       for (mbnum = 0; mbnum < 1624; ++mbnum)
-               if (go->modet_map[mbnum] == region)
-                       go->modet_map[mbnum] = 0;
-
-       /* Claim macroblocks in this list */
-       clip_ptr = clip_list;
-       while (clip_ptr) {
-               if (copy_from_user(&clip, clip_ptr, sizeof(clip)))
-                       return -EFAULT;
-               for (y = 0; y < clip.c.height; y += 16)
-                       for (x = 0; x < clip.c.width; x += 16) {
-                               mbnum = (go->width >> 4) *
-                                               ((clip.c.top + y) >> 4) +
-                                       ((clip.c.left + x) >> 4);
-                               go->modet_map[mbnum] = region;
-                       }
-               clip_ptr = clip.next;
-       }
-       return 0;
-}
-#endif
-
-static int mpeg_query_ctrl(struct v4l2_queryctrl *ctrl)
-{
-       static const u32 mpeg_ctrls[] = {
-               V4L2_CID_MPEG_CLASS,
-               V4L2_CID_MPEG_STREAM_TYPE,
-               V4L2_CID_MPEG_VIDEO_ENCODING,
-               V4L2_CID_MPEG_VIDEO_ASPECT,
-               V4L2_CID_MPEG_VIDEO_GOP_SIZE,
-               V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
-               V4L2_CID_MPEG_VIDEO_BITRATE,
-               0
-       };
-       static const u32 *ctrl_classes[] = {
-               mpeg_ctrls,
-               NULL
-       };
-
-       ctrl->id = v4l2_ctrl_next(ctrl_classes, ctrl->id);
-
-       switch (ctrl->id) {
-       case V4L2_CID_MPEG_CLASS:
-               return v4l2_ctrl_query_fill(ctrl, 0, 0, 0, 0);
-       case V4L2_CID_MPEG_STREAM_TYPE:
-               return v4l2_ctrl_query_fill(ctrl,
-                               V4L2_MPEG_STREAM_TYPE_MPEG2_DVD,
-                               V4L2_MPEG_STREAM_TYPE_MPEG_ELEM, 1,
-                               V4L2_MPEG_STREAM_TYPE_MPEG_ELEM);
-       case V4L2_CID_MPEG_VIDEO_ENCODING:
-               return v4l2_ctrl_query_fill(ctrl,
-                               V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
-                               V4L2_MPEG_VIDEO_ENCODING_MPEG_4, 1,
-                               V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
-       case V4L2_CID_MPEG_VIDEO_ASPECT:
-               return v4l2_ctrl_query_fill(ctrl,
-                               V4L2_MPEG_VIDEO_ASPECT_1x1,
-                               V4L2_MPEG_VIDEO_ASPECT_16x9, 1,
-                               V4L2_MPEG_VIDEO_ASPECT_1x1);
-       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-               return v4l2_ctrl_query_fill(ctrl, 0, 34, 1, 15);
-       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
-               return v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
-       case V4L2_CID_MPEG_VIDEO_BITRATE:
-               return v4l2_ctrl_query_fill(ctrl,
-                               64000,
-                               10000000, 1,
-                               1500000);
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int mpeg_s_ctrl(struct v4l2_control *ctrl, struct go7007 *go)
-{
-       /* pretty sure we can't change any of these while streaming */
-       if (go->streaming)
-               return -EBUSY;
-
-       switch (ctrl->id) {
-       case V4L2_CID_MPEG_STREAM_TYPE:
-               switch (ctrl->value) {
-               case V4L2_MPEG_STREAM_TYPE_MPEG2_DVD:
-                       go->format = GO7007_FORMAT_MPEG2;
-                       go->bitrate = 9800000;
-                       go->gop_size = 15;
-                       go->pali = 0x48;
-                       go->closed_gop = 1;
-                       go->repeat_seqhead = 0;
-                       go->seq_header_enable = 1;
-                       go->gop_header_enable = 1;
-                       go->dvd_mode = 1;
-                       break;
-               case V4L2_MPEG_STREAM_TYPE_MPEG_ELEM:
-                       /* todo: */
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       case V4L2_CID_MPEG_VIDEO_ENCODING:
-               switch (ctrl->value) {
-               case V4L2_MPEG_VIDEO_ENCODING_MPEG_1:
-                       go->format = GO7007_FORMAT_MPEG1;
-                       go->pali = 0;
-                       break;
-               case V4L2_MPEG_VIDEO_ENCODING_MPEG_2:
-                       go->format = GO7007_FORMAT_MPEG2;
-                       /*if (mpeg->pali >> 24 == 2)
-                               go->pali = mpeg->pali & 0xff;
-                       else*/
-                               go->pali = 0x48;
-                       break;
-               case V4L2_MPEG_VIDEO_ENCODING_MPEG_4:
-                       go->format = GO7007_FORMAT_MPEG4;
-                       /*if (mpeg->pali >> 24 == 4)
-                               go->pali = mpeg->pali & 0xff;
-                       else*/
-                               go->pali = 0xf5;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               go->gop_header_enable =
-                       /*mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER
-                       ? 0 :*/ 1;
-               /*if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER)
-                       go->repeat_seqhead = 1;
-               else*/
-                       go->repeat_seqhead = 0;
-               go->dvd_mode = 0;
-               break;
-       case V4L2_CID_MPEG_VIDEO_ASPECT:
-               if (go->format == GO7007_FORMAT_MJPEG)
-                       return -EINVAL;
-               switch (ctrl->value) {
-               case V4L2_MPEG_VIDEO_ASPECT_1x1:
-                       go->aspect_ratio = GO7007_RATIO_1_1;
-                       break;
-               case V4L2_MPEG_VIDEO_ASPECT_4x3:
-                       go->aspect_ratio = GO7007_RATIO_4_3;
-                       break;
-               case V4L2_MPEG_VIDEO_ASPECT_16x9:
-                       go->aspect_ratio = GO7007_RATIO_16_9;
-                       break;
-               case V4L2_MPEG_VIDEO_ASPECT_221x100:
-               default:
-                       return -EINVAL;
-               }
-               break;
-       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-               if (ctrl->value < 0 || ctrl->value > 34)
-                       return -EINVAL;
-               go->gop_size = ctrl->value;
-               break;
-       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
-               if (ctrl->value != 0 && ctrl->value != 1)
-                       return -EINVAL;
-               go->closed_gop = ctrl->value;
-               break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE:
-               /* Upper bound is kind of arbitrary here */
-               if (ctrl->value < 64000 || ctrl->value > 10000000)
-                       return -EINVAL;
-               go->bitrate = ctrl->value;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int mpeg_g_ctrl(struct v4l2_control *ctrl, struct go7007 *go)
-{
-       switch (ctrl->id) {
-       case V4L2_CID_MPEG_STREAM_TYPE:
-               if (go->dvd_mode)
-                       ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_DVD;
-               else
-                       ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG_ELEM;
-               break;
-       case V4L2_CID_MPEG_VIDEO_ENCODING:
-               switch (go->format) {
-               case GO7007_FORMAT_MPEG1:
-                       ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
-                       break;
-               case GO7007_FORMAT_MPEG2:
-                       ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
-                       break;
-               case GO7007_FORMAT_MPEG4:
-                       ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       case V4L2_CID_MPEG_VIDEO_ASPECT:
-               switch (go->aspect_ratio) {
-               case GO7007_RATIO_1_1:
-                       ctrl->value = V4L2_MPEG_VIDEO_ASPECT_1x1;
-                       break;
-               case GO7007_RATIO_4_3:
-                       ctrl->value = V4L2_MPEG_VIDEO_ASPECT_4x3;
-                       break;
-               case GO7007_RATIO_16_9:
-                       ctrl->value = V4L2_MPEG_VIDEO_ASPECT_16x9;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-               ctrl->value = go->gop_size;
-               break;
-       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
-               ctrl->value = go->closed_gop;
-               break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE:
-               ctrl->value = go->bitrate;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int vidioc_querycap(struct file *file, void  *priv,
-                                       struct v4l2_capability *cap)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       strlcpy(cap->driver, "go7007", sizeof(cap->driver));
-       strlcpy(cap->card, go->name, sizeof(cap->card));
-#if 0
-       strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info));
-#endif
-
-       cap->version = KERNEL_VERSION(0, 9, 8);
-
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-                           V4L2_CAP_STREAMING; /* | V4L2_CAP_AUDIO; */
-
-       if (go->board_info->flags & GO7007_BOARD_HAS_TUNER)
-               cap->capabilities |= V4L2_CAP_TUNER;
-
-       return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
-                                       struct v4l2_fmtdesc *fmt)
-{
-       char *desc = NULL;
-
-       switch (fmt->index) {
-       case 0:
-               fmt->pixelformat = V4L2_PIX_FMT_MJPEG;
-               desc = "Motion-JPEG";
-               break;
-       case 1:
-               fmt->pixelformat = V4L2_PIX_FMT_MPEG;
-               desc = "MPEG1/MPEG2/MPEG4";
-               break;
-       default:
-               return -EINVAL;
-       }
-       fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       fmt->flags = V4L2_FMT_FLAG_COMPRESSED;
-
-       strncpy(fmt->description, desc, sizeof(fmt->description));
-
-       return 0;
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
-                                       struct v4l2_format *fmt)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       fmt->fmt.pix.width = go->width;
-       fmt->fmt.pix.height = go->height;
-       fmt->fmt.pix.pixelformat = (go->format == GO7007_FORMAT_MJPEG) ?
-                                  V4L2_PIX_FMT_MJPEG : V4L2_PIX_FMT_MPEG;
-       fmt->fmt.pix.field = V4L2_FIELD_NONE;
-       fmt->fmt.pix.bytesperline = 0;
-       fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
-       fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-
-       return 0;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
-                       struct v4l2_format *fmt)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       return set_capture_size(go, fmt, 1);
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
-                       struct v4l2_format *fmt)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       if (go->streaming)
-               return -EBUSY;
-
-       return set_capture_size(go, fmt, 0);
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
-                         struct v4l2_requestbuffers *req)
-{
-       struct go7007_file *gofh = priv;
-       struct go7007 *go = gofh->go;
-       int retval = -EBUSY;
-       unsigned int count, i;
-
-       if (go->streaming)
-               return retval;
-
-       if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                       req->memory != V4L2_MEMORY_MMAP)
-               return -EINVAL;
-
-       mutex_lock(&gofh->lock);
-       for (i = 0; i < gofh->buf_count; ++i)
-               if (gofh->bufs[i].mapped > 0)
-                       goto unlock_and_return;
-
-       mutex_lock(&go->hw_lock);
-       if (go->in_use > 0 && gofh->buf_count == 0) {
-               mutex_unlock(&go->hw_lock);
-               goto unlock_and_return;
-       }
-
-       if (gofh->buf_count > 0)
-               kfree(gofh->bufs);
-
-       retval = -ENOMEM;
-       count = req->count;
-       if (count > 0) {
-               if (count < 2)
-                       count = 2;
-               if (count > 32)
-                       count = 32;
-
-               gofh->bufs = kcalloc(count, sizeof(struct go7007_buffer),
-                                    GFP_KERNEL);
-
-               if (!gofh->bufs) {
-                       mutex_unlock(&go->hw_lock);
-                       goto unlock_and_return;
-               }
-
-               for (i = 0; i < count; ++i) {
-                       gofh->bufs[i].go = go;
-                       gofh->bufs[i].index = i;
-                       gofh->bufs[i].state = BUF_STATE_IDLE;
-                       gofh->bufs[i].mapped = 0;
-               }
-
-               go->in_use = 1;
-       } else {
-               go->in_use = 0;
-       }
-
-       gofh->buf_count = count;
-       mutex_unlock(&go->hw_lock);
-       mutex_unlock(&gofh->lock);
-
-       memset(req, 0, sizeof(*req));
-
-       req->count = count;
-       req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       req->memory = V4L2_MEMORY_MMAP;
-
-       return 0;
-
-unlock_and_return:
-       mutex_unlock(&gofh->lock);
-       return retval;
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
-                          struct v4l2_buffer *buf)
-{
-       struct go7007_file *gofh = priv;
-       int retval = -EINVAL;
-       unsigned int index;
-
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return retval;
-
-       index = buf->index;
-
-       mutex_lock(&gofh->lock);
-       if (index >= gofh->buf_count)
-               goto unlock_and_return;
-
-       memset(buf, 0, sizeof(*buf));
-       buf->index = index;
-       buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-       switch (gofh->bufs[index].state) {
-       case BUF_STATE_QUEUED:
-               buf->flags = V4L2_BUF_FLAG_QUEUED;
-               break;
-       case BUF_STATE_DONE:
-               buf->flags = V4L2_BUF_FLAG_DONE;
-               break;
-       default:
-               buf->flags = 0;
-       }
-
-       if (gofh->bufs[index].mapped)
-               buf->flags |= V4L2_BUF_FLAG_MAPPED;
-       buf->memory = V4L2_MEMORY_MMAP;
-       buf->m.offset = index * GO7007_BUF_SIZE;
-       buf->length = GO7007_BUF_SIZE;
-       mutex_unlock(&gofh->lock);
-
-       return 0;
-
-unlock_and_return:
-       mutex_unlock(&gofh->lock);
-       return retval;
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-       struct go7007_file *gofh = priv;
-       struct go7007 *go = gofh->go;
-       struct go7007_buffer *gobuf;
-       unsigned long flags;
-       int retval = -EINVAL;
-       int ret;
-
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-                       buf->memory != V4L2_MEMORY_MMAP)
-               return retval;
-
-       mutex_lock(&gofh->lock);
-       if (buf->index < 0 || buf->index >= gofh->buf_count)
-               goto unlock_and_return;
-
-       gobuf = &gofh->bufs[buf->index];
-       if (!gobuf->mapped)
-               goto unlock_and_return;
-
-       retval = -EBUSY;
-       if (gobuf->state != BUF_STATE_IDLE)
-               goto unlock_and_return;
-
-       /* offset will be 0 until we really support USERPTR streaming */
-       gobuf->offset = gobuf->user_addr & ~PAGE_MASK;
-       gobuf->bytesused = 0;
-       gobuf->frame_offset = 0;
-       gobuf->modet_active = 0;
-       if (gobuf->offset > 0)
-               gobuf->page_count = GO7007_BUF_PAGES + 1;
-       else
-               gobuf->page_count = GO7007_BUF_PAGES;
-
-       retval = -ENOMEM;
-       down_read(&current->mm->mmap_sem);
-       ret = get_user_pages(current, current->mm,
-                       gobuf->user_addr & PAGE_MASK, gobuf->page_count,
-                       1, 1, gobuf->pages, NULL);
-       up_read(&current->mm->mmap_sem);
-
-       if (ret != gobuf->page_count) {
-               int i;
-               for (i = 0; i < ret; ++i)
-                       page_cache_release(gobuf->pages[i]);
-               gobuf->page_count = 0;
-               goto unlock_and_return;
-       }
-
-       gobuf->state = BUF_STATE_QUEUED;
-       spin_lock_irqsave(&go->spinlock, flags);
-       list_add_tail(&gobuf->stream, &go->stream);
-       spin_unlock_irqrestore(&go->spinlock, flags);
-       mutex_unlock(&gofh->lock);
-
-       return 0;
-
-unlock_and_return:
-       mutex_unlock(&gofh->lock);
-       return retval;
-}
-
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-       struct go7007_file *gofh = priv;
-       struct go7007 *go = gofh->go;
-       struct go7007_buffer *gobuf;
-       int retval = -EINVAL;
-       unsigned long flags;
-       u32 frame_type_flag;
-       DEFINE_WAIT(wait);
-
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return retval;
-       if (buf->memory != V4L2_MEMORY_MMAP)
-               return retval;
-
-       mutex_lock(&gofh->lock);
-       if (list_empty(&go->stream))
-               goto unlock_and_return;
-       gobuf = list_entry(go->stream.next,
-                       struct go7007_buffer, stream);
-
-       retval = -EAGAIN;
-       if (gobuf->state != BUF_STATE_DONE &&
-                       !(file->f_flags & O_NONBLOCK)) {
-               for (;;) {
-                       prepare_to_wait(&go->frame_waitq, &wait,
-                                       TASK_INTERRUPTIBLE);
-                       if (gobuf->state == BUF_STATE_DONE)
-                               break;
-                       if (signal_pending(current)) {
-                               retval = -ERESTARTSYS;
-                               break;
-                       }
-                       schedule();
-               }
-               finish_wait(&go->frame_waitq, &wait);
-       }
-       if (gobuf->state != BUF_STATE_DONE)
-               goto unlock_and_return;
-
-       spin_lock_irqsave(&go->spinlock, flags);
-       deactivate_buffer(gobuf);
-       spin_unlock_irqrestore(&go->spinlock, flags);
-       frame_type_flag = get_frame_type_flag(gobuf, go->format);
-       gobuf->state = BUF_STATE_IDLE;
-
-       memset(buf, 0, sizeof(*buf));
-       buf->index = gobuf->index;
-       buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       buf->bytesused = gobuf->bytesused;
-       buf->flags = V4L2_BUF_FLAG_MAPPED | frame_type_flag;
-       buf->field = V4L2_FIELD_NONE;
-       buf->timestamp = gobuf->timestamp;
-       buf->sequence = gobuf->seq;
-       buf->memory = V4L2_MEMORY_MMAP;
-       buf->m.offset = gobuf->index * GO7007_BUF_SIZE;
-       buf->length = GO7007_BUF_SIZE;
-       buf->reserved = gobuf->modet_active;
-
-       mutex_unlock(&gofh->lock);
-       return 0;
-
-unlock_and_return:
-       mutex_unlock(&gofh->lock);
-       return retval;
-}
-
-static int vidioc_streamon(struct file *file, void *priv,
-                                       enum v4l2_buf_type type)
-{
-       struct go7007_file *gofh = priv;
-       struct go7007 *go = gofh->go;
-       int retval = 0;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       mutex_lock(&gofh->lock);
-       mutex_lock(&go->hw_lock);
-
-       if (!go->streaming) {
-               go->streaming = 1;
-               go->next_seq = 0;
-               go->active_buf = NULL;
-               if (go7007_start_encoder(go) < 0)
-                       retval = -EIO;
-               else
-                       retval = 0;
-       }
-       mutex_unlock(&go->hw_lock);
-       mutex_unlock(&gofh->lock);
-
-       return retval;
-}
-
-static int vidioc_streamoff(struct file *file, void *priv,
-                                       enum v4l2_buf_type type)
-{
-       struct go7007_file *gofh = priv;
-       struct go7007 *go = gofh->go;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       mutex_lock(&gofh->lock);
-       go7007_streamoff(go);
-       mutex_unlock(&gofh->lock);
-
-       return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
-                          struct v4l2_queryctrl *query)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-       int id = query->id;
-
-       if (0 == call_all(&go->v4l2_dev, core, queryctrl, query))
-               return 0;
-
-       query->id = id;
-       return mpeg_query_ctrl(query);
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctrl)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       if (0 == call_all(&go->v4l2_dev, core, g_ctrl, ctrl))
-               return 0;
-
-       return mpeg_g_ctrl(ctrl, go);
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                               struct v4l2_control *ctrl)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       if (0 == call_all(&go->v4l2_dev, core, s_ctrl, ctrl))
-               return 0;
-
-       return mpeg_s_ctrl(ctrl, go);
-}
-
-static int vidioc_g_parm(struct file *filp, void *priv,
-               struct v4l2_streamparm *parm)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-       struct v4l2_fract timeperframe = {
-               .numerator = 1001 *  go->fps_scale,
-               .denominator = go->sensor_framerate,
-       };
-
-       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME;
-       parm->parm.capture.timeperframe = timeperframe;
-
-       return 0;
-}
-
-static int vidioc_s_parm(struct file *filp, void *priv,
-               struct v4l2_streamparm *parm)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-       unsigned int n, d;
-
-       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-       if (parm->parm.capture.capturemode != 0)
-               return -EINVAL;
-
-       n = go->sensor_framerate *
-               parm->parm.capture.timeperframe.numerator;
-       d = 1001 * parm->parm.capture.timeperframe.denominator;
-       if (n != 0 && d != 0 && n > d)
-               go->fps_scale = (n + d/2) / d;
-       else
-               go->fps_scale = 1;
-
-       return 0;
-}
-
-/* VIDIOC_ENUMSTD on go7007 were used for enumberating the supported fps and
-   its resolution, when the device is not connected to TV.
-   This were an API abuse, probably used by the lack of specific IOCTL's to
-   enumberate it, by the time the driver were written.
-
-   However, since kernel 2.6.19, two new ioctls (VIDIOC_ENUM_FRAMEINTERVALS
-   and VIDIOC_ENUM_FRAMESIZES) were added for this purpose.
-
-   The two functions bellow implements the newer ioctls
-*/
-static int vidioc_enum_framesizes(struct file *filp, void *priv,
-                                 struct v4l2_frmsizeenum *fsize)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       /* Return -EINVAL, if it is a TV board */
-       if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) ||
-           (go->board_info->sensor_flags & GO7007_SENSOR_TV))
-               return -EINVAL;
-
-       if (fsize->index > 0)
-               return -EINVAL;
-
-       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
-       fsize->discrete.width = go->board_info->sensor_width;
-       fsize->discrete.height = go->board_info->sensor_height;
-
-       return 0;
-}
-
-static int vidioc_enum_frameintervals(struct file *filp, void *priv,
-                                     struct v4l2_frmivalenum *fival)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       /* Return -EINVAL, if it is a TV board */
-       if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) ||
-           (go->board_info->sensor_flags & GO7007_SENSOR_TV))
-               return -EINVAL;
-
-       if (fival->index > 0)
-               return -EINVAL;
-
-       fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
-       fival->discrete.numerator = 1001;
-       fival->discrete.denominator = go->board_info->sensor_framerate;
-
-       return 0;
-}
-
-static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       switch (go->standard) {
-       case GO7007_STD_NTSC:
-               *std = V4L2_STD_NTSC;
-               break;
-       case GO7007_STD_PAL:
-               *std = V4L2_STD_PAL;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       if (go->streaming)
-               return -EBUSY;
-
-       if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) && *std != 0)
-               return -EINVAL;
-
-       if (*std == 0)
-               return -EINVAL;
-
-       if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
-                       go->input == go->board_info->num_inputs - 1) {
-               if (!go->i2c_adapter_online)
-                       return -EIO;
-               if (call_all(&go->v4l2_dev, core, s_std, *std) < 0)
-                       return -EINVAL;
-       }
-
-       if (*std & V4L2_STD_NTSC) {
-               go->standard = GO7007_STD_NTSC;
-               go->sensor_framerate = 30000;
-       } else if (*std & V4L2_STD_PAL) {
-               go->standard = GO7007_STD_PAL;
-               go->sensor_framerate = 25025;
-       } else if (*std & V4L2_STD_SECAM) {
-               go->standard = GO7007_STD_PAL;
-               go->sensor_framerate = 25025;
-       } else
-               return -EINVAL;
-
-       call_all(&go->v4l2_dev, core, s_std, *std);
-       set_capture_size(go, NULL, 0);
-
-       return 0;
-}
-
-static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
-                       go->input == go->board_info->num_inputs - 1) {
-               if (!go->i2c_adapter_online)
-                       return -EIO;
-               return call_all(&go->v4l2_dev, video, querystd, std);
-       } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
-               *std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
-       else
-               *std = 0;
-
-       return 0;
-}
-
-static int vidioc_enum_input(struct file *file, void *priv,
-                               struct v4l2_input *inp)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       if (inp->index >= go->board_info->num_inputs)
-               return -EINVAL;
-
-       strncpy(inp->name, go->board_info->inputs[inp->index].name,
-                       sizeof(inp->name));
-
-       /* If this board has a tuner, it will be the last input */
-       if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
-                       inp->index == go->board_info->num_inputs - 1)
-               inp->type = V4L2_INPUT_TYPE_TUNER;
-       else
-               inp->type = V4L2_INPUT_TYPE_CAMERA;
-
-       inp->audioset = 0;
-       inp->tuner = 0;
-       if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
-               inp->std = V4L2_STD_NTSC | V4L2_STD_PAL |
-                                               V4L2_STD_SECAM;
-       else
-               inp->std = 0;
-
-       return 0;
-}
-
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *input)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       *input = go->input;
-
-       return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int input)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       if (input >= go->board_info->num_inputs)
-               return -EINVAL;
-       if (go->streaming)
-               return -EBUSY;
-
-       go->input = input;
-
-       return call_all(&go->v4l2_dev, video, s_routing, input, 0, 0);
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-                               struct v4l2_tuner *t)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
-               return -EINVAL;
-       if (t->index != 0)
-               return -EINVAL;
-       if (!go->i2c_adapter_online)
-               return -EIO;
-
-       return call_all(&go->v4l2_dev, tuner, g_tuner, t);
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
-                               struct v4l2_tuner *t)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
-               return -EINVAL;
-       if (t->index != 0)
-               return -EINVAL;
-       if (!go->i2c_adapter_online)
-               return -EIO;
-
-       switch (go->board_id) {
-       case GO7007_BOARDID_PX_TV402U_NA:
-       case GO7007_BOARDID_PX_TV402U_JP:
-               /* No selectable options currently */
-               if (t->audmode != V4L2_TUNER_MODE_STEREO)
-                       return -EINVAL;
-               break;
-       }
-
-       return call_all(&go->v4l2_dev, tuner, s_tuner, t);
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-                               struct v4l2_frequency *f)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
-               return -EINVAL;
-       if (!go->i2c_adapter_online)
-               return -EIO;
-
-       f->type = V4L2_TUNER_ANALOG_TV;
-
-       return call_all(&go->v4l2_dev, tuner, g_frequency, f);
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
-                               struct v4l2_frequency *f)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
-               return -EINVAL;
-       if (!go->i2c_adapter_online)
-               return -EIO;
-
-       return call_all(&go->v4l2_dev, tuner, s_frequency, f);
-}
-
-static int vidioc_cropcap(struct file *file, void *priv,
-                                       struct v4l2_cropcap *cropcap)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       /* These specify the raw input of the sensor */
-       switch (go->standard) {
-       case GO7007_STD_NTSC:
-               cropcap->bounds.top = 0;
-               cropcap->bounds.left = 0;
-               cropcap->bounds.width = 720;
-               cropcap->bounds.height = 480;
-               cropcap->defrect.top = 0;
-               cropcap->defrect.left = 0;
-               cropcap->defrect.width = 720;
-               cropcap->defrect.height = 480;
-               break;
-       case GO7007_STD_PAL:
-               cropcap->bounds.top = 0;
-               cropcap->bounds.left = 0;
-               cropcap->bounds.width = 720;
-               cropcap->bounds.height = 576;
-               cropcap->defrect.top = 0;
-               cropcap->defrect.left = 0;
-               cropcap->defrect.width = 720;
-               cropcap->defrect.height = 576;
-               break;
-       case GO7007_STD_OTHER:
-               cropcap->bounds.top = 0;
-               cropcap->bounds.left = 0;
-               cropcap->bounds.width = go->board_info->sensor_width;
-               cropcap->bounds.height = go->board_info->sensor_height;
-               cropcap->defrect.top = 0;
-               cropcap->defrect.left = 0;
-               cropcap->defrect.width = go->board_info->sensor_width;
-               cropcap->defrect.height = go->board_info->sensor_height;
-               break;
-       }
-
-       return 0;
-}
-
-static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
-{
-       struct go7007 *go = ((struct go7007_file *) priv)->go;
-
-       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-       /* These specify the raw input of the sensor */
-       switch (go->standard) {
-       case GO7007_STD_NTSC:
-               crop->c.top = 0;
-               crop->c.left = 0;
-               crop->c.width = 720;
-               crop->c.height = 480;
-               break;
-       case GO7007_STD_PAL:
-               crop->c.top = 0;
-               crop->c.left = 0;
-               crop->c.width = 720;
-               crop->c.height = 576;
-               break;
-       case GO7007_STD_OTHER:
-               crop->c.top = 0;
-               crop->c.left = 0;
-               crop->c.width = go->board_info->sensor_width;
-               crop->c.height = go->board_info->sensor_height;
-               break;
-       }
-
-       return 0;
-}
-
-/* FIXME: vidioc_s_crop is not really implemented!!!
- */
-static int vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop)
-{
-       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int vidioc_g_jpegcomp(struct file *file, void *priv,
-                        struct v4l2_jpegcompression *params)
-{
-       memset(params, 0, sizeof(*params));
-       params->quality = 50; /* ?? */
-       params->jpeg_markers = V4L2_JPEG_MARKER_DHT |
-                               V4L2_JPEG_MARKER_DQT;
-
-       return 0;
-}
-
-static int vidioc_s_jpegcomp(struct file *file, void *priv,
-                        struct v4l2_jpegcompression *params)
-{
-       if (params->quality != 50 ||
-                       params->jpeg_markers != (V4L2_JPEG_MARKER_DHT |
-                                               V4L2_JPEG_MARKER_DQT))
-               return -EINVAL;
-
-       return 0;
-}
-
-/* FIXME:
-       Those ioctls are private, and not needed, since several standard
-       extended controls already provide streaming control.
-       So, those ioctls should be converted into vidioc_g_ext_ctrls()
-       and vidioc_s_ext_ctrls()
- */
-
-#if 0
-       /* Temporary ioctls for controlling compression characteristics */
-       case GO7007IOC_S_BITRATE:
-       {
-               int *bitrate = arg;
-
-               if (go->streaming)
-                       return -EINVAL;
-               /* Upper bound is kind of arbitrary here */
-               if (*bitrate < 64000 || *bitrate > 10000000)
-                       return -EINVAL;
-               go->bitrate = *bitrate;
-               return 0;
-       }
-       case GO7007IOC_G_BITRATE:
-       {
-               int *bitrate = arg;
-
-               *bitrate = go->bitrate;
-               return 0;
-       }
-       case GO7007IOC_S_COMP_PARAMS:
-       {
-               struct go7007_comp_params *comp = arg;
-
-               if (go->format == GO7007_FORMAT_MJPEG)
-                       return -EINVAL;
-               if (comp->gop_size > 0)
-                       go->gop_size = comp->gop_size;
-               else
-                       go->gop_size = go->sensor_framerate / 1000;
-               if (go->gop_size != 15)
-                       go->dvd_mode = 0;
-               /*go->ipb = comp->max_b_frames > 0;*/ /* completely untested */
-               if (go->board_info->sensor_flags & GO7007_SENSOR_TV) {
-                       switch (comp->aspect_ratio) {
-                       case GO7007_ASPECT_RATIO_4_3_NTSC:
-                       case GO7007_ASPECT_RATIO_4_3_PAL:
-                               go->aspect_ratio = GO7007_RATIO_4_3;
-                               break;
-                       case GO7007_ASPECT_RATIO_16_9_NTSC:
-                       case GO7007_ASPECT_RATIO_16_9_PAL:
-                               go->aspect_ratio = GO7007_RATIO_16_9;
-                               break;
-                       default:
-                               go->aspect_ratio = GO7007_RATIO_1_1;
-                               break;
-                       }
-               }
-               if (comp->flags & GO7007_COMP_OMIT_SEQ_HEADER) {
-                       go->dvd_mode = 0;
-                       go->seq_header_enable = 0;
-               } else {
-                       go->seq_header_enable = 1;
-               }
-               /* fall-through */
-       }
-       case GO7007IOC_G_COMP_PARAMS:
-       {
-               struct go7007_comp_params *comp = arg;
-
-               if (go->format == GO7007_FORMAT_MJPEG)
-                       return -EINVAL;
-               memset(comp, 0, sizeof(*comp));
-               comp->gop_size = go->gop_size;
-               comp->max_b_frames = go->ipb ? 2 : 0;
-               switch (go->aspect_ratio) {
-               case GO7007_RATIO_4_3:
-                       if (go->standard == GO7007_STD_NTSC)
-                               comp->aspect_ratio =
-                                       GO7007_ASPECT_RATIO_4_3_NTSC;
-                       else
-                               comp->aspect_ratio =
-                                       GO7007_ASPECT_RATIO_4_3_PAL;
-                       break;
-               case GO7007_RATIO_16_9:
-                       if (go->standard == GO7007_STD_NTSC)
-                               comp->aspect_ratio =
-                                       GO7007_ASPECT_RATIO_16_9_NTSC;
-                       else
-                               comp->aspect_ratio =
-                                       GO7007_ASPECT_RATIO_16_9_PAL;
-                       break;
-               default:
-                       comp->aspect_ratio = GO7007_ASPECT_RATIO_1_1;
-                       break;
-               }
-               if (go->closed_gop)
-                       comp->flags |= GO7007_COMP_CLOSED_GOP;
-               if (!go->seq_header_enable)
-                       comp->flags |= GO7007_COMP_OMIT_SEQ_HEADER;
-               return 0;
-       }
-       case GO7007IOC_S_MPEG_PARAMS:
-       {
-               struct go7007_mpeg_params *mpeg = arg;
-
-               if (go->format != GO7007_FORMAT_MPEG1 &&
-                               go->format != GO7007_FORMAT_MPEG2 &&
-                               go->format != GO7007_FORMAT_MPEG4)
-                       return -EINVAL;
-
-               if (mpeg->flags & GO7007_MPEG_FORCE_DVD_MODE) {
-                       go->format = GO7007_FORMAT_MPEG2;
-                       go->bitrate = 9800000;
-                       go->gop_size = 15;
-                       go->pali = 0x48;
-                       go->closed_gop = 1;
-                       go->repeat_seqhead = 0;
-                       go->seq_header_enable = 1;
-                       go->gop_header_enable = 1;
-                       go->dvd_mode = 1;
-               } else {
-                       switch (mpeg->mpeg_video_standard) {
-                       case GO7007_MPEG_VIDEO_MPEG1:
-                               go->format = GO7007_FORMAT_MPEG1;
-                               go->pali = 0;
-                               break;
-                       case GO7007_MPEG_VIDEO_MPEG2:
-                               go->format = GO7007_FORMAT_MPEG2;
-                               if (mpeg->pali >> 24 == 2)
-                                       go->pali = mpeg->pali & 0xff;
-                               else
-                                       go->pali = 0x48;
-                               break;
-                       case GO7007_MPEG_VIDEO_MPEG4:
-                               go->format = GO7007_FORMAT_MPEG4;
-                               if (mpeg->pali >> 24 == 4)
-                                       go->pali = mpeg->pali & 0xff;
-                               else
-                                       go->pali = 0xf5;
-                               break;
-                       default:
-                               return -EINVAL;
-                       }
-                       go->gop_header_enable =
-                               mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER
-                               ? 0 : 1;
-                       if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER)
-                               go->repeat_seqhead = 1;
-                       else
-                               go->repeat_seqhead = 0;
-                       go->dvd_mode = 0;
-               }
-               /* fall-through */
-       }
-       case GO7007IOC_G_MPEG_PARAMS:
-       {
-               struct go7007_mpeg_params *mpeg = arg;
-
-               memset(mpeg, 0, sizeof(*mpeg));
-               switch (go->format) {
-               case GO7007_FORMAT_MPEG1:
-                       mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG1;
-                       mpeg->pali = 0;
-                       break;
-               case GO7007_FORMAT_MPEG2:
-                       mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2;
-                       mpeg->pali = GO7007_MPEG_PROFILE(2, go->pali);
-                       break;
-               case GO7007_FORMAT_MPEG4:
-                       mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4;
-                       mpeg->pali = GO7007_MPEG_PROFILE(4, go->pali);
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               if (!go->gop_header_enable)
-                       mpeg->flags |= GO7007_MPEG_OMIT_GOP_HEADER;
-               if (go->repeat_seqhead)
-                       mpeg->flags |= GO7007_MPEG_REPEAT_SEQHEADER;
-               if (go->dvd_mode)
-                       mpeg->flags |= GO7007_MPEG_FORCE_DVD_MODE;
-               return 0;
-       }
-       case GO7007IOC_S_MD_PARAMS:
-       {
-               struct go7007_md_params *mdp = arg;
-
-               if (mdp->region > 3)
-                       return -EINVAL;
-               if (mdp->trigger > 0) {
-                       go->modet[mdp->region].pixel_threshold =
-                                       mdp->pixel_threshold >> 1;
-                       go->modet[mdp->region].motion_threshold =
-                                       mdp->motion_threshold >> 1;
-                       go->modet[mdp->region].mb_threshold =
-                                       mdp->trigger >> 1;
-                       go->modet[mdp->region].enable = 1;
-               } else
-                       go->modet[mdp->region].enable = 0;
-               /* fall-through */
-       }
-       case GO7007IOC_G_MD_PARAMS:
-       {
-               struct go7007_md_params *mdp = arg;
-               int region = mdp->region;
-
-               if (mdp->region > 3)
-                       return -EINVAL;
-               memset(mdp, 0, sizeof(struct go7007_md_params));
-               mdp->region = region;
-               if (!go->modet[region].enable)
-                       return 0;
-               mdp->pixel_threshold =
-                       (go->modet[region].pixel_threshold << 1) + 1;
-               mdp->motion_threshold =
-                       (go->modet[region].motion_threshold << 1) + 1;
-               mdp->trigger =
-                       (go->modet[region].mb_threshold << 1) + 1;
-               return 0;
-       }
-       case GO7007IOC_S_MD_REGION:
-       {
-               struct go7007_md_region *region = arg;
-
-               if (region->region < 1 || region->region > 3)
-                       return -EINVAL;
-               return clip_to_modet_map(go, region->region, region->clips);
-       }
-#endif
-
-static ssize_t go7007_read(struct file *file, char __user *data,
-               size_t count, loff_t *ppos)
-{
-       return -EINVAL;
-}
-
-static void go7007_vm_open(struct vm_area_struct *vma)
-{
-       struct go7007_buffer *gobuf = vma->vm_private_data;
-
-       ++gobuf->mapped;
-}
-
-static void go7007_vm_close(struct vm_area_struct *vma)
-{
-       struct go7007_buffer *gobuf = vma->vm_private_data;
-       unsigned long flags;
-
-       if (--gobuf->mapped == 0) {
-               spin_lock_irqsave(&gobuf->go->spinlock, flags);
-               deactivate_buffer(gobuf);
-               spin_unlock_irqrestore(&gobuf->go->spinlock, flags);
-       }
-}
-
-/* Copied from videobuf-dma-sg.c */
-static int go7007_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
-{
-       struct page *page;
-
-       page = alloc_page(GFP_USER | __GFP_DMA32);
-       if (!page)
-               return VM_FAULT_OOM;
-       clear_user_highpage(page, (unsigned long)vmf->virtual_address);
-       vmf->page = page;
-       return 0;
-}
-
-static struct vm_operations_struct go7007_vm_ops = {
-       .open   = go7007_vm_open,
-       .close  = go7007_vm_close,
-       .fault  = go7007_vm_fault,
-};
-
-static int go7007_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct go7007_file *gofh = file->private_data;
-       unsigned int index;
-
-       if (gofh->go->status != STATUS_ONLINE)
-               return -EIO;
-       if (!(vma->vm_flags & VM_SHARED))
-               return -EINVAL; /* only support VM_SHARED mapping */
-       if (vma->vm_end - vma->vm_start != GO7007_BUF_SIZE)
-               return -EINVAL; /* must map exactly one full buffer */
-       mutex_lock(&gofh->lock);
-       index = vma->vm_pgoff / GO7007_BUF_PAGES;
-       if (index >= gofh->buf_count) {
-               mutex_unlock(&gofh->lock);
-               return -EINVAL; /* trying to map beyond requested buffers */
-       }
-       if (index * GO7007_BUF_PAGES != vma->vm_pgoff) {
-               mutex_unlock(&gofh->lock);
-               return -EINVAL; /* offset is not aligned on buffer boundary */
-       }
-       if (gofh->bufs[index].mapped > 0) {
-               mutex_unlock(&gofh->lock);
-               return -EBUSY;
-       }
-       gofh->bufs[index].mapped = 1;
-       gofh->bufs[index].user_addr = vma->vm_start;
-       vma->vm_ops = &go7007_vm_ops;
-       vma->vm_flags |= VM_DONTEXPAND;
-       vma->vm_flags &= ~VM_IO;
-       vma->vm_private_data = &gofh->bufs[index];
-       mutex_unlock(&gofh->lock);
-       return 0;
-}
-
-static unsigned int go7007_poll(struct file *file, poll_table *wait)
-{
-       struct go7007_file *gofh = file->private_data;
-       struct go7007_buffer *gobuf;
-
-       if (list_empty(&gofh->go->stream))
-               return POLLERR;
-       gobuf = list_entry(gofh->go->stream.next, struct go7007_buffer, stream);
-       poll_wait(file, &gofh->go->frame_waitq, wait);
-       if (gobuf->state == BUF_STATE_DONE)
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-static void go7007_vfl_release(struct video_device *vfd)
-{
-       struct go7007 *go = video_get_drvdata(vfd);
-
-       video_device_release(vfd);
-       if (--go->ref_count == 0)
-               kfree(go);
-}
-
-static struct v4l2_file_operations go7007_fops = {
-       .owner          = THIS_MODULE,
-       .open           = go7007_open,
-       .release        = go7007_release,
-       .ioctl          = video_ioctl2,
-       .read           = go7007_read,
-       .mmap           = go7007_mmap,
-       .poll           = go7007_poll,
-};
-
-static const struct v4l2_ioctl_ops video_ioctl_ops = {
-       .vidioc_querycap          = vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
-       .vidioc_reqbufs           = vidioc_reqbufs,
-       .vidioc_querybuf          = vidioc_querybuf,
-       .vidioc_qbuf              = vidioc_qbuf,
-       .vidioc_dqbuf             = vidioc_dqbuf,
-       .vidioc_g_std             = vidioc_g_std,
-       .vidioc_s_std             = vidioc_s_std,
-       .vidioc_querystd          = vidioc_querystd,
-       .vidioc_enum_input        = vidioc_enum_input,
-       .vidioc_g_input           = vidioc_g_input,
-       .vidioc_s_input           = vidioc_s_input,
-       .vidioc_queryctrl         = vidioc_queryctrl,
-       .vidioc_g_ctrl            = vidioc_g_ctrl,
-       .vidioc_s_ctrl            = vidioc_s_ctrl,
-       .vidioc_streamon          = vidioc_streamon,
-       .vidioc_streamoff         = vidioc_streamoff,
-       .vidioc_g_tuner           = vidioc_g_tuner,
-       .vidioc_s_tuner           = vidioc_s_tuner,
-       .vidioc_g_frequency       = vidioc_g_frequency,
-       .vidioc_s_frequency       = vidioc_s_frequency,
-       .vidioc_g_parm            = vidioc_g_parm,
-       .vidioc_s_parm            = vidioc_s_parm,
-       .vidioc_enum_framesizes   = vidioc_enum_framesizes,
-       .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
-       .vidioc_cropcap           = vidioc_cropcap,
-       .vidioc_g_crop            = vidioc_g_crop,
-       .vidioc_s_crop            = vidioc_s_crop,
-       .vidioc_g_jpegcomp        = vidioc_g_jpegcomp,
-       .vidioc_s_jpegcomp        = vidioc_s_jpegcomp,
-};
-
-static struct video_device go7007_template = {
-       .name           = "go7007",
-       .fops           = &go7007_fops,
-       .release        = go7007_vfl_release,
-       .ioctl_ops      = &video_ioctl_ops,
-       .tvnorms        = V4L2_STD_ALL,
-       .current_norm   = V4L2_STD_NTSC,
-};
-
-int go7007_v4l2_init(struct go7007 *go)
-{
-       int rv;
-
-       go->video_dev = video_device_alloc();
-       if (go->video_dev == NULL)
-               return -ENOMEM;
-       *go->video_dev = go7007_template;
-       go->video_dev->parent = go->dev;
-       rv = video_register_device(go->video_dev, VFL_TYPE_GRABBER, -1);
-       if (rv < 0) {
-               video_device_release(go->video_dev);
-               go->video_dev = NULL;
-               return rv;
-       }
-       rv = v4l2_device_register(go->dev, &go->v4l2_dev);
-       if (rv < 0) {
-               video_device_release(go->video_dev);
-               go->video_dev = NULL;
-               return rv;
-       }
-       video_set_drvdata(go->video_dev, go);
-       ++go->ref_count;
-       printk(KERN_INFO "%s: registered device %s [v4l2]\n",
-              go->video_dev->name, video_device_node_name(go->video_dev));
-
-       return 0;
-}
-
-void go7007_v4l2_remove(struct go7007 *go)
-{
-       unsigned long flags;
-
-       mutex_lock(&go->hw_lock);
-       if (go->streaming) {
-               go->streaming = 0;
-               go7007_stream_stop(go);
-               spin_lock_irqsave(&go->spinlock, flags);
-               abort_queued(go);
-               spin_unlock_irqrestore(&go->spinlock, flags);
-       }
-       mutex_unlock(&go->hw_lock);
-       if (go->video_dev)
-               video_unregister_device(go->video_dev);
-       v4l2_device_unregister(&go->v4l2_dev);
-}
diff --git a/drivers/staging/go7007/go7007.h b/drivers/staging/go7007/go7007.h
deleted file mode 100644 (file)
index 7399c91..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and the associated README documentation file (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/* DEPRECATED -- use V4L2_PIX_FMT_MPEG and then call GO7007IOC_S_MPEG_PARAMS
- * to select between MPEG1, MPEG2, and MPEG4 */
-#define V4L2_PIX_FMT_MPEG4     v4l2_fourcc('M', 'P', 'G', '4') /* MPEG4 */
-
-/* These will be replaced with a better interface
- * soon, so don't get too attached to them */
-#define        GO7007IOC_S_BITRATE     _IOW('V', BASE_VIDIOC_PRIVATE + 0, int)
-#define        GO7007IOC_G_BITRATE     _IOR('V', BASE_VIDIOC_PRIVATE + 1, int)
-
-enum go7007_aspect_ratio {
-       GO7007_ASPECT_RATIO_1_1 = 0,
-       GO7007_ASPECT_RATIO_4_3_NTSC = 1,
-       GO7007_ASPECT_RATIO_4_3_PAL = 2,
-       GO7007_ASPECT_RATIO_16_9_NTSC = 3,
-       GO7007_ASPECT_RATIO_16_9_PAL = 4,
-};
-
-/* Used to set generic compression parameters */
-struct go7007_comp_params {
-       __u32 gop_size;
-       __u32 max_b_frames;
-       enum go7007_aspect_ratio aspect_ratio;
-       __u32 flags;
-       __u32 reserved[8];
-};
-
-#define GO7007_COMP_CLOSED_GOP         0x00000001
-#define GO7007_COMP_OMIT_SEQ_HEADER    0x00000002
-
-enum go7007_mpeg_video_standard {
-       GO7007_MPEG_VIDEO_MPEG1 = 0,
-       GO7007_MPEG_VIDEO_MPEG2 = 1,
-       GO7007_MPEG_VIDEO_MPEG4 = 2,
-};
-
-/* Used to set parameters for V4L2_PIX_FMT_MPEG format */
-struct go7007_mpeg_params {
-       enum go7007_mpeg_video_standard mpeg_video_standard;
-       __u32 flags;
-       __u32 pali;
-       __u32 reserved[8];
-};
-
-#define GO7007_MPEG_FORCE_DVD_MODE     0x00000001
-#define GO7007_MPEG_OMIT_GOP_HEADER    0x00000002
-#define GO7007_MPEG_REPEAT_SEQHEADER   0x00000004
-
-#define GO7007_MPEG_PROFILE(format, pali)      (((format)<<24)|(pali))
-
-#define GO7007_MPEG2_PROFILE_MAIN_MAIN         GO7007_MPEG_PROFILE(2, 0x48)
-
-#define GO7007_MPEG4_PROFILE_S_L0              GO7007_MPEG_PROFILE(4, 0x08)
-#define GO7007_MPEG4_PROFILE_S_L1              GO7007_MPEG_PROFILE(4, 0x01)
-#define GO7007_MPEG4_PROFILE_S_L2              GO7007_MPEG_PROFILE(4, 0x02)
-#define GO7007_MPEG4_PROFILE_S_L3              GO7007_MPEG_PROFILE(4, 0x03)
-#define GO7007_MPEG4_PROFILE_ARTS_L1           GO7007_MPEG_PROFILE(4, 0x91)
-#define GO7007_MPEG4_PROFILE_ARTS_L2           GO7007_MPEG_PROFILE(4, 0x92)
-#define GO7007_MPEG4_PROFILE_ARTS_L3           GO7007_MPEG_PROFILE(4, 0x93)
-#define GO7007_MPEG4_PROFILE_ARTS_L4           GO7007_MPEG_PROFILE(4, 0x94)
-#define GO7007_MPEG4_PROFILE_AS_L0             GO7007_MPEG_PROFILE(4, 0xf0)
-#define GO7007_MPEG4_PROFILE_AS_L1             GO7007_MPEG_PROFILE(4, 0xf1)
-#define GO7007_MPEG4_PROFILE_AS_L2             GO7007_MPEG_PROFILE(4, 0xf2)
-#define GO7007_MPEG4_PROFILE_AS_L3             GO7007_MPEG_PROFILE(4, 0xf3)
-#define GO7007_MPEG4_PROFILE_AS_L4             GO7007_MPEG_PROFILE(4, 0xf4)
-#define GO7007_MPEG4_PROFILE_AS_L5             GO7007_MPEG_PROFILE(4, 0xf5)
-
-struct go7007_md_params {
-       __u16 region;
-       __u16 trigger;
-       __u16 pixel_threshold;
-       __u16 motion_threshold;
-       __u32 reserved[8];
-};
-
-struct go7007_md_region {
-       __u16 region;
-       __u16 flags;
-       struct v4l2_clip *clips;
-       __u32 reserved[8];
-};
-
-#define        GO7007IOC_S_MPEG_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 2, \
-                                       struct go7007_mpeg_params)
-#define        GO7007IOC_G_MPEG_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 3, \
-                                       struct go7007_mpeg_params)
-#define        GO7007IOC_S_COMP_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 4, \
-                                       struct go7007_comp_params)
-#define        GO7007IOC_G_COMP_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 5, \
-                                       struct go7007_comp_params)
-#define        GO7007IOC_S_MD_PARAMS   _IOWR('V', BASE_VIDIOC_PRIVATE + 6, \
-                                       struct go7007_md_params)
-#define        GO7007IOC_G_MD_PARAMS   _IOR('V', BASE_VIDIOC_PRIVATE + 7, \
-                                       struct go7007_md_params)
-#define        GO7007IOC_S_MD_REGION   _IOW('V', BASE_VIDIOC_PRIVATE + 8, \
-                                       struct go7007_md_region)
diff --git a/drivers/staging/go7007/go7007.txt b/drivers/staging/go7007/go7007.txt
deleted file mode 100644 (file)
index 9db1f39..0000000
+++ /dev/null
@@ -1,481 +0,0 @@
-This is a driver for the WIS GO7007SB multi-format video encoder.
-
-Pete Eberlein <pete@sensoray.com>
-
-The driver was originally released under the GPL and is currently hosted at:
-http://nikosapi.org/wiki/index.php/WIS_Go7007_Linux_driver
-The go7007 firmware can be acquired from the package on the site above.
-
-I've modified the driver to support the following Video4Linux2 MPEG
-controls, with acceptable values:
-
-V4L2_CID_MPEG_STREAM_TYPE      V4L2_MPEG_STREAM_TYPE_MPEG2_DVD
-                               V4L2_MPEG_STREAM_TYPE_MPEG_ELEM
-V4L2_CID_MPEG_VIDEO_ENCODING   V4L2_MPEG_VIDEO_ENCODING_MPEG_1
-                               V4L2_MPEG_VIDEO_ENCODING_MPEG_2
-                               V4L2_MPEG_VIDEO_ENCODING_MPEG_4
-V4L2_CID_MPEG_VIDEO_ASPECT     V4L2_MPEG_VIDEO_ASPECT_1x1
-                               V4L2_MPEG_VIDEO_ASPECT_4x3
-                               V4L2_MPEG_VIDEO_ASPECT_16x9
-V4L2_CID_MPEG_VIDEO_GOP_SIZE   integer
-V4L2_CID_MPEG_VIDEO_BITRATE    64000 .. 10000000
-
-These should be used instead of the non-standard GO7007 ioctls described
-below.
-
-
-The README files from the orignal package appear below:
-
----------------------------------------------------------------------------
-                    WIS GO7007SB Public Linux Driver
----------------------------------------------------------------------------
-
-
-*** Please see the file RELEASE-NOTES for important last-minute updates ***
-
-
-  0. OVERVIEW AND LICENSING/DISCLAIMER
-
-
-This driver kit contains Linux drivers for the WIS GO7007SB multi-format
-video encoder.  Only kernel version 2.6.x is supported.  The video stream
-is available through the Video4Linux2 API and the audio stream is available
-through the ALSA API (or the OSS emulation layer of the ALSA system).
-
-The files in kernel/ and hotplug/ are licensed under the GNU General Public
-License Version 2 from the Free Software Foundation.  A copy of the license
-is included in the file COPYING.
-
-The example applications in apps/ and C header files in include/ are
-licensed under a permissive license included in the source files which
-allows copying, modification and redistribution for any purpose without
-attribution.
-
-The firmware files included in the firmware/ directory may be freely
-redistributed only in conjunction with this document; but modification,
-tampering and reverse engineering are prohibited.
-
-MICRONAS USA, INC., MAKES NO WARRANTIES TO ANY PERSON OR ENTITY WITH
-RESPECT TO THE SOFTWARE OR ANY DERIVATIVES THEREOF OR ANY SERVICES OR
-LICENSES AND DISCLAIMS ALL IMPLIED WARRANTIES, INCLUDING WITHOUT LIMITATION
-WARRANTIES OF MERCHANTABILITY, SUPPORT, AND FITNESS FOR A PARTICULAR
-PURPOSE AND NON-INFRINGEMENT.
-
-
-  1. SYSTEM REQUIREMENTS
-
-
-This driver requires Linux kernel 2.6.  Kernel 2.4 is not supported.  Using
-kernel 2.6.10 or later is recommended, as earlier kernels are known to have
-unstable USB 2.0 support.
-
-A fully built kernel source tree must be available.  Typically this will be
-linked from "/lib/modules/<KERNEL VERSION>/build" for convenience.  If this
-link does not exist, an extra parameter will need to be passed to the
-`make` command.
-
-All vendor-built kernels should already be configured properly.  However,
-for custom-built kernels, the following options need to be enabled in the
-kernel as built-in or modules:
-
-       CONFIG_HOTPLUG           - Support for hot-pluggable devices
-       CONFIG_MODULES           - Enable loadable module support
-       CONFIG_KMOD              - Automatic kernel module loading
-       CONFIG_FW_LOADER         - Hotplug firmware loading support
-       CONFIG_I2C               - I2C support
-       CONFIG_VIDEO_DEV         - Video For Linux
-       CONFIG_SOUND             - Sound card support
-       CONFIG_SND               - Advanced Linux Sound Architecture
-       CONFIG_USB               - Support for Host-side USB
-       CONFIG_USB_DEVICEFS      - USB device filesystem
-       CONFIG_USB_EHCI_HCD      - EHCI HCD (USB 2.0) support
-
-Additionally, to use the example application, the following options need to
-be enabled in the ALSA section:
-
-       CONFIG_SND_MIXER_OSS     - OSS Mixer API
-       CONFIG_SND_PCM_OSS       - OSS PCM (digital audio) API
-
-The hotplug scripts, along with the fxload utility, must also be installed.
-These scripts can be obtained from <http://linux-hotplug.sourceforge.net/>.
-Hotplugging is used for loading firmware into the Cypruss EZ-USB chip using
-fxload and for loading firmware into the driver using the firmware agent.
-
-
-  2. COMPILING AND INSTALLING THE DRIVER
-
-
-Most users should be able to compile the driver by simply running:
-
-       $ make
-
-in the top-level directory of the driver kit.  First the kernel modules
-will be built, followed by the example applications.
-
-If the build system is unable to locate the kernel source tree for the
-currently-running kernel, or if the module should be built for a kernel
-other than the currently-running kernel, an additional parameter will need
-to be passed to make to specify the appropriate kernel source directory:
-
-       $ make KERNELSRC=/usr/src/linux-2.6.10-custom3
-
-Once the compile completes, the driver and firmware files should be
-installed by running:
-
-       $ make install
-
-The kernel modules will be placed in "/lib/modules/<KERNEL VERSION>/extra"
-and the firmware files will be placed in the appropriate hotplug firmware
-directory, usually /lib/firmware.  In addition, USB maps and scripts will
-be placed in /etc/hotplug/usb to enable fxload to initialize the EZ-USB
-control chip when the device is connected.
-
-
-  3. PAL/SECAM TUNER CONFIGURATION (TV402U-EU only)
-
-
-The PAL model of the Plextor ConvertX TV402U may require additional
-configuration to correctly select the appropriate TV frequency band and
-audio subchannel.
-
-Users with a device other than the Plextor ConvertX TV402U-EU should skip
-this section.
-
-The wide variety of PAL TV systems used in Europe requires that additional
-information about the local TV standards be passed to the driver in order
-to properly tune TV channels.  The two necessary parameters are (a) the PAL
-TV band, and (b) the audio subchannel format in use.
-
-In many cases, the appropriate TV band selection is passed to the driver
-from applications.  However, in some cases, the application only specifies
-that the driver should use PAL but not the specific information about the
-appropriate TV band.  To work around this issue, the correct TV band may be
-specified in the "force_band" parameter to the wis-sony-tuner module:
-
-     TV band           force_band
-     -------           ----------
-     PAL B/G                B
-     PAL I                  I
-     PAL D/K                D
-     SECAM L                L
-
-If the "force_band" parameter is specified, the driver will ignore any TV
-band specified by applications and will always use the band provided in the
-module parameter.
-
-The other parameter that can be specified is the audio subchannel format.
-There are several stereo audio carrier systems in use, including NICAM and
-three varieties of A2.  To receive audio broadcast on one of these stereo
-carriers, the "force_mpx_mode" parameter must be specified to the
-wis-sony-tuner module.
-
-     TV band           Audio subcarrier       force_mpx_mode
-     -------           ----------------       --------------
-     PAL B/G            Mono (default)               1
-     PAL B/G                  A2                     2
-     PAL B/G                 NICAM                   3
-     PAL I              Mono (default)               4
-     PAL I                   NICAM                   5
-     PAL D/K            Mono (default)               6
-     PAL D/K                 A2 (1)                  7
-     PAL D/K                 A2 (2)                  8
-     PAL D/K                 A2 (3)                  9
-     PAL D/K                 NICAM                  10
-     SECAM L            Mono (default)              11
-     SECAM L                 NICAM                  12
-
-If the "force_mpx_mode" parameter is not specified, the correct mono-only
-mode will be chosen based on the TV band.  However, the tuner will not
-receive stereo audio or bilingual broadcasts correctly.
-
-To pass the "force_band" or "force_mpx_mode" parameters to the
-wis-sony-tuner module, the following line must be added to the modprobe
-configuration file, which varies from one Linux distribution to another.
-
-     options wis-sony-tuner force_band=B force_mpx_mode=2
-
-The above example would force the tuner to the PAL B/G TV band and receive
-stereo audio broadcasts on the A2 carrier.
-
-To verify that the configuration has been placed in the correct location,
-execute:
-
-       $ modprobe -c | grep wis-sony-tuner
-
-If the configuration line appears, then modprobe will pass the parameters
-correctly the next time the wis-sony-tuner module is loaded into the
-kernel.
-
-
-  4. TESTING THE DRIVER
-
-
-Because few Linux applications are able to correctly capture from
-Video4Linux2 devices with only compressed formats supported, the new driver
-should be tested with the "gorecord" application in the apps/ directory.
-
-First connect a video source to the device, such as a DVD player or VCR.
-This will be captured to a file for testing the driver.  If an input source
-is unavailable, a test file can still be captured, but the video will be
-black and the audio will be silent.
-
-This application will auto-detect the V4L2 and ALSA/OSS device names of the
-hardware and will record video and audio to an AVI file for a specified
-number of seconds.  For example:
-
-       $ apps/gorecord -duration 60 capture.avi
-
-If this application does not successfully record an AVI file, the error
-messages produced by gorecord and recorded in the system log (usually in
-/var/log/messages) should provide information to help resolve the problem.
-
-Supplying no parameters to gorecord will cause it to probe the available
-devices and exit.  Use the -help flag for usage information.
-
-
-  5. USING THE DRIVER
-
-
-The V4L2 device implemented by the driver provides a standard compressed
-format API, within the following criteria:
-
-  * Applications that only support the original Video4Linux1 API will not
-    be able to communicate with this driver at all.
-
-  * No raw video modes are supported, so applications like xawtv that
-    expect only uncompressed video will not function.
-
-  * Supported compression formats are: Motion-JPEG, MPEG1, MPEG2 and MPEG4.
-
-  * MPEG video formats are delivered as Video Elementary Streams only.
-    Program Stream (PS), Transport Stream (TS) and Packetized Elementary
-    Stream (PES) formats are not supported.
-
-  * Video parameters such as format and input port may not be changed while
-    the encoder is active.
-
-  * The audio capture device only functions when the video encoder is
-    actively capturing video.  Attempts to read from the audio device when
-    the encoder is inactive will result in an I/O error.
-
-  * The native format of the audio device is 48Khz 2-channel 16-bit
-    little-endian PCM, delivered through the ALSA system.  No audio
-    compression is implemented in the hardware.  ALSA may convert to other
-    uncompressed formats on the fly.
-
-The include/ directory contains a C header file describing non-standard
-features of the GO7007SB encoder, which are described below:
-
-
-  GO7007IOC_S_COMP_PARAMS, GO7007IOC_G_COMP_PARAMS
-
-    These ioctls are used to negotiate general compression parameters.
-
-    To query the current parameters, call the GO7007IOC_G_COMP_PARAMS ioctl
-    with a pointer to a struct go7007_comp_params.  If the driver is not
-    set to MPEG format, the EINVAL error code will be returned.
-
-    To change the current parameters, initialize all fields of a struct
-    go7007_comp_params and call the GO7007_IOC_S_COMP_PARAMS ioctl with a
-    pointer to this structure.  The driver will return the current
-    parameters with any necessary changes to conform to the limitations of
-    the hardware or current compression mode.  Any or all fields can be set
-    to zero to request a reasonable default value.  If the driver is not
-    set to MPEG format, the EINVAL error code will be returned.  When I/O
-    is in progress, the EBUSY error code will be returned.
-
-    Fields in struct go7007_comp_params:
-
-       __u32                        The maximum number of frames in each
-         gop_size                   Group Of Pictures; i.e. the maximum
-                                    number of frames minus one between
-                                    each key frame.
-
-       __u32                        The maximum number of sequential
-         max_b_frames               bidirectionally-predicted frames.
-                                    (B-frames are not yet supported.)
-
-       enum go7007_aspect_ratio     The aspect ratio to be encoded in the
-         aspect_ratio               meta-data of the compressed format.
-
-                                    Choices are:
-                                       GO7007_ASPECT_RATIO_1_1
-                                       GO7007_ASPECT_RATIO_4_3_NTSC
-                                       GO7007_ASPECT_RATIO_4_3_PAL
-                                       GO7007_ASPECT_RATIO_16_9_NTSC
-                                       GO7007_ASPECT_RATIO_16_9_PAL
-
-       __u32                        Bit-wise OR of control flags (below)
-         flags
-
-    Flags in struct go7007_comp_params:
-
-       GO7007_COMP_CLOSED_GOP       Only produce self-contained GOPs, used
-                                    to produce streams appropriate for
-                                    random seeking.
-
-       GO7007_COMP_OMIT_SEQ_HEADER  Omit the stream sequence header.
-
-
-  GO7007IOC_S_MPEG_PARAMS, GO7007IOC_G_MPEG_PARAMS
-
-    These ioctls are used to negotiate MPEG-specific stream parameters when
-    the pixelformat has been set to V4L2_PIX_FMT_MPEG.
-
-    To query the current parameters, call the GO7007IOC_G_MPEG_PARAMS ioctl
-    with a pointer to a struct go7007_mpeg_params.  If the driver is not
-    set to MPEG format, the EINVAL error code will be returned.
-
-    To change the current parameters, initialize all fields of a struct
-    go7007_mpeg_params and call the GO7007_IOC_S_MPEG_PARAMS ioctl with a
-    pointer to this structure.  The driver will return the current
-    parameters with any necessary changes to conform to the limitations of
-    the hardware or selected MPEG mode.  Any or all fields can be set to
-    zero to request a reasonable default value.  If the driver is not set
-    to MPEG format, the EINVAL error code will be returned.  When I/O is in
-    progress, the EBUSY error code will be returned.
-
-    Fields in struct go7007_mpeg_params:
-
-       enum go7007_mpeg_video_standard
-         mpeg_video_standard        The MPEG video standard in which to
-                                    compress the video.
-
-                                    Choices are:
-                                       GO7007_MPEG_VIDEO_MPEG1
-                                       GO7007_MPEG_VIDEO_MPEG2
-                                       GO7007_MPEG_VIDEO_MPEG4
-
-       __u32                        Bit-wise OR of control flags (below)
-         flags
-
-       __u32                        The profile and level indication to be
-         pali                       stored in the sequence header.  This
-                                    is only used as an indicator to the
-                                    decoder, and does not affect the MPEG
-                                    features used in the video stream.
-                                    Not valid for MPEG1.
-
-                                    Choices for MPEG2 are:
-                                       GO7007_MPEG2_PROFILE_MAIN_MAIN
-
-                                    Choices for MPEG4 are:
-                                       GO7007_MPEG4_PROFILE_S_L0
-                                       GO7007_MPEG4_PROFILE_S_L1
-                                       GO7007_MPEG4_PROFILE_S_L2
-                                       GO7007_MPEG4_PROFILE_S_L3
-                                       GO7007_MPEG4_PROFILE_ARTS_L1
-                                       GO7007_MPEG4_PROFILE_ARTS_L2
-                                       GO7007_MPEG4_PROFILE_ARTS_L3
-                                       GO7007_MPEG4_PROFILE_ARTS_L4
-                                       GO7007_MPEG4_PROFILE_AS_L0
-                                       GO7007_MPEG4_PROFILE_AS_L1
-                                       GO7007_MPEG4_PROFILE_AS_L2
-                                       GO7007_MPEG4_PROFILE_AS_L3
-                                       GO7007_MPEG4_PROFILE_AS_L4
-                                       GO7007_MPEG4_PROFILE_AS_L5
-
-    Flags in struct go7007_mpeg_params:
-
-       GO7007_MPEG_FORCE_DVD_MODE   Force all compression parameters and
-                                    bitrate control settings to comply
-                                    with DVD MPEG2 stream requirements.
-                                    This overrides most compression and
-                                    bitrate settings!
-
-       GO7007_MPEG_OMIT_GOP_HEADER  Omit the GOP header.
-
-       GO7007_MPEG_REPEAT_SEQHEADER Repeat the MPEG sequence header at
-                                    the start of each GOP.
-
-
-  GO7007IOC_S_BITRATE, GO7007IOC_G_BITRATE
-
-    These ioctls are used to set and query the target bitrate value for the
-    compressed video stream.  The bitrate may be selected by storing the
-    target bits per second in an int and calling GO7007IOC_S_BITRATE with a
-    pointer to the int.  The bitrate may be queried by calling
-    GO7007IOC_G_BITRATE with a pointer to an int where the current bitrate
-    will be stored.
-
-    Note that this is the primary means of controlling the video quality
-    for all compression modes, including V4L2_PIX_FMT_MJPEG.  The
-    VIDIOC_S_JPEGCOMP ioctl is not supported.
-
-
-----------------------------------------------------------------------------
-                  Installing the WIS PCI Voyager Driver
----------------------------------------------------------------------------
-
-The WIS PCI Voyager driver requires several patches to the Linux 2.6.11.x
-kernel source tree before compiling the driver.  These patches update the
-in-kernel SAA7134 driver to the newest development version and patch bugs
-in the TDA8290/TDA8275 tuner driver.
-
-The following patches must be downloaded from Gerd Knorr's website and
-applied in the order listed:
-
-       http://dl.bytesex.org/patches/2.6.11-2/i2c-tuner
-       http://dl.bytesex.org/patches/2.6.11-2/i2c-tuner2
-       http://dl.bytesex.org/patches/2.6.11-2/v4l2-api-mpeg
-       http://dl.bytesex.org/patches/2.6.11-2/saa7134-update
-
-The following patches are included with this SDK and can be applied in any
-order:
-
-       patches/2.6.11/saa7134-voyager.diff
-       patches/2.6.11/tda8275-newaddr.diff
-       patches/2.6.11/tda8290-ntsc.diff
-
-Check to make sure the CONFIG_VIDEO_SAA7134 option is enabled in the kernel
-configuration, and build and install the kernel.
-
-After rebooting into the new kernel, the GO7007 driver can be compiled and
-installed:
-
-       $ make SAA7134_BUILD=y
-       $ make install
-       $ modprobe saa7134-go7007
-
-There will be two V4L video devices associated with the PCI Voyager.  The
-first device (most likely /dev/video0) provides access to the raw video
-capture mode of the SAA7133 device and is used to configure the source
-video parameters and tune the TV tuner.  This device can be used with xawtv
-or other V4L(2) video software as a standard uncompressed device.
-
-The second device (most likely /dev/video1) provides access to the
-compression functions of the GO7007.  It can be tested using the gorecord
-application in the apps/ directory of this SDK:
-
-       $ apps/gorecord -vdevice /dev/video1 -noaudio test.avi
-
-Currently the frame resolution is fixed at 720x480 (NTSC) or 720x576 (PAL),
-and the video standard must be specified to both the raw and the compressed
-video devices (xawtv and gorecord, for example).
-
-
---------------------------------------------------------------------------
-RELEASE NOTES FOR WIS GO7007SB LINUX DRIVER
----------------------------------------------------------------------------
-
-Last updated: 5 November 2005
-
- - Release 0.9.7 includes new support for using udev to run fxload.  The
-   install script should automatically detect whether the old hotplug
-   scripts or the new udev rules should be used.  To force the use of
-   hotplug, run "make install USE_UDEV=n".  To force the use of udev, run
-   "make install USE_UDEV=y".
-
- - Motion detection is supported but undocumented.  Try the `modet` app
-   for a demonstration of how to use the facility.
-
- - Using USB2.0 devices such as the TV402U with USB1.1 HCDs or hubs can
-   cause buffer overruns and frame drops, even at low framerates, due to
-   inconsistency in the bitrate control mechanism.
-
- - On devices with an SAA7115, including the Plextor ConvertX, video height
-   values of 96, 128, 160, 192, 256, 320, and 384 do not work in NTSC mode.
-   All valid heights up to 512 work correctly in PAL mode.
-
- - The WIS Star Trek and PCI Voyager boards have no support yet for audio
-   or the TV tuner.
diff --git a/drivers/staging/go7007/s2250-board.c b/drivers/staging/go7007/s2250-board.c
deleted file mode 100644 (file)
index e7736a9..0000000
+++ /dev/null
@@ -1,698 +0,0 @@
-/*
- * Copyright (C) 2008 Sensoray Company Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/slab.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-subdev.h>
-#include "go7007-priv.h"
-
-MODULE_DESCRIPTION("Sensoray 2250/2251 i2c v4l2 subdev driver");
-MODULE_LICENSE("GPL v2");
-
-#define TLV320_ADDRESS      0x34
-#define VPX322_ADDR_ANALOGCONTROL1     0x02
-#define VPX322_ADDR_BRIGHTNESS0                0x0127
-#define VPX322_ADDR_BRIGHTNESS1                0x0131
-#define VPX322_ADDR_CONTRAST0          0x0128
-#define VPX322_ADDR_CONTRAST1          0x0132
-#define VPX322_ADDR_HUE                        0x00dc
-#define VPX322_ADDR_SAT                        0x0030
-
-struct go7007_usb_board {
-       unsigned int flags;
-       struct go7007_board_info main_info;
-};
-
-struct go7007_usb {
-       struct go7007_usb_board *board;
-       struct mutex i2c_lock;
-       struct usb_device *usbdev;
-       struct urb *video_urbs[8];
-       struct urb *audio_urbs[8];
-       struct urb *intr_urb;
-};
-
-static unsigned char aud_regs[] = {
-       0x1e, 0x00,
-       0x00, 0x17,
-       0x02, 0x17,
-       0x04, 0xf9,
-       0x06, 0xf9,
-       0x08, 0x02,
-       0x0a, 0x00,
-       0x0c, 0x00,
-       0x0a, 0x00,
-       0x0c, 0x00,
-       0x0e, 0x02,
-       0x10, 0x00,
-       0x12, 0x01,
-       0x00, 0x00,
-};
-
-
-static unsigned char vid_regs[] = {
-       0xF2, 0x0f,
-       0xAA, 0x00,
-       0xF8, 0xff,
-       0x00, 0x00,
-};
-
-static u16 vid_regs_fp[] = {
-       0x028, 0x067,
-       0x120, 0x016,
-       0x121, 0xcF2,
-       0x122, 0x0F2,
-       0x123, 0x00c,
-       0x124, 0x2d0,
-       0x125, 0x2e0,
-       0x126, 0x004,
-       0x128, 0x1E0,
-       0x12A, 0x016,
-       0x12B, 0x0F2,
-       0x12C, 0x0F2,
-       0x12D, 0x00c,
-       0x12E, 0x2d0,
-       0x12F, 0x2e0,
-       0x130, 0x004,
-       0x132, 0x1E0,
-       0x140, 0x060,
-       0x153, 0x00C,
-       0x154, 0x200,
-       0x150, 0x801,
-       0x000, 0x000
-};
-
-/* PAL specific values */
-static u16 vid_regs_fp_pal[] =
-{
-       0x120, 0x017,
-       0x121, 0xd22,
-       0x122, 0x122,
-       0x12A, 0x017,
-       0x12B, 0x122,
-       0x12C, 0x122,
-       0x140, 0x060,
-       0x000, 0x000,
-};
-
-struct s2250 {
-       struct v4l2_subdev sd;
-       v4l2_std_id std;
-       int input;
-       int brightness;
-       int contrast;
-       int saturation;
-       int hue;
-       int reg12b_val;
-       int audio_input;
-       struct i2c_client *audio;
-};
-
-static inline struct s2250 *to_state(struct v4l2_subdev *sd)
-{
-       return container_of(sd, struct s2250, sd);
-}
-
-/* from go7007-usb.c which is Copyright (C) 2005-2006 Micronas USA Inc.*/
-static int go7007_usb_vendor_request(struct go7007 *go, u16 request,
-       u16 value, u16 index, void *transfer_buffer, int length, int in)
-{
-       struct go7007_usb *usb = go->hpi_context;
-       int timeout = 5000;
-
-       if (in) {
-               return usb_control_msg(usb->usbdev,
-                               usb_rcvctrlpipe(usb->usbdev, 0), request,
-                               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                               value, index, transfer_buffer, length, timeout);
-       } else {
-               return usb_control_msg(usb->usbdev,
-                               usb_sndctrlpipe(usb->usbdev, 0), request,
-                               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                               value, index, transfer_buffer, length, timeout);
-       }
-}
-/* end from go7007-usb.c which is Copyright (C) 2005-2006 Micronas USA Inc.*/
-
-static int write_reg(struct i2c_client *client, u8 reg, u8 value)
-{
-       struct go7007 *go = i2c_get_adapdata(client->adapter);
-       struct go7007_usb *usb;
-       int rc;
-       int dev_addr = client->addr << 1;  /* firmware wants 8-bit address */
-       u8 *buf;
-
-       if (go == NULL)
-               return -ENODEV;
-
-       if (go->status == STATUS_SHUTDOWN)
-               return -EBUSY;
-
-       buf = kzalloc(16, GFP_KERNEL);
-       if (buf == NULL)
-               return -ENOMEM;
-
-       usb = go->hpi_context;
-       if (mutex_lock_interruptible(&usb->i2c_lock) != 0) {
-               printk(KERN_INFO "i2c lock failed\n");
-               kfree(buf);
-               return -EINTR;
-       }
-       rc = go7007_usb_vendor_request(go, 0x55, dev_addr,
-                                      (reg<<8 | value),
-                                      buf,
-                                      16, 1);
-
-       mutex_unlock(&usb->i2c_lock);
-       kfree(buf);
-       return rc;
-}
-
-static int write_reg_fp(struct i2c_client *client, u16 addr, u16 val)
-{
-       struct go7007 *go = i2c_get_adapdata(client->adapter);
-       struct go7007_usb *usb;
-       u8 *buf;
-       struct s2250 *dec = i2c_get_clientdata(client);
-
-       if (go == NULL)
-               return -ENODEV;
-
-       if (go->status == STATUS_SHUTDOWN)
-               return -EBUSY;
-
-       buf = kzalloc(16, GFP_KERNEL);
-
-       if (buf == NULL)
-               return -ENOMEM;
-
-
-
-       memset(buf, 0xcd, 6);
-
-       usb = go->hpi_context;
-       if (mutex_lock_interruptible(&usb->i2c_lock) != 0) {
-               printk(KERN_INFO "i2c lock failed\n");
-               kfree(buf);
-               return -EINTR;
-       }
-       if (go7007_usb_vendor_request(go, 0x57, addr, val, buf, 16, 1) < 0) {
-               kfree(buf);
-               return -EFAULT;
-       }
-
-       mutex_unlock(&usb->i2c_lock);
-       if (buf[0] == 0) {
-               unsigned int subaddr, val_read;
-
-               subaddr = (buf[4] << 8) + buf[5];
-               val_read = (buf[2] << 8) + buf[3];
-               kfree(buf);
-               if (val_read != val) {
-                       printk(KERN_INFO "invalid fp write %x %x\n",
-                              val_read, val);
-                       return -EFAULT;
-               }
-               if (subaddr != addr) {
-                       printk(KERN_INFO "invalid fp write addr %x %x\n",
-                              subaddr, addr);
-                       return -EFAULT;
-               }
-       } else {
-               kfree(buf);
-               return -EFAULT;
-       }
-
-       /* save last 12b value */
-       if (addr == 0x12b)
-               dec->reg12b_val = val;
-
-       return 0;
-}
-
-static int read_reg_fp(struct i2c_client *client, u16 addr, u16 *val)
-{
-       struct go7007 *go = i2c_get_adapdata(client->adapter);
-       struct go7007_usb *usb;
-       u8 *buf;
-
-       if (go == NULL)
-               return -ENODEV;
-
-       if (go->status == STATUS_SHUTDOWN)
-               return -EBUSY;
-
-       buf = kzalloc(16, GFP_KERNEL);
-
-       if (buf == NULL)
-               return -ENOMEM;
-
-
-
-       memset(buf, 0xcd, 6);
-       usb = go->hpi_context;
-       if (mutex_lock_interruptible(&usb->i2c_lock) != 0) {
-               printk(KERN_INFO "i2c lock failed\n");
-               kfree(buf);
-               return -EINTR;
-       }
-       if (go7007_usb_vendor_request(go, 0x58, addr, 0, buf, 16, 1) < 0) {
-               kfree(buf);
-               return -EFAULT;
-       }
-       mutex_unlock(&usb->i2c_lock);
-
-       *val = (buf[0] << 8) | buf[1];
-       kfree(buf);
-
-       return 0;
-}
-
-
-static int write_regs(struct i2c_client *client, u8 *regs)
-{
-       int i;
-
-       for (i = 0; !((regs[i] == 0x00) && (regs[i+1] == 0x00)); i += 2) {
-               if (write_reg(client, regs[i], regs[i+1]) < 0) {
-                       printk(KERN_INFO "s2250: failed\n");
-                       return -1;
-               }
-       }
-       return 0;
-}
-
-static int write_regs_fp(struct i2c_client *client, u16 *regs)
-{
-       int i;
-
-       for (i = 0; !((regs[i] == 0x00) && (regs[i+1] == 0x00)); i += 2) {
-               if (write_reg_fp(client, regs[i], regs[i+1]) < 0) {
-                       printk(KERN_INFO "s2250: failed fp\n");
-                       return -1;
-               }
-       }
-       return 0;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-static int s2250_s_video_routing(struct v4l2_subdev *sd, u32 input, u32 output,
-                                u32 config)
-{
-       struct s2250 *state = to_state(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int vidsys;
-
-       vidsys = (state->std == V4L2_STD_NTSC) ? 0x01 : 0x00;
-       if (input == 0) {
-               /* composite */
-               write_reg_fp(client, 0x20, 0x020 | vidsys);
-               write_reg_fp(client, 0x21, 0x662);
-               write_reg_fp(client, 0x140, 0x060);
-       } else if (input == 1) {
-               /* S-Video */
-               write_reg_fp(client, 0x20, 0x040 | vidsys);
-               write_reg_fp(client, 0x21, 0x666);
-               write_reg_fp(client, 0x140, 0x060);
-       } else {
-               return -EINVAL;
-       }
-       state->input = input;
-       return 0;
-}
-
-static int s2250_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
-{
-       struct s2250 *state = to_state(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       u16 vidsource;
-
-       vidsource = (state->input == 1) ? 0x040 : 0x020;
-       switch (norm) {
-       case V4L2_STD_NTSC:
-               write_regs_fp(client, vid_regs_fp);
-               write_reg_fp(client, 0x20, vidsource | 1);
-               break;
-       case V4L2_STD_PAL:
-               write_regs_fp(client, vid_regs_fp);
-               write_regs_fp(client, vid_regs_fp_pal);
-               write_reg_fp(client, 0x20, vidsource);
-               break;
-       default:
-               return -EINVAL;
-       }
-       state->std = norm;
-       return 0;
-}
-
-static int s2250_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *query)
-{
-       switch (query->id) {
-       case V4L2_CID_BRIGHTNESS:
-               return v4l2_ctrl_query_fill(query, 0, 100, 1, 50);
-       case V4L2_CID_CONTRAST:
-               return v4l2_ctrl_query_fill(query, 0, 100, 1, 50);
-       case V4L2_CID_SATURATION:
-               return v4l2_ctrl_query_fill(query, 0, 100, 1, 50);
-       case V4L2_CID_HUE:
-               return v4l2_ctrl_query_fill(query, -50, 50, 1, 0);
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int s2250_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct s2250 *state = to_state(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int value1;
-       u16 oldvalue;
-
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-               if (ctrl->value > 100)
-                       state->brightness = 100;
-               else if (ctrl->value < 0)
-                       state->brightness = 0;
-               else
-                       state->brightness = ctrl->value;
-               value1 = (state->brightness - 50) * 255 / 100;
-               read_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, &oldvalue);
-               write_reg_fp(client, VPX322_ADDR_BRIGHTNESS0,
-                            value1 | (oldvalue & ~0xff));
-               read_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, &oldvalue);
-               write_reg_fp(client, VPX322_ADDR_BRIGHTNESS1,
-                            value1 | (oldvalue & ~0xff));
-               write_reg_fp(client, 0x140, 0x60);
-               break;
-       case V4L2_CID_CONTRAST:
-               if (ctrl->value > 100)
-                       state->contrast = 100;
-               else if (ctrl->value < 0)
-                       state->contrast = 0;
-               else
-                       state->contrast = ctrl->value;
-               value1 = state->contrast * 0x40 / 100;
-               if (value1 > 0x3f)
-                       value1 = 0x3f; /* max */
-               read_reg_fp(client, VPX322_ADDR_CONTRAST0, &oldvalue);
-               write_reg_fp(client, VPX322_ADDR_CONTRAST0,
-                            value1 | (oldvalue & ~0x3f));
-               read_reg_fp(client, VPX322_ADDR_CONTRAST1, &oldvalue);
-               write_reg_fp(client, VPX322_ADDR_CONTRAST1,
-                            value1 | (oldvalue & ~0x3f));
-               write_reg_fp(client, 0x140, 0x60);
-               break;
-       case V4L2_CID_SATURATION:
-               if (ctrl->value > 100)
-                       state->saturation = 100;
-               else if (ctrl->value < 0)
-                       state->saturation = 0;
-               else
-                       state->saturation = ctrl->value;
-               value1 = state->saturation * 4140 / 100;
-               if (value1 > 4094)
-                       value1 = 4094;
-               write_reg_fp(client, VPX322_ADDR_SAT, value1);
-               break;
-       case V4L2_CID_HUE:
-               if (ctrl->value > 50)
-                       state->hue = 50;
-               else if (ctrl->value < -50)
-                       state->hue = -50;
-               else
-                       state->hue = ctrl->value;
-               /* clamp the hue range */
-               value1 = state->hue * 280 / 50;
-               write_reg_fp(client, VPX322_ADDR_HUE, value1);
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int s2250_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct s2250 *state = to_state(sd);
-
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-               ctrl->value = state->brightness;
-               break;
-       case V4L2_CID_CONTRAST:
-               ctrl->value = state->contrast;
-               break;
-       case V4L2_CID_SATURATION:
-               ctrl->value = state->saturation;
-               break;
-       case V4L2_CID_HUE:
-               ctrl->value = state->hue;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int s2250_s_mbus_fmt(struct v4l2_subdev *sd,
-                       struct v4l2_mbus_framefmt *fmt)
-{
-       struct s2250 *state = to_state(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (fmt->height < 640) {
-               write_reg_fp(client, 0x12b, state->reg12b_val | 0x400);
-               write_reg_fp(client, 0x140, 0x060);
-       } else {
-               write_reg_fp(client, 0x12b, state->reg12b_val & ~0x400);
-               write_reg_fp(client, 0x140, 0x060);
-       }
-       return 0;
-}
-
-static int s2250_s_audio_routing(struct v4l2_subdev *sd, u32 input, u32 output,
-                                u32 config)
-{
-       struct s2250 *state = to_state(sd);
-
-       switch (input) {
-       case 0:
-               write_reg(state->audio, 0x08, 0x02); /* Line In */
-               break;
-       case 1:
-               write_reg(state->audio, 0x08, 0x04); /* Mic */
-               break;
-       case 2:
-               write_reg(state->audio, 0x08, 0x05); /* Mic Boost */
-               break;
-       default:
-               return -EINVAL;
-       }
-       state->audio_input = input;
-       return 0;
-}
-
-
-static int s2250_log_status(struct v4l2_subdev *sd)
-{
-       struct s2250 *state = to_state(sd);
-
-       v4l2_info(sd, "Standard: %s\n", state->std == V4L2_STD_NTSC ? "NTSC" :
-                                       state->std == V4L2_STD_PAL ? "PAL" :
-                                       state->std == V4L2_STD_SECAM ? "SECAM" :
-                                       "unknown");
-       v4l2_info(sd, "Input: %s\n", state->input == 0 ? "Composite" :
-                                       state->input == 1 ? "S-video" :
-                                       "error");
-       v4l2_info(sd, "Brightness: %d\n", state->brightness);
-       v4l2_info(sd, "Contrast: %d\n", state->contrast);
-       v4l2_info(sd, "Saturation: %d\n", state->saturation);
-       v4l2_info(sd, "Hue: %d\n", state->hue); return 0;
-       v4l2_info(sd, "Audio input: %s\n", state->audio_input == 0 ? "Line In" :
-                                       state->audio_input == 1 ? "Mic" :
-                                       state->audio_input == 2 ? "Mic Boost" :
-                                       "error");
-       return 0;
-}
-
-/* --------------------------------------------------------------------------*/
-
-static const struct v4l2_subdev_core_ops s2250_core_ops = {
-       .log_status = s2250_log_status,
-       .g_ctrl = s2250_g_ctrl,
-       .s_ctrl = s2250_s_ctrl,
-       .queryctrl = s2250_queryctrl,
-       .s_std = s2250_s_std,
-};
-
-static const struct v4l2_subdev_audio_ops s2250_audio_ops = {
-       .s_routing = s2250_s_audio_routing,
-};
-
-static const struct v4l2_subdev_video_ops s2250_video_ops = {
-       .s_routing = s2250_s_video_routing,
-       .s_mbus_fmt = s2250_s_mbus_fmt,
-};
-
-static const struct v4l2_subdev_ops s2250_ops = {
-       .core = &s2250_core_ops,
-       .audio = &s2250_audio_ops,
-       .video = &s2250_video_ops,
-};
-
-/* --------------------------------------------------------------------------*/
-
-static int s2250_probe(struct i2c_client *client,
-                      const struct i2c_device_id *id)
-{
-       struct i2c_client *audio;
-       struct i2c_adapter *adapter = client->adapter;
-       struct s2250 *state;
-       struct v4l2_subdev *sd;
-       u8 *data;
-       struct go7007 *go = i2c_get_adapdata(adapter);
-       struct go7007_usb *usb = go->hpi_context;
-
-       audio = i2c_new_dummy(adapter, TLV320_ADDRESS >> 1);
-       if (audio == NULL)
-               return -ENOMEM;
-
-       state = kmalloc(sizeof(struct s2250), GFP_KERNEL);
-       if (state == NULL) {
-               i2c_unregister_device(audio);
-               return -ENOMEM;
-       }
-
-       sd = &state->sd;
-       v4l2_i2c_subdev_init(sd, client, &s2250_ops);
-
-       v4l2_info(sd, "initializing %s at address 0x%x on %s\n",
-              "Sensoray 2250/2251", client->addr, client->adapter->name);
-
-       state->std = V4L2_STD_NTSC;
-       state->brightness = 50;
-       state->contrast = 50;
-       state->saturation = 50;
-       state->hue = 0;
-       state->audio = audio;
-
-       /* initialize the audio */
-       if (write_regs(audio, aud_regs) < 0) {
-               printk(KERN_ERR
-                      "s2250: error initializing audio\n");
-               i2c_unregister_device(audio);
-               kfree(state);
-               return 0;
-       }
-
-       if (write_regs(client, vid_regs) < 0) {
-               printk(KERN_ERR
-                      "s2250: error initializing decoder\n");
-               i2c_unregister_device(audio);
-               kfree(state);
-               return 0;
-       }
-       if (write_regs_fp(client, vid_regs_fp) < 0) {
-               printk(KERN_ERR
-                      "s2250: error initializing decoder\n");
-               i2c_unregister_device(audio);
-               kfree(state);
-               return 0;
-       }
-       /* set default channel */
-       /* composite */
-       write_reg_fp(client, 0x20, 0x020 | 1);
-       write_reg_fp(client, 0x21, 0x662);
-       write_reg_fp(client, 0x140, 0x060);
-
-       /* set default audio input */
-       state->audio_input = 0;
-       write_reg(client, 0x08, 0x02); /* Line In */
-
-       if (mutex_lock_interruptible(&usb->i2c_lock) == 0) {
-               data = kzalloc(16, GFP_KERNEL);
-               if (data != NULL) {
-                       int rc;
-                       rc = go7007_usb_vendor_request(go, 0x41, 0, 0,
-                                                      data, 16, 1);
-                       if (rc > 0) {
-                               u8 mask;
-                               data[0] = 0;
-                               mask = 1<<5;
-                               data[0] &= ~mask;
-                               data[1] |= mask;
-                               go7007_usb_vendor_request(go, 0x40, 0,
-                                                         (data[1]<<8)
-                                                         + data[1],
-                                                         data, 16, 0);
-                       }
-                       kfree(data);
-               }
-               mutex_unlock(&usb->i2c_lock);
-       }
-
-       v4l2_info(sd, "initialized successfully\n");
-       return 0;
-}
-
-static int s2250_remove(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-
-       v4l2_device_unregister_subdev(sd);
-       kfree(to_state(sd));
-       return 0;
-}
-
-static const struct i2c_device_id s2250_id[] = {
-       { "s2250", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, s2250_id);
-
-static struct i2c_driver s2250_driver = {
-       .driver = {
-               .owner  = THIS_MODULE,
-               .name   = "s2250",
-       },
-       .probe          = s2250_probe,
-       .remove         = s2250_remove,
-       .id_table       = s2250_id,
-};
-
-static __init int init_s2250(void)
-{
-       return i2c_add_driver(&s2250_driver);
-}
-
-static __exit void exit_s2250(void)
-{
-       i2c_del_driver(&s2250_driver);
-}
-
-module_init(init_s2250);
-module_exit(exit_s2250);
diff --git a/drivers/staging/go7007/s2250-loader.c b/drivers/staging/go7007/s2250-loader.c
deleted file mode 100644 (file)
index 4e13251..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2008 Sensoray Company Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <dvb-usb.h>
-
-#define S2250_LOADER_FIRMWARE  "s2250_loader.fw"
-#define S2250_FIRMWARE         "s2250.fw"
-
-typedef struct device_extension_s {
-    struct kref     kref;
-    int minor;
-    struct usb_device *usbdev;
-} device_extension_t, *pdevice_extension_t;
-
-#define USB_s2250loader_MAJOR 240
-#define USB_s2250loader_MINOR_BASE 0
-#define MAX_DEVICES 256
-
-static pdevice_extension_t s2250_dev_table[MAX_DEVICES];
-static DEFINE_MUTEX(s2250_dev_table_mutex);
-
-#define to_s2250loader_dev_common(d) container_of(d, device_extension_t, kref)
-static void s2250loader_delete(struct kref *kref)
-{
-       pdevice_extension_t s = to_s2250loader_dev_common(kref);
-       s2250_dev_table[s->minor] = NULL;
-       kfree(s);
-}
-
-static int s2250loader_probe(struct usb_interface *interface,
-                               const struct usb_device_id *id)
-{
-       struct usb_device *usbdev;
-       int minor, ret;
-       pdevice_extension_t s = NULL;
-       const struct firmware *fw;
-
-       usbdev = usb_get_dev(interface_to_usbdev(interface));
-       if (!usbdev) {
-               printk(KERN_ERR "Enter s2250loader_probe failed\n");
-               return -1;
-       }
-       printk(KERN_INFO "Enter s2250loader_probe 2.6 kernel\n");
-       printk(KERN_INFO "vendor id 0x%x, device id 0x%x devnum:%d\n",
-          usbdev->descriptor.idVendor, usbdev->descriptor.idProduct,
-          usbdev->devnum);
-
-       if (usbdev->descriptor.bNumConfigurations != 1) {
-               printk(KERN_ERR "can't handle multiple config\n");
-               return -1;
-       }
-       mutex_lock(&s2250_dev_table_mutex);
-
-       for (minor = 0; minor < MAX_DEVICES; minor++) {
-               if (s2250_dev_table[minor] == NULL)
-                       break;
-       }
-
-       if (minor < 0 || minor >= MAX_DEVICES) {
-               printk(KERN_ERR "Invalid minor: %d\n", minor);
-               goto failed;
-       }
-
-       /* Allocate dev data structure */
-       s = kmalloc(sizeof(device_extension_t), GFP_KERNEL);
-       if (s == NULL) {
-               printk(KERN_ERR "Out of memory\n");
-               goto failed;
-       }
-       s2250_dev_table[minor] = s;
-
-       printk(KERN_INFO "s2250loader_probe: Device %d on Bus %d Minor %d\n",
-               usbdev->devnum, usbdev->bus->busnum, minor);
-
-       memset(s, 0, sizeof(device_extension_t));
-       s->usbdev = usbdev;
-       printk(KERN_INFO "loading 2250 loader\n");
-
-       kref_init(&(s->kref));
-
-       mutex_unlock(&s2250_dev_table_mutex);
-
-       if (request_firmware(&fw, S2250_LOADER_FIRMWARE, &usbdev->dev)) {
-               printk(KERN_ERR
-                       "s2250: unable to load firmware from file \"%s\"\n",
-                       S2250_LOADER_FIRMWARE);
-               goto failed2;
-       }
-       ret = usb_cypress_load_firmware(usbdev, fw, CYPRESS_FX2);
-       release_firmware(fw);
-       if (0 != ret) {
-               printk(KERN_ERR "loader download failed\n");
-               goto failed2;
-       }
-
-       if (request_firmware(&fw, S2250_FIRMWARE, &usbdev->dev)) {
-               printk(KERN_ERR
-                       "s2250: unable to load firmware from file \"%s\"\n",
-                       S2250_FIRMWARE);
-               goto failed2;
-       }
-       ret = usb_cypress_load_firmware(usbdev, fw, CYPRESS_FX2);
-       release_firmware(fw);
-       if (0 != ret) {
-               printk(KERN_ERR "firmware_s2250 download failed\n");
-               goto failed2;
-       }
-
-       usb_set_intfdata(interface, s);
-       return 0;
-
-failed:
-       mutex_unlock(&s2250_dev_table_mutex);
-failed2:
-       if (s)
-               kref_put(&(s->kref), s2250loader_delete);
-
-       printk(KERN_ERR "probe failed\n");
-       return -1;
-}
-
-static void s2250loader_disconnect(struct usb_interface *interface)
-{
-       pdevice_extension_t s;
-       printk(KERN_INFO "s2250: disconnect\n");
-       s = usb_get_intfdata(interface);
-       usb_set_intfdata(interface, NULL);
-       kref_put(&(s->kref), s2250loader_delete);
-}
-
-static const struct usb_device_id s2250loader_ids[] = {
-       {USB_DEVICE(0x1943, 0xa250)},
-       {}                          /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, s2250loader_ids);
-
-static struct usb_driver s2250loader_driver = {
-       .name           = "s2250-loader",
-       .probe          = s2250loader_probe,
-       .disconnect     = s2250loader_disconnect,
-       .id_table       = s2250loader_ids,
-};
-
-static int __init s2250loader_init(void)
-{
-       int r;
-       unsigned i = 0;
-
-       for (i = 0; i < MAX_DEVICES; i++)
-               s2250_dev_table[i] = NULL;
-
-       r = usb_register(&s2250loader_driver);
-       if (r) {
-               printk(KERN_ERR "usb_register failed. Error number %d\n", r);
-               return -1;
-       }
-
-       printk(KERN_INFO "s2250loader_init: driver registered\n");
-       return 0;
-}
-module_init(s2250loader_init);
-
-static void __exit s2250loader_cleanup(void)
-{
-       printk(KERN_INFO "s2250loader_cleanup\n");
-       usb_deregister(&s2250loader_driver);
-}
-module_exit(s2250loader_cleanup);
-
-MODULE_AUTHOR("");
-MODULE_DESCRIPTION("firmware loader for Sensoray 2250/2251");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/s2250-loader.h b/drivers/staging/go7007/s2250-loader.h
deleted file mode 100644 (file)
index b7c301a..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#ifndef _S2250_LOADER_H_
-#define _S2250_LOADER_H_
-
-extern int s2250loader_init(void);
-extern void s2250loader_cleanup(void);
-
-#endif
diff --git a/drivers/staging/go7007/saa7134-go7007.c b/drivers/staging/go7007/saa7134-go7007.c
deleted file mode 100644 (file)
index cf7c34a..0000000
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/time.h>
-#include <linux/mm.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-#include <asm/byteorder.h>
-#include <media/v4l2-common.h>
-
-#include "saa7134-reg.h"
-#include "saa7134.h"
-#include "go7007-priv.h"
-
-#define GO7007_HPI_DEBUG
-
-enum hpi_address {
-       HPI_ADDR_VIDEO_BUFFER = 0xe4,
-       HPI_ADDR_INIT_BUFFER = 0xea,
-       HPI_ADDR_INTR_RET_VALUE = 0xee,
-       HPI_ADDR_INTR_RET_DATA = 0xec,
-       HPI_ADDR_INTR_STATUS = 0xf4,
-       HPI_ADDR_INTR_WR_PARAM = 0xf6,
-       HPI_ADDR_INTR_WR_INDEX = 0xf8,
-};
-
-enum gpio_command {
-       GPIO_COMMAND_RESET = 0x00, /* 000b */
-       GPIO_COMMAND_REQ1  = 0x04, /* 001b */
-       GPIO_COMMAND_WRITE = 0x20, /* 010b */
-       GPIO_COMMAND_REQ2  = 0x24, /* 011b */
-       GPIO_COMMAND_READ  = 0x80, /* 100b */
-       GPIO_COMMAND_VIDEO = 0x84, /* 101b */
-       GPIO_COMMAND_IDLE  = 0xA0, /* 110b */
-       GPIO_COMMAND_ADDR  = 0xA4, /* 111b */
-};
-
-struct saa7134_go7007 {
-       struct saa7134_dev *dev;
-       u8 *top;
-       u8 *bottom;
-       dma_addr_t top_dma;
-       dma_addr_t bottom_dma;
-};
-
-static struct go7007_board_info board_voyager = {
-       .firmware        = "go7007tv.bin",
-       .flags           = 0,
-       .sensor_flags    = GO7007_SENSOR_656 |
-                               GO7007_SENSOR_VALID_ENABLE |
-                               GO7007_SENSOR_TV |
-                               GO7007_SENSOR_VBI,
-       .audio_flags    = GO7007_AUDIO_I2S_MODE_1 |
-                               GO7007_AUDIO_WORD_16,
-       .audio_rate      = 48000,
-       .audio_bclk_div  = 8,
-       .audio_main_div  = 2,
-       .hpi_buffer_cap  = 7,
-       .num_inputs      = 1,
-       .inputs          = {
-               {
-                       .name           = "SAA7134",
-               },
-       },
-};
-MODULE_FIRMWARE("go7007tv.bin");
-
-/********************* Driver for GPIO HPI interface *********************/
-
-static int gpio_write(struct saa7134_dev *dev, u8 addr, u16 data)
-{
-       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
-
-       /* Write HPI address */
-       saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
-
-       /* Write low byte */
-       saa_writeb(SAA7134_GPIO_GPSTATUS0, data & 0xff);
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
-
-       /* Write high byte */
-       saa_writeb(SAA7134_GPIO_GPSTATUS0, data >> 8);
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
-
-       return 0;
-}
-
-static int gpio_read(struct saa7134_dev *dev, u8 addr, u16 *data)
-{
-       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
-
-       /* Write HPI address */
-       saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
-
-       saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
-
-       /* Read low byte */
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
-       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
-       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
-       *data = saa_readb(SAA7134_GPIO_GPSTATUS0);
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
-
-       /* Read high byte */
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
-       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
-       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
-       *data |= saa_readb(SAA7134_GPIO_GPSTATUS0) << 8;
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
-
-       return 0;
-}
-
-static int saa7134_go7007_interface_reset(struct go7007 *go)
-{
-       struct saa7134_go7007 *saa = go->hpi_context;
-       struct saa7134_dev *dev = saa->dev;
-       u32 status;
-       u16 intr_val, intr_data;
-       int count = 20;
-
-       saa_clearb(SAA7134_TS_PARALLEL, 0x80); /* Disable TS interface */
-       saa_writeb(SAA7134_GPIO_GPMODE2, 0xa4);
-       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
-
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_RESET);
-       msleep(1);
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
-       msleep(10);
-
-       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
-       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
-
-       status = saa_readb(SAA7134_GPIO_GPSTATUS2);
-       /*printk(KERN_DEBUG "status is %s\n", status & 0x40 ? "OK" : "not OK"); */
-
-       /* enter command mode...(?) */
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
-
-       do {
-               saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
-               saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
-               status = saa_readb(SAA7134_GPIO_GPSTATUS2);
-               /*printk(KERN_INFO "gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */
-       } while (--count > 0);
-
-       /* Wait for an interrupt to indicate successful hardware reset */
-       if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
-                       (intr_val & ~0x1) != 0x55aa) {
-               printk(KERN_ERR
-                       "saa7134-go7007: unable to reset the GO7007\n");
-               return -1;
-       }
-       return 0;
-}
-
-static int saa7134_go7007_write_interrupt(struct go7007 *go, int addr, int data)
-{
-       struct saa7134_go7007 *saa = go->hpi_context;
-       struct saa7134_dev *dev = saa->dev;
-       int i;
-       u16 status_reg;
-
-#ifdef GO7007_HPI_DEBUG
-       printk(KERN_DEBUG
-               "saa7134-go7007: WriteInterrupt: %04x %04x\n", addr, data);
-#endif
-
-       for (i = 0; i < 100; ++i) {
-               gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
-               if (!(status_reg & 0x0010))
-                       break;
-               msleep(10);
-       }
-       if (i == 100) {
-               printk(KERN_ERR
-                       "saa7134-go7007: device is hung, status reg = 0x%04x\n",
-                       status_reg);
-               return -1;
-       }
-       gpio_write(dev, HPI_ADDR_INTR_WR_PARAM, data);
-       gpio_write(dev, HPI_ADDR_INTR_WR_INDEX, addr);
-
-       return 0;
-}
-
-static int saa7134_go7007_read_interrupt(struct go7007 *go)
-{
-       struct saa7134_go7007 *saa = go->hpi_context;
-       struct saa7134_dev *dev = saa->dev;
-
-       /* XXX we need to wait if there is no interrupt available */
-       go->interrupt_available = 1;
-       gpio_read(dev, HPI_ADDR_INTR_RET_VALUE, &go->interrupt_value);
-       gpio_read(dev, HPI_ADDR_INTR_RET_DATA, &go->interrupt_data);
-#ifdef GO7007_HPI_DEBUG
-       printk(KERN_DEBUG "saa7134-go7007: ReadInterrupt: %04x %04x\n",
-                       go->interrupt_value, go->interrupt_data);
-#endif
-       return 0;
-}
-
-static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev,
-                                               unsigned long status)
-{
-       struct go7007 *go = video_get_drvdata(dev->empress_dev);
-       struct saa7134_go7007 *saa = go->hpi_context;
-
-       if (!go->streaming)
-               return;
-       if (0 != (status & 0x000f0000))
-               printk(KERN_DEBUG "saa7134-go7007: irq: lost %ld\n",
-                               (status >> 16) & 0x0f);
-       if (status & 0x100000) {
-               dma_sync_single_for_cpu(&dev->pci->dev,
-                                       saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE);
-               go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE);
-               saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma));
-       } else {
-               dma_sync_single_for_cpu(&dev->pci->dev,
-                                       saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE);
-               go7007_parse_video_stream(go, saa->top, PAGE_SIZE);
-               saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma));
-       }
-}
-
-static int saa7134_go7007_stream_start(struct go7007 *go)
-{
-       struct saa7134_go7007 *saa = go->hpi_context;
-       struct saa7134_dev *dev = saa->dev;
-
-       saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top),
-                       0, PAGE_SIZE, DMA_FROM_DEVICE);
-       if (!saa->top_dma)
-               return -ENOMEM;
-       saa->bottom_dma = dma_map_page(&dev->pci->dev,
-                       virt_to_page(saa->bottom),
-                       0, PAGE_SIZE, DMA_FROM_DEVICE);
-       if (!saa->bottom_dma) {
-               dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
-                               DMA_FROM_DEVICE);
-               return -ENOMEM;
-       }
-
-       saa_writel(SAA7134_VIDEO_PORT_CTRL0 >> 2, 0xA300B000);
-       saa_writel(SAA7134_VIDEO_PORT_CTRL4 >> 2, 0x40000200);
-
-       /* Set HPI interface for video */
-       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
-       saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_VIDEO_BUFFER);
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
-       saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
-
-       /* Enable TS interface */
-       saa_writeb(SAA7134_TS_PARALLEL, 0xe6);
-
-       /* Reset TS interface */
-       saa_setb(SAA7134_TS_SERIAL1, 0x01);
-       saa_clearb(SAA7134_TS_SERIAL1, 0x01);
-
-       /* Set up transfer block size */
-       saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1);
-       saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1);
-       saa_writeb(SAA7134_TS_DMA1, 0);
-       saa_writeb(SAA7134_TS_DMA2, 0);
-
-       /* Enable video streaming mode */
-       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO);
-
-       saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma));
-       saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma));
-       saa_writel(SAA7134_RS_PITCH(5), 128);
-       saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX);
-
-       /* Enable TS FIFO */
-       saa_setl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
-
-       /* Enable DMA IRQ */
-       saa_setl(SAA7134_IRQ1,
-                       SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
-
-       return 0;
-}
-
-static int saa7134_go7007_stream_stop(struct go7007 *go)
-{
-       struct saa7134_go7007 *saa = go->hpi_context;
-       struct saa7134_dev *dev;
-
-       if (!saa)
-               return -EINVAL;
-       dev = saa->dev;
-       if (!dev)
-               return -EINVAL;
-
-       /* Shut down TS FIFO */
-       saa_clearl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
-
-       /* Disable DMA IRQ */
-       saa_clearl(SAA7134_IRQ1,
-                       SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
-
-       /* Disable TS interface */
-       saa_clearb(SAA7134_TS_PARALLEL, 0x80);
-
-       dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
-                       DMA_FROM_DEVICE);
-       dma_unmap_page(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE,
-                       DMA_FROM_DEVICE);
-
-       return 0;
-}
-
-static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len)
-{
-       struct saa7134_go7007 *saa = go->hpi_context;
-       struct saa7134_dev *dev = saa->dev;
-       u16 status_reg;
-       int i;
-
-#ifdef GO7007_HPI_DEBUG
-       printk(KERN_DEBUG "saa7134-go7007: DownloadBuffer "
-                       "sending %d bytes\n", len);
-#endif
-
-       while (len > 0) {
-               i = len > 64 ? 64 : len;
-               saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
-               saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_INIT_BUFFER);
-               saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
-               saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
-               while (i-- > 0) {
-                       saa_writeb(SAA7134_GPIO_GPSTATUS0, *data);
-                       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
-                       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
-                       ++data;
-                       --len;
-               }
-               for (i = 0; i < 100; ++i) {
-                       gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
-                       if (!(status_reg & 0x0002))
-                               break;
-               }
-               if (i == 100) {
-                       printk(KERN_ERR "saa7134-go7007: device is hung, "
-                                       "status reg = 0x%04x\n", status_reg);
-                       return -1;
-               }
-       }
-       return 0;
-}
-
-static int saa7134_go7007_send_command(struct go7007 *go, unsigned int cmd,
-                                       void *arg)
-{
-       struct saa7134_go7007 *saa = go->hpi_context;
-       struct saa7134_dev *dev = saa->dev;
-
-       switch (cmd) {
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *std = arg;
-               return saa7134_s_std_internal(dev, NULL, std);
-       }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *std = arg;
-               *std = dev->tvnorm->id;
-               return 0;
-       }
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *ctrl = arg;
-               if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER)
-                       return saa7134_queryctrl(NULL, NULL, ctrl);
-       }
-       case VIDIOC_G_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-               if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER)
-                       return saa7134_g_ctrl_internal(dev, NULL, ctrl);
-       }
-       case VIDIOC_S_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-               if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER)
-                       return saa7134_s_ctrl_internal(dev, NULL, ctrl);
-       }
-       }
-       return -EINVAL;
-
-}
-
-static struct go7007_hpi_ops saa7134_go7007_hpi_ops = {
-       .interface_reset        = saa7134_go7007_interface_reset,
-       .write_interrupt        = saa7134_go7007_write_interrupt,
-       .read_interrupt         = saa7134_go7007_read_interrupt,
-       .stream_start           = saa7134_go7007_stream_start,
-       .stream_stop            = saa7134_go7007_stream_stop,
-       .send_firmware          = saa7134_go7007_send_firmware,
-       .send_command           = saa7134_go7007_send_command,
-};
-
-/********************* Add/remove functions *********************/
-
-static int saa7134_go7007_init(struct saa7134_dev *dev)
-{
-       struct go7007 *go;
-       struct saa7134_go7007 *saa;
-
-       printk(KERN_DEBUG "saa7134-go7007: probing new SAA713X board\n");
-
-       saa = kzalloc(sizeof(struct saa7134_go7007), GFP_KERNEL);
-       if (saa == NULL)
-               return -ENOMEM;
-
-       /* Allocate a couple pages for receiving the compressed stream */
-       saa->top = (u8 *)get_zeroed_page(GFP_KERNEL);
-       if (!saa->top)
-               goto allocfail;
-       saa->bottom = (u8 *)get_zeroed_page(GFP_KERNEL);
-       if (!saa->bottom)
-               goto allocfail;
-
-       go = go7007_alloc(&board_voyager, &dev->pci->dev);
-       if (go == NULL)
-               goto allocfail;
-       go->board_id = GO7007_BOARDID_PCI_VOYAGER;
-       strncpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name));
-       go->hpi_ops = &saa7134_go7007_hpi_ops;
-       go->hpi_context = saa;
-       saa->dev = dev;
-
-       /* Boot the GO7007 */
-       if (go7007_boot_encoder(go, go->board_info->flags &
-                                       GO7007_BOARD_USE_ONBOARD_I2C) < 0)
-               goto initfail;
-
-       /* Do any final GO7007 initialization, then register the
-        * V4L2 and ALSA interfaces */
-       if (go7007_register_encoder(go) < 0)
-               goto initfail;
-       dev->empress_dev = go->video_dev;
-       video_set_drvdata(dev->empress_dev, go);
-
-       go->status = STATUS_ONLINE;
-       return 0;
-
-initfail:
-       go->status = STATUS_SHUTDOWN;
-       return 0;
-
-allocfail:
-       if (saa->top)
-               free_page((unsigned long)saa->top);
-       if (saa->bottom)
-               free_page((unsigned long)saa->bottom);
-       kfree(saa);
-       return -ENOMEM;
-}
-
-static int saa7134_go7007_fini(struct saa7134_dev *dev)
-{
-       struct go7007 *go;
-       struct saa7134_go7007 *saa;
-
-       if (NULL == dev->empress_dev)
-               return 0;
-
-       go = video_get_drvdata(dev->empress_dev);
-       saa = go->hpi_context;
-       go->status = STATUS_SHUTDOWN;
-       free_page((unsigned long)saa->top);
-       free_page((unsigned long)saa->bottom);
-       kfree(saa);
-       go7007_remove(go);
-       dev->empress_dev = NULL;
-
-       return 0;
-}
-
-static struct saa7134_mpeg_ops saa7134_go7007_ops = {
-       .type          = SAA7134_MPEG_GO7007,
-       .init          = saa7134_go7007_init,
-       .fini          = saa7134_go7007_fini,
-       .irq_ts_done   = saa7134_go7007_irq_ts_done,
-};
-
-static int __init saa7134_go7007_mod_init(void)
-{
-       return saa7134_ts_register(&saa7134_go7007_ops);
-}
-
-static void __exit saa7134_go7007_mod_cleanup(void)
-{
-       saa7134_ts_unregister(&saa7134_go7007_ops);
-}
-
-module_init(saa7134_go7007_mod_init);
-module_exit(saa7134_go7007_mod_cleanup);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/snd-go7007.c b/drivers/staging/go7007/snd-go7007.c
deleted file mode 100644 (file)
index deac938..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/vmalloc.h>
-#include <linux/time.h>
-#include <linux/mm.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <linux/slab.h>
-#include <asm/system.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/initval.h>
-
-#include "go7007-priv.h"
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
-
-module_param_array(index, int, NULL, 0444);
-module_param_array(id, charp, NULL, 0444);
-module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for the go7007 audio driver");
-MODULE_PARM_DESC(id, "ID string for the go7007 audio driver");
-MODULE_PARM_DESC(enable, "Enable for the go7007 audio driver");
-
-struct go7007_snd {
-       struct snd_card *card;
-       struct snd_pcm *pcm;
-       struct snd_pcm_substream *substream;
-       spinlock_t lock;
-       int w_idx;
-       int hw_ptr;
-       int avail;
-       int capturing;
-};
-
-static struct snd_pcm_hardware go7007_snd_capture_hw = {
-       .info                   = (SNDRV_PCM_INFO_MMAP |
-                                       SNDRV_PCM_INFO_INTERLEAVED |
-                                       SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                       SNDRV_PCM_INFO_MMAP_VALID),
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
-       .rates                  = SNDRV_PCM_RATE_48000,
-       .rate_min               = 48000,
-       .rate_max               = 48000,
-       .channels_min           = 2,
-       .channels_max           = 2,
-       .buffer_bytes_max       = (128*1024),
-       .period_bytes_min       = 4096,
-       .period_bytes_max       = (128*1024),
-       .periods_min            = 1,
-       .periods_max            = 32,
-};
-
-static void parse_audio_stream_data(struct go7007 *go, u8 *buf, int length)
-{
-       struct go7007_snd *gosnd = go->snd_context;
-       struct snd_pcm_runtime *runtime = gosnd->substream->runtime;
-       int frames = bytes_to_frames(runtime, length);
-
-       spin_lock(&gosnd->lock);
-       gosnd->hw_ptr += frames;
-       if (gosnd->hw_ptr >= runtime->buffer_size)
-               gosnd->hw_ptr -= runtime->buffer_size;
-       gosnd->avail += frames;
-       spin_unlock(&gosnd->lock);
-       if (gosnd->w_idx + length > runtime->dma_bytes) {
-               int cpy = runtime->dma_bytes - gosnd->w_idx;
-
-               memcpy(runtime->dma_area + gosnd->w_idx, buf, cpy);
-               length -= cpy;
-               buf += cpy;
-               gosnd->w_idx = 0;
-       }
-       memcpy(runtime->dma_area + gosnd->w_idx, buf, length);
-       gosnd->w_idx += length;
-       spin_lock(&gosnd->lock);
-       if (gosnd->avail < runtime->period_size) {
-               spin_unlock(&gosnd->lock);
-               return;
-       }
-       gosnd->avail -= runtime->period_size;
-       spin_unlock(&gosnd->lock);
-       if (gosnd->capturing)
-               snd_pcm_period_elapsed(gosnd->substream);
-}
-
-static int go7007_snd_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *hw_params)
-{
-       struct go7007 *go = snd_pcm_substream_chip(substream);
-       unsigned int bytes;
-
-       bytes = params_buffer_bytes(hw_params);
-       if (substream->runtime->dma_bytes > 0)
-               vfree(substream->runtime->dma_area);
-       substream->runtime->dma_bytes = 0;
-       substream->runtime->dma_area = vmalloc(bytes);
-       if (substream->runtime->dma_area == NULL)
-               return -ENOMEM;
-       substream->runtime->dma_bytes = bytes;
-       go->audio_deliver = parse_audio_stream_data;
-       return 0;
-}
-
-static int go7007_snd_hw_free(struct snd_pcm_substream *substream)
-{
-       struct go7007 *go = snd_pcm_substream_chip(substream);
-
-       go->audio_deliver = NULL;
-       if (substream->runtime->dma_bytes > 0)
-               vfree(substream->runtime->dma_area);
-       substream->runtime->dma_bytes = 0;
-       return 0;
-}
-
-static int go7007_snd_capture_open(struct snd_pcm_substream *substream)
-{
-       struct go7007 *go = snd_pcm_substream_chip(substream);
-       struct go7007_snd *gosnd = go->snd_context;
-       unsigned long flags;
-       int r;
-
-       spin_lock_irqsave(&gosnd->lock, flags);
-       if (gosnd->substream == NULL) {
-               gosnd->substream = substream;
-               substream->runtime->hw = go7007_snd_capture_hw;
-               r = 0;
-       } else
-               r = -EBUSY;
-       spin_unlock_irqrestore(&gosnd->lock, flags);
-       return r;
-}
-
-static int go7007_snd_capture_close(struct snd_pcm_substream *substream)
-{
-       struct go7007 *go = snd_pcm_substream_chip(substream);
-       struct go7007_snd *gosnd = go->snd_context;
-
-       gosnd->substream = NULL;
-       return 0;
-}
-
-static int go7007_snd_pcm_prepare(struct snd_pcm_substream *substream)
-{
-       return 0;
-}
-
-static int go7007_snd_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct go7007 *go = snd_pcm_substream_chip(substream);
-       struct go7007_snd *gosnd = go->snd_context;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               /* Just set a flag to indicate we should signal ALSA when
-                * sound comes in */
-               gosnd->capturing = 1;
-               return 0;
-       case SNDRV_PCM_TRIGGER_STOP:
-               gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0;
-               gosnd->capturing = 0;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-static snd_pcm_uframes_t go7007_snd_pcm_pointer(struct snd_pcm_substream *substream)
-{
-       struct go7007 *go = snd_pcm_substream_chip(substream);
-       struct go7007_snd *gosnd = go->snd_context;
-
-       return gosnd->hw_ptr;
-}
-
-static struct page *go7007_snd_pcm_page(struct snd_pcm_substream *substream,
-                                       unsigned long offset)
-{
-       return vmalloc_to_page(substream->runtime->dma_area + offset);
-}
-
-static struct snd_pcm_ops go7007_snd_capture_ops = {
-       .open           = go7007_snd_capture_open,
-       .close          = go7007_snd_capture_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = go7007_snd_hw_params,
-       .hw_free        = go7007_snd_hw_free,
-       .prepare        = go7007_snd_pcm_prepare,
-       .trigger        = go7007_snd_pcm_trigger,
-       .pointer        = go7007_snd_pcm_pointer,
-       .page           = go7007_snd_pcm_page,
-};
-
-static int go7007_snd_free(struct snd_device *device)
-{
-       struct go7007 *go = device->device_data;
-
-       kfree(go->snd_context);
-       go->snd_context = NULL;
-       if (--go->ref_count == 0)
-               kfree(go);
-       return 0;
-}
-
-static struct snd_device_ops go7007_snd_device_ops = {
-       .dev_free       = go7007_snd_free,
-};
-
-int go7007_snd_init(struct go7007 *go)
-{
-       static int dev;
-       struct go7007_snd *gosnd;
-       int ret = 0;
-
-       if (dev >= SNDRV_CARDS)
-               return -ENODEV;
-       if (!enable[dev]) {
-               dev++;
-               return -ENOENT;
-       }
-       gosnd = kmalloc(sizeof(struct go7007_snd), GFP_KERNEL);
-       if (gosnd == NULL)
-               return -ENOMEM;
-       spin_lock_init(&gosnd->lock);
-       gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0;
-       gosnd->capturing = 0;
-       ret = snd_card_create(index[dev], id[dev], THIS_MODULE, 0,
-                             &gosnd->card);
-       if (ret < 0) {
-               kfree(gosnd);
-               return ret;
-       }
-       ret = snd_device_new(gosnd->card, SNDRV_DEV_LOWLEVEL, go,
-                       &go7007_snd_device_ops);
-       if (ret < 0) {
-               kfree(gosnd);
-               return ret;
-       }
-       snd_card_set_dev(gosnd->card, go->dev);
-       ret = snd_pcm_new(gosnd->card, "go7007", 0, 0, 1, &gosnd->pcm);
-       if (ret < 0) {
-               snd_card_free(gosnd->card);
-               kfree(gosnd);
-               return ret;
-       }
-       strncpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver));
-       strncpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->driver));
-       strncpy(gosnd->card->longname, gosnd->card->shortname,
-                       sizeof(gosnd->card->longname));
-
-       gosnd->pcm->private_data = go;
-       snd_pcm_set_ops(gosnd->pcm, SNDRV_PCM_STREAM_CAPTURE,
-                       &go7007_snd_capture_ops);
-
-       ret = snd_card_register(gosnd->card);
-       if (ret < 0) {
-               snd_card_free(gosnd->card);
-               kfree(gosnd);
-               return ret;
-       }
-
-       gosnd->substream = NULL;
-       go->snd_context = gosnd;
-       ++dev;
-       ++go->ref_count;
-
-       return 0;
-}
-EXPORT_SYMBOL(go7007_snd_init);
-
-int go7007_snd_remove(struct go7007 *go)
-{
-       struct go7007_snd *gosnd = go->snd_context;
-
-       snd_card_disconnect(gosnd->card);
-       snd_card_free_when_closed(gosnd->card);
-       return 0;
-}
-EXPORT_SYMBOL(go7007_snd_remove);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/wis-i2c.h b/drivers/staging/go7007/wis-i2c.h
deleted file mode 100644 (file)
index 3c2b9be..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-/* Temporary I2C IDs -- these need to be replaced with real registered IDs */
-#define        I2C_DRIVERID_WIS_SAA7115        0xf0f0
-#define        I2C_DRIVERID_WIS_UDA1342        0xf0f1
-#define        I2C_DRIVERID_WIS_SONY_TUNER     0xf0f2
-#define        I2C_DRIVERID_WIS_TW9903         0xf0f3
-#define        I2C_DRIVERID_WIS_SAA7113        0xf0f4
-#define        I2C_DRIVERID_WIS_OV7640         0xf0f5
-#define        I2C_DRIVERID_WIS_TW2804         0xf0f6
-#define        I2C_DRIVERID_S2250              0xf0f7
-
-/* Flag to indicate that the client needs to be accessed with SCCB semantics */
-/* We re-use the I2C_M_TEN value so the flag passes through the masks in the
- * core I2C code.  Major kludge, but the I2C layer ain't exactly flexible. */
-#define        I2C_CLIENT_SCCB                 0x10
-
-/* Definitions for new video decoder commands */
-
-struct video_decoder_resolution {
-       unsigned int width;
-       unsigned int height;
-};
-
-#define        DECODER_SET_RESOLUTION  _IOW('d', 200, struct video_decoder_resolution)
-#define        DECODER_SET_CHANNEL     _IOW('d', 201, int)
-
-/* Sony tuner types */
-
-#define TUNER_SONY_BTF_PG472Z          200
-#define TUNER_SONY_BTF_PK467Z          201
-#define TUNER_SONY_BTF_PB463Z          202
diff --git a/drivers/staging/go7007/wis-ov7640.c b/drivers/staging/go7007/wis-ov7640.c
deleted file mode 100644 (file)
index 6bc9470..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-
-#include "wis-i2c.h"
-
-struct wis_ov7640 {
-       int brightness;
-       int contrast;
-       int saturation;
-       int hue;
-};
-
-static u8 initial_registers[] =
-{
-       0x12, 0x80,
-       0x12, 0x54,
-       0x14, 0x24,
-       0x15, 0x01,
-       0x28, 0x20,
-       0x75, 0x82,
-       0xFF, 0xFF, /* Terminator (reg 0xFF is unused) */
-};
-
-static int write_regs(struct i2c_client *client, u8 *regs)
-{
-       int i;
-
-       for (i = 0; regs[i] != 0xFF; i += 2)
-               if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
-                       return -1;
-       return 0;
-}
-
-static int wis_ov7640_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
-{
-       struct i2c_adapter *adapter = client->adapter;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return -ENODEV;
-
-       client->flags = I2C_CLIENT_SCCB;
-
-       printk(KERN_DEBUG
-               "wis-ov7640: initializing OV7640 at address %d on %s\n",
-               client->addr, adapter->name);
-
-       if (write_regs(client, initial_registers) < 0) {
-               printk(KERN_ERR "wis-ov7640: error initializing OV7640\n");
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static int wis_ov7640_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
-static const struct i2c_device_id wis_ov7640_id[] = {
-       { "wis_ov7640", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wis_ov7640_id);
-
-static struct i2c_driver wis_ov7640_driver = {
-       .driver = {
-               .name   = "WIS OV7640 I2C driver",
-       },
-       .probe          = wis_ov7640_probe,
-       .remove         = wis_ov7640_remove,
-       .id_table       = wis_ov7640_id,
-};
-
-static int __init wis_ov7640_init(void)
-{
-       return i2c_add_driver(&wis_ov7640_driver);
-}
-
-static void __exit wis_ov7640_cleanup(void)
-{
-       i2c_del_driver(&wis_ov7640_driver);
-}
-
-module_init(wis_ov7640_init);
-module_exit(wis_ov7640_cleanup);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/go7007/wis-saa7113.c
deleted file mode 100644 (file)
index 05e0e10..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-
-#include "wis-i2c.h"
-
-struct wis_saa7113 {
-       int norm;
-       int brightness;
-       int contrast;
-       int saturation;
-       int hue;
-};
-
-static u8 initial_registers[] =
-{
-       0x01, 0x08,
-       0x02, 0xc0,
-       0x03, 0x33,
-       0x04, 0x00,
-       0x05, 0x00,
-       0x06, 0xe9,
-       0x07, 0x0d,
-       0x08, 0xd8,
-       0x09, 0x40,
-       0x0a, 0x80,
-       0x0b, 0x47,
-       0x0c, 0x40,
-       0x0d, 0x00,
-       0x0e, 0x01,
-       0x0f, 0x2a,
-       0x10, 0x40,
-       0x11, 0x0c,
-       0x12, 0xfe,
-       0x13, 0x00,
-       0x14, 0x00,
-       0x15, 0x04,
-       0x16, 0x00,
-       0x17, 0x00,
-       0x18, 0x00,
-       0x19, 0x00,
-       0x1a, 0x00,
-       0x1b, 0x00,
-       0x1c, 0x00,
-       0x1d, 0x00,
-       0x1e, 0x00,
-       0x1f, 0xc8,
-       0x40, 0x00,
-       0x41, 0xff,
-       0x42, 0xff,
-       0x43, 0xff,
-       0x44, 0xff,
-       0x45, 0xff,
-       0x46, 0xff,
-       0x47, 0xff,
-       0x48, 0xff,
-       0x49, 0xff,
-       0x4a, 0xff,
-       0x4b, 0xff,
-       0x4c, 0xff,
-       0x4d, 0xff,
-       0x4e, 0xff,
-       0x4f, 0xff,
-       0x50, 0xff,
-       0x51, 0xff,
-       0x52, 0xff,
-       0x53, 0xff,
-       0x54, 0xff,
-       0x55, 0xff,
-       0x56, 0xff,
-       0x57, 0xff,
-       0x58, 0x00,
-       0x59, 0x54,
-       0x5a, 0x07,
-       0x5b, 0x83,
-       0x5c, 0x00,
-       0x5d, 0x00,
-       0x5e, 0x00,
-       0x5f, 0x00,
-       0x60, 0x00,
-       0x61, 0x00,
-       0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
-};
-
-static int write_reg(struct i2c_client *client, u8 reg, u8 value)
-{
-       return i2c_smbus_write_byte_data(client, reg, value);
-}
-
-static int write_regs(struct i2c_client *client, u8 *regs)
-{
-       int i;
-
-       for (i = 0; regs[i] != 0x00; i += 2)
-               if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
-                       return -1;
-       return 0;
-}
-
-static int wis_saa7113_command(struct i2c_client *client,
-                               unsigned int cmd, void *arg)
-{
-       struct wis_saa7113 *dec = i2c_get_clientdata(client);
-
-       switch (cmd) {
-       case VIDIOC_S_INPUT:
-       {
-               int *input = arg;
-
-               i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input);
-               i2c_smbus_write_byte_data(client, 0x09,
-                               *input < 6 ? 0x40 : 0x80);
-               break;
-       }
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *input = arg;
-               dec->norm = *input;
-               if (dec->norm & V4L2_STD_NTSC) {
-                       write_reg(client, 0x0e, 0x01);
-                       write_reg(client, 0x10, 0x40);
-               } else if (dec->norm & V4L2_STD_PAL) {
-                       write_reg(client, 0x0e, 0x01);
-                       write_reg(client, 0x10, 0x48);
-               } else if (dec->norm * V4L2_STD_SECAM) {
-                       write_reg(client, 0x0e, 0x50);
-                       write_reg(client, 0x10, 0x48);
-               }
-               break;
-       }
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *ctrl = arg;
-
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
-                       ctrl->minimum = 0;
-                       ctrl->maximum = 255;
-                       ctrl->step = 1;
-                       ctrl->default_value = 128;
-                       ctrl->flags = 0;
-                       break;
-               case V4L2_CID_CONTRAST:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
-                       ctrl->minimum = 0;
-                       ctrl->maximum = 127;
-                       ctrl->step = 1;
-                       ctrl->default_value = 71;
-                       ctrl->flags = 0;
-                       break;
-               case V4L2_CID_SATURATION:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
-                       ctrl->minimum = 0;
-                       ctrl->maximum = 127;
-                       ctrl->step = 1;
-                       ctrl->default_value = 64;
-                       ctrl->flags = 0;
-                       break;
-               case V4L2_CID_HUE:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
-                       ctrl->minimum = -128;
-                       ctrl->maximum = 127;
-                       ctrl->step = 1;
-                       ctrl->default_value = 0;
-                       ctrl->flags = 0;
-                       break;
-               }
-               break;
-       }
-       case VIDIOC_S_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       if (ctrl->value > 255)
-                               dec->brightness = 255;
-                       else if (ctrl->value < 0)
-                               dec->brightness = 0;
-                       else
-                               dec->brightness = ctrl->value;
-                       write_reg(client, 0x0a, dec->brightness);
-                       break;
-               case V4L2_CID_CONTRAST:
-                       if (ctrl->value > 127)
-                               dec->contrast = 127;
-                       else if (ctrl->value < 0)
-                               dec->contrast = 0;
-                       else
-                               dec->contrast = ctrl->value;
-                       write_reg(client, 0x0b, dec->contrast);
-                       break;
-               case V4L2_CID_SATURATION:
-                       if (ctrl->value > 127)
-                               dec->saturation = 127;
-                       else if (ctrl->value < 0)
-                               dec->saturation = 0;
-                       else
-                               dec->saturation = ctrl->value;
-                       write_reg(client, 0x0c, dec->saturation);
-                       break;
-               case V4L2_CID_HUE:
-                       if (ctrl->value > 127)
-                               dec->hue = 127;
-                       else if (ctrl->value < -128)
-                               dec->hue = -128;
-                       else
-                               dec->hue = ctrl->value;
-                       write_reg(client, 0x0d, dec->hue);
-                       break;
-               }
-               break;
-       }
-       case VIDIOC_G_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       ctrl->value = dec->brightness;
-                       break;
-               case V4L2_CID_CONTRAST:
-                       ctrl->value = dec->contrast;
-                       break;
-               case V4L2_CID_SATURATION:
-                       ctrl->value = dec->saturation;
-                       break;
-               case V4L2_CID_HUE:
-                       ctrl->value = dec->hue;
-                       break;
-               }
-               break;
-       }
-       default:
-               break;
-       }
-       return 0;
-}
-
-static int wis_saa7113_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
-{
-       struct i2c_adapter *adapter = client->adapter;
-       struct wis_saa7113 *dec;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return -ENODEV;
-
-       dec = kmalloc(sizeof(struct wis_saa7113), GFP_KERNEL);
-       if (dec == NULL)
-               return -ENOMEM;
-
-       dec->norm = V4L2_STD_NTSC;
-       dec->brightness = 128;
-       dec->contrast = 71;
-       dec->saturation = 64;
-       dec->hue = 0;
-       i2c_set_clientdata(client, dec);
-
-       printk(KERN_DEBUG
-               "wis-saa7113: initializing SAA7113 at address %d on %s\n",
-               client->addr, adapter->name);
-
-       if (write_regs(client, initial_registers) < 0) {
-               printk(KERN_ERR
-                       "wis-saa7113: error initializing SAA7113\n");
-               kfree(dec);
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static int wis_saa7113_remove(struct i2c_client *client)
-{
-       struct wis_saa7113 *dec = i2c_get_clientdata(client);
-
-       kfree(dec);
-       return 0;
-}
-
-static const struct i2c_device_id wis_saa7113_id[] = {
-       { "wis_saa7113", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wis_saa7113_id);
-
-static struct i2c_driver wis_saa7113_driver = {
-       .driver = {
-               .name   = "WIS SAA7113 I2C driver",
-       },
-       .probe          = wis_saa7113_probe,
-       .remove         = wis_saa7113_remove,
-       .command        = wis_saa7113_command,
-       .id_table       = wis_saa7113_id,
-};
-
-static int __init wis_saa7113_init(void)
-{
-       return i2c_add_driver(&wis_saa7113_driver);
-}
-
-static void __exit wis_saa7113_cleanup(void)
-{
-       i2c_del_driver(&wis_saa7113_driver);
-}
-
-module_init(wis_saa7113_init);
-module_exit(wis_saa7113_cleanup);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/go7007/wis-saa7115.c
deleted file mode 100644 (file)
index 46cff59..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-
-#include "wis-i2c.h"
-
-struct wis_saa7115 {
-       int norm;
-       int brightness;
-       int contrast;
-       int saturation;
-       int hue;
-};
-
-static u8 initial_registers[] =
-{
-       0x01, 0x08,
-       0x02, 0xc0,
-       0x03, 0x20,
-       0x04, 0x80,
-       0x05, 0x80,
-       0x06, 0xeb,
-       0x07, 0xe0,
-       0x08, 0xf0,     /* always toggle FID */
-       0x09, 0x40,
-       0x0a, 0x80,
-       0x0b, 0x40,
-       0x0c, 0x40,
-       0x0d, 0x00,
-       0x0e, 0x03,
-       0x0f, 0x2a,
-       0x10, 0x0e,
-       0x11, 0x00,
-       0x12, 0x8d,
-       0x13, 0x00,
-       0x14, 0x00,
-       0x15, 0x11,
-       0x16, 0x01,
-       0x17, 0xda,
-       0x18, 0x40,
-       0x19, 0x80,
-       0x1a, 0x00,
-       0x1b, 0x42,
-       0x1c, 0xa9,
-       0x30, 0x66,
-       0x31, 0x90,
-       0x32, 0x01,
-       0x34, 0x00,
-       0x35, 0x00,
-       0x36, 0x20,
-       0x38, 0x03,
-       0x39, 0x20,
-       0x3a, 0x88,
-       0x40, 0x00,
-       0x41, 0xff,
-       0x42, 0xff,
-       0x43, 0xff,
-       0x44, 0xff,
-       0x45, 0xff,
-       0x46, 0xff,
-       0x47, 0xff,
-       0x48, 0xff,
-       0x49, 0xff,
-       0x4a, 0xff,
-       0x4b, 0xff,
-       0x4c, 0xff,
-       0x4d, 0xff,
-       0x4e, 0xff,
-       0x4f, 0xff,
-       0x50, 0xff,
-       0x51, 0xff,
-       0x52, 0xff,
-       0x53, 0xff,
-       0x54, 0xf4 /*0xff*/,
-       0x55, 0xff,
-       0x56, 0xff,
-       0x57, 0xff,
-       0x58, 0x40,
-       0x59, 0x47,
-       0x5a, 0x06 /*0x03*/,
-       0x5b, 0x83,
-       0x5d, 0x06,
-       0x5e, 0x00,
-       0x80, 0x30, /* window defined scaler operation, task A and B enabled */
-       0x81, 0x03, /* use scaler datapath generated V */
-       0x83, 0x00,
-       0x84, 0x00,
-       0x85, 0x00,
-       0x86, 0x45,
-       0x87, 0x31,
-       0x88, 0xc0,
-       0x90, 0x02, /* task A process top field */
-       0x91, 0x08,
-       0x92, 0x09,
-       0x93, 0x80,
-       0x94, 0x06,
-       0x95, 0x00,
-       0x96, 0xc0,
-       0x97, 0x02,
-       0x98, 0x12,
-       0x99, 0x00,
-       0x9a, 0xf2,
-       0x9b, 0x00,
-       0x9c, 0xd0,
-       0x9d, 0x02,
-       0x9e, 0xf2,
-       0x9f, 0x00,
-       0xa0, 0x01,
-       0xa1, 0x01,
-       0xa2, 0x01,
-       0xa4, 0x80,
-       0xa5, 0x40,
-       0xa6, 0x40,
-       0xa8, 0x00,
-       0xa9, 0x04,
-       0xaa, 0x00,
-       0xac, 0x00,
-       0xad, 0x02,
-       0xae, 0x00,
-       0xb0, 0x00,
-       0xb1, 0x04,
-       0xb2, 0x00,
-       0xb3, 0x04,
-       0xb4, 0x00,
-       0xb8, 0x00,
-       0xbc, 0x00,
-       0xc0, 0x03,     /* task B process bottom field */
-       0xc1, 0x08,
-       0xc2, 0x09,
-       0xc3, 0x80,
-       0xc4, 0x06,
-       0xc5, 0x00,
-       0xc6, 0xc0,
-       0xc7, 0x02,
-       0xc8, 0x12,
-       0xc9, 0x00,
-       0xca, 0xf2,
-       0xcb, 0x00,
-       0xcc, 0xd0,
-       0xcd, 0x02,
-       0xce, 0xf2,
-       0xcf, 0x00,
-       0xd0, 0x01,
-       0xd1, 0x01,
-       0xd2, 0x01,
-       0xd4, 0x80,
-       0xd5, 0x40,
-       0xd6, 0x40,
-       0xd8, 0x00,
-       0xd9, 0x04,
-       0xda, 0x00,
-       0xdc, 0x00,
-       0xdd, 0x02,
-       0xde, 0x00,
-       0xe0, 0x00,
-       0xe1, 0x04,
-       0xe2, 0x00,
-       0xe3, 0x04,
-       0xe4, 0x00,
-       0xe8, 0x00,
-       0x88, 0xf0, /* End of original static list */
-       0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
-};
-
-static int write_reg(struct i2c_client *client, u8 reg, u8 value)
-{
-       return i2c_smbus_write_byte_data(client, reg, value);
-}
-
-static int write_regs(struct i2c_client *client, u8 *regs)
-{
-       int i;
-
-       for (i = 0; regs[i] != 0x00; i += 2)
-               if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
-                       return -1;
-       return 0;
-}
-
-static int wis_saa7115_command(struct i2c_client *client,
-                               unsigned int cmd, void *arg)
-{
-       struct wis_saa7115 *dec = i2c_get_clientdata(client);
-
-       switch (cmd) {
-       case VIDIOC_S_INPUT:
-       {
-               int *input = arg;
-
-               i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input);
-               i2c_smbus_write_byte_data(client, 0x09,
-                               *input < 6 ? 0x40 : 0xC0);
-               break;
-       }
-       case DECODER_SET_RESOLUTION:
-       {
-               struct video_decoder_resolution *res = arg;
-               /* Course-grained scaler */
-               int h_integer_scaler = res->width < 704 ? 704 / res->width : 1;
-               /* Fine-grained scaler to take care of remainder */
-               int h_scaling_increment = (704 / h_integer_scaler) *
-                                       1024 / res->width;
-               /* Fine-grained scaler only */
-               int v_scaling_increment = (dec->norm & V4L2_STD_NTSC ?
-                               240 : 288) * 1024 / res->height;
-               u8 regs[] = {
-                       0x88,   0xc0,
-                       0x9c,   res->width & 0xff,
-                       0x9d,   res->width >> 8,
-                       0x9e,   res->height & 0xff,
-                       0x9f,   res->height >> 8,
-                       0xa0,   h_integer_scaler,
-                       0xa1,   1,
-                       0xa2,   1,
-                       0xa8,   h_scaling_increment & 0xff,
-                       0xa9,   h_scaling_increment >> 8,
-                       0xac,   (h_scaling_increment / 2) & 0xff,
-                       0xad,   (h_scaling_increment / 2) >> 8,
-                       0xb0,   v_scaling_increment & 0xff,
-                       0xb1,   v_scaling_increment >> 8,
-                       0xb2,   v_scaling_increment & 0xff,
-                       0xb3,   v_scaling_increment >> 8,
-                       0xcc,   res->width & 0xff,
-                       0xcd,   res->width >> 8,
-                       0xce,   res->height & 0xff,
-                       0xcf,   res->height >> 8,
-                       0xd0,   h_integer_scaler,
-                       0xd1,   1,
-                       0xd2,   1,
-                       0xd8,   h_scaling_increment & 0xff,
-                       0xd9,   h_scaling_increment >> 8,
-                       0xdc,   (h_scaling_increment / 2) & 0xff,
-                       0xdd,   (h_scaling_increment / 2) >> 8,
-                       0xe0,   v_scaling_increment & 0xff,
-                       0xe1,   v_scaling_increment >> 8,
-                       0xe2,   v_scaling_increment & 0xff,
-                       0xe3,   v_scaling_increment >> 8,
-                       0x88,   0xf0,
-                       0,      0,
-               };
-               write_regs(client, regs);
-               break;
-       }
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *input = arg;
-               u8 regs[] = {
-                       0x88,   0xc0,
-                       0x98,   *input & V4L2_STD_NTSC ? 0x12 : 0x16,
-                       0x9a,   *input & V4L2_STD_NTSC ? 0xf2 : 0x20,
-                       0x9b,   *input & V4L2_STD_NTSC ? 0x00 : 0x01,
-                       0xc8,   *input & V4L2_STD_NTSC ? 0x12 : 0x16,
-                       0xca,   *input & V4L2_STD_NTSC ? 0xf2 : 0x20,
-                       0xcb,   *input & V4L2_STD_NTSC ? 0x00 : 0x01,
-                       0x88,   0xf0,
-                       0x30,   *input & V4L2_STD_NTSC ? 0x66 : 0x00,
-                       0x31,   *input & V4L2_STD_NTSC ? 0x90 : 0xe0,
-                       0,      0,
-               };
-               write_regs(client, regs);
-               dec->norm = *input;
-               break;
-       }
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *ctrl = arg;
-
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
-                       ctrl->minimum = 0;
-                       ctrl->maximum = 255;
-                       ctrl->step = 1;
-                       ctrl->default_value = 128;
-                       ctrl->flags = 0;
-                       break;
-               case V4L2_CID_CONTRAST:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
-                       ctrl->minimum = 0;
-                       ctrl->maximum = 127;
-                       ctrl->step = 1;
-                       ctrl->default_value = 64;
-                       ctrl->flags = 0;
-                       break;
-               case V4L2_CID_SATURATION:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
-                       ctrl->minimum = 0;
-                       ctrl->maximum = 127;
-                       ctrl->step = 1;
-                       ctrl->default_value = 64;
-                       ctrl->flags = 0;
-                       break;
-               case V4L2_CID_HUE:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
-                       ctrl->minimum = -128;
-                       ctrl->maximum = 127;
-                       ctrl->step = 1;
-                       ctrl->default_value = 0;
-                       ctrl->flags = 0;
-                       break;
-               }
-               break;
-       }
-       case VIDIOC_S_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       if (ctrl->value > 255)
-                               dec->brightness = 255;
-                       else if (ctrl->value < 0)
-                               dec->brightness = 0;
-                       else
-                               dec->brightness = ctrl->value;
-                       write_reg(client, 0x0a, dec->brightness);
-                       break;
-               case V4L2_CID_CONTRAST:
-                       if (ctrl->value > 127)
-                               dec->contrast = 127;
-                       else if (ctrl->value < 0)
-                               dec->contrast = 0;
-                       else
-                               dec->contrast = ctrl->value;
-                       write_reg(client, 0x0b, dec->contrast);
-                       break;
-               case V4L2_CID_SATURATION:
-                       if (ctrl->value > 127)
-                               dec->saturation = 127;
-                       else if (ctrl->value < 0)
-                               dec->saturation = 0;
-                       else
-                               dec->saturation = ctrl->value;
-                       write_reg(client, 0x0c, dec->saturation);
-                       break;
-               case V4L2_CID_HUE:
-                       if (ctrl->value > 127)
-                               dec->hue = 127;
-                       else if (ctrl->value < -128)
-                               dec->hue = -128;
-                       else
-                               dec->hue = ctrl->value;
-                       write_reg(client, 0x0d, dec->hue);
-                       break;
-               }
-               break;
-       }
-       case VIDIOC_G_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       ctrl->value = dec->brightness;
-                       break;
-               case V4L2_CID_CONTRAST:
-                       ctrl->value = dec->contrast;
-                       break;
-               case V4L2_CID_SATURATION:
-                       ctrl->value = dec->saturation;
-                       break;
-               case V4L2_CID_HUE:
-                       ctrl->value = dec->hue;
-                       break;
-               }
-               break;
-       }
-       default:
-               break;
-       }
-       return 0;
-}
-
-static int wis_saa7115_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
-{
-       struct i2c_adapter *adapter = client->adapter;
-       struct wis_saa7115 *dec;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return -ENODEV;
-
-       dec = kmalloc(sizeof(struct wis_saa7115), GFP_KERNEL);
-       if (dec == NULL)
-               return -ENOMEM;
-
-       dec->norm = V4L2_STD_NTSC;
-       dec->brightness = 128;
-       dec->contrast = 64;
-       dec->saturation = 64;
-       dec->hue = 0;
-       i2c_set_clientdata(client, dec);
-
-       printk(KERN_DEBUG
-               "wis-saa7115: initializing SAA7115 at address %d on %s\n",
-               client->addr, adapter->name);
-
-       if (write_regs(client, initial_registers) < 0) {
-               printk(KERN_ERR
-                       "wis-saa7115: error initializing SAA7115\n");
-               kfree(dec);
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static int wis_saa7115_remove(struct i2c_client *client)
-{
-       struct wis_saa7115 *dec = i2c_get_clientdata(client);
-
-       kfree(dec);
-       return 0;
-}
-
-static const struct i2c_device_id wis_saa7115_id[] = {
-       { "wis_saa7115", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wis_saa7115_id);
-
-static struct i2c_driver wis_saa7115_driver = {
-       .driver = {
-               .name   = "WIS SAA7115 I2C driver",
-       },
-       .probe          = wis_saa7115_probe,
-       .remove         = wis_saa7115_remove,
-       .command        = wis_saa7115_command,
-       .id_table       = wis_saa7115_id,
-};
-
-static int __init wis_saa7115_init(void)
-{
-       return i2c_add_driver(&wis_saa7115_driver);
-}
-
-static void __exit wis_saa7115_cleanup(void)
-{
-       i2c_del_driver(&wis_saa7115_driver);
-}
-
-module_init(wis_saa7115_init);
-module_exit(wis_saa7115_cleanup);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c
deleted file mode 100644 (file)
index 8f1b7d4..0000000
+++ /dev/null
@@ -1,720 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/slab.h>
-#include <media/tuner.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-
-#include "wis-i2c.h"
-
-/* #define MPX_DEBUG */
-
-/* AS(IF/MPX) pin:      LOW      HIGH/OPEN
- * IF/MPX address:   0x42/0x40   0x43/0x44
- */
-#define IF_I2C_ADDR    0x43
-#define MPX_I2C_ADDR   0x44
-
-static v4l2_std_id force_band;
-static char force_band_str[] = "-";
-module_param_string(force_band, force_band_str, sizeof(force_band_str), 0644);
-static int force_mpx_mode = -1;
-module_param(force_mpx_mode, int, 0644);
-
-/* Store tuner info in the same format as tuner.c, so maybe we can put the
- * Sony tuner support in there. */
-struct sony_tunertype {
-       char *name;
-       unsigned char Vendor; /* unused here */
-       unsigned char Type; /* unused here */
-
-       unsigned short thresh1; /*  band switch VHF_LO <=> VHF_HI */
-       unsigned short thresh2; /*  band switch VHF_HI <=> UHF */
-       unsigned char VHF_L;
-       unsigned char VHF_H;
-       unsigned char UHF;
-       unsigned char config;
-       unsigned short IFPCoff;
-};
-
-/* This array is indexed by (tuner_type - 200) */
-static struct sony_tunertype sony_tuners[] = {
-       { "Sony PAL+SECAM (BTF-PG472Z)", 0, 0,
-         16*144.25, 16*427.25, 0x01, 0x02, 0x04, 0xc6, 623},
-       { "Sony NTSC_JP (BTF-PK467Z)", 0, 0,
-         16*220.25, 16*467.25, 0x01, 0x02, 0x04, 0xc6, 940},
-       { "Sony NTSC (BTF-PB463Z)", 0, 0,
-         16*130.25, 16*364.25, 0x01, 0x02, 0x04, 0xc6, 732},
-};
-
-struct wis_sony_tuner {
-       int type;
-       v4l2_std_id std;
-       unsigned int freq;
-       int mpxmode;
-       u32 audmode;
-};
-
-/* Basically the same as default_set_tv_freq() in tuner.c */
-static int set_freq(struct i2c_client *client, int freq)
-{
-       struct wis_sony_tuner *t = i2c_get_clientdata(client);
-       char *band_name;
-       int n;
-       int band_select;
-       struct sony_tunertype *tun;
-       u8 buffer[4];
-
-       tun = &sony_tuners[t->type - 200];
-       if (freq < tun->thresh1) {
-               band_name = "VHF_L";
-               band_select = tun->VHF_L;
-       } else if (freq < tun->thresh2) {
-               band_name = "VHF_H";
-               band_select = tun->VHF_H;
-       } else {
-               band_name = "UHF";
-               band_select = tun->UHF;
-       }
-       printk(KERN_DEBUG "wis-sony-tuner: tuning to frequency %d.%04d (%s)\n",
-                       freq / 16, (freq % 16) * 625, band_name);
-       n = freq + tun->IFPCoff;
-
-       buffer[0] = n >> 8;
-       buffer[1] = n & 0xff;
-       buffer[2] = tun->config;
-       buffer[3] = band_select;
-       i2c_master_send(client, buffer, 4);
-
-       return 0;
-}
-
-static int mpx_write(struct i2c_client *client, int dev, int addr, int val)
-{
-       u8 buffer[5];
-       struct i2c_msg msg;
-
-       buffer[0] = dev;
-       buffer[1] = addr >> 8;
-       buffer[2] = addr & 0xff;
-       buffer[3] = val >> 8;
-       buffer[4] = val & 0xff;
-       msg.addr = MPX_I2C_ADDR;
-       msg.flags = 0;
-       msg.len = 5;
-       msg.buf = buffer;
-       i2c_transfer(client->adapter, &msg, 1);
-       return 0;
-}
-
-/*
- * MPX register values for the BTF-PG472Z:
- *
- *                                 FM_     NICAM_  SCART_
- *          MODUS  SOURCE    ACB   PRESCAL PRESCAL PRESCAL SYSTEM  VOLUME
- *         10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000
- *         ---------------------------------------------------------------
- * Auto     1003    0020    0100    2603    5000    XXXX    0001    7500
- *
- * B/G
- *  Mono    1003    0020    0100    2603    5000    XXXX    0003    7500
- *  A2      1003    0020    0100    2601    5000    XXXX    0003    7500
- *  NICAM   1003    0120    0100    2603    5000    XXXX    0008    7500
- *
- * I
- *  Mono    1003    0020    0100    2603    7900    XXXX    000A    7500
- *  NICAM   1003    0120    0100    2603    7900    XXXX    000A    7500
- *
- * D/K
- *  Mono    1003    0020    0100    2603    5000    XXXX    0004    7500
- *  A2-1    1003    0020    0100    2601    5000    XXXX    0004    7500
- *  A2-2    1003    0020    0100    2601    5000    XXXX    0005    7500
- *  A2-3    1003    0020    0100    2601    5000    XXXX    0007    7500
- *  NICAM   1003    0120    0100    2603    5000    XXXX    000B    7500
- *
- * L/L'
- *  Mono    0003    0200    0100    7C03    5000    2200    0009    7500
- *  NICAM   0003    0120    0100    7C03    5000    XXXX    0009    7500
- *
- * M
- *  Mono    1003    0200    0100    2B03    5000    2B00    0002    7500
- *
- * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX.
- *
- * Bilingual selection in A2/NICAM:
- *
- *         High byte of SOURCE     Left chan   Right chan
- *                 0x01              MAIN         SUB
- *                 0x03              MAIN         MAIN
- *                 0x04              SUB          SUB
- *
- * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or
- * 0x00 (all other bands).  Force mono in A2 with FMONO_A2:
- *
- *                      FMONO_A2
- *                      10/0022
- *                      --------
- *     Forced mono ON     07F0
- *     Forced mono OFF    0190
- */
-
-static struct {
-       enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode;
-       u16 modus;
-       u16 source;
-       u16 acb;
-       u16 fm_prescale;
-       u16 nicam_prescale;
-       u16 scart_prescale;
-       u16 system;
-       u16 volume;
-} mpx_audio_modes[] = {
-       /* Auto */      { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
-                                       0x5000, 0x0000, 0x0001, 0x7500 },
-       /* B/G Mono */  { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
-                                       0x5000, 0x0000, 0x0003, 0x7500 },
-       /* B/G A2 */    { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
-                                       0x5000, 0x0000, 0x0003, 0x7500 },
-       /* B/G NICAM */ { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
-                                       0x5000, 0x0000, 0x0008, 0x7500 },
-       /* I Mono */    { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
-                                       0x7900, 0x0000, 0x000A, 0x7500 },
-       /* I NICAM */   { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
-                                       0x7900, 0x0000, 0x000A, 0x7500 },
-       /* D/K Mono */  { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
-                                       0x5000, 0x0000, 0x0004, 0x7500 },
-       /* D/K A2-1 */  { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
-                                       0x5000, 0x0000, 0x0004, 0x7500 },
-       /* D/K A2-2 */  { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
-                                       0x5000, 0x0000, 0x0005, 0x7500 },
-       /* D/K A2-3 */  { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
-                                       0x5000, 0x0000, 0x0007, 0x7500 },
-       /* D/K NICAM */ { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
-                                       0x5000, 0x0000, 0x000B, 0x7500 },
-       /* L/L' Mono */ { AUD_MONO,     0x0003, 0x0200, 0x0100, 0x7C03,
-                                       0x5000, 0x2200, 0x0009, 0x7500 },
-       /* L/L' NICAM */{ AUD_NICAM_L,  0x0003, 0x0120, 0x0100, 0x7C03,
-                                       0x5000, 0x0000, 0x0009, 0x7500 },
-};
-
-#define MPX_NUM_MODES  ARRAY_SIZE(mpx_audio_modes)
-
-static int mpx_setup(struct i2c_client *client)
-{
-       struct wis_sony_tuner *t = i2c_get_clientdata(client);
-       u16 source = 0;
-       u8 buffer[3];
-       struct i2c_msg msg;
-
-       /* reset MPX */
-       buffer[0] = 0x00;
-       buffer[1] = 0x80;
-       buffer[2] = 0x00;
-       msg.addr = MPX_I2C_ADDR;
-       msg.flags = 0;
-       msg.len = 3;
-       msg.buf = buffer;
-       i2c_transfer(client->adapter, &msg, 1);
-       buffer[1] = 0x00;
-       i2c_transfer(client->adapter, &msg, 1);
-
-       if (mpx_audio_modes[t->mpxmode].audio_mode != AUD_MONO) {
-               switch (t->audmode) {
-               case V4L2_TUNER_MODE_MONO:
-                       switch (mpx_audio_modes[t->mpxmode].audio_mode) {
-                       case AUD_A2:
-                               source = mpx_audio_modes[t->mpxmode].source;
-                               break;
-                       case AUD_NICAM:
-                               source = 0x0000;
-                               break;
-                       case AUD_NICAM_L:
-                               source = 0x0200;
-                               break;
-                       default:
-                               break;
-                       }
-                       break;
-               case V4L2_TUNER_MODE_STEREO:
-                       source = mpx_audio_modes[t->mpxmode].source;
-                       break;
-               case V4L2_TUNER_MODE_LANG1:
-                       source = 0x0300;
-                       break;
-               case V4L2_TUNER_MODE_LANG2:
-                       source = 0x0400;
-                       break;
-               }
-               source |= mpx_audio_modes[t->mpxmode].source & 0x00ff;
-       } else
-               source = mpx_audio_modes[t->mpxmode].source;
-
-       mpx_write(client, 0x10, 0x0030, mpx_audio_modes[t->mpxmode].modus);
-       mpx_write(client, 0x12, 0x0008, source);
-       mpx_write(client, 0x12, 0x0013, mpx_audio_modes[t->mpxmode].acb);
-       mpx_write(client, 0x12, 0x000e,
-                       mpx_audio_modes[t->mpxmode].fm_prescale);
-       mpx_write(client, 0x12, 0x0010,
-                       mpx_audio_modes[t->mpxmode].nicam_prescale);
-       mpx_write(client, 0x12, 0x000d,
-                       mpx_audio_modes[t->mpxmode].scart_prescale);
-       mpx_write(client, 0x10, 0x0020, mpx_audio_modes[t->mpxmode].system);
-       mpx_write(client, 0x12, 0x0000, mpx_audio_modes[t->mpxmode].volume);
-       if (mpx_audio_modes[t->mpxmode].audio_mode == AUD_A2)
-               mpx_write(client, 0x10, 0x0022,
-                       t->audmode == V4L2_TUNER_MODE_MONO ?  0x07f0 : 0x0190);
-
-#ifdef MPX_DEBUG
-       {
-               u8 buf1[3], buf2[2];
-               struct i2c_msg msgs[2];
-
-               printk(KERN_DEBUG "wis-sony-tuner: MPX registers: %04x %04x "
-                               "%04x %04x %04x %04x %04x %04x\n",
-                               mpx_audio_modes[t->mpxmode].modus,
-                               source,
-                               mpx_audio_modes[t->mpxmode].acb,
-                               mpx_audio_modes[t->mpxmode].fm_prescale,
-                               mpx_audio_modes[t->mpxmode].nicam_prescale,
-                               mpx_audio_modes[t->mpxmode].scart_prescale,
-                               mpx_audio_modes[t->mpxmode].system,
-                               mpx_audio_modes[t->mpxmode].volume);
-               buf1[0] = 0x11;
-               buf1[1] = 0x00;
-               buf1[2] = 0x7e;
-               msgs[0].addr = MPX_I2C_ADDR;
-               msgs[0].flags = 0;
-               msgs[0].len = 3;
-               msgs[0].buf = buf1;
-               msgs[1].addr = MPX_I2C_ADDR;
-               msgs[1].flags = I2C_M_RD;
-               msgs[1].len = 2;
-               msgs[1].buf = buf2;
-               i2c_transfer(client->adapter, msgs, 2);
-               printk(KERN_DEBUG "wis-sony-tuner: MPX system: %02x%02x\n",
-                               buf2[0], buf2[1]);
-               buf1[0] = 0x11;
-               buf1[1] = 0x02;
-               buf1[2] = 0x00;
-               i2c_transfer(client->adapter, msgs, 2);
-               printk(KERN_DEBUG "wis-sony-tuner: MPX status: %02x%02x\n",
-                               buf2[0], buf2[1]);
-       }
-#endif
-       return 0;
-}
-
-/*
- * IF configuration values for the BTF-PG472Z:
- *
- *     B/G: 0x94 0x70 0x49
- *     I:   0x14 0x70 0x4a
- *     D/K: 0x14 0x70 0x4b
- *     L:   0x04 0x70 0x4b
- *     L':  0x44 0x70 0x53
- *     M:   0x50 0x30 0x4c
- */
-
-static int set_if(struct i2c_client *client)
-{
-       struct wis_sony_tuner *t = i2c_get_clientdata(client);
-       u8 buffer[4];
-       struct i2c_msg msg;
-       int default_mpx_mode = 0;
-
-       /* configure IF */
-       buffer[0] = 0;
-       if (t->std & V4L2_STD_PAL_BG) {
-               buffer[1] = 0x94;
-               buffer[2] = 0x70;
-               buffer[3] = 0x49;
-               default_mpx_mode = 1;
-       } else if (t->std & V4L2_STD_PAL_I) {
-               buffer[1] = 0x14;
-               buffer[2] = 0x70;
-               buffer[3] = 0x4a;
-               default_mpx_mode = 4;
-       } else if (t->std & V4L2_STD_PAL_DK) {
-               buffer[1] = 0x14;
-               buffer[2] = 0x70;
-               buffer[3] = 0x4b;
-               default_mpx_mode = 6;
-       } else if (t->std & V4L2_STD_SECAM_L) {
-               buffer[1] = 0x04;
-               buffer[2] = 0x70;
-               buffer[3] = 0x4b;
-               default_mpx_mode = 11;
-       }
-       msg.addr = IF_I2C_ADDR;
-       msg.flags = 0;
-       msg.len = 4;
-       msg.buf = buffer;
-       i2c_transfer(client->adapter, &msg, 1);
-
-       /* Select MPX mode if not forced by the user */
-       if (force_mpx_mode >= 0 && force_mpx_mode < MPX_NUM_MODES)
-               t->mpxmode = force_mpx_mode;
-       else
-               t->mpxmode = default_mpx_mode;
-       printk(KERN_DEBUG "wis-sony-tuner: setting MPX to mode %d\n",
-                       t->mpxmode);
-       mpx_setup(client);
-
-       return 0;
-}
-
-static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-       struct wis_sony_tuner *t = i2c_get_clientdata(client);
-
-       switch (cmd) {
-#if 0
-#ifdef TUNER_SET_TYPE_ADDR
-       case TUNER_SET_TYPE_ADDR:
-       {
-               struct tuner_setup *tun_setup = arg;
-               int *type = &tun_setup->type;
-#else
-       case TUNER_SET_TYPE:
-       {
-               int *type = arg;
-#endif
-
-               if (t->type >= 0) {
-                       if (t->type != *type)
-                               printk(KERN_ERR "wis-sony-tuner: type already "
-                                       "set to %d, ignoring request for %d\n",
-                                       t->type, *type);
-                       break;
-               }
-               t->type = *type;
-               switch (t->type) {
-               case TUNER_SONY_BTF_PG472Z:
-                       switch (force_band_str[0]) {
-                       case 'b':
-                       case 'B':
-                       case 'g':
-                       case 'G':
-                               printk(KERN_INFO "wis-sony-tuner: forcing "
-                                               "tuner to PAL-B/G bands\n");
-                               force_band = V4L2_STD_PAL_BG;
-                               break;
-                       case 'i':
-                       case 'I':
-                               printk(KERN_INFO "wis-sony-tuner: forcing "
-                                               "tuner to PAL-I band\n");
-                               force_band = V4L2_STD_PAL_I;
-                               break;
-                       case 'd':
-                       case 'D':
-                       case 'k':
-                       case 'K':
-                               printk(KERN_INFO "wis-sony-tuner: forcing "
-                                               "tuner to PAL-D/K bands\n");
-                               force_band = V4L2_STD_PAL_I;
-                               break;
-                       case 'l':
-                       case 'L':
-                               printk(KERN_INFO "wis-sony-tuner: forcing "
-                                               "tuner to SECAM-L band\n");
-                               force_band = V4L2_STD_SECAM_L;
-                               break;
-                       default:
-                               force_band = 0;
-                               break;
-                       }
-                       if (force_band)
-                               t->std = force_band;
-                       else
-                               t->std = V4L2_STD_PAL_BG;
-                       set_if(client);
-                       break;
-               case TUNER_SONY_BTF_PK467Z:
-                       t->std = V4L2_STD_NTSC_M_JP;
-                       break;
-               case TUNER_SONY_BTF_PB463Z:
-                       t->std = V4L2_STD_NTSC_M;
-                       break;
-               default:
-                       printk(KERN_ERR "wis-sony-tuner: tuner type %d is not "
-                                       "supported by this module\n", *type);
-                       break;
-               }
-               if (type >= 0)
-                       printk(KERN_INFO
-                               "wis-sony-tuner: type set to %d (%s)\n",
-                               t->type, sony_tuners[t->type - 200].name);
-               break;
-       }
-#endif
-       case VIDIOC_G_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
-
-               f->frequency = t->freq;
-               break;
-       }
-       case VIDIOC_S_FREQUENCY:
-       {
-               struct v4l2_frequency *f = arg;
-
-               t->freq = f->frequency;
-               set_freq(client, t->freq);
-               break;
-       }
-       case VIDIOC_ENUMSTD:
-       {
-               struct v4l2_standard *std = arg;
-
-               switch (t->type) {
-               case TUNER_SONY_BTF_PG472Z:
-                       switch (std->index) {
-                       case 0:
-                               v4l2_video_std_construct(std,
-                                               V4L2_STD_PAL_BG, "PAL-B/G");
-                               break;
-                       case 1:
-                               v4l2_video_std_construct(std,
-                                               V4L2_STD_PAL_I, "PAL-I");
-                               break;
-                       case 2:
-                               v4l2_video_std_construct(std,
-                                               V4L2_STD_PAL_DK, "PAL-D/K");
-                               break;
-                       case 3:
-                               v4l2_video_std_construct(std,
-                                               V4L2_STD_SECAM_L, "SECAM-L");
-                               break;
-                       default:
-                               std->id = 0; /* hack to indicate EINVAL */
-                               break;
-                       }
-                       break;
-               case TUNER_SONY_BTF_PK467Z:
-                       if (std->index != 0) {
-                               std->id = 0; /* hack to indicate EINVAL */
-                               break;
-                       }
-                       v4l2_video_std_construct(std,
-                                       V4L2_STD_NTSC_M_JP, "NTSC-J");
-                       break;
-               case TUNER_SONY_BTF_PB463Z:
-                       if (std->index != 0) {
-                               std->id = 0; /* hack to indicate EINVAL */
-                               break;
-                       }
-                       v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC");
-                       break;
-               }
-               break;
-       }
-       case VIDIOC_G_STD:
-       {
-               v4l2_std_id *std = arg;
-
-               *std = t->std;
-               break;
-       }
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *std = arg;
-               v4l2_std_id old = t->std;
-
-               switch (t->type) {
-               case TUNER_SONY_BTF_PG472Z:
-                       if (force_band && (*std & force_band) != *std &&
-                                       *std != V4L2_STD_PAL &&
-                                       *std != V4L2_STD_SECAM) {
-                               printk(KERN_DEBUG "wis-sony-tuner: ignoring "
-                                               "requested TV standard in "
-                                               "favor of force_band value\n");
-                               t->std = force_band;
-                       } else if (*std & V4L2_STD_PAL_BG) { /* default */
-                               t->std = V4L2_STD_PAL_BG;
-                       } else if (*std & V4L2_STD_PAL_I) {
-                               t->std = V4L2_STD_PAL_I;
-                       } else if (*std & V4L2_STD_PAL_DK) {
-                               t->std = V4L2_STD_PAL_DK;
-                       } else if (*std & V4L2_STD_SECAM_L) {
-                               t->std = V4L2_STD_SECAM_L;
-                       } else {
-                               printk(KERN_ERR "wis-sony-tuner: TV standard "
-                                               "not supported\n");
-                               *std = 0; /* hack to indicate EINVAL */
-                               break;
-                       }
-                       if (old != t->std)
-                               set_if(client);
-                       break;
-               case TUNER_SONY_BTF_PK467Z:
-                       if (!(*std & V4L2_STD_NTSC_M_JP)) {
-                               printk(KERN_ERR "wis-sony-tuner: TV standard "
-                                               "not supported\n");
-                               *std = 0; /* hack to indicate EINVAL */
-                       }
-                       break;
-               case TUNER_SONY_BTF_PB463Z:
-                       if (!(*std & V4L2_STD_NTSC_M)) {
-                               printk(KERN_ERR "wis-sony-tuner: TV standard "
-                                               "not supported\n");
-                               *std = 0; /* hack to indicate EINVAL */
-                       }
-                       break;
-               }
-               break;
-       }
-       case VIDIOC_QUERYSTD:
-       {
-               v4l2_std_id *std = arg;
-
-               switch (t->type) {
-               case TUNER_SONY_BTF_PG472Z:
-                       if (force_band)
-                               *std = force_band;
-                       else
-                               *std = V4L2_STD_PAL_BG | V4L2_STD_PAL_I |
-                                       V4L2_STD_PAL_DK | V4L2_STD_SECAM_L;
-                       break;
-               case TUNER_SONY_BTF_PK467Z:
-                       *std = V4L2_STD_NTSC_M_JP;
-                       break;
-               case TUNER_SONY_BTF_PB463Z:
-                       *std = V4L2_STD_NTSC_M;
-                       break;
-               }
-               break;
-       }
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *tun = arg;
-
-               memset(tun, 0, sizeof(*tun));
-               strcpy(tun->name, "Television");
-               tun->type = V4L2_TUNER_ANALOG_TV;
-               tun->rangelow = 0UL; /* does anything use these? */
-               tun->rangehigh = 0xffffffffUL;
-               switch (t->type) {
-               case TUNER_SONY_BTF_PG472Z:
-                       tun->capability = V4L2_TUNER_CAP_NORM |
-                               V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
-                               V4L2_TUNER_CAP_LANG2;
-                       tun->rxsubchans = V4L2_TUNER_SUB_MONO |
-                               V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 |
-                               V4L2_TUNER_SUB_LANG2;
-                       break;
-               case TUNER_SONY_BTF_PK467Z:
-               case TUNER_SONY_BTF_PB463Z:
-                       tun->capability = V4L2_TUNER_CAP_STEREO;
-                       tun->rxsubchans = V4L2_TUNER_SUB_MONO |
-                                               V4L2_TUNER_SUB_STEREO;
-                       break;
-               }
-               tun->audmode = t->audmode;
-               return 0;
-       }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *tun = arg;
-
-               switch (t->type) {
-               case TUNER_SONY_BTF_PG472Z:
-                       if (tun->audmode != t->audmode) {
-                               t->audmode = tun->audmode;
-                               mpx_setup(client);
-                       }
-                       break;
-               case TUNER_SONY_BTF_PK467Z:
-               case TUNER_SONY_BTF_PB463Z:
-                       break;
-               }
-               return 0;
-       }
-       default:
-               break;
-       }
-       return 0;
-}
-
-static int wis_sony_tuner_probe(struct i2c_client *client,
-                               const struct i2c_device_id *id)
-{
-       struct i2c_adapter *adapter = client->adapter;
-       struct wis_sony_tuner *t;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
-               return -ENODEV;
-
-       t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL);
-       if (t == NULL)
-               return -ENOMEM;
-
-       t->type = -1;
-       t->freq = 0;
-       t->mpxmode = 0;
-       t->audmode = V4L2_TUNER_MODE_STEREO;
-       i2c_set_clientdata(client, t);
-
-       printk(KERN_DEBUG
-               "wis-sony-tuner: initializing tuner at address %d on %s\n",
-               client->addr, adapter->name);
-
-       return 0;
-}
-
-static int wis_sony_tuner_remove(struct i2c_client *client)
-{
-       struct wis_sony_tuner *t = i2c_get_clientdata(client);
-
-       kfree(t);
-       return 0;
-}
-
-static const struct i2c_device_id wis_sony_tuner_id[] = {
-       { "wis_sony_tuner", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wis_sony_tuner_id);
-
-static struct i2c_driver wis_sony_tuner_driver = {
-       .driver = {
-               .name   = "WIS Sony TV Tuner I2C driver",
-       },
-       .probe          = wis_sony_tuner_probe,
-       .remove         = wis_sony_tuner_remove,
-       .command        = tuner_command,
-       .id_table       = wis_sony_tuner_id,
-};
-
-static int __init wis_sony_tuner_init(void)
-{
-       return i2c_add_driver(&wis_sony_tuner_driver);
-}
-
-static void __exit wis_sony_tuner_cleanup(void)
-{
-       i2c_del_driver(&wis_sony_tuner_driver);
-}
-
-module_init(wis_sony_tuner_init);
-module_exit(wis_sony_tuner_cleanup);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/go7007/wis-tw2804.c
deleted file mode 100644 (file)
index 9134f03..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-
-#include "wis-i2c.h"
-
-struct wis_tw2804 {
-       int channel;
-       int norm;
-       int brightness;
-       int contrast;
-       int saturation;
-       int hue;
-};
-
-static u8 global_registers[] = {
-       0x39, 0x00,
-       0x3a, 0xff,
-       0x3b, 0x84,
-       0x3c, 0x80,
-       0x3d, 0x80,
-       0x3e, 0x82,
-       0x3f, 0x82,
-       0xff, 0xff, /* Terminator (reg 0xff does not exist) */
-};
-
-static u8 channel_registers[] = {
-       0x01, 0xc4,
-       0x02, 0xa5,
-       0x03, 0x20,
-       0x04, 0xd0,
-       0x05, 0x20,
-       0x06, 0xd0,
-       0x07, 0x88,
-       0x08, 0x20,
-       0x09, 0x07,
-       0x0a, 0xf0,
-       0x0b, 0x07,
-       0x0c, 0xf0,
-       0x0d, 0x40,
-       0x0e, 0xd2,
-       0x0f, 0x80,
-       0x10, 0x80,
-       0x11, 0x80,
-       0x12, 0x80,
-       0x13, 0x1f,
-       0x14, 0x00,
-       0x15, 0x00,
-       0x16, 0x00,
-       0x17, 0x00,
-       0x18, 0xff,
-       0x19, 0xff,
-       0x1a, 0xff,
-       0x1b, 0xff,
-       0x1c, 0xff,
-       0x1d, 0xff,
-       0x1e, 0xff,
-       0x1f, 0xff,
-       0x20, 0x07,
-       0x21, 0x07,
-       0x22, 0x00,
-       0x23, 0x91,
-       0x24, 0x51,
-       0x25, 0x03,
-       0x26, 0x00,
-       0x27, 0x00,
-       0x28, 0x00,
-       0x29, 0x00,
-       0x2a, 0x00,
-       0x2b, 0x00,
-       0x2c, 0x00,
-       0x2d, 0x00,
-       0x2e, 0x00,
-       0x2f, 0x00,
-       0x30, 0x00,
-       0x31, 0x00,
-       0x32, 0x00,
-       0x33, 0x00,
-       0x34, 0x00,
-       0x35, 0x00,
-       0x36, 0x00,
-       0x37, 0x00,
-       0xff, 0xff, /* Terminator (reg 0xff does not exist) */
-};
-
-static int write_reg(struct i2c_client *client, u8 reg, u8 value, int channel)
-{
-       return i2c_smbus_write_byte_data(client, reg | (channel << 6), value);
-}
-
-static int write_regs(struct i2c_client *client, u8 *regs, int channel)
-{
-       int i;
-
-       for (i = 0; regs[i] != 0xff; i += 2)
-               if (i2c_smbus_write_byte_data(client,
-                               regs[i] | (channel << 6), regs[i + 1]) < 0)
-                       return -1;
-       return 0;
-}
-
-static int wis_tw2804_command(struct i2c_client *client,
-                               unsigned int cmd, void *arg)
-{
-       struct wis_tw2804 *dec = i2c_get_clientdata(client);
-
-       if (cmd == DECODER_SET_CHANNEL) {
-               int *input = arg;
-
-               if (*input < 0 || *input > 3) {
-                       printk(KERN_ERR "wis-tw2804: channel %d is not "
-                                       "between 0 and 3!\n", *input);
-                       return 0;
-               }
-               dec->channel = *input;
-               printk(KERN_DEBUG "wis-tw2804: initializing TW2804 "
-                               "channel %d\n", dec->channel);
-               if (dec->channel == 0 &&
-                               write_regs(client, global_registers, 0) < 0) {
-                       printk(KERN_ERR "wis-tw2804: error initializing "
-                                       "TW2804 global registers\n");
-                       return 0;
-               }
-               if (write_regs(client, channel_registers, dec->channel) < 0) {
-                       printk(KERN_ERR "wis-tw2804: error initializing "
-                                       "TW2804 channel %d\n", dec->channel);
-                       return 0;
-               }
-               return 0;
-       }
-
-       if (dec->channel < 0) {
-               printk(KERN_DEBUG "wis-tw2804: ignoring command %08x until "
-                               "channel number is set\n", cmd);
-               return 0;
-       }
-
-       switch (cmd) {
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *input = arg;
-               u8 regs[] = {
-                       0x01, *input & V4L2_STD_NTSC ? 0xc4 : 0x84,
-                       0x09, *input & V4L2_STD_NTSC ? 0x07 : 0x04,
-                       0x0a, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
-                       0x0b, *input & V4L2_STD_NTSC ? 0x07 : 0x04,
-                       0x0c, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
-                       0x0d, *input & V4L2_STD_NTSC ? 0x40 : 0x4a,
-                       0x16, *input & V4L2_STD_NTSC ? 0x00 : 0x40,
-                       0x17, *input & V4L2_STD_NTSC ? 0x00 : 0x40,
-                       0x20, *input & V4L2_STD_NTSC ? 0x07 : 0x0f,
-                       0x21, *input & V4L2_STD_NTSC ? 0x07 : 0x0f,
-                       0xff,   0xff,
-               };
-               write_regs(client, regs, dec->channel);
-               dec->norm = *input;
-               break;
-       }
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *ctrl = arg;
-
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
-                       ctrl->minimum = 0;
-                       ctrl->maximum = 255;
-                       ctrl->step = 1;
-                       ctrl->default_value = 128;
-                       ctrl->flags = 0;
-                       break;
-               case V4L2_CID_CONTRAST:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
-                       ctrl->minimum = 0;
-                       ctrl->maximum = 255;
-                       ctrl->step = 1;
-                       ctrl->default_value = 128;
-                       ctrl->flags = 0;
-                       break;
-               case V4L2_CID_SATURATION:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
-                       ctrl->minimum = 0;
-                       ctrl->maximum = 255;
-                       ctrl->step = 1;
-                       ctrl->default_value = 128;
-                       ctrl->flags = 0;
-                       break;
-               case V4L2_CID_HUE:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
-                       ctrl->minimum = 0;
-                       ctrl->maximum = 255;
-                       ctrl->step = 1;
-                       ctrl->default_value = 128;
-                       ctrl->flags = 0;
-                       break;
-               }
-               break;
-       }
-       case VIDIOC_S_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       if (ctrl->value > 255)
-                               dec->brightness = 255;
-                       else if (ctrl->value < 0)
-                               dec->brightness = 0;
-                       else
-                               dec->brightness = ctrl->value;
-                       write_reg(client, 0x12, dec->brightness, dec->channel);
-                       break;
-               case V4L2_CID_CONTRAST:
-                       if (ctrl->value > 255)
-                               dec->contrast = 255;
-                       else if (ctrl->value < 0)
-                               dec->contrast = 0;
-                       else
-                               dec->contrast = ctrl->value;
-                       write_reg(client, 0x11, dec->contrast, dec->channel);
-                       break;
-               case V4L2_CID_SATURATION:
-                       if (ctrl->value > 255)
-                               dec->saturation = 255;
-                       else if (ctrl->value < 0)
-                               dec->saturation = 0;
-                       else
-                               dec->saturation = ctrl->value;
-                       write_reg(client, 0x10, dec->saturation, dec->channel);
-                       break;
-               case V4L2_CID_HUE:
-                       if (ctrl->value > 255)
-                               dec->hue = 255;
-                       else if (ctrl->value < 0)
-                               dec->hue = 0;
-                       else
-                               dec->hue = ctrl->value;
-                       write_reg(client, 0x0f, dec->hue, dec->channel);
-                       break;
-               }
-               break;
-       }
-       case VIDIOC_G_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       ctrl->value = dec->brightness;
-                       break;
-               case V4L2_CID_CONTRAST:
-                       ctrl->value = dec->contrast;
-                       break;
-               case V4L2_CID_SATURATION:
-                       ctrl->value = dec->saturation;
-                       break;
-               case V4L2_CID_HUE:
-                       ctrl->value = dec->hue;
-                       break;
-               }
-               break;
-       }
-       default:
-               break;
-       }
-       return 0;
-}
-
-static int wis_tw2804_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
-{
-       struct i2c_adapter *adapter = client->adapter;
-       struct wis_tw2804 *dec;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return -ENODEV;
-
-       dec = kmalloc(sizeof(struct wis_tw2804), GFP_KERNEL);
-       if (dec == NULL)
-               return -ENOMEM;
-
-       dec->channel = -1;
-       dec->norm = V4L2_STD_NTSC;
-       dec->brightness = 128;
-       dec->contrast = 128;
-       dec->saturation = 128;
-       dec->hue = 128;
-       i2c_set_clientdata(client, dec);
-
-       printk(KERN_DEBUG "wis-tw2804: creating TW2804 at address %d on %s\n",
-               client->addr, adapter->name);
-
-       return 0;
-}
-
-static int wis_tw2804_remove(struct i2c_client *client)
-{
-       struct wis_tw2804 *dec = i2c_get_clientdata(client);
-
-       kfree(dec);
-       return 0;
-}
-
-static const struct i2c_device_id wis_tw2804_id[] = {
-       { "wis_tw2804", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wis_tw2804_id);
-
-static struct i2c_driver wis_tw2804_driver = {
-       .driver = {
-               .name   = "WIS TW2804 I2C driver",
-       },
-       .probe          = wis_tw2804_probe,
-       .remove         = wis_tw2804_remove,
-       .command        = wis_tw2804_command,
-       .id_table       = wis_tw2804_id,
-};
-
-static int __init wis_tw2804_init(void)
-{
-       return i2c_add_driver(&wis_tw2804_driver);
-}
-
-static void __exit wis_tw2804_cleanup(void)
-{
-       i2c_del_driver(&wis_tw2804_driver);
-}
-
-module_init(wis_tw2804_init);
-module_exit(wis_tw2804_cleanup);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/go7007/wis-tw9903.c
deleted file mode 100644 (file)
index 9230f4a..0000000
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-
-#include "wis-i2c.h"
-
-struct wis_tw9903 {
-       int norm;
-       int brightness;
-       int contrast;
-       int hue;
-};
-
-static u8 initial_registers[] =
-{
-       0x02, 0x44, /* input 1, composite */
-       0x03, 0x92, /* correct digital format */
-       0x04, 0x00,
-       0x05, 0x80, /* or 0x00 for PAL */
-       0x06, 0x40, /* second internal current reference */
-       0x07, 0x02, /* window */
-       0x08, 0x14, /* window */
-       0x09, 0xf0, /* window */
-       0x0a, 0x81, /* window */
-       0x0b, 0xd0, /* window */
-       0x0c, 0x8c,
-       0x0d, 0x00, /* scaling */
-       0x0e, 0x11, /* scaling */
-       0x0f, 0x00, /* scaling */
-       0x10, 0x00, /* brightness */
-       0x11, 0x60, /* contrast */
-       0x12, 0x01, /* sharpness */
-       0x13, 0x7f, /* U gain */
-       0x14, 0x5a, /* V gain */
-       0x15, 0x00, /* hue */
-       0x16, 0xc3, /* sharpness */
-       0x18, 0x00,
-       0x19, 0x58, /* vbi */
-       0x1a, 0x80,
-       0x1c, 0x0f, /* video norm */
-       0x1d, 0x7f, /* video norm */
-       0x20, 0xa0, /* clamping gain (working 0x50) */
-       0x21, 0x22,
-       0x22, 0xf0,
-       0x23, 0xfe,
-       0x24, 0x3c,
-       0x25, 0x38,
-       0x26, 0x44,
-       0x27, 0x20,
-       0x28, 0x00,
-       0x29, 0x15,
-       0x2a, 0xa0,
-       0x2b, 0x44,
-       0x2c, 0x37,
-       0x2d, 0x00,
-       0x2e, 0xa5, /* burst PLL control (working: a9) */
-       0x2f, 0xe0, /* 0xea is blue test frame -- 0xe0 for normal */
-       0x31, 0x00,
-       0x33, 0x22,
-       0x34, 0x11,
-       0x35, 0x35,
-       0x3b, 0x05,
-       0x06, 0xc0, /* reset device */
-       0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
-};
-
-static int write_reg(struct i2c_client *client, u8 reg, u8 value)
-{
-       return i2c_smbus_write_byte_data(client, reg, value);
-}
-
-static int write_regs(struct i2c_client *client, u8 *regs)
-{
-       int i;
-
-       for (i = 0; regs[i] != 0x00; i += 2)
-               if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
-                       return -1;
-       return 0;
-}
-
-static int wis_tw9903_command(struct i2c_client *client,
-                               unsigned int cmd, void *arg)
-{
-       struct wis_tw9903 *dec = i2c_get_clientdata(client);
-
-       switch (cmd) {
-       case VIDIOC_S_INPUT:
-       {
-               int *input = arg;
-
-               i2c_smbus_write_byte_data(client, 0x02, 0x40 | (*input << 1));
-               break;
-       }
-#if 0
-       /* The scaler on this thing seems to be horribly broken */
-       case DECODER_SET_RESOLUTION:
-       {
-               struct video_decoder_resolution *res = arg;
-               /*int hscale = 256 * 720 / res->width;*/
-               int hscale = 256 * 720 / (res->width - (res->width > 704 ? 0 : 8));
-               int vscale = 256 * (dec->norm & V4L2_STD_NTSC ?  240 : 288)
-                               / res->height;
-               u8 regs[] = {
-                       0x0d, vscale & 0xff,
-                       0x0f, hscale & 0xff,
-                       0x0e, ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8),
-                       0x06, 0xc0, /* reset device */
-                       0,      0,
-               };
-               printk(KERN_DEBUG "vscale is %04x, hscale is %04x\n",
-                               vscale, hscale);
-               /*write_regs(client, regs);*/
-               break;
-       }
-#endif
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *input = arg;
-               u8 regs[] = {
-                       0x05, *input & V4L2_STD_NTSC ? 0x80 : 0x00,
-                       0x07, *input & V4L2_STD_NTSC ? 0x02 : 0x12,
-                       0x08, *input & V4L2_STD_NTSC ? 0x14 : 0x18,
-                       0x09, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
-                       0,      0,
-               };
-               write_regs(client, regs);
-               dec->norm = *input;
-               break;
-       }
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *ctrl = arg;
-
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
-                       ctrl->minimum = -128;
-                       ctrl->maximum = 127;
-                       ctrl->step = 1;
-                       ctrl->default_value = 0x00;
-                       ctrl->flags = 0;
-                       break;
-               case V4L2_CID_CONTRAST:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
-                       ctrl->minimum = 0;
-                       ctrl->maximum = 255;
-                       ctrl->step = 1;
-                       ctrl->default_value = 0x60;
-                       ctrl->flags = 0;
-                       break;
-#if 0
-               /* I don't understand how the Chroma Gain registers work... */
-               case V4L2_CID_SATURATION:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
-                       ctrl->minimum = 0;
-                       ctrl->maximum = 127;
-                       ctrl->step = 1;
-                       ctrl->default_value = 64;
-                       ctrl->flags = 0;
-                       break;
-#endif
-               case V4L2_CID_HUE:
-                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
-                       strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
-                       ctrl->minimum = -128;
-                       ctrl->maximum = 127;
-                       ctrl->step = 1;
-                       ctrl->default_value = 0;
-                       ctrl->flags = 0;
-                       break;
-               }
-               break;
-       }
-       case VIDIOC_S_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       if (ctrl->value > 127)
-                               dec->brightness = 127;
-                       else if (ctrl->value < -128)
-                               dec->brightness = -128;
-                       else
-                               dec->brightness = ctrl->value;
-                       write_reg(client, 0x10, dec->brightness);
-                       break;
-               case V4L2_CID_CONTRAST:
-                       if (ctrl->value > 255)
-                               dec->contrast = 255;
-                       else if (ctrl->value < 0)
-                               dec->contrast = 0;
-                       else
-                               dec->contrast = ctrl->value;
-                       write_reg(client, 0x11, dec->contrast);
-                       break;
-#if 0
-               case V4L2_CID_SATURATION:
-                       if (ctrl->value > 127)
-                               dec->saturation = 127;
-                       else if (ctrl->value < 0)
-                               dec->saturation = 0;
-                       else
-                               dec->saturation = ctrl->value;
-                       /*write_reg(client, 0x0c, dec->saturation);*/
-                       break;
-#endif
-               case V4L2_CID_HUE:
-                       if (ctrl->value > 127)
-                               dec->hue = 127;
-                       else if (ctrl->value < -128)
-                               dec->hue = -128;
-                       else
-                               dec->hue = ctrl->value;
-                       write_reg(client, 0x15, dec->hue);
-                       break;
-               }
-               break;
-       }
-       case VIDIOC_G_CTRL:
-       {
-               struct v4l2_control *ctrl = arg;
-
-               switch (ctrl->id) {
-               case V4L2_CID_BRIGHTNESS:
-                       ctrl->value = dec->brightness;
-                       break;
-               case V4L2_CID_CONTRAST:
-                       ctrl->value = dec->contrast;
-                       break;
-#if 0
-               case V4L2_CID_SATURATION:
-                       ctrl->value = dec->saturation;
-                       break;
-#endif
-               case V4L2_CID_HUE:
-                       ctrl->value = dec->hue;
-                       break;
-               }
-               break;
-       }
-       default:
-               break;
-       }
-       return 0;
-}
-
-static int wis_tw9903_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
-{
-       struct i2c_adapter *adapter = client->adapter;
-       struct wis_tw9903 *dec;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return -ENODEV;
-
-       dec = kmalloc(sizeof(struct wis_tw9903), GFP_KERNEL);
-       if (dec == NULL)
-               return -ENOMEM;
-
-       dec->norm = V4L2_STD_NTSC;
-       dec->brightness = 0;
-       dec->contrast = 0x60;
-       dec->hue = 0;
-       i2c_set_clientdata(client, dec);
-
-       printk(KERN_DEBUG
-               "wis-tw9903: initializing TW9903 at address %d on %s\n",
-               client->addr, adapter->name);
-
-       if (write_regs(client, initial_registers) < 0) {
-               printk(KERN_ERR "wis-tw9903: error initializing TW9903\n");
-               kfree(dec);
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static int wis_tw9903_remove(struct i2c_client *client)
-{
-       struct wis_tw9903 *dec = i2c_get_clientdata(client);
-
-       kfree(dec);
-       return 0;
-}
-
-static const struct i2c_device_id wis_tw9903_id[] = {
-       { "wis_tw9903", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wis_tw9903_id);
-
-static struct i2c_driver wis_tw9903_driver = {
-       .driver = {
-               .name   = "WIS TW9903 I2C driver",
-       },
-       .probe          = wis_tw9903_probe,
-       .remove         = wis_tw9903_remove,
-       .command        = wis_tw9903_command,
-       .id_table       = wis_tw9903_id,
-};
-
-static int __init wis_tw9903_init(void)
-{
-       return i2c_add_driver(&wis_tw9903_driver);
-}
-
-static void __exit wis_tw9903_cleanup(void)
-{
-       i2c_del_driver(&wis_tw9903_driver);
-}
-
-module_init(wis_tw9903_init);
-module_exit(wis_tw9903_cleanup);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/wis-uda1342.c b/drivers/staging/go7007/wis-uda1342.c
deleted file mode 100644 (file)
index 0127be2..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <media/tvaudio.h>
-#include <media/v4l2-common.h>
-
-#include "wis-i2c.h"
-
-static int write_reg(struct i2c_client *client, int reg, int value)
-{
-       /* UDA1342 wants MSB first, but SMBus sends LSB first */
-       i2c_smbus_write_word_data(client, reg, swab16(value));
-       return 0;
-}
-
-static int wis_uda1342_command(struct i2c_client *client,
-                               unsigned int cmd, void *arg)
-{
-       switch (cmd) {
-       case VIDIOC_S_AUDIO:
-       {
-               int *inp = arg;
-
-               switch (*inp) {
-               case TVAUDIO_INPUT_TUNER:
-                       write_reg(client, 0x00, 0x1441); /* select input 2 */
-                       break;
-               case TVAUDIO_INPUT_EXTERN:
-                       write_reg(client, 0x00, 0x1241); /* select input 1 */
-                       break;
-               default:
-                       printk(KERN_ERR "wis-uda1342: input %d not supported\n",
-                                       *inp);
-                       break;
-               }
-               break;
-       }
-       default:
-               break;
-       }
-       return 0;
-}
-
-static int wis_uda1342_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
-{
-       struct i2c_adapter *adapter = client->adapter;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
-               return -ENODEV;
-
-       printk(KERN_DEBUG
-               "wis-uda1342: initializing UDA1342 at address %d on %s\n",
-               client->addr, adapter->name);
-
-       write_reg(client, 0x00, 0x8000); /* reset registers */
-       write_reg(client, 0x00, 0x1241); /* select input 1 */
-
-       return 0;
-}
-
-static int wis_uda1342_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
-static const struct i2c_device_id wis_uda1342_id[] = {
-       { "wis_uda1342", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wis_uda1342_id);
-
-static struct i2c_driver wis_uda1342_driver = {
-       .driver = {
-               .name   = "WIS UDA1342 I2C driver",
-       },
-       .probe          = wis_uda1342_probe,
-       .remove         = wis_uda1342_remove,
-       .command        = wis_uda1342_command,
-       .id_table       = wis_uda1342_id,
-};
-
-static int __init wis_uda1342_init(void)
-{
-       return i2c_add_driver(&wis_uda1342_driver);
-}
-
-static void __exit wis_uda1342_cleanup(void)
-{
-       i2c_del_driver(&wis_uda1342_driver);
-}
-
-module_init(wis_uda1342_init);
-module_exit(wis_uda1342_cleanup);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/lirc/Kconfig b/drivers/staging/lirc/Kconfig
deleted file mode 100644 (file)
index 526ec0f..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#
-# LIRC driver(s) configuration
-#
-menuconfig LIRC_STAGING
-       bool "Linux Infrared Remote Control IR receiver/transmitter drivers"
-       depends on LIRC
-       help
-         Say Y here, and all supported Linux Infrared Remote Control IR and
-         RF receiver and transmitter drivers will be displayed. When paired
-         with a remote control and the lirc daemon, the receiver drivers
-         allow control of your Linux system via remote control.
-
-if LIRC_STAGING
-
-config LIRC_BT829
-        tristate "BT829 based hardware"
-       depends on LIRC && PCI
-       help
-         Driver for the IR interface on BT829-based hardware
-
-config LIRC_IGORPLUGUSB
-       tristate "Igor Cesko's USB IR Receiver"
-       depends on LIRC && USB
-       help
-         Driver for Igor Cesko's USB IR Receiver
-
-config LIRC_IMON
-       tristate "Legacy SoundGraph iMON Receiver and Display"
-       depends on LIRC && USB
-       help
-         Driver for the original SoundGraph iMON IR Receiver and Display
-
-         Current generation iMON devices use the input layer imon driver.
-
-config LIRC_PARALLEL
-       tristate "Homebrew Parallel Port Receiver"
-       depends on LIRC && PARPORT
-       help
-         Driver for Homebrew Parallel Port Receivers
-
-config LIRC_SASEM
-       tristate "Sasem USB IR Remote"
-       depends on LIRC && USB
-       help
-         Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module
-
-config LIRC_SERIAL
-       tristate "Homebrew Serial Port Receiver"
-       depends on LIRC
-       help
-         Driver for Homebrew Serial Port Receivers
-
-config LIRC_SERIAL_TRANSMITTER
-       bool "Serial Port Transmitter"
-       default y
-       depends on LIRC_SERIAL
-       help
-         Serial Port Transmitter support
-
-config LIRC_SIR
-       tristate "Built-in SIR IrDA port"
-       depends on LIRC
-       help
-         Driver for the SIR IrDA port
-
-config LIRC_TTUSBIR
-       tristate "Technotrend USB IR Receiver"
-       depends on LIRC && USB
-       help
-         Driver for the Technotrend USB IR Receiver
-
-config LIRC_ZILOG
-       tristate "Zilog/Hauppauge IR Transmitter"
-       depends on LIRC && I2C
-       help
-         Driver for the Zilog/Hauppauge IR Transmitter, found on
-         PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards
-endif
diff --git a/drivers/staging/lirc/Makefile b/drivers/staging/lirc/Makefile
deleted file mode 100644 (file)
index d76b0fa..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# Makefile for the lirc drivers.
-#
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_LIRC_BT829)       += lirc_bt829.o
-obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o
-obj-$(CONFIG_LIRC_IMON)                += lirc_imon.o
-obj-$(CONFIG_LIRC_PARALLEL)    += lirc_parallel.o
-obj-$(CONFIG_LIRC_SASEM)       += lirc_sasem.o
-obj-$(CONFIG_LIRC_SERIAL)      += lirc_serial.o
-obj-$(CONFIG_LIRC_SIR)         += lirc_sir.o
-obj-$(CONFIG_LIRC_TTUSBIR)     += lirc_ttusbir.o
-obj-$(CONFIG_LIRC_ZILOG)       += lirc_zilog.o
diff --git a/drivers/staging/lirc/TODO b/drivers/staging/lirc/TODO
deleted file mode 100644 (file)
index b6cb593..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-- All drivers should either be ported to ir-core, or dropped entirely
-  (see drivers/media/IR/mceusb.c vs. lirc_mceusb.c in lirc cvs for an
-  example of a previously completed port).
-
-Please send patches to:
-Jarod Wilson <jarod@wilsonet.com>
-Greg Kroah-Hartman <greg@kroah.com>
-
diff --git a/drivers/staging/lirc/TODO.lirc_zilog b/drivers/staging/lirc/TODO.lirc_zilog
deleted file mode 100644 (file)
index a97800a..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-1. Both ir-kbd-i2c and lirc_zilog provide support for RX events for
-the chips supported by lirc_zilog.  Before moving lirc_zilog out of staging:
-
-a. ir-kbd-i2c needs a module parameter added to allow the user to tell
-   ir-kbd-i2c to ignore Z8 IR units.
-
-b. lirc_zilog should provide Rx key presses to the rc core like ir-kbd-i2c
-   does.
-
-
-2. lirc_zilog module ref-counting need examination.  It has not been
-verified that cdev and lirc_dev will take the proper module references on
-lirc_zilog to prevent removal of lirc_zilog when the /dev/lircN device node
-is open.
-
-(The good news is ref-counting of lirc_zilog internal structures appears to be
-complete.  Testing has shown the cx18 module can be unloaded out from under
-irw + lircd + lirc_dev, with the /dev/lirc0 device node open, with no adverse
-effects.  The cx18 module could then be reloaded and irw properly began
-receiving button presses again and ir_send worked without error.)
-
-
-3. Bridge drivers, if able, should provide a chip reset() callback
-to lirc_zilog via struct IR_i2c_init_data.  cx18 and ivtv already have routines
-to perform Z8 chip resets via GPIO manipulations.  This would allow lirc_zilog
-to bring the chip back to normal when it hangs, in the same places the
-original lirc_pvr150 driver code does.  This is not strictly needed, so it
-is not required to move lirc_zilog out of staging.
-
-Note: Both lirc_zilog and ir-kbd-i2c support the Zilog Z8 for IR, as programmed
-and installed on Hauppauge products.  When working on either module, developers
-must consider at least the following bridge drivers which mention an IR Rx unit
-at address 0x71 (indicative of a Z8):
-
-       ivtv cx18 hdpvr pvrusb2 bt8xx cx88 saa7134
-
diff --git a/drivers/staging/lirc/lirc_bt829.c b/drivers/staging/lirc/lirc_bt829.c
deleted file mode 100644 (file)
index c5a0d27..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * Remote control driver for the TV-card based on bt829
- *
- *  by Leonid Froenchenko <lfroen@galileo.co.il>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/threads.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-
-#include <media/lirc_dev.h>
-
-static int poll_main(void);
-static int atir_init_start(void);
-
-static void write_index(unsigned char index, unsigned int value);
-static unsigned int read_index(unsigned char index);
-
-static void do_i2c_start(void);
-static void do_i2c_stop(void);
-
-static void seems_wr_byte(unsigned char al);
-static unsigned char seems_rd_byte(void);
-
-static unsigned int read_index(unsigned char al);
-static void write_index(unsigned char ah, unsigned int edx);
-
-static void cycle_delay(int cycle);
-
-static void do_set_bits(unsigned char bl);
-static unsigned char do_get_bits(void);
-
-#define DATA_PCI_OFF 0x7FFC00
-#define WAIT_CYCLE   20
-
-#define DRIVER_NAME "lirc_bt829"
-
-static int debug;
-#define dprintk(fmt, args...)                                           \
-       do {                                                             \
-               if (debug)                                               \
-                       printk(KERN_DEBUG DRIVER_NAME ": "fmt, ## args); \
-       } while (0)
-
-static int atir_minor;
-static unsigned long pci_addr_phys;
-static unsigned char *pci_addr_lin;
-
-static struct lirc_driver atir_driver;
-
-static struct pci_dev *do_pci_probe(void)
-{
-       struct pci_dev *my_dev;
-       my_dev = pci_get_device(PCI_VENDOR_ID_ATI,
-                               PCI_DEVICE_ID_ATI_264VT, NULL);
-       if (my_dev) {
-               printk(KERN_ERR DRIVER_NAME ": Using device: %s\n",
-                      pci_name(my_dev));
-               pci_addr_phys = 0;
-               if (my_dev->resource[0].flags & IORESOURCE_MEM) {
-                       pci_addr_phys = my_dev->resource[0].start;
-                       printk(KERN_INFO DRIVER_NAME ": memory at 0x%08X\n",
-                              (unsigned int)pci_addr_phys);
-               }
-               if (pci_addr_phys == 0) {
-                       printk(KERN_ERR DRIVER_NAME ": no memory resource ?\n");
-                       return NULL;
-               }
-       } else {
-               printk(KERN_ERR DRIVER_NAME ": pci_probe failed\n");
-               return NULL;
-       }
-       return my_dev;
-}
-
-static int atir_add_to_buf(void *data, struct lirc_buffer *buf)
-{
-       unsigned char key;
-       int status;
-       status = poll_main();
-       key = (status >> 8) & 0xFF;
-       if (status & 0xFF) {
-               dprintk("reading key %02X\n", key);
-               lirc_buffer_write(buf, &key);
-               return 0;
-       }
-       return -ENODATA;
-}
-
-static int atir_set_use_inc(void *data)
-{
-       dprintk("driver is opened\n");
-       return 0;
-}
-
-static void atir_set_use_dec(void *data)
-{
-       dprintk("driver is closed\n");
-}
-
-int init_module(void)
-{
-       struct pci_dev *pdev;
-
-       pdev = do_pci_probe();
-       if (pdev == NULL)
-               return -ENODEV;
-
-       if (!atir_init_start())
-               return -ENODEV;
-
-       strcpy(atir_driver.name, "ATIR");
-       atir_driver.minor       = -1;
-       atir_driver.code_length = 8;
-       atir_driver.sample_rate = 10;
-       atir_driver.data        = 0;
-       atir_driver.add_to_buf  = atir_add_to_buf;
-       atir_driver.set_use_inc = atir_set_use_inc;
-       atir_driver.set_use_dec = atir_set_use_dec;
-       atir_driver.dev         = &pdev->dev;
-       atir_driver.owner       = THIS_MODULE;
-
-       atir_minor = lirc_register_driver(&atir_driver);
-       if (atir_minor < 0) {
-               printk(KERN_ERR DRIVER_NAME ": failed to register driver!\n");
-               return atir_minor;
-       }
-       dprintk("driver is registered on minor %d\n", atir_minor);
-
-       return 0;
-}
-
-
-void cleanup_module(void)
-{
-       lirc_unregister_driver(atir_minor);
-}
-
-
-static int atir_init_start(void)
-{
-       pci_addr_lin = ioremap(pci_addr_phys + DATA_PCI_OFF, 0x400);
-       if (pci_addr_lin == 0) {
-               printk(KERN_INFO DRIVER_NAME ": pci mem must be mapped\n");
-               return 0;
-       }
-       return 1;
-}
-
-static void cycle_delay(int cycle)
-{
-       udelay(WAIT_CYCLE*cycle);
-}
-
-
-static int poll_main()
-{
-       unsigned char status_high, status_low;
-
-       do_i2c_start();
-
-       seems_wr_byte(0xAA);
-       seems_wr_byte(0x01);
-
-       do_i2c_start();
-
-       seems_wr_byte(0xAB);
-
-       status_low = seems_rd_byte();
-       status_high = seems_rd_byte();
-
-       do_i2c_stop();
-
-       return (status_high << 8) | status_low;
-}
-
-static void do_i2c_start(void)
-{
-       do_set_bits(3);
-       cycle_delay(4);
-
-       do_set_bits(1);
-       cycle_delay(7);
-
-       do_set_bits(0);
-       cycle_delay(2);
-}
-
-static void do_i2c_stop(void)
-{
-       unsigned char bits;
-       bits =  do_get_bits() & 0xFD;
-       do_set_bits(bits);
-       cycle_delay(1);
-
-       bits |= 1;
-       do_set_bits(bits);
-       cycle_delay(2);
-
-       bits |= 2;
-       do_set_bits(bits);
-       bits = 3;
-       do_set_bits(bits);
-       cycle_delay(2);
-}
-
-static void seems_wr_byte(unsigned char value)
-{
-       int i;
-       unsigned char reg;
-
-       reg = do_get_bits();
-       for (i = 0; i < 8; i++) {
-               if (value & 0x80)
-                       reg |= 0x02;
-               else
-                       reg &= 0xFD;
-
-               do_set_bits(reg);
-               cycle_delay(1);
-
-               reg |= 1;
-               do_set_bits(reg);
-               cycle_delay(1);
-
-               reg &= 0xFE;
-               do_set_bits(reg);
-               cycle_delay(1);
-               value <<= 1;
-       }
-       cycle_delay(2);
-
-       reg |= 2;
-       do_set_bits(reg);
-
-       reg |= 1;
-       do_set_bits(reg);
-
-       cycle_delay(1);
-       do_get_bits();
-
-       reg &= 0xFE;
-       do_set_bits(reg);
-       cycle_delay(3);
-}
-
-static unsigned char seems_rd_byte(void)
-{
-       int i;
-       int rd_byte;
-       unsigned char bits_2, bits_1;
-
-       bits_1 = do_get_bits() | 2;
-       do_set_bits(bits_1);
-
-       rd_byte = 0;
-       for (i = 0; i < 8; i++) {
-               bits_1 &= 0xFE;
-               do_set_bits(bits_1);
-               cycle_delay(2);
-
-               bits_1 |= 1;
-               do_set_bits(bits_1);
-               cycle_delay(1);
-
-               bits_2 = do_get_bits();
-               if (bits_2 & 2)
-                       rd_byte |= 1;
-
-               rd_byte <<= 1;
-       }
-
-       bits_1 = 0;
-       if (bits_2 == 0)
-               bits_1 |= 2;
-
-       do_set_bits(bits_1);
-       cycle_delay(2);
-
-       bits_1 |= 1;
-       do_set_bits(bits_1);
-       cycle_delay(3);
-
-       bits_1 &= 0xFE;
-       do_set_bits(bits_1);
-       cycle_delay(2);
-
-       rd_byte >>= 1;
-       rd_byte &= 0xFF;
-       return rd_byte;
-}
-
-static void do_set_bits(unsigned char new_bits)
-{
-       int reg_val;
-       reg_val = read_index(0x34);
-       if (new_bits & 2) {
-               reg_val &= 0xFFFFFFDF;
-               reg_val |= 1;
-       } else {
-               reg_val &= 0xFFFFFFFE;
-               reg_val |= 0x20;
-       }
-       reg_val |= 0x10;
-       write_index(0x34, reg_val);
-
-       reg_val = read_index(0x31);
-       if (new_bits & 1)
-               reg_val |= 0x1000000;
-       else
-               reg_val &= 0xFEFFFFFF;
-
-       reg_val |= 0x8000000;
-       write_index(0x31, reg_val);
-}
-
-static unsigned char do_get_bits(void)
-{
-       unsigned char bits;
-       int reg_val;
-
-       reg_val = read_index(0x34);
-       reg_val |= 0x10;
-       reg_val &= 0xFFFFFFDF;
-       write_index(0x34, reg_val);
-
-       reg_val = read_index(0x34);
-       bits = 0;
-       if (reg_val & 8)
-               bits |= 2;
-       else
-               bits &= 0xFD;
-
-       reg_val = read_index(0x31);
-       if (reg_val & 0x1000000)
-               bits |= 1;
-       else
-               bits &= 0xFE;
-
-       return bits;
-}
-
-static unsigned int read_index(unsigned char index)
-{
-       unsigned char *addr;
-       unsigned int value;
-       /*  addr = pci_addr_lin + DATA_PCI_OFF + ((index & 0xFF) << 2); */
-       addr = pci_addr_lin + ((index & 0xFF) << 2);
-       value = readl(addr);
-       return value;
-}
-
-static void write_index(unsigned char index, unsigned int reg_val)
-{
-       unsigned char *addr;
-       addr = pci_addr_lin + ((index & 0xFF) << 2);
-       writel(reg_val, addr);
-}
-
-MODULE_AUTHOR("Froenchenko Leonid");
-MODULE_DESCRIPTION("IR remote driver for bt829 based TV cards");
-MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/staging/lirc/lirc_ene0100.h b/drivers/staging/lirc/lirc_ene0100.h
deleted file mode 100644 (file)
index 06bebd6..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * driver for ENE KB3926 B/C/D CIR (also known as ENE0100)
- *
- * Copyright (C) 2009 Maxim Levitsky <maximlevitsky@gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- */
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-/* hardware address */
-#define ENE_STATUS             0        /* hardware status - unused */
-#define ENE_ADDR_HI            1        /* hi byte of register address */
-#define ENE_ADDR_LO            2        /* low byte of register address */
-#define ENE_IO                 3        /* read/write window */
-#define ENE_MAX_IO             4
-
-/* 8 bytes of samples, divided in 2 halfs*/
-#define ENE_SAMPLE_BUFFER      0xF8F0   /* regular sample buffer */
-#define ENE_SAMPLE_SPC_MASK    (1 << 7) /* sample is space */
-#define ENE_SAMPLE_VALUE_MASK  0x7F
-#define ENE_SAMPLE_OVERFLOW    0x7F
-#define ENE_SAMPLES_SIZE       4
-
-/* fan input sample buffer */
-#define ENE_SAMPLE_BUFFER_FAN  0xF8FB   /* this buffer holds high byte of */
-                                        /* each sample of normal buffer */
-
-#define ENE_FAN_SMPL_PULS_MSK  0x8000   /* this bit of combined sample */
-                                        /* if set, says that sample is pulse */
-#define ENE_FAN_VALUE_MASK     0x0FFF   /* mask for valid bits of the value */
-
-/* first firmware register */
-#define ENE_FW1                        0xF8F8
-#define        ENE_FW1_ENABLE          (1 << 0) /* enable fw processing */
-#define ENE_FW1_TXIRQ          (1 << 1) /* TX interrupt pending */
-#define ENE_FW1_WAKE           (1 << 6) /* enable wake from S3 */
-#define ENE_FW1_IRQ            (1 << 7) /* enable interrupt */
-
-/* second firmware register */
-#define ENE_FW2                        0xF8F9
-#define ENE_FW2_BUF_HIGH       (1 << 0) /* which half of the buffer to read */
-#define ENE_FW2_IRQ_CLR                (1 << 2) /* clear this on IRQ */
-#define ENE_FW2_GP40_AS_LEARN  (1 << 4) /* normal input is used as */
-                                        /* learning input */
-#define ENE_FW2_FAN_AS_NRML_IN (1 << 6) /* fan is used as normal input */
-#define ENE_FW2_LEARNING       (1 << 7) /* hardware supports learning and TX */
-
-/* fan as input settings - only if learning capable */
-#define ENE_FAN_AS_IN1         0xFE30   /* fan init reg 1 */
-#define ENE_FAN_AS_IN1_EN      0xCD
-#define ENE_FAN_AS_IN2         0xFE31   /* fan init reg 2 */
-#define ENE_FAN_AS_IN2_EN      0x03
-#define ENE_SAMPLE_PERIOD_FAN   61      /* fan input has fixed sample period */
-
-/* IRQ registers block (for revision B) */
-#define ENEB_IRQ               0xFD09   /* IRQ number */
-#define ENEB_IRQ_UNK1          0xFD17   /* unknown setting = 1 */
-#define ENEB_IRQ_STATUS                0xFD80   /* irq status */
-#define ENEB_IRQ_STATUS_IR     (1 << 5) /* IR irq */
-
-/* IRQ registers block (for revision C,D) */
-#define ENEC_IRQ               0xFE9B   /* new irq settings register */
-#define ENEC_IRQ_MASK          0x0F     /* irq number mask */
-#define ENEC_IRQ_UNK_EN                (1 << 4) /* always enabled */
-#define ENEC_IRQ_STATUS                (1 << 5) /* irq status and ACK */
-
-/* CIR block settings */
-#define ENE_CIR_CONF1          0xFEC0
-#define ENE_CIR_CONF1_ADC_ON   0x7      /* receiver on gpio40 enabled */
-#define ENE_CIR_CONF1_LEARN1   (1 << 3) /* enabled on learning mode */
-#define ENE_CIR_CONF1_TX_ON    0x30     /* enabled on transmit */
-#define ENE_CIR_CONF1_TX_CARR  (1 << 7) /* send TX carrier or not */
-
-#define ENE_CIR_CONF2          0xFEC1   /* unknown setting = 0 */
-#define ENE_CIR_CONF2_LEARN2   (1 << 4) /* set on enable learning */
-#define ENE_CIR_CONF2_GPIO40DIS        (1 << 5) /* disable normal input via gpio40 */
-
-#define ENE_CIR_SAMPLE_PERIOD  0xFEC8   /* sample period in us */
-#define ENE_CIR_SAMPLE_OVERFLOW        (1 << 7) /* interrupt on overflows if set */
-
-
-/* transmitter - not implemented yet */
-/* KB3926C and higher */
-/* transmission is very similar to receiving, a byte is written to */
-/* ENE_TX_INPUT, in same manner as it is read from sample buffer */
-/* sample period is fixed*/
-
-
-/* transmitter ports */
-#define ENE_TX_PORT1           0xFC01   /* this enables one or both */
-#define ENE_TX_PORT1_EN                (1 << 5) /* TX ports */
-#define ENE_TX_PORT2           0xFC08
-#define ENE_TX_PORT2_EN                (1 << 1)
-
-#define ENE_TX_INPUT           0xFEC9   /* next byte to transmit */
-#define ENE_TX_SPC_MASK                (1 << 7) /* Transmitted sample is space */
-#define ENE_TX_UNK1            0xFECB   /* set to 0x63 */
-#define ENE_TX_SMPL_PERIOD     50       /* transmit sample period */
-
-
-#define ENE_TX_CARRIER         0xFECE   /* TX carrier * 2 (khz) */
-#define ENE_TX_CARRIER_UNKBIT  0x80     /* This bit set on transmit */
-#define ENE_TX_CARRIER_LOW     0xFECF   /* TX carrier / 2 */
-
-/* Hardware versions */
-#define ENE_HW_VERSION         0xFF00   /* hardware revision */
-#define ENE_HW_UNK             0xFF1D
-#define ENE_HW_UNK_CLR         (1 << 2)
-#define ENE_HW_VER_MAJOR       0xFF1E   /* chip version */
-#define ENE_HW_VER_MINOR       0xFF1F
-#define ENE_HW_VER_OLD         0xFD00
-
-#define same_sign(a, b) ((((a) > 0) && (b) > 0) || ((a) < 0 && (b) < 0))
-
-#define ENE_DRIVER_NAME                "enecir"
-#define ENE_MAXGAP             250000   /* this is amount of time we wait
-                                        before turning the sampler, chosen
-                                        arbitry */
-
-#define space(len)            (-(len))  /* add a space */
-
-/* software defines */
-#define ENE_IRQ_RX             1
-#define ENE_IRQ_TX             2
-
-#define  ENE_HW_B              1       /* 3926B */
-#define  ENE_HW_C              2       /* 3926C */
-#define  ENE_HW_D              3       /* 3926D */
-
-#define ene_printk(level, text, ...) \
-       printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__)
-
-struct ene_device {
-       struct pnp_dev *pnp_dev;
-       struct lirc_driver *lirc_driver;
-
-       /* hw settings */
-       unsigned long hw_io;
-       int irq;
-
-       int hw_revision;                        /* hardware revision */
-       int hw_learning_and_tx_capable;         /* learning capable */
-       int hw_gpio40_learning;                 /* gpio40 is learning */
-       int hw_fan_as_normal_input;     /* fan input is used as regular input */
-
-       /* device data */
-       int idle;
-       int fan_input_inuse;
-
-       int sample;
-       int in_use;
-
-       struct timeval gap_start;
-};
diff --git a/drivers/staging/lirc/lirc_igorplugusb.c b/drivers/staging/lirc/lirc_igorplugusb.c
deleted file mode 100644 (file)
index 0dc2c2b..0000000
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
- * lirc_igorplugusb - USB remote support for LIRC
- *
- * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware.
- * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm
- *
- * The device can only record bursts of up to 36 pulses/spaces.
- * Works fine with RC5. Longer commands lead to device buffer overrun.
- * (Maybe a better firmware or a microcontroller with more ram can help?)
- *
- * Version 0.1  [beta status]
- *
- * Copyright (C) 2004 Jan M. Hochstein
- *     <hochstein@algo.informatik.tu-darmstadt.de>
- *
- * This driver was derived from:
- *   Paul Miller <pmiller9@users.sourceforge.net>
- *      "lirc_atiusb" module
- *   Vladimir Dergachev <volodya@minspring.com>'s 2002
- *      "USB ATI Remote support" (input device)
- *   Adrian Dewhurst <sailor-lk@sailorfrag.net>'s 2002
- *      "USB StreamZap remote driver" (LIRC)
- *   Artur Lipowski <alipowski@kki.net.pl>'s 2002
- *      "lirc_dev" and "lirc_gpio" LIRC modules
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/kmod.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/usb.h>
-#include <linux/time.h>
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-
-/* module identification */
-#define DRIVER_VERSION         "0.2"
-#define DRIVER_AUTHOR          \
-       "Jan M. Hochstein <hochstein@algo.informatik.tu-darmstadt.de>"
-#define DRIVER_DESC            "Igorplug USB remote driver for LIRC"
-#define DRIVER_NAME            "lirc_igorplugusb"
-
-/* debugging support */
-#ifdef CONFIG_USB_DEBUG
-static int debug = 1;
-#else
-static int debug;
-#endif
-
-#define dprintk(fmt, args...)                                  \
-       do {                                                    \
-               if (debug)                                      \
-                       printk(KERN_DEBUG fmt, ## args);        \
-       } while (0)
-
-/* One mode2 pulse/space has 4 bytes. */
-#define CODE_LENGTH         sizeof(int)
-
-/* Igor's firmware cannot record bursts longer than 36. */
-#define DEVICE_BUFLEN     36
-
-/*
- * Header at the beginning of the device's buffer:
- *     unsigned char data_length
- *     unsigned char data_start    (!=0 means ring-buffer overrun)
- *     unsigned char counter       (incremented by each burst)
- */
-#define DEVICE_HEADERLEN       3
-
-/* This is for the gap */
-#define ADDITIONAL_LIRC_BYTES   2
-
-/* times to poll per second */
-#define SAMPLE_RATE         100
-static int sample_rate = SAMPLE_RATE;
-
-
-/**** Igor's USB Request Codes */
-
-#define SET_INFRABUFFER_EMPTY   1
-/**
- * Params: none
- * Answer: empty
- */
-
-#define GET_INFRACODE     2
-/**
- * Params:
- *   wValue: offset to begin reading infra buffer
- *
- * Answer: infra data
- */
-
-#define SET_DATAPORT_DIRECTION  3
-/**
- * Params:
- *   wValue: (byte) 1 bit for each data port pin (0=in, 1=out)
- *
- * Answer: empty
- */
-
-#define GET_DATAPORT_DIRECTION  4
-/**
- * Params: none
- *
- * Answer: (byte) 1 bit for each data port pin (0=in, 1=out)
- */
-
-#define SET_OUT_DATAPORT       5
-/**
- * Params:
- *   wValue: byte to write to output data port
- *
- * Answer: empty
- */
-
-#define GET_OUT_DATAPORT       6
-/**
- * Params: none
- *
- * Answer: least significant 3 bits read from output data port
- */
-
-#define GET_IN_DATAPORT         7
-/**
- * Params: none
- *
- * Answer: least significant 3 bits read from input data port
- */
-
-#define READ_EEPROM         8
-/**
- * Params:
- *   wValue: offset to begin reading EEPROM
- *
- * Answer: EEPROM bytes
- */
-
-#define WRITE_EEPROM       9
-/**
- * Params:
- *   wValue: offset to EEPROM byte
- *   wIndex: byte to write
- *
- * Answer: empty
- */
-
-#define SEND_RS232           10
-/**
- * Params:
- *   wValue: byte to send
- *
- * Answer: empty
- */
-
-#define RECV_RS232           11
-/**
- * Params: none
- *
- * Answer: byte received
- */
-
-#define SET_RS232_BAUD   12
-/**
- * Params:
- *   wValue: byte to write to UART bit rate register (UBRR)
- *
- * Answer: empty
- */
-
-#define GET_RS232_BAUD   13
-/**
- * Params: none
- *
- * Answer: byte read from UART bit rate register (UBRR)
- */
-
-
-/* data structure for each usb remote */
-struct igorplug {
-
-       /* usb */
-       struct usb_device *usbdev;
-       int devnum;
-
-       unsigned char *buf_in;
-       unsigned int len_in;
-       int in_space;
-       struct timeval last_time;
-
-       dma_addr_t dma_in;
-
-       /* lirc */
-       struct lirc_driver *d;
-
-       /* handle sending (init strings) */
-       int send_flags;
-};
-
-static int unregister_from_lirc(struct igorplug *ir)
-{
-       struct lirc_driver *d;
-       int devnum;
-
-       if (!ir) {
-               printk(KERN_ERR "%s: called with NULL device struct!\n",
-                      __func__);
-               return -EINVAL;
-       }
-
-       devnum = ir->devnum;
-       d = ir->d;
-
-       if (!d) {
-               printk(KERN_ERR "%s: called with NULL lirc driver struct!\n",
-                      __func__);
-               return -EINVAL;
-       }
-
-       dprintk(DRIVER_NAME "[%d]: calling lirc_unregister_driver\n", devnum);
-       lirc_unregister_driver(d->minor);
-
-       kfree(d);
-       ir->d = NULL;
-       kfree(ir);
-
-       return devnum;
-}
-
-static int set_use_inc(void *data)
-{
-       struct igorplug *ir = data;
-
-       if (!ir) {
-               printk(DRIVER_NAME "[?]: set_use_inc called with no context\n");
-               return -EIO;
-       }
-
-       dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum);
-
-       if (!ir->usbdev)
-               return -ENODEV;
-
-       return 0;
-}
-
-static void set_use_dec(void *data)
-{
-       struct igorplug *ir = data;
-
-       if (!ir) {
-               printk(DRIVER_NAME "[?]: set_use_dec called with no context\n");
-               return;
-       }
-
-       dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum);
-}
-
-static void send_fragment(struct igorplug *ir, struct lirc_buffer *buf,
-                          int i, int max)
-{
-       int code;
-
-       /* MODE2: pulse/space (PULSE_BIT) in 1us units */
-       while (i < max) {
-               /* 1 Igor-tick = 85.333333 us */
-               code = (unsigned int)ir->buf_in[i] * 85 +
-                       (unsigned int)ir->buf_in[i] / 3;
-               ir->last_time.tv_usec += code;
-               if (ir->in_space)
-                       code |= PULSE_BIT;
-               lirc_buffer_write(buf, (unsigned char *)&code);
-               /* 1 chunk = CODE_LENGTH bytes */
-               ir->in_space ^= 1;
-               ++i;
-       }
-}
-
-/**
- * Called in user context.
- * return 0 if data was added to the buffer and
- * -ENODATA if none was available. This should add some number of bits
- * evenly divisible by code_length to the buffer
- */
-static int igorplugusb_remote_poll(void *data, struct lirc_buffer *buf)
-{
-       int ret;
-       struct igorplug *ir = (struct igorplug *)data;
-
-       if (!ir || !ir->usbdev)  /* Has the device been removed? */
-               return -ENODEV;
-
-       memset(ir->buf_in, 0, ir->len_in);
-
-       ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
-                             GET_INFRACODE, USB_TYPE_VENDOR | USB_DIR_IN,
-                             0/* offset */, /*unused*/0,
-                             ir->buf_in, ir->len_in,
-                             /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
-       if (ret > 0) {
-               int code, timediff;
-               struct timeval now;
-
-               /* ACK packet has 1 byte --> ignore */
-               if (ret < DEVICE_HEADERLEN)
-                       return -ENODATA;
-
-               dprintk(DRIVER_NAME ": Got %d bytes. Header: %02x %02x %02x\n",
-                       ret, ir->buf_in[0], ir->buf_in[1], ir->buf_in[2]);
-
-               do_gettimeofday(&now);
-               timediff = now.tv_sec - ir->last_time.tv_sec;
-               if (timediff + 1 > PULSE_MASK / 1000000)
-                       timediff = PULSE_MASK;
-               else {
-                       timediff *= 1000000;
-                       timediff += now.tv_usec - ir->last_time.tv_usec;
-               }
-               ir->last_time.tv_sec = now.tv_sec;
-               ir->last_time.tv_usec = now.tv_usec;
-
-               /* create leading gap  */
-               code = timediff;
-               lirc_buffer_write(buf, (unsigned char *)&code);
-               ir->in_space = 1;   /* next comes a pulse */
-
-               if (ir->buf_in[2] == 0)
-                       send_fragment(ir, buf, DEVICE_HEADERLEN, ret);
-               else {
-                       printk(KERN_WARNING DRIVER_NAME
-                              "[%d]: Device buffer overrun.\n", ir->devnum);
-                       /* HHHNNNNNNNNNNNOOOOOOOO H = header
-                             <---[2]--->         N = newer
-                          <---------ret--------> O = older */
-                       ir->buf_in[2] %= ret - DEVICE_HEADERLEN; /* sanitize */
-                       /* keep even-ness to not desync pulse/pause */
-                       send_fragment(ir, buf, DEVICE_HEADERLEN +
-                                     ir->buf_in[2] - (ir->buf_in[2] & 1), ret);
-                       send_fragment(ir, buf, DEVICE_HEADERLEN,
-                                     DEVICE_HEADERLEN + ir->buf_in[2]);
-               }
-
-               ret = usb_control_msg(
-                     ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
-                     SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN,
-                     /*unused*/0, /*unused*/0,
-                     /*dummy*/ir->buf_in, /*dummy*/ir->len_in,
-                     /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
-               if (ret < 0)
-                       printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: "
-                              "error %d\n", ir->devnum, ret);
-               return 0;
-       } else if (ret < 0)
-               printk(DRIVER_NAME "[%d]: GET_INFRACODE: error %d\n",
-                       ir->devnum, ret);
-
-       return -ENODATA;
-}
-
-
-
-static int igorplugusb_remote_probe(struct usb_interface *intf,
-                                   const struct usb_device_id *id)
-{
-       struct usb_device *dev = NULL;
-       struct usb_host_interface *idesc = NULL;
-       struct usb_endpoint_descriptor *ep;
-       struct igorplug *ir = NULL;
-       struct lirc_driver *driver = NULL;
-       int devnum, pipe, maxp;
-       int minor = 0;
-       char buf[63], name[128] = "";
-       int mem_failure = 0;
-       int ret;
-
-       dprintk(DRIVER_NAME ": usb probe called.\n");
-
-       dev = interface_to_usbdev(intf);
-
-       idesc = intf->cur_altsetting;
-
-       if (idesc->desc.bNumEndpoints != 1)
-               return -ENODEV;
-
-       ep = &idesc->endpoint->desc;
-       if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
-           != USB_DIR_IN)
-           || (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-           != USB_ENDPOINT_XFER_CONTROL)
-               return -ENODEV;
-
-       pipe = usb_rcvctrlpipe(dev, ep->bEndpointAddress);
-       devnum = dev->devnum;
-       maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
-
-       dprintk(DRIVER_NAME "[%d]: bytes_in_key=%zu maxp=%d\n",
-               devnum, CODE_LENGTH, maxp);
-
-       mem_failure = 0;
-       ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL);
-       if (!ir) {
-               mem_failure = 1;
-               goto mem_failure_switch;
-       }
-       driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
-       if (!driver) {
-               mem_failure = 2;
-               goto mem_failure_switch;
-       }
-
-       ir->buf_in = usb_alloc_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN,
-                                       GFP_ATOMIC, &ir->dma_in);
-       if (!ir->buf_in) {
-               mem_failure = 3;
-               goto mem_failure_switch;
-       }
-
-       strcpy(driver->name, DRIVER_NAME " ");
-       driver->minor = -1;
-       driver->code_length = CODE_LENGTH * 8; /* in bits */
-       driver->features = LIRC_CAN_REC_MODE2;
-       driver->data = ir;
-       driver->chunk_size = CODE_LENGTH;
-       driver->buffer_size = DEVICE_BUFLEN + ADDITIONAL_LIRC_BYTES;
-       driver->set_use_inc = &set_use_inc;
-       driver->set_use_dec = &set_use_dec;
-       driver->sample_rate = sample_rate;    /* per second */
-       driver->add_to_buf = &igorplugusb_remote_poll;
-       driver->dev = &intf->dev;
-       driver->owner = THIS_MODULE;
-
-       minor = lirc_register_driver(driver);
-       if (minor < 0)
-               mem_failure = 9;
-
-mem_failure_switch:
-
-       switch (mem_failure) {
-       case 9:
-               usb_free_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN,
-                       ir->buf_in, ir->dma_in);
-       case 3:
-               kfree(driver);
-       case 2:
-               kfree(ir);
-       case 1:
-               printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n",
-                       devnum, mem_failure);
-               return -ENOMEM;
-       }
-
-       driver->minor = minor;
-       ir->d = driver;
-       ir->devnum = devnum;
-       ir->usbdev = dev;
-       ir->len_in = DEVICE_BUFLEN + DEVICE_HEADERLEN;
-       ir->in_space = 1; /* First mode2 event is a space. */
-       do_gettimeofday(&ir->last_time);
-
-       if (dev->descriptor.iManufacturer
-           && usb_string(dev, dev->descriptor.iManufacturer,
-                         buf, sizeof(buf)) > 0)
-               strlcpy(name, buf, sizeof(name));
-       if (dev->descriptor.iProduct
-           && usb_string(dev, dev->descriptor.iProduct, buf, sizeof(buf)) > 0)
-               snprintf(name + strlen(name), sizeof(name) - strlen(name),
-                        " %s", buf);
-       printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", devnum, name,
-              dev->bus->busnum, devnum);
-
-       /* clear device buffer */
-       ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
-               SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN,
-               /*unused*/0, /*unused*/0,
-               /*dummy*/ir->buf_in, /*dummy*/ir->len_in,
-               /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
-       if (ret < 0)
-               printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: error %d\n",
-                       devnum, ret);
-
-       usb_set_intfdata(intf, ir);
-       return 0;
-}
-
-
-static void igorplugusb_remote_disconnect(struct usb_interface *intf)
-{
-       struct usb_device *usbdev = interface_to_usbdev(intf);
-       struct igorplug *ir = usb_get_intfdata(intf);
-       struct device *dev = &intf->dev;
-       int devnum;
-
-       usb_set_intfdata(intf, NULL);
-
-       if (!ir || !ir->d)
-               return;
-
-       ir->usbdev = NULL;
-
-       usb_free_coherent(usbdev, ir->len_in, ir->buf_in, ir->dma_in);
-
-       devnum = unregister_from_lirc(ir);
-
-       dev_info(dev, DRIVER_NAME "[%d]: %s done\n", devnum, __func__);
-}
-
-static struct usb_device_id igorplugusb_remote_id_table[] = {
-       /* Igor Plug USB (Atmel's Manufact. ID) */
-       { USB_DEVICE(0x03eb, 0x0002) },
-       /* Fit PC2 Infrared Adapter */
-       { USB_DEVICE(0x03eb, 0x21fe) },
-
-       /* Terminating entry */
-       { }
-};
-
-static struct usb_driver igorplugusb_remote_driver = {
-       .name =         DRIVER_NAME,
-       .probe =        igorplugusb_remote_probe,
-       .disconnect =   igorplugusb_remote_disconnect,
-       .id_table =     igorplugusb_remote_id_table
-};
-
-static int __init igorplugusb_remote_init(void)
-{
-       int ret = 0;
-
-       dprintk(DRIVER_NAME ": loaded, debug mode enabled\n");
-
-       ret = usb_register(&igorplugusb_remote_driver);
-       if (ret)
-               printk(KERN_ERR DRIVER_NAME ": usb register failed!\n");
-
-       return ret;
-}
-
-static void __exit igorplugusb_remote_exit(void)
-{
-       usb_deregister(&igorplugusb_remote_driver);
-}
-
-module_init(igorplugusb_remote_init);
-module_exit(igorplugusb_remote_exit);
-
-#include <linux/vermagic.h>
-MODULE_INFO(vermagic, VERMAGIC_STRING);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(usb, igorplugusb_remote_id_table);
-
-module_param(sample_rate, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/lirc/lirc_imon.c
deleted file mode 100644 (file)
index f5308d5..0000000
+++ /dev/null
@@ -1,1050 +0,0 @@
-/*
- *   lirc_imon.c:  LIRC/VFD/LCD driver for SoundGraph iMON IR/VFD/LCD
- *                including the iMON PAD model
- *
- *   Copyright(C) 2004  Venky Raju(dev@venky.ws)
- *   Copyright(C) 2009  Jarod Wilson <jarod@wilsonet.com>
- *
- *   lirc_imon is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/usb.h>
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-
-#define MOD_AUTHOR     "Venky Raju <dev@venky.ws>"
-#define MOD_DESC       "Driver for SoundGraph iMON MultiMedia IR/Display"
-#define MOD_NAME       "lirc_imon"
-#define MOD_VERSION    "0.8"
-
-#define DISPLAY_MINOR_BASE     144
-#define DEVICE_NAME    "lcd%d"
-
-#define BUF_CHUNK_SIZE 4
-#define BUF_SIZE       128
-
-#define BIT_DURATION   250     /* each bit received is 250us */
-
-/*** P R O T O T Y P E S ***/
-
-/* USB Callback prototypes */
-static int imon_probe(struct usb_interface *interface,
-                     const struct usb_device_id *id);
-static void imon_disconnect(struct usb_interface *interface);
-static void usb_rx_callback(struct urb *urb);
-static void usb_tx_callback(struct urb *urb);
-
-/* suspend/resume support */
-static int imon_resume(struct usb_interface *intf);
-static int imon_suspend(struct usb_interface *intf, pm_message_t message);
-
-/* Display file_operations function prototypes */
-static int display_open(struct inode *inode, struct file *file);
-static int display_close(struct inode *inode, struct file *file);
-
-/* VFD write operation */
-static ssize_t vfd_write(struct file *file, const char *buf,
-                        size_t n_bytes, loff_t *pos);
-
-/* LIRC driver function prototypes */
-static int ir_open(void *data);
-static void ir_close(void *data);
-
-/* Driver init/exit prototypes */
-static int __init imon_init(void);
-static void __exit imon_exit(void);
-
-/*** G L O B A L S ***/
-#define IMON_DATA_BUF_SZ       35
-
-struct imon_context {
-       struct usb_device *usbdev;
-       /* Newer devices have two interfaces */
-       int display;                    /* not all controllers do */
-       int display_isopen;             /* display port has been opened */
-       int ir_isopen;                  /* IR port open */
-       int dev_present;                /* USB device presence */
-       struct mutex ctx_lock;          /* to lock this object */
-       wait_queue_head_t remove_ok;    /* For unexpected USB disconnects */
-
-       int vfd_proto_6p;               /* some VFD require a 6th packet */
-
-       struct lirc_driver *driver;
-       struct usb_endpoint_descriptor *rx_endpoint;
-       struct usb_endpoint_descriptor *tx_endpoint;
-       struct urb *rx_urb;
-       struct urb *tx_urb;
-       unsigned char usb_rx_buf[8];
-       unsigned char usb_tx_buf[8];
-
-       struct rx_data {
-               int count;              /* length of 0 or 1 sequence */
-               int prev_bit;           /* logic level of sequence */
-               int initial_space;      /* initial space flag */
-       } rx;
-
-       struct tx_t {
-               unsigned char data_buf[IMON_DATA_BUF_SZ]; /* user data buffer */
-               struct completion finished;     /* wait for write to finish */
-               atomic_t busy;                  /* write in progress */
-               int status;                     /* status of tx completion */
-       } tx;
-};
-
-static const struct file_operations display_fops = {
-       .owner          = THIS_MODULE,
-       .open           = &display_open,
-       .write          = &vfd_write,
-       .release        = &display_close,
-       .llseek         = noop_llseek,
-};
-
-/*
- * USB Device ID for iMON USB Control Boards
- *
- * The Windows drivers contain 6 different inf files, more or less one for
- * each new device until the 0x0034-0x0046 devices, which all use the same
- * driver. Some of the devices in the 34-46 range haven't been definitively
- * identified yet. Early devices have either a TriGem Computer, Inc. or a
- * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later
- * devices use the SoundGraph vendor ID (0x15c2).
- */
-static struct usb_device_id imon_usb_id_table[] = {
-       /* TriGem iMON (IR only) -- TG_iMON.inf */
-       { USB_DEVICE(0x0aa8, 0x8001) },
-
-       /* SoundGraph iMON (IR only) -- sg_imon.inf */
-       { USB_DEVICE(0x04e8, 0xff30) },
-
-       /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */
-       { USB_DEVICE(0x0aa8, 0xffda) },
-
-       /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */
-       { USB_DEVICE(0x15c2, 0xffda) },
-
-       {}
-};
-
-/* Some iMON VFD models requires a 6th packet for VFD writes */
-static struct usb_device_id vfd_proto_6p_list[] = {
-       { USB_DEVICE(0x15c2, 0xffda) },
-       {}
-};
-
-/* Some iMON devices have no lcd/vfd, don't set one up */
-static struct usb_device_id ir_only_list[] = {
-       { USB_DEVICE(0x0aa8, 0x8001) },
-       { USB_DEVICE(0x04e8, 0xff30) },
-       {}
-};
-
-/* USB Device data */
-static struct usb_driver imon_driver = {
-       .name           = MOD_NAME,
-       .probe          = imon_probe,
-       .disconnect     = imon_disconnect,
-       .suspend        = imon_suspend,
-       .resume         = imon_resume,
-       .id_table       = imon_usb_id_table,
-};
-
-static struct usb_class_driver imon_class = {
-       .name           = DEVICE_NAME,
-       .fops           = &display_fops,
-       .minor_base     = DISPLAY_MINOR_BASE,
-};
-
-/* to prevent races between open() and disconnect(), probing, etc */
-static DEFINE_MUTEX(driver_lock);
-
-static int debug;
-
-/***  M O D U L E   C O D E ***/
-
-MODULE_AUTHOR(MOD_AUTHOR);
-MODULE_DESCRIPTION(MOD_DESC);
-MODULE_VERSION(MOD_VERSION);
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(usb, imon_usb_id_table);
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)");
-
-static void free_imon_context(struct imon_context *context)
-{
-       struct device *dev = context->driver->dev;
-       usb_free_urb(context->tx_urb);
-       usb_free_urb(context->rx_urb);
-       lirc_buffer_free(context->driver->rbuf);
-       kfree(context->driver->rbuf);
-       kfree(context->driver);
-       kfree(context);
-
-       dev_dbg(dev, "%s: iMON context freed\n", __func__);
-}
-
-static void deregister_from_lirc(struct imon_context *context)
-{
-       int retval;
-       int minor = context->driver->minor;
-
-       retval = lirc_unregister_driver(minor);
-       if (retval)
-               err("%s: unable to deregister from lirc(%d)",
-                       __func__, retval);
-       else
-               printk(KERN_INFO MOD_NAME ": Deregistered iMON driver "
-                      "(minor:%d)\n", minor);
-
-}
-
-/**
- * Called when the Display device (e.g. /dev/lcd0)
- * is opened by the application.
- */
-static int display_open(struct inode *inode, struct file *file)
-{
-       struct usb_interface *interface;
-       struct imon_context *context = NULL;
-       int subminor;
-       int retval = 0;
-
-       /* prevent races with disconnect */
-       mutex_lock(&driver_lock);
-
-       subminor = iminor(inode);
-       interface = usb_find_interface(&imon_driver, subminor);
-       if (!interface) {
-               err("%s: could not find interface for minor %d",
-                   __func__, subminor);
-               retval = -ENODEV;
-               goto exit;
-       }
-       context = usb_get_intfdata(interface);
-
-       if (!context) {
-               err("%s: no context found for minor %d",
-                                       __func__, subminor);
-               retval = -ENODEV;
-               goto exit;
-       }
-
-       mutex_lock(&context->ctx_lock);
-
-       if (!context->display) {
-               err("%s: display not supported by device", __func__);
-               retval = -ENODEV;
-       } else if (context->display_isopen) {
-               err("%s: display port is already open", __func__);
-               retval = -EBUSY;
-       } else {
-               context->display_isopen = 1;
-               file->private_data = context;
-               dev_info(context->driver->dev, "display port opened\n");
-       }
-
-       mutex_unlock(&context->ctx_lock);
-
-exit:
-       mutex_unlock(&driver_lock);
-       return retval;
-}
-
-/**
- * Called when the display device (e.g. /dev/lcd0)
- * is closed by the application.
- */
-static int display_close(struct inode *inode, struct file *file)
-{
-       struct imon_context *context = NULL;
-       int retval = 0;
-
-       context = file->private_data;
-
-       if (!context) {
-               err("%s: no context for device", __func__);
-               return -ENODEV;
-       }
-
-       mutex_lock(&context->ctx_lock);
-
-       if (!context->display) {
-               err("%s: display not supported by device", __func__);
-               retval = -ENODEV;
-       } else if (!context->display_isopen) {
-               err("%s: display is not open", __func__);
-               retval = -EIO;
-       } else {
-               context->display_isopen = 0;
-               dev_info(context->driver->dev, "display port closed\n");
-               if (!context->dev_present && !context->ir_isopen) {
-                       /*
-                        * Device disconnected before close and IR port is not
-                        * open. If IR port is open, context will be deleted by
-                        * ir_close.
-                        */
-                       mutex_unlock(&context->ctx_lock);
-                       free_imon_context(context);
-                       return retval;
-               }
-       }
-
-       mutex_unlock(&context->ctx_lock);
-       return retval;
-}
-
-/**
- * Sends a packet to the device -- this function must be called
- * with context->ctx_lock held.
- */
-static int send_packet(struct imon_context *context)
-{
-       unsigned int pipe;
-       int interval = 0;
-       int retval = 0;
-
-       /* Check if we need to use control or interrupt urb */
-       pipe = usb_sndintpipe(context->usbdev,
-                             context->tx_endpoint->bEndpointAddress);
-       interval = context->tx_endpoint->bInterval;
-
-       usb_fill_int_urb(context->tx_urb, context->usbdev, pipe,
-                        context->usb_tx_buf,
-                        sizeof(context->usb_tx_buf),
-                        usb_tx_callback, context, interval);
-
-       context->tx_urb->actual_length = 0;
-
-       init_completion(&context->tx.finished);
-       atomic_set(&(context->tx.busy), 1);
-
-       retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
-       if (retval) {
-               atomic_set(&(context->tx.busy), 0);
-               err("%s: error submitting urb(%d)", __func__, retval);
-       } else {
-               /* Wait for transmission to complete (or abort) */
-               mutex_unlock(&context->ctx_lock);
-               retval = wait_for_completion_interruptible(
-                               &context->tx.finished);
-               if (retval)
-                       err("%s: task interrupted", __func__);
-               mutex_lock(&context->ctx_lock);
-
-               retval = context->tx.status;
-               if (retval)
-                       err("%s: packet tx failed (%d)", __func__, retval);
-       }
-
-       return retval;
-}
-
-/**
- * Writes data to the VFD.  The iMON VFD is 2x16 characters
- * and requires data in 5 consecutive USB interrupt packets,
- * each packet but the last carrying 7 bytes.
- *
- * I don't know if the VFD board supports features such as
- * scrolling, clearing rows, blanking, etc. so at
- * the caller must provide a full screen of data.  If fewer
- * than 32 bytes are provided spaces will be appended to
- * generate a full screen.
- */
-static ssize_t vfd_write(struct file *file, const char *buf,
-                        size_t n_bytes, loff_t *pos)
-{
-       int i;
-       int offset;
-       int seq;
-       int retval = 0;
-       struct imon_context *context;
-       const unsigned char vfd_packet6[] = {
-               0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
-       int *data_buf = NULL;
-
-       context = file->private_data;
-       if (!context) {
-               err("%s: no context for device", __func__);
-               return -ENODEV;
-       }
-
-       mutex_lock(&context->ctx_lock);
-
-       if (!context->dev_present) {
-               err("%s: no iMON device present", __func__);
-               retval = -ENODEV;
-               goto exit;
-       }
-
-       if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) {
-               err("%s: invalid payload size", __func__);
-               retval = -EINVAL;
-               goto exit;
-       }
-
-       data_buf = memdup_user(buf, n_bytes);
-       if (IS_ERR(data_buf)) {
-               retval = PTR_ERR(data_buf);
-               goto exit;
-       }
-
-       memcpy(context->tx.data_buf, data_buf, n_bytes);
-
-       /* Pad with spaces */
-       for (i = n_bytes; i < IMON_DATA_BUF_SZ - 3; ++i)
-               context->tx.data_buf[i] = ' ';
-
-       for (i = IMON_DATA_BUF_SZ - 3; i < IMON_DATA_BUF_SZ; ++i)
-               context->tx.data_buf[i] = 0xFF;
-
-       offset = 0;
-       seq = 0;
-
-       do {
-               memcpy(context->usb_tx_buf, context->tx.data_buf + offset, 7);
-               context->usb_tx_buf[7] = (unsigned char) seq;
-
-               retval = send_packet(context);
-               if (retval) {
-                       err("%s: send packet failed for packet #%d",
-                                       __func__, seq/2);
-                       goto exit;
-               } else {
-                       seq += 2;
-                       offset += 7;
-               }
-
-       } while (offset < IMON_DATA_BUF_SZ);
-
-       if (context->vfd_proto_6p) {
-               /* Send packet #6 */
-               memcpy(context->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6));
-               context->usb_tx_buf[7] = (unsigned char) seq;
-               retval = send_packet(context);
-               if (retval)
-                       err("%s: send packet failed for packet #%d",
-                                       __func__, seq/2);
-       }
-
-exit:
-       mutex_unlock(&context->ctx_lock);
-       kfree(data_buf);
-
-       return (!retval) ? n_bytes : retval;
-}
-
-/**
- * Callback function for USB core API: transmit data
- */
-static void usb_tx_callback(struct urb *urb)
-{
-       struct imon_context *context;
-
-       if (!urb)
-               return;
-       context = (struct imon_context *)urb->context;
-       if (!context)
-               return;
-
-       context->tx.status = urb->status;
-
-       /* notify waiters that write has finished */
-       atomic_set(&context->tx.busy, 0);
-       complete(&context->tx.finished);
-
-       return;
-}
-
-/**
- * Called by lirc_dev when the application opens /dev/lirc
- */
-static int ir_open(void *data)
-{
-       int retval = 0;
-       struct imon_context *context;
-
-       /* prevent races with disconnect */
-       mutex_lock(&driver_lock);
-
-       context = (struct imon_context *)data;
-
-       /* initial IR protocol decode variables */
-       context->rx.count = 0;
-       context->rx.initial_space = 1;
-       context->rx.prev_bit = 0;
-
-       context->ir_isopen = 1;
-       dev_info(context->driver->dev, "IR port opened\n");
-
-       mutex_unlock(&driver_lock);
-       return retval;
-}
-
-/**
- * Called by lirc_dev when the application closes /dev/lirc
- */
-static void ir_close(void *data)
-{
-       struct imon_context *context;
-
-       context = (struct imon_context *)data;
-       if (!context) {
-               err("%s: no context for device", __func__);
-               return;
-       }
-
-       mutex_lock(&context->ctx_lock);
-
-       context->ir_isopen = 0;
-       dev_info(context->driver->dev, "IR port closed\n");
-
-       if (!context->dev_present) {
-               /*
-                * Device disconnected while IR port was still open. Driver
-                * was not deregistered at disconnect time, so do it now.
-                */
-               deregister_from_lirc(context);
-
-               if (!context->display_isopen) {
-                       mutex_unlock(&context->ctx_lock);
-                       free_imon_context(context);
-                       return;
-               }
-               /*
-                * If display port is open, context will be deleted by
-                * display_close
-                */
-       }
-
-       mutex_unlock(&context->ctx_lock);
-       return;
-}
-
-/**
- * Convert bit count to time duration (in us) and submit
- * the value to lirc_dev.
- */
-static void submit_data(struct imon_context *context)
-{
-       unsigned char buf[4];
-       int value = context->rx.count;
-       int i;
-
-       dev_dbg(context->driver->dev, "submitting data to LIRC\n");
-
-       value *= BIT_DURATION;
-       value &= PULSE_MASK;
-       if (context->rx.prev_bit)
-               value |= PULSE_BIT;
-
-       for (i = 0; i < 4; ++i)
-               buf[i] = value>>(i*8);
-
-       lirc_buffer_write(context->driver->rbuf, buf);
-       wake_up(&context->driver->rbuf->wait_poll);
-       return;
-}
-
-static inline int tv2int(const struct timeval *a, const struct timeval *b)
-{
-       int usecs = 0;
-       int sec   = 0;
-
-       if (b->tv_usec > a->tv_usec) {
-               usecs = 1000000;
-               sec--;
-       }
-
-       usecs += a->tv_usec - b->tv_usec;
-
-       sec += a->tv_sec - b->tv_sec;
-       sec *= 1000;
-       usecs /= 1000;
-       sec += usecs;
-
-       if (sec < 0)
-               sec = 1000;
-
-       return sec;
-}
-
-/**
- * Process the incoming packet
- */
-static void imon_incoming_packet(struct imon_context *context,
-                                struct urb *urb, int intf)
-{
-       int len = urb->actual_length;
-       unsigned char *buf = urb->transfer_buffer;
-       struct device *dev = context->driver->dev;
-       int octet, bit;
-       unsigned char mask;
-       int i;
-
-       /*
-        * just bail out if no listening IR client
-        */
-       if (!context->ir_isopen)
-               return;
-
-       if (len != 8) {
-               dev_warn(dev, "imon %s: invalid incoming packet "
-                        "size (len = %d, intf%d)\n", __func__, len, intf);
-               return;
-       }
-
-       if (debug) {
-               printk(KERN_INFO "raw packet: ");
-               for (i = 0; i < len; ++i)
-                       printk("%02x ", buf[i]);
-               printk("\n");
-       }
-
-       /*
-        * Translate received data to pulse and space lengths.
-        * Received data is active low, i.e. pulses are 0 and
-        * spaces are 1.
-        *
-        * My original algorithm was essentially similar to
-        * Changwoo Ryu's with the exception that he switched
-        * the incoming bits to active high and also fed an
-        * initial space to LIRC at the start of a new sequence
-        * if the previous bit was a pulse.
-        *
-        * I've decided to adopt his algorithm.
-        */
-
-       if (buf[7] == 1 && context->rx.initial_space) {
-               /* LIRC requires a leading space */
-               context->rx.prev_bit = 0;
-               context->rx.count = 4;
-               submit_data(context);
-               context->rx.count = 0;
-       }
-
-       for (octet = 0; octet < 5; ++octet) {
-               mask = 0x80;
-               for (bit = 0; bit < 8; ++bit) {
-                       int curr_bit = !(buf[octet] & mask);
-                       if (curr_bit != context->rx.prev_bit) {
-                               if (context->rx.count) {
-                                       submit_data(context);
-                                       context->rx.count = 0;
-                               }
-                               context->rx.prev_bit = curr_bit;
-                       }
-                       ++context->rx.count;
-                       mask >>= 1;
-               }
-       }
-
-       if (buf[7] == 10) {
-               if (context->rx.count) {
-                       submit_data(context);
-                       context->rx.count = 0;
-               }
-               context->rx.initial_space = context->rx.prev_bit;
-       }
-}
-
-/**
- * Callback function for USB core API: receive data
- */
-static void usb_rx_callback(struct urb *urb)
-{
-       struct imon_context *context;
-       int intfnum = 0;
-
-       if (!urb)
-               return;
-
-       context = (struct imon_context *)urb->context;
-       if (!context)
-               return;
-
-       switch (urb->status) {
-       case -ENOENT:           /* usbcore unlink successful! */
-               return;
-
-       case 0:
-               imon_incoming_packet(context, urb, intfnum);
-               break;
-
-       default:
-               dev_warn(context->driver->dev, "imon %s: status(%d): ignored\n",
-                        __func__, urb->status);
-               break;
-       }
-
-       usb_submit_urb(context->rx_urb, GFP_ATOMIC);
-
-       return;
-}
-
-/**
- * Callback function for USB core API: Probe
- */
-static int imon_probe(struct usb_interface *interface,
-                     const struct usb_device_id *id)
-{
-       struct usb_device *usbdev = NULL;
-       struct usb_host_interface *iface_desc = NULL;
-       struct usb_endpoint_descriptor *rx_endpoint = NULL;
-       struct usb_endpoint_descriptor *tx_endpoint = NULL;
-       struct urb *rx_urb = NULL;
-       struct urb *tx_urb = NULL;
-       struct lirc_driver *driver = NULL;
-       struct lirc_buffer *rbuf = NULL;
-       struct device *dev = &interface->dev;
-       int ifnum;
-       int lirc_minor = 0;
-       int num_endpts;
-       int retval = 0;
-       int display_ep_found = 0;
-       int ir_ep_found = 0;
-       int alloc_status = 0;
-       int vfd_proto_6p = 0;
-       struct imon_context *context = NULL;
-       int i;
-       u16 vendor, product;
-
-       /* prevent races probing devices w/multiple interfaces */
-       mutex_lock(&driver_lock);
-
-       context = kzalloc(sizeof(struct imon_context), GFP_KERNEL);
-       if (!context) {
-               err("%s: kzalloc failed for context", __func__);
-               alloc_status = 1;
-               goto alloc_status_switch;
-       }
-
-       /*
-        * Try to auto-detect the type of display if the user hasn't set
-        * it by hand via the display_type modparam. Default is VFD.
-        */
-       if (usb_match_id(interface, ir_only_list))
-               context->display = 0;
-       else
-               context->display = 1;
-
-       usbdev     = usb_get_dev(interface_to_usbdev(interface));
-       iface_desc = interface->cur_altsetting;
-       num_endpts = iface_desc->desc.bNumEndpoints;
-       ifnum      = iface_desc->desc.bInterfaceNumber;
-       vendor     = le16_to_cpu(usbdev->descriptor.idVendor);
-       product    = le16_to_cpu(usbdev->descriptor.idProduct);
-
-       dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n",
-               __func__, vendor, product, ifnum);
-
-       /*
-        * Scan the endpoint list and set:
-        *      first input endpoint = IR endpoint
-        *      first output endpoint = display endpoint
-        */
-       for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) {
-               struct usb_endpoint_descriptor *ep;
-               int ep_dir;
-               int ep_type;
-               ep = &iface_desc->endpoint[i].desc;
-               ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
-               ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
-
-               if (!ir_ep_found &&
-                       ep_dir == USB_DIR_IN &&
-                       ep_type == USB_ENDPOINT_XFER_INT) {
-
-                       rx_endpoint = ep;
-                       ir_ep_found = 1;
-                       dev_dbg(dev, "%s: found IR endpoint\n", __func__);
-
-               } else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
-                          ep_type == USB_ENDPOINT_XFER_INT) {
-                       tx_endpoint = ep;
-                       display_ep_found = 1;
-                       dev_dbg(dev, "%s: found display endpoint\n", __func__);
-               }
-       }
-
-       /*
-        * Some iMON receivers have no display. Unfortunately, it seems
-        * that SoundGraph recycles device IDs between devices both with
-        * and without... :\
-        */
-       if (context->display == 0) {
-               display_ep_found = 0;
-               dev_dbg(dev, "%s: device has no display\n", __func__);
-       }
-
-       /* Input endpoint is mandatory */
-       if (!ir_ep_found) {
-               err("%s: no valid input (IR) endpoint found.", __func__);
-               retval = -ENODEV;
-               alloc_status = 2;
-               goto alloc_status_switch;
-       }
-
-       /* Determine if display requires 6 packets */
-       if (display_ep_found) {
-               if (usb_match_id(interface, vfd_proto_6p_list))
-                       vfd_proto_6p = 1;
-
-               dev_dbg(dev, "%s: vfd_proto_6p: %d\n",
-                       __func__, vfd_proto_6p);
-       }
-
-       driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
-       if (!driver) {
-               err("%s: kzalloc failed for lirc_driver", __func__);
-               alloc_status = 2;
-               goto alloc_status_switch;
-       }
-       rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
-       if (!rbuf) {
-               err("%s: kmalloc failed for lirc_buffer", __func__);
-               alloc_status = 3;
-               goto alloc_status_switch;
-       }
-       if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
-               err("%s: lirc_buffer_init failed", __func__);
-               alloc_status = 4;
-               goto alloc_status_switch;
-       }
-       rx_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!rx_urb) {
-               err("%s: usb_alloc_urb failed for IR urb", __func__);
-               alloc_status = 5;
-               goto alloc_status_switch;
-       }
-       tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!tx_urb) {
-               err("%s: usb_alloc_urb failed for display urb",
-                   __func__);
-               alloc_status = 6;
-               goto alloc_status_switch;
-       }
-
-       mutex_init(&context->ctx_lock);
-       context->vfd_proto_6p = vfd_proto_6p;
-
-       strcpy(driver->name, MOD_NAME);
-       driver->minor = -1;
-       driver->code_length = BUF_CHUNK_SIZE * 8;
-       driver->sample_rate = 0;
-       driver->features = LIRC_CAN_REC_MODE2;
-       driver->data = context;
-       driver->rbuf = rbuf;
-       driver->set_use_inc = ir_open;
-       driver->set_use_dec = ir_close;
-       driver->dev = &interface->dev;
-       driver->owner = THIS_MODULE;
-
-       mutex_lock(&context->ctx_lock);
-
-       context->driver = driver;
-       /* start out in keyboard mode */
-
-       lirc_minor = lirc_register_driver(driver);
-       if (lirc_minor < 0) {
-               err("%s: lirc_register_driver failed", __func__);
-               alloc_status = 7;
-               goto unlock;
-       } else
-               dev_info(dev, "Registered iMON driver "
-                        "(lirc minor: %d)\n", lirc_minor);
-
-       /* Needed while unregistering! */
-       driver->minor = lirc_minor;
-
-       context->usbdev = usbdev;
-       context->dev_present = 1;
-       context->rx_endpoint = rx_endpoint;
-       context->rx_urb = rx_urb;
-
-       /*
-        * tx is used to send characters to lcd/vfd, associate RF
-        * remotes, set IR protocol, and maybe more...
-        */
-       context->tx_endpoint = tx_endpoint;
-       context->tx_urb = tx_urb;
-
-       if (display_ep_found)
-               context->display = 1;
-
-       usb_fill_int_urb(context->rx_urb, context->usbdev,
-               usb_rcvintpipe(context->usbdev,
-                       context->rx_endpoint->bEndpointAddress),
-               context->usb_rx_buf, sizeof(context->usb_rx_buf),
-               usb_rx_callback, context,
-               context->rx_endpoint->bInterval);
-
-       retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
-
-       if (retval) {
-               err("%s: usb_submit_urb failed for intf0 (%d)",
-                   __func__, retval);
-               mutex_unlock(&context->ctx_lock);
-               goto exit;
-       }
-
-       usb_set_intfdata(interface, context);
-
-       if (context->display && ifnum == 0) {
-               dev_dbg(dev, "%s: Registering iMON display with sysfs\n",
-                       __func__);
-
-               if (usb_register_dev(interface, &imon_class)) {
-                       /* Not a fatal error, so ignore */
-                       dev_info(dev, "%s: could not get a minor number for "
-                                "display\n", __func__);
-               }
-       }
-
-       dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
-                "usb<%d:%d> initialized\n", vendor, product, ifnum,
-                usbdev->bus->busnum, usbdev->devnum);
-
-unlock:
-       mutex_unlock(&context->ctx_lock);
-alloc_status_switch:
-
-       switch (alloc_status) {
-       case 7:
-               usb_free_urb(tx_urb);
-       case 6:
-               usb_free_urb(rx_urb);
-       case 5:
-               if (rbuf)
-                       lirc_buffer_free(rbuf);
-       case 4:
-               kfree(rbuf);
-       case 3:
-               kfree(driver);
-       case 2:
-               kfree(context);
-               context = NULL;
-       case 1:
-               if (retval != -ENODEV)
-                       retval = -ENOMEM;
-               break;
-       case 0:
-               retval = 0;
-       }
-
-exit:
-       mutex_unlock(&driver_lock);
-
-       return retval;
-}
-
-/**
- * Callback function for USB core API: disconnect
- */
-static void imon_disconnect(struct usb_interface *interface)
-{
-       struct imon_context *context;
-       int ifnum;
-
-       /* prevent races with ir_open()/display_open() */
-       mutex_lock(&driver_lock);
-
-       context = usb_get_intfdata(interface);
-       ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
-
-       mutex_lock(&context->ctx_lock);
-
-       usb_set_intfdata(interface, NULL);
-
-       /* Abort ongoing write */
-       if (atomic_read(&context->tx.busy)) {
-               usb_kill_urb(context->tx_urb);
-               complete_all(&context->tx.finished);
-       }
-
-       context->dev_present = 0;
-       usb_kill_urb(context->rx_urb);
-       if (context->display)
-               usb_deregister_dev(interface, &imon_class);
-
-       if (!context->ir_isopen && !context->dev_present) {
-               deregister_from_lirc(context);
-               mutex_unlock(&context->ctx_lock);
-               if (!context->display_isopen)
-                       free_imon_context(context);
-       } else
-               mutex_unlock(&context->ctx_lock);
-
-       mutex_unlock(&driver_lock);
-
-       printk(KERN_INFO "%s: iMON device (intf%d) disconnected\n",
-              __func__, ifnum);
-}
-
-static int imon_suspend(struct usb_interface *intf, pm_message_t message)
-{
-       struct imon_context *context = usb_get_intfdata(intf);
-
-       usb_kill_urb(context->rx_urb);
-
-       return 0;
-}
-
-static int imon_resume(struct usb_interface *intf)
-{
-       int rc = 0;
-       struct imon_context *context = usb_get_intfdata(intf);
-
-       usb_fill_int_urb(context->rx_urb, context->usbdev,
-               usb_rcvintpipe(context->usbdev,
-                       context->rx_endpoint->bEndpointAddress),
-               context->usb_rx_buf, sizeof(context->usb_rx_buf),
-               usb_rx_callback, context,
-               context->rx_endpoint->bInterval);
-
-       rc = usb_submit_urb(context->rx_urb, GFP_ATOMIC);
-
-       return rc;
-}
-
-static int __init imon_init(void)
-{
-       int rc;
-
-       printk(KERN_INFO MOD_NAME ": " MOD_DESC ", v" MOD_VERSION "\n");
-
-       rc = usb_register(&imon_driver);
-       if (rc) {
-               err("%s: usb register failed(%d)", __func__, rc);
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static void __exit imon_exit(void)
-{
-       usb_deregister(&imon_driver);
-       printk(KERN_INFO MOD_NAME ": module removed. Goodbye!\n");
-}
-
-module_init(imon_init);
-module_exit(imon_exit);
diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/lirc/lirc_parallel.c
deleted file mode 100644 (file)
index 792aac0..0000000
+++ /dev/null
@@ -1,755 +0,0 @@
-/*
- * lirc_parallel.c
- *
- * lirc_parallel - device driver for infra-red signal receiving and
- *                 transmitting unit built by the author
- *
- * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-/*** Includes ***/
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/time.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/uaccess.h>
-#include <asm/div64.h>
-
-#include <linux/poll.h>
-#include <linux/parport.h>
-#include <linux/platform_device.h>
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-#include "lirc_parallel.h"
-
-#define LIRC_DRIVER_NAME "lirc_parallel"
-
-#ifndef LIRC_IRQ
-#define LIRC_IRQ 7
-#endif
-#ifndef LIRC_PORT
-#define LIRC_PORT 0x378
-#endif
-#ifndef LIRC_TIMER
-#define LIRC_TIMER 65536
-#endif
-
-/*** Global Variables ***/
-
-static int debug;
-static int check_pselecd;
-
-unsigned int irq = LIRC_IRQ;
-unsigned int io = LIRC_PORT;
-#ifdef LIRC_TIMER
-unsigned int timer;
-unsigned int default_timer = LIRC_TIMER;
-#endif
-
-#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */
-
-static int rbuf[RBUF_SIZE];
-
-DECLARE_WAIT_QUEUE_HEAD(lirc_wait);
-
-unsigned int rptr;
-unsigned int wptr;
-unsigned int lost_irqs;
-int is_open;
-
-struct parport *pport;
-struct pardevice *ppdevice;
-int is_claimed;
-
-unsigned int tx_mask = 1;
-
-/*** Internal Functions ***/
-
-static unsigned int in(int offset)
-{
-       switch (offset) {
-       case LIRC_LP_BASE:
-               return parport_read_data(pport);
-       case LIRC_LP_STATUS:
-               return parport_read_status(pport);
-       case LIRC_LP_CONTROL:
-               return parport_read_control(pport);
-       }
-       return 0; /* make compiler happy */
-}
-
-static void out(int offset, int value)
-{
-       switch (offset) {
-       case LIRC_LP_BASE:
-               parport_write_data(pport, value);
-               break;
-       case LIRC_LP_CONTROL:
-               parport_write_control(pport, value);
-               break;
-       case LIRC_LP_STATUS:
-               printk(KERN_INFO "%s: attempt to write to status register\n",
-                      LIRC_DRIVER_NAME);
-               break;
-       }
-}
-
-static unsigned int lirc_get_timer(void)
-{
-       return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT;
-}
-
-static unsigned int lirc_get_signal(void)
-{
-       return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT;
-}
-
-static void lirc_on(void)
-{
-       out(LIRC_PORT_DATA, tx_mask);
-}
-
-static void lirc_off(void)
-{
-       out(LIRC_PORT_DATA, 0);
-}
-
-static unsigned int init_lirc_timer(void)
-{
-       struct timeval tv, now;
-       unsigned int level, newlevel, timeelapsed, newtimer;
-       int count = 0;
-
-       do_gettimeofday(&tv);
-       tv.tv_sec++;                     /* wait max. 1 sec. */
-       level = lirc_get_timer();
-       do {
-               newlevel = lirc_get_timer();
-               if (level == 0 && newlevel != 0)
-                       count++;
-               level = newlevel;
-               do_gettimeofday(&now);
-       } while (count < 1000 && (now.tv_sec < tv.tv_sec
-                            || (now.tv_sec == tv.tv_sec
-                                && now.tv_usec < tv.tv_usec)));
-
-       timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000
-                    + (now.tv_usec - tv.tv_usec));
-       if (count >= 1000 && timeelapsed > 0) {
-               if (default_timer == 0) {
-                       /* autodetect timer */
-                       newtimer = (1000000*count)/timeelapsed;
-                       printk(KERN_INFO "%s: %u Hz timer detected\n",
-                              LIRC_DRIVER_NAME, newtimer);
-                       return newtimer;
-               }  else {
-                       newtimer = (1000000*count)/timeelapsed;
-                       if (abs(newtimer - default_timer) > default_timer/10) {
-                               /* bad timer */
-                               printk(KERN_NOTICE "%s: bad timer: %u Hz\n",
-                                      LIRC_DRIVER_NAME, newtimer);
-                               printk(KERN_NOTICE "%s: using default timer: "
-                                      "%u Hz\n",
-                                      LIRC_DRIVER_NAME, default_timer);
-                               return default_timer;
-                       } else {
-                               printk(KERN_INFO "%s: %u Hz timer detected\n",
-                                      LIRC_DRIVER_NAME, newtimer);
-                               return newtimer; /* use detected value */
-                       }
-               }
-       } else {
-               printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME);
-               return 0;
-       }
-}
-
-static int lirc_claim(void)
-{
-       if (parport_claim(ppdevice) != 0) {
-               printk(KERN_WARNING "%s: could not claim port\n",
-                      LIRC_DRIVER_NAME);
-               printk(KERN_WARNING "%s: waiting for port becoming available"
-                      "\n", LIRC_DRIVER_NAME);
-               if (parport_claim_or_block(ppdevice) < 0) {
-                       printk(KERN_NOTICE "%s: could not claim port, giving"
-                              " up\n", LIRC_DRIVER_NAME);
-                       return 0;
-               }
-       }
-       out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
-       is_claimed = 1;
-       return 1;
-}
-
-/*** interrupt handler ***/
-
-static void rbuf_write(int signal)
-{
-       unsigned int nwptr;
-
-       nwptr = (wptr + 1) & (RBUF_SIZE - 1);
-       if (nwptr == rptr) {
-               /* no new signals will be accepted */
-               lost_irqs++;
-               printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME);
-               return;
-       }
-       rbuf[wptr] = signal;
-       wptr = nwptr;
-}
-
-static void irq_handler(void *blah)
-{
-       struct timeval tv;
-       static struct timeval lasttv;
-       static int init;
-       long signal;
-       int data;
-       unsigned int level, newlevel;
-       unsigned int timeout;
-
-       if (!is_open)
-               return;
-
-       if (!is_claimed)
-               return;
-
-#if 0
-       /* disable interrupt */
-         disable_irq(irq);
-         out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN));
-#endif
-       if (check_pselecd && (in(1) & LP_PSELECD))
-               return;
-
-#ifdef LIRC_TIMER
-       if (init) {
-               do_gettimeofday(&tv);
-
-               signal = tv.tv_sec - lasttv.tv_sec;
-               if (signal > 15)
-                       /* really long time */
-                       data = PULSE_MASK;
-               else
-                       data = (int) (signal*1000000 +
-                                        tv.tv_usec - lasttv.tv_usec +
-                                        LIRC_SFH506_DELAY);
-
-               rbuf_write(data); /* space */
-       } else {
-               if (timer == 0) {
-                       /*
-                        * wake up; we'll lose this signal, but it will be
-                        * garbage if the device is turned on anyway
-                        */
-                       timer = init_lirc_timer();
-                       /* enable_irq(irq); */
-                       return;
-               }
-               init = 1;
-       }
-
-       timeout = timer/10;     /* timeout after 1/10 sec. */
-       signal = 1;
-       level = lirc_get_timer();
-       do {
-               newlevel = lirc_get_timer();
-               if (level == 0 && newlevel != 0)
-                       signal++;
-               level = newlevel;
-
-               /* giving up */
-               if (signal > timeout
-                   || (check_pselecd && (in(1) & LP_PSELECD))) {
-                       signal = 0;
-                       printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME);
-                       break;
-               }
-       } while (lirc_get_signal());
-
-       if (signal != 0) {
-               /* adjust value to usecs */
-               __u64 helper;
-
-               helper = ((__u64) signal)*1000000;
-               do_div(helper, timer);
-               signal = (long) helper;
-
-               if (signal > LIRC_SFH506_DELAY)
-                       data = signal - LIRC_SFH506_DELAY;
-               else
-                       data = 1;
-               rbuf_write(PULSE_BIT|data); /* pulse */
-       }
-       do_gettimeofday(&lasttv);
-#else
-       /* add your code here */
-#endif
-
-       wake_up_interruptible(&lirc_wait);
-
-       /* enable interrupt */
-       /*
-         enable_irq(irq);
-         out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN);
-       */
-}
-
-/*** file operations ***/
-
-static loff_t lirc_lseek(struct file *filep, loff_t offset, int orig)
-{
-       return -ESPIPE;
-}
-
-static ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos)
-{
-       int result = 0;
-       int count = 0;
-       DECLARE_WAITQUEUE(wait, current);
-
-       if (n % sizeof(int))
-               return -EINVAL;
-
-       add_wait_queue(&lirc_wait, &wait);
-       set_current_state(TASK_INTERRUPTIBLE);
-       while (count < n) {
-               if (rptr != wptr) {
-                       if (copy_to_user(buf+count, (char *) &rbuf[rptr],
-                                        sizeof(int))) {
-                               result = -EFAULT;
-                               break;
-                       }
-                       rptr = (rptr + 1) & (RBUF_SIZE - 1);
-                       count += sizeof(int);
-               } else {
-                       if (filep->f_flags & O_NONBLOCK) {
-                               result = -EAGAIN;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               result = -ERESTARTSYS;
-                               break;
-                       }
-                       schedule();
-                       set_current_state(TASK_INTERRUPTIBLE);
-               }
-       }
-       remove_wait_queue(&lirc_wait, &wait);
-       set_current_state(TASK_RUNNING);
-       return count ? count : result;
-}
-
-static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
-                         loff_t *ppos)
-{
-       int count;
-       unsigned int i;
-       unsigned int level, newlevel;
-       unsigned long flags;
-       int counttimer;
-       int *wbuf;
-       ssize_t ret;
-
-       if (!is_claimed)
-               return -EBUSY;
-
-       count = n / sizeof(int);
-
-       if (n % sizeof(int) || count % 2 == 0)
-               return -EINVAL;
-
-       wbuf = memdup_user(buf, n);
-       if (IS_ERR(wbuf))
-               return PTR_ERR(wbuf);
-
-#ifdef LIRC_TIMER
-       if (timer == 0) {
-               /* try again if device is ready */
-               timer = init_lirc_timer();
-               if (timer == 0) {
-                       ret = -EIO;
-                       goto out;
-               }
-       }
-
-       /* adjust values from usecs */
-       for (i = 0; i < count; i++) {
-               __u64 helper;
-
-               helper = ((__u64) wbuf[i])*timer;
-               do_div(helper, 1000000);
-               wbuf[i] = (int) helper;
-       }
-
-       local_irq_save(flags);
-       i = 0;
-       while (i < count) {
-               level = lirc_get_timer();
-               counttimer = 0;
-               lirc_on();
-               do {
-                       newlevel = lirc_get_timer();
-                       if (level == 0 && newlevel != 0)
-                               counttimer++;
-                       level = newlevel;
-                       if (check_pselecd && (in(1) & LP_PSELECD)) {
-                               lirc_off();
-                               local_irq_restore(flags);
-                               ret = -EIO;
-                               goto out;
-                       }
-               } while (counttimer < wbuf[i]);
-               i++;
-
-               lirc_off();
-               if (i == count)
-                       break;
-               counttimer = 0;
-               do {
-                       newlevel = lirc_get_timer();
-                       if (level == 0 && newlevel != 0)
-                               counttimer++;
-                       level = newlevel;
-                       if (check_pselecd && (in(1) & LP_PSELECD)) {
-                               local_irq_restore(flags);
-                               ret = -EIO;
-                               goto out;
-                       }
-               } while (counttimer < wbuf[i]);
-               i++;
-       }
-       local_irq_restore(flags);
-#else
-       /* place code that handles write without external timer here */
-#endif
-       ret = n;
-out:
-       kfree(wbuf);
-
-       return ret;
-}
-
-static unsigned int lirc_poll(struct file *file, poll_table *wait)
-{
-       poll_wait(file, &lirc_wait, wait);
-       if (rptr != wptr)
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
-{
-       int result;
-       __u32 features = LIRC_CAN_SET_TRANSMITTER_MASK |
-                        LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
-       __u32 mode;
-       __u32 value;
-
-       switch (cmd) {
-       case LIRC_GET_FEATURES:
-               result = put_user(features, (__u32 *) arg);
-               if (result)
-                       return result;
-               break;
-       case LIRC_GET_SEND_MODE:
-               result = put_user(LIRC_MODE_PULSE, (__u32 *) arg);
-               if (result)
-                       return result;
-               break;
-       case LIRC_GET_REC_MODE:
-               result = put_user(LIRC_MODE_MODE2, (__u32 *) arg);
-               if (result)
-                       return result;
-               break;
-       case LIRC_SET_SEND_MODE:
-               result = get_user(mode, (__u32 *) arg);
-               if (result)
-                       return result;
-               if (mode != LIRC_MODE_PULSE)
-                       return -EINVAL;
-               break;
-       case LIRC_SET_REC_MODE:
-               result = get_user(mode, (__u32 *) arg);
-               if (result)
-                       return result;
-               if (mode != LIRC_MODE_MODE2)
-                       return -ENOSYS;
-               break;
-       case LIRC_SET_TRANSMITTER_MASK:
-               result = get_user(value, (__u32 *) arg);
-               if (result)
-                       return result;
-               if ((value & LIRC_PARALLEL_TRANSMITTER_MASK) != value)
-                       return LIRC_PARALLEL_MAX_TRANSMITTERS;
-               tx_mask = value;
-               break;
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static int lirc_open(struct inode *node, struct file *filep)
-{
-       if (is_open || !lirc_claim())
-               return -EBUSY;
-
-       parport_enable_irq(pport);
-
-       /* init read ptr */
-       rptr = 0;
-       wptr = 0;
-       lost_irqs = 0;
-
-       is_open = 1;
-       return 0;
-}
-
-static int lirc_close(struct inode *node, struct file *filep)
-{
-       if (is_claimed) {
-               is_claimed = 0;
-               parport_release(ppdevice);
-       }
-       is_open = 0;
-       return 0;
-}
-
-static const struct file_operations lirc_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = lirc_lseek,
-       .read           = lirc_read,
-       .write          = lirc_write,
-       .poll           = lirc_poll,
-       .unlocked_ioctl = lirc_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl   = lirc_ioctl,
-#endif
-       .open           = lirc_open,
-       .release        = lirc_close
-};
-
-static int set_use_inc(void *data)
-{
-       return 0;
-}
-
-static void set_use_dec(void *data)
-{
-}
-
-static struct lirc_driver driver = {
-       .name           = LIRC_DRIVER_NAME,
-       .minor          = -1,
-       .code_length    = 1,
-       .sample_rate    = 0,
-       .data           = NULL,
-       .add_to_buf     = NULL,
-       .set_use_inc    = set_use_inc,
-       .set_use_dec    = set_use_dec,
-       .fops           = &lirc_fops,
-       .dev            = NULL,
-       .owner          = THIS_MODULE,
-};
-
-static struct platform_device *lirc_parallel_dev;
-
-static int __devinit lirc_parallel_probe(struct platform_device *dev)
-{
-       return 0;
-}
-
-static int __devexit lirc_parallel_remove(struct platform_device *dev)
-{
-       return 0;
-}
-
-static int lirc_parallel_suspend(struct platform_device *dev,
-                                       pm_message_t state)
-{
-       return 0;
-}
-
-static int lirc_parallel_resume(struct platform_device *dev)
-{
-       return 0;
-}
-
-static struct platform_driver lirc_parallel_driver = {
-       .probe  = lirc_parallel_probe,
-       .remove = __devexit_p(lirc_parallel_remove),
-       .suspend        = lirc_parallel_suspend,
-       .resume = lirc_parallel_resume,
-       .driver = {
-               .name   = LIRC_DRIVER_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int pf(void *handle)
-{
-       parport_disable_irq(pport);
-       is_claimed = 0;
-       return 0;
-}
-
-static void kf(void *handle)
-{
-       if (!is_open)
-               return;
-       if (!lirc_claim())
-               return;
-       parport_enable_irq(pport);
-       lirc_off();
-       /* this is a bit annoying when you actually print...*/
-       /*
-       printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME);
-       */
-}
-
-/*** module initialization and cleanup ***/
-
-static int __init lirc_parallel_init(void)
-{
-       int result;
-
-       result = platform_driver_register(&lirc_parallel_driver);
-       if (result) {
-               printk(KERN_NOTICE "platform_driver_register"
-                                       " returned %d\n", result);
-               return result;
-       }
-
-       lirc_parallel_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
-       if (!lirc_parallel_dev) {
-               result = -ENOMEM;
-               goto exit_driver_unregister;
-       }
-
-       result = platform_device_add(lirc_parallel_dev);
-       if (result)
-               goto exit_device_put;
-
-       pport = parport_find_base(io);
-       if (pport == NULL) {
-               printk(KERN_NOTICE "%s: no port at %x found\n",
-                      LIRC_DRIVER_NAME, io);
-               result = -ENXIO;
-               goto exit_device_put;
-       }
-       ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME,
-                                          pf, kf, irq_handler, 0, NULL);
-       parport_put_port(pport);
-       if (ppdevice == NULL) {
-               printk(KERN_NOTICE "%s: parport_register_device() failed\n",
-                      LIRC_DRIVER_NAME);
-               result = -ENXIO;
-               goto exit_device_put;
-       }
-       if (parport_claim(ppdevice) != 0)
-               goto skip_init;
-       is_claimed = 1;
-       out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
-
-#ifdef LIRC_TIMER
-       if (debug)
-               out(LIRC_PORT_DATA, tx_mask);
-
-       timer = init_lirc_timer();
-
-#if 0  /* continue even if device is offline */
-       if (timer == 0) {
-               is_claimed = 0;
-               parport_release(pport);
-               parport_unregister_device(ppdevice);
-               result = -EIO;
-               goto exit_device_put;
-       }
-
-#endif
-       if (debug)
-               out(LIRC_PORT_DATA, 0);
-#endif
-
-       is_claimed = 0;
-       parport_release(ppdevice);
- skip_init:
-       driver.dev = &lirc_parallel_dev->dev;
-       driver.minor = lirc_register_driver(&driver);
-       if (driver.minor < 0) {
-               printk(KERN_NOTICE "%s: register_chrdev() failed\n",
-                      LIRC_DRIVER_NAME);
-               parport_unregister_device(ppdevice);
-               result = -EIO;
-               goto exit_device_put;
-       }
-       printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n",
-              LIRC_DRIVER_NAME, io, irq);
-       return 0;
-
-exit_device_put:
-       platform_device_put(lirc_parallel_dev);
-exit_driver_unregister:
-       platform_driver_unregister(&lirc_parallel_driver);
-       return result;
-}
-
-static void __exit lirc_parallel_exit(void)
-{
-       parport_unregister_device(ppdevice);
-       lirc_unregister_driver(driver.minor);
-
-       platform_device_unregister(lirc_parallel_dev);
-       platform_driver_unregister(&lirc_parallel_driver);
-}
-
-module_init(lirc_parallel_init);
-module_exit(lirc_parallel_exit);
-
-MODULE_DESCRIPTION("Infrared receiver driver for parallel ports.");
-MODULE_AUTHOR("Christoph Bartelmus");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, S_IRUGO);
-MODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)");
-
-module_param(irq, int, S_IRUGO);
-MODULE_PARM_DESC(irq, "Interrupt (7 or 5)");
-
-module_param(tx_mask, int, S_IRUGO);
-MODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable debugging messages");
-
-module_param(check_pselecd, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Check for printer (default: 0)");
diff --git a/drivers/staging/lirc/lirc_parallel.h b/drivers/staging/lirc/lirc_parallel.h
deleted file mode 100644 (file)
index 4bed6af..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* lirc_parallel.h */
-
-#ifndef _LIRC_PARALLEL_H
-#define _LIRC_PARALLEL_H
-
-#include <linux/lp.h>
-
-#define LIRC_PORT_LEN 3
-
-#define LIRC_LP_BASE    0
-#define LIRC_LP_STATUS  1
-#define LIRC_LP_CONTROL 2
-
-#define LIRC_PORT_DATA           LIRC_LP_BASE    /* base */
-#define LIRC_PORT_TIMER        LIRC_LP_STATUS    /* status port */
-#define LIRC_PORT_TIMER_BIT          LP_PBUSY    /* busy signal */
-#define LIRC_PORT_SIGNAL       LIRC_LP_STATUS    /* status port */
-#define LIRC_PORT_SIGNAL_BIT          LP_PACK    /* ack signal */
-#define LIRC_PORT_IRQ         LIRC_LP_CONTROL    /* control port */
-
-#define LIRC_SFH506_DELAY 0             /* delay t_phl in usecs */
-
-#define LIRC_PARALLEL_MAX_TRANSMITTERS 8
-#define LIRC_PARALLEL_TRANSMITTER_MASK ((1<<LIRC_PARALLEL_MAX_TRANSMITTERS) - 1)
-
-#endif
diff --git a/drivers/staging/lirc/lirc_sasem.c b/drivers/staging/lirc/lirc_sasem.c
deleted file mode 100644 (file)
index a2d18b0..0000000
+++ /dev/null
@@ -1,939 +0,0 @@
-/*
- * lirc_sasem.c - USB remote support for LIRC
- * Version 0.5
- *
- * Copyright (C) 2004-2005 Oliver Stabel <oliver.stabel@gmx.de>
- *                      Tim Davies <tim@opensystems.net.au>
- *
- * This driver was derived from:
- *   Venky Raju <dev@venky.ws>
- *      "lirc_imon - "LIRC/VFD driver for Ahanix/Soundgraph IMON IR/VFD"
- *   Paul Miller <pmiller9@users.sourceforge.net>'s 2003-2004
- *      "lirc_atiusb - USB remote support for LIRC"
- *   Culver Consulting Services <henry@culcon.com>'s 2003
- *      "Sasem OnAir VFD/IR USB driver"
- *
- *
- * NOTE - The LCDproc iMon driver should work with this module.  More info at
- *     http://www.frogstorm.info/sasem
- */
-
-/*
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/usb.h>
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-
-#define MOD_AUTHOR     "Oliver Stabel <oliver.stabel@gmx.de>, " \
-                       "Tim Davies <tim@opensystems.net.au>"
-#define MOD_DESC       "USB Driver for Sasem Remote Controller V1.1"
-#define MOD_NAME       "lirc_sasem"
-#define MOD_VERSION    "0.5"
-
-#define VFD_MINOR_BASE 144     /* Same as LCD */
-#define DEVICE_NAME    "lcd%d"
-
-#define BUF_CHUNK_SIZE 8
-#define BUF_SIZE       128
-
-#define IOCTL_LCD_CONTRAST 1
-
-/*** P R O T O T Y P E S ***/
-
-/* USB Callback prototypes */
-static int sasem_probe(struct usb_interface *interface,
-                       const struct usb_device_id *id);
-static void sasem_disconnect(struct usb_interface *interface);
-static void usb_rx_callback(struct urb *urb);
-static void usb_tx_callback(struct urb *urb);
-
-/* VFD file_operations function prototypes */
-static int vfd_open(struct inode *inode, struct file *file);
-static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg);
-static int vfd_close(struct inode *inode, struct file *file);
-static ssize_t vfd_write(struct file *file, const char *buf,
-                               size_t n_bytes, loff_t *pos);
-
-/* LIRC driver function prototypes */
-static int ir_open(void *data);
-static void ir_close(void *data);
-
-/* Driver init/exit prototypes */
-static int __init sasem_init(void);
-static void __exit sasem_exit(void);
-
-/*** G L O B A L S ***/
-#define SASEM_DATA_BUF_SZ      32
-
-struct sasem_context {
-
-       struct usb_device *dev;
-       int vfd_isopen;                 /* VFD port has been opened       */
-       unsigned int vfd_contrast;      /* VFD contrast            */
-       int ir_isopen;                  /* IR port has been opened      */
-       int dev_present;                /* USB device presence      */
-       struct mutex ctx_lock;          /* to lock this object      */
-       wait_queue_head_t remove_ok;    /* For unexpected USB disconnects */
-
-       struct lirc_driver *driver;
-       struct usb_endpoint_descriptor *rx_endpoint;
-       struct usb_endpoint_descriptor *tx_endpoint;
-       struct urb *rx_urb;
-       struct urb *tx_urb;
-       unsigned char usb_rx_buf[8];
-       unsigned char usb_tx_buf[8];
-
-       struct tx_t {
-               unsigned char data_buf[SASEM_DATA_BUF_SZ]; /* user data buffer */
-               struct completion finished;  /* wait for write to finish  */
-               atomic_t busy;               /* write in progress        */
-               int status;                  /* status of tx completion   */
-       } tx;
-
-       /* for dealing with repeat codes (wish there was a toggle bit!) */
-       struct timeval presstime;
-       char lastcode[8];
-       int codesaved;
-};
-
-/* VFD file operations */
-static const struct file_operations vfd_fops = {
-       .owner          = THIS_MODULE,
-       .open           = &vfd_open,
-       .write          = &vfd_write,
-       .unlocked_ioctl = &vfd_ioctl,
-       .release        = &vfd_close,
-       .llseek         = noop_llseek,
-};
-
-/* USB Device ID for Sasem USB Control Board */
-static struct usb_device_id sasem_usb_id_table[] = {
-       /* Sasem USB Control Board */
-       { USB_DEVICE(0x11ba, 0x0101) },
-       /* Terminating entry */
-       {}
-};
-
-/* USB Device data */
-static struct usb_driver sasem_driver = {
-       .name           = MOD_NAME,
-       .probe          = sasem_probe,
-       .disconnect     = sasem_disconnect,
-       .id_table       = sasem_usb_id_table,
-};
-
-static struct usb_class_driver sasem_class = {
-       .name           = DEVICE_NAME,
-       .fops           = &vfd_fops,
-       .minor_base     = VFD_MINOR_BASE,
-};
-
-/* to prevent races between open() and disconnect() */
-static DEFINE_MUTEX(disconnect_lock);
-
-static int debug;
-
-
-/*** M O D U L E   C O D E ***/
-
-MODULE_AUTHOR(MOD_AUTHOR);
-MODULE_DESCRIPTION(MOD_DESC);
-MODULE_LICENSE("GPL");
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)");
-
-static void delete_context(struct sasem_context *context)
-{
-       usb_free_urb(context->tx_urb);  /* VFD */
-       usb_free_urb(context->rx_urb);  /* IR */
-       lirc_buffer_free(context->driver->rbuf);
-       kfree(context->driver->rbuf);
-       kfree(context->driver);
-       kfree(context);
-
-       if (debug)
-               printk(KERN_INFO "%s: context deleted\n", __func__);
-}
-
-static void deregister_from_lirc(struct sasem_context *context)
-{
-       int retval;
-       int minor = context->driver->minor;
-
-       retval = lirc_unregister_driver(minor);
-       if (retval)
-               err("%s: unable to deregister from lirc (%d)",
-                       __func__, retval);
-       else
-               printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n",
-                      minor);
-
-}
-
-/**
- * Called when the VFD device (e.g. /dev/usb/lcd)
- * is opened by the application.
- */
-static int vfd_open(struct inode *inode, struct file *file)
-{
-       struct usb_interface *interface;
-       struct sasem_context *context = NULL;
-       int subminor;
-       int retval = 0;
-
-       /* prevent races with disconnect */
-       mutex_lock(&disconnect_lock);
-
-       subminor = iminor(inode);
-       interface = usb_find_interface(&sasem_driver, subminor);
-       if (!interface) {
-               err("%s: could not find interface for minor %d",
-                   __func__, subminor);
-               retval = -ENODEV;
-               goto exit;
-       }
-       context = usb_get_intfdata(interface);
-
-       if (!context) {
-               err("%s: no context found for minor %d",
-                                       __func__, subminor);
-               retval = -ENODEV;
-               goto exit;
-       }
-
-       mutex_lock(&context->ctx_lock);
-
-       if (context->vfd_isopen) {
-               err("%s: VFD port is already open", __func__);
-               retval = -EBUSY;
-       } else {
-               context->vfd_isopen = 1;
-               file->private_data = context;
-               printk(KERN_INFO "VFD port opened\n");
-       }
-
-       mutex_unlock(&context->ctx_lock);
-
-exit:
-       mutex_unlock(&disconnect_lock);
-       return retval;
-}
-
-/**
- * Called when the VFD device (e.g. /dev/usb/lcd)
- * is closed by the application.
- */
-static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg)
-{
-       struct sasem_context *context = NULL;
-
-       context = (struct sasem_context *) file->private_data;
-
-       if (!context) {
-               err("%s: no context for device", __func__);
-               return -ENODEV;
-       }
-
-       mutex_lock(&context->ctx_lock);
-
-       switch (cmd) {
-       case IOCTL_LCD_CONTRAST:
-               if (arg > 1000)
-                       arg = 1000;
-               context->vfd_contrast = (unsigned int)arg;
-               break;
-       default:
-               printk(KERN_INFO "Unknown IOCTL command\n");
-               mutex_unlock(&context->ctx_lock);
-               return -ENOIOCTLCMD;  /* not supported */
-       }
-
-       mutex_unlock(&context->ctx_lock);
-       return 0;
-}
-
-/**
- * Called when the VFD device (e.g. /dev/usb/lcd)
- * is closed by the application.
- */
-static int vfd_close(struct inode *inode, struct file *file)
-{
-       struct sasem_context *context = NULL;
-       int retval = 0;
-
-       context = (struct sasem_context *) file->private_data;
-
-       if (!context) {
-               err("%s: no context for device", __func__);
-               return -ENODEV;
-       }
-
-       mutex_lock(&context->ctx_lock);
-
-       if (!context->vfd_isopen) {
-               err("%s: VFD is not open", __func__);
-               retval = -EIO;
-       } else {
-               context->vfd_isopen = 0;
-               printk(KERN_INFO "VFD port closed\n");
-               if (!context->dev_present && !context->ir_isopen) {
-
-                       /* Device disconnected before close and IR port is
-                        * not open. If IR port is open, context will be
-                        * deleted by ir_close. */
-                       mutex_unlock(&context->ctx_lock);
-                       delete_context(context);
-                       return retval;
-               }
-       }
-
-       mutex_unlock(&context->ctx_lock);
-       return retval;
-}
-
-/**
- * Sends a packet to the VFD.
- */
-static int send_packet(struct sasem_context *context)
-{
-       unsigned int pipe;
-       int interval = 0;
-       int retval = 0;
-
-       pipe = usb_sndintpipe(context->dev,
-                       context->tx_endpoint->bEndpointAddress);
-       interval = context->tx_endpoint->bInterval;
-
-       usb_fill_int_urb(context->tx_urb, context->dev, pipe,
-               context->usb_tx_buf, sizeof(context->usb_tx_buf),
-               usb_tx_callback, context, interval);
-
-       context->tx_urb->actual_length = 0;
-
-       init_completion(&context->tx.finished);
-       atomic_set(&(context->tx.busy), 1);
-
-       retval =  usb_submit_urb(context->tx_urb, GFP_KERNEL);
-       if (retval) {
-               atomic_set(&(context->tx.busy), 0);
-               err("%s: error submitting urb (%d)", __func__, retval);
-       } else {
-               /* Wait for transmission to complete (or abort) */
-               mutex_unlock(&context->ctx_lock);
-               wait_for_completion(&context->tx.finished);
-               mutex_lock(&context->ctx_lock);
-
-               retval = context->tx.status;
-               if (retval)
-                       err("%s: packet tx failed (%d)", __func__, retval);
-       }
-
-       return retval;
-}
-
-/**
- * Writes data to the VFD.  The Sasem VFD is 2x16 characters
- * and requires data in 9 consecutive USB interrupt packets,
- * each packet carrying 8 bytes.
- */
-static ssize_t vfd_write(struct file *file, const char *buf,
-                               size_t n_bytes, loff_t *pos)
-{
-       int i;
-       int retval = 0;
-       struct sasem_context *context;
-       int *data_buf = NULL;
-
-       context = (struct sasem_context *) file->private_data;
-       if (!context) {
-               err("%s: no context for device", __func__);
-               return -ENODEV;
-       }
-
-       mutex_lock(&context->ctx_lock);
-
-       if (!context->dev_present) {
-               err("%s: no Sasem device present", __func__);
-               retval = -ENODEV;
-               goto exit;
-       }
-
-       if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) {
-               err("%s: invalid payload size", __func__);
-               retval = -EINVAL;
-               goto exit;
-       }
-
-       data_buf = memdup_user(buf, n_bytes);
-       if (IS_ERR(data_buf)) {
-               retval = PTR_ERR(data_buf);
-               goto exit;
-       }
-
-       memcpy(context->tx.data_buf, data_buf, n_bytes);
-
-       /* Pad with spaces */
-       for (i = n_bytes; i < SASEM_DATA_BUF_SZ; ++i)
-               context->tx.data_buf[i] = ' ';
-
-       /* Nine 8 byte packets to be sent */
-       /* NOTE: "\x07\x01\0\0\0\0\0\0" or "\x0c\0\0\0\0\0\0\0"
-        *       will clear the VFD */
-       for (i = 0; i < 9; i++) {
-               switch (i) {
-               case 0:
-                       memcpy(context->usb_tx_buf, "\x07\0\0\0\0\0\0\0", 8);
-                       context->usb_tx_buf[1] = (context->vfd_contrast) ?
-                               (0x2B - (context->vfd_contrast - 1) / 250)
-                               : 0x2B;
-                       break;
-               case 1:
-                       memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8);
-                       break;
-               case 2:
-                       memcpy(context->usb_tx_buf, "\x0b\x01\0\0\0\0\0\0", 8);
-                       break;
-               case 3:
-                       memcpy(context->usb_tx_buf, context->tx.data_buf, 8);
-                       break;
-               case 4:
-                       memcpy(context->usb_tx_buf,
-                              context->tx.data_buf + 8, 8);
-                       break;
-               case 5:
-                       memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8);
-                       break;
-               case 6:
-                       memcpy(context->usb_tx_buf, "\x0b\x02\0\0\0\0\0\0", 8);
-                       break;
-               case 7:
-                       memcpy(context->usb_tx_buf,
-                              context->tx.data_buf + 16, 8);
-                       break;
-               case 8:
-                       memcpy(context->usb_tx_buf,
-                              context->tx.data_buf + 24, 8);
-                       break;
-               }
-               retval = send_packet(context);
-               if (retval) {
-
-                       err("%s: send packet failed for packet #%d",
-                                       __func__, i);
-                       goto exit;
-               }
-       }
-exit:
-
-       mutex_unlock(&context->ctx_lock);
-       kfree(data_buf);
-
-       return (!retval) ? n_bytes : retval;
-}
-
-/**
- * Callback function for USB core API: transmit data
- */
-static void usb_tx_callback(struct urb *urb)
-{
-       struct sasem_context *context;
-
-       if (!urb)
-               return;
-       context = (struct sasem_context *) urb->context;
-       if (!context)
-               return;
-
-       context->tx.status = urb->status;
-
-       /* notify waiters that write has finished */
-       atomic_set(&context->tx.busy, 0);
-       complete(&context->tx.finished);
-
-       return;
-}
-
-/**
- * Called by lirc_dev when the application opens /dev/lirc
- */
-static int ir_open(void *data)
-{
-       int retval = 0;
-       struct sasem_context *context;
-
-       /* prevent races with disconnect */
-       mutex_lock(&disconnect_lock);
-
-       context = (struct sasem_context *) data;
-
-       mutex_lock(&context->ctx_lock);
-
-       if (context->ir_isopen) {
-               err("%s: IR port is already open", __func__);
-               retval = -EBUSY;
-               goto exit;
-       }
-
-       usb_fill_int_urb(context->rx_urb, context->dev,
-               usb_rcvintpipe(context->dev,
-                               context->rx_endpoint->bEndpointAddress),
-               context->usb_rx_buf, sizeof(context->usb_rx_buf),
-               usb_rx_callback, context, context->rx_endpoint->bInterval);
-
-       retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
-
-       if (retval)
-               err("%s: usb_submit_urb failed for ir_open (%d)",
-                   __func__, retval);
-       else {
-               context->ir_isopen = 1;
-               printk(KERN_INFO "IR port opened\n");
-       }
-
-exit:
-       mutex_unlock(&context->ctx_lock);
-
-       mutex_unlock(&disconnect_lock);
-       return retval;
-}
-
-/**
- * Called by lirc_dev when the application closes /dev/lirc
- */
-static void ir_close(void *data)
-{
-       struct sasem_context *context;
-
-       context = (struct sasem_context *)data;
-       if (!context) {
-               err("%s: no context for device", __func__);
-               return;
-       }
-
-       mutex_lock(&context->ctx_lock);
-
-       usb_kill_urb(context->rx_urb);
-       context->ir_isopen = 0;
-       printk(KERN_INFO "IR port closed\n");
-
-       if (!context->dev_present) {
-
-               /*
-                * Device disconnected while IR port was
-                * still open. Driver was not deregistered
-                * at disconnect time, so do it now.
-                */
-               deregister_from_lirc(context);
-
-               if (!context->vfd_isopen) {
-
-                       mutex_unlock(&context->ctx_lock);
-                       delete_context(context);
-                       return;
-               }
-               /* If VFD port is open, context will be deleted by vfd_close */
-       }
-
-       mutex_unlock(&context->ctx_lock);
-       return;
-}
-
-/**
- * Process the incoming packet
- */
-static void incoming_packet(struct sasem_context *context,
-                                  struct urb *urb)
-{
-       int len = urb->actual_length;
-       unsigned char *buf = urb->transfer_buffer;
-       long ms;
-       struct timeval tv;
-       int i;
-
-       if (len != 8) {
-               printk(KERN_WARNING "%s: invalid incoming packet size (%d)\n",
-                    __func__, len);
-               return;
-       }
-
-       if (debug) {
-               printk(KERN_INFO "Incoming data: ");
-               for (i = 0; i < 8; ++i)
-                       printk(KERN_CONT "%02x ", buf[i]);
-               printk(KERN_CONT "\n");
-       }
-
-       /*
-        * Lirc could deal with the repeat code, but we really need to block it
-        * if it arrives too late.  Otherwise we could repeat the wrong code.
-        */
-
-       /* get the time since the last button press */
-       do_gettimeofday(&tv);
-       ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 +
-            (tv.tv_usec - context->presstime.tv_usec) / 1000;
-
-       if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) {
-               /*
-                * the repeat code is being sent, so we copy
-                * the old code to LIRC
-                */
-
-               /*
-                * NOTE: Only if the last code was less than 250ms ago
-                * - no one should be able to push another (undetected) button
-                *   in that time and then get a false repeat of the previous
-                *   press but it is long enough for a genuine repeat
-                */
-               if ((ms < 250) && (context->codesaved != 0)) {
-                       memcpy(buf, &context->lastcode, 8);
-                       context->presstime.tv_sec = tv.tv_sec;
-                       context->presstime.tv_usec = tv.tv_usec;
-               }
-       } else {
-               /* save the current valid code for repeats */
-               memcpy(&context->lastcode, buf, 8);
-               /*
-                * set flag to signal a valid code was save;
-                * just for safety reasons
-                */
-               context->codesaved = 1;
-               context->presstime.tv_sec = tv.tv_sec;
-               context->presstime.tv_usec = tv.tv_usec;
-       }
-
-       lirc_buffer_write(context->driver->rbuf, buf);
-       wake_up(&context->driver->rbuf->wait_poll);
-}
-
-/**
- * Callback function for USB core API: receive data
- */
-static void usb_rx_callback(struct urb *urb)
-{
-       struct sasem_context *context;
-
-       if (!urb)
-               return;
-       context = (struct sasem_context *) urb->context;
-       if (!context)
-               return;
-
-       switch (urb->status) {
-
-       case -ENOENT:           /* usbcore unlink successful! */
-               return;
-
-       case 0:
-               if (context->ir_isopen)
-                       incoming_packet(context, urb);
-               break;
-
-       default:
-               printk(KERN_WARNING "%s: status (%d): ignored",
-                        __func__, urb->status);
-               break;
-       }
-
-       usb_submit_urb(context->rx_urb, GFP_ATOMIC);
-       return;
-}
-
-
-
-/**
- * Callback function for USB core API: Probe
- */
-static int sasem_probe(struct usb_interface *interface,
-                       const struct usb_device_id *id)
-{
-       struct usb_device *dev = NULL;
-       struct usb_host_interface *iface_desc = NULL;
-       struct usb_endpoint_descriptor *rx_endpoint = NULL;
-       struct usb_endpoint_descriptor *tx_endpoint = NULL;
-       struct urb *rx_urb = NULL;
-       struct urb *tx_urb = NULL;
-       struct lirc_driver *driver = NULL;
-       struct lirc_buffer *rbuf = NULL;
-       int lirc_minor = 0;
-       int num_endpoints;
-       int retval = 0;
-       int vfd_ep_found;
-       int ir_ep_found;
-       int alloc_status;
-       struct sasem_context *context = NULL;
-       int i;
-
-       printk(KERN_INFO "%s: found Sasem device\n", __func__);
-
-
-       dev = usb_get_dev(interface_to_usbdev(interface));
-       iface_desc = interface->cur_altsetting;
-       num_endpoints = iface_desc->desc.bNumEndpoints;
-
-       /*
-        * Scan the endpoint list and set:
-        *      first input endpoint = IR endpoint
-        *      first output endpoint = VFD endpoint
-        */
-
-       ir_ep_found = 0;
-       vfd_ep_found = 0;
-
-       for (i = 0; i < num_endpoints && !(ir_ep_found && vfd_ep_found); ++i) {
-
-               struct usb_endpoint_descriptor *ep;
-               int ep_dir;
-               int ep_type;
-               ep = &iface_desc->endpoint [i].desc;
-               ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
-               ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
-
-               if (!ir_ep_found &&
-                       ep_dir == USB_DIR_IN &&
-                       ep_type == USB_ENDPOINT_XFER_INT) {
-
-                       rx_endpoint = ep;
-                       ir_ep_found = 1;
-                       if (debug)
-                               printk(KERN_INFO "%s: found IR endpoint\n",
-                                      __func__);
-
-               } else if (!vfd_ep_found &&
-                       ep_dir == USB_DIR_OUT &&
-                       ep_type == USB_ENDPOINT_XFER_INT) {
-
-                       tx_endpoint = ep;
-                       vfd_ep_found = 1;
-                       if (debug)
-                               printk(KERN_INFO "%s: found VFD endpoint\n",
-                                      __func__);
-               }
-       }
-
-       /* Input endpoint is mandatory */
-       if (!ir_ep_found) {
-
-               err("%s: no valid input (IR) endpoint found.", __func__);
-               retval = -ENODEV;
-               goto exit;
-       }
-
-       if (!vfd_ep_found)
-               printk(KERN_INFO "%s: no valid output (VFD) endpoint found.\n",
-                      __func__);
-
-
-       /* Allocate memory */
-       alloc_status = 0;
-
-       context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL);
-       if (!context) {
-               err("%s: kzalloc failed for context", __func__);
-               alloc_status = 1;
-               goto alloc_status_switch;
-       }
-       driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
-       if (!driver) {
-               err("%s: kzalloc failed for lirc_driver", __func__);
-               alloc_status = 2;
-               goto alloc_status_switch;
-       }
-       rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
-       if (!rbuf) {
-               err("%s: kmalloc failed for lirc_buffer", __func__);
-               alloc_status = 3;
-               goto alloc_status_switch;
-       }
-       if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
-               err("%s: lirc_buffer_init failed", __func__);
-               alloc_status = 4;
-               goto alloc_status_switch;
-       }
-       rx_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!rx_urb) {
-               err("%s: usb_alloc_urb failed for IR urb", __func__);
-               alloc_status = 5;
-               goto alloc_status_switch;
-       }
-       if (vfd_ep_found) {
-               tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!tx_urb) {
-                       err("%s: usb_alloc_urb failed for VFD urb",
-                           __func__);
-                       alloc_status = 6;
-                       goto alloc_status_switch;
-               }
-       }
-
-       mutex_init(&context->ctx_lock);
-
-       strcpy(driver->name, MOD_NAME);
-       driver->minor = -1;
-       driver->code_length = 64;
-       driver->sample_rate = 0;
-       driver->features = LIRC_CAN_REC_LIRCCODE;
-       driver->data = context;
-       driver->rbuf = rbuf;
-       driver->set_use_inc = ir_open;
-       driver->set_use_dec = ir_close;
-       driver->dev   = &interface->dev;
-       driver->owner = THIS_MODULE;
-
-       mutex_lock(&context->ctx_lock);
-
-       lirc_minor = lirc_register_driver(driver);
-       if (lirc_minor < 0) {
-               err("%s: lirc_register_driver failed", __func__);
-               alloc_status = 7;
-               retval = lirc_minor;
-               goto unlock;
-       } else
-               printk(KERN_INFO "%s: Registered Sasem driver (minor:%d)\n",
-                       __func__, lirc_minor);
-
-       /* Needed while unregistering! */
-       driver->minor = lirc_minor;
-
-       context->dev = dev;
-       context->dev_present = 1;
-       context->rx_endpoint = rx_endpoint;
-       context->rx_urb = rx_urb;
-       if (vfd_ep_found) {
-               context->tx_endpoint = tx_endpoint;
-               context->tx_urb = tx_urb;
-               context->vfd_contrast = 1000;   /* range 0 - 1000 */
-       }
-       context->driver = driver;
-
-       usb_set_intfdata(interface, context);
-
-       if (vfd_ep_found) {
-
-               if (debug)
-                       printk(KERN_INFO "Registering VFD with sysfs\n");
-               if (usb_register_dev(interface, &sasem_class))
-                       /* Not a fatal error, so ignore */
-                       printk(KERN_INFO "%s: could not get a minor number "
-                              "for VFD\n", __func__);
-       }
-
-       printk(KERN_INFO "%s: Sasem device on usb<%d:%d> initialized\n",
-                       __func__, dev->bus->busnum, dev->devnum);
-unlock:
-       mutex_unlock(&context->ctx_lock);
-
-alloc_status_switch:
-       switch (alloc_status) {
-
-       case 7:
-               if (vfd_ep_found)
-                       usb_free_urb(tx_urb);
-       case 6:
-               usb_free_urb(rx_urb);
-       case 5:
-               lirc_buffer_free(rbuf);
-       case 4:
-               kfree(rbuf);
-       case 3:
-               kfree(driver);
-       case 2:
-               kfree(context);
-               context = NULL;
-       case 1:
-               if (retval == 0)
-                       retval = -ENOMEM;
-       }
-
-exit:
-       return retval;
-}
-
-/**
- * Callback function for USB core API: disonnect
- */
-static void sasem_disconnect(struct usb_interface *interface)
-{
-       struct sasem_context *context;
-
-       /* prevent races with ir_open()/vfd_open() */
-       mutex_lock(&disconnect_lock);
-
-       context = usb_get_intfdata(interface);
-       mutex_lock(&context->ctx_lock);
-
-       printk(KERN_INFO "%s: Sasem device disconnected\n", __func__);
-
-       usb_set_intfdata(interface, NULL);
-       context->dev_present = 0;
-
-       /* Stop reception */
-       usb_kill_urb(context->rx_urb);
-
-       /* Abort ongoing write */
-       if (atomic_read(&context->tx.busy)) {
-
-               usb_kill_urb(context->tx_urb);
-               wait_for_completion(&context->tx.finished);
-       }
-
-       /* De-register from lirc_dev if IR port is not open */
-       if (!context->ir_isopen)
-               deregister_from_lirc(context);
-
-       usb_deregister_dev(interface, &sasem_class);
-
-       mutex_unlock(&context->ctx_lock);
-
-       if (!context->ir_isopen && !context->vfd_isopen)
-               delete_context(context);
-
-       mutex_unlock(&disconnect_lock);
-}
-
-static int __init sasem_init(void)
-{
-       int rc;
-
-       printk(KERN_INFO MOD_DESC ", v" MOD_VERSION "\n");
-       printk(KERN_INFO MOD_AUTHOR "\n");
-
-       rc = usb_register(&sasem_driver);
-       if (rc < 0) {
-               err("%s: usb register failed (%d)", __func__, rc);
-               return -ENODEV;
-       }
-       return 0;
-}
-
-static void __exit sasem_exit(void)
-{
-       usb_deregister(&sasem_driver);
-       printk(KERN_INFO "module removed. Goodbye!\n");
-}
-
-
-module_init(sasem_init);
-module_exit(sasem_exit);
diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/lirc/lirc_serial.c
deleted file mode 100644 (file)
index 8a060a8..0000000
+++ /dev/null
@@ -1,1315 +0,0 @@
-/*
- * lirc_serial.c
- *
- * lirc_serial - Device driver that records pulse- and pause-lengths
- *            (space-lengths) between DDCD event on a serial port.
- *
- * Copyright (C) 1996,97 Ralph Metzler <rjkm@thp.uni-koeln.de>
- * Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu>
- * Copyright (C) 1998 Ben Pfaff <blp@gnu.org>
- * Copyright (C) 1999 Christoph Bartelmus <lirc@bartelmus.de>
- * Copyright (C) 2007 Andrei Tanas <andrei@tanas.ca> (suspend/resume support)
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-/*
- * Steve's changes to improve transmission fidelity:
- *   - for systems with the rdtsc instruction and the clock counter, a
- *     send_pule that times the pulses directly using the counter.
- *     This means that the LIRC_SERIAL_TRANSMITTER_LATENCY fudge is
- *     not needed. Measurement shows very stable waveform, even where
- *     PCI activity slows the access to the UART, which trips up other
- *     versions.
- *   - For other system, non-integer-microsecond pulse/space lengths,
- *     done using fixed point binary. So, much more accurate carrier
- *     frequency.
- *   - fine tuned transmitter latency, taking advantage of fractional
- *     microseconds in previous change
- *   - Fixed bug in the way transmitter latency was accounted for by
- *     tuning the pulse lengths down - the send_pulse routine ignored
- *     this overhead as it timed the overall pulse length - so the
- *     pulse frequency was right but overall pulse length was too
- *     long. Fixed by accounting for latency on each pulse/space
- *     iteration.
- *
- * Steve Davies <steve@daviesfam.org>  July 2001
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/serial_reg.h>
-#include <linux/time.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/poll.h>
-#include <linux/platform_device.h>
-
-#include <asm/system.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/fcntl.h>
-#include <linux/spinlock.h>
-
-#ifdef CONFIG_LIRC_SERIAL_NSLU2
-#include <asm/hardware.h>
-#endif
-/* From Intel IXP42X Developer's Manual (#252480-005): */
-/* ftp://download.intel.com/design/network/manuals/25248005.pdf */
-#define UART_IE_IXP42X_UUE   0x40 /* IXP42X UART Unit enable */
-#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-#define LIRC_DRIVER_NAME "lirc_serial"
-
-struct lirc_serial {
-       int signal_pin;
-       int signal_pin_change;
-       u8 on;
-       u8 off;
-       long (*send_pulse)(unsigned long length);
-       void (*send_space)(long length);
-       int features;
-       spinlock_t lock;
-};
-
-#define LIRC_HOMEBREW          0
-#define LIRC_IRDEO             1
-#define LIRC_IRDEO_REMOTE      2
-#define LIRC_ANIMAX            3
-#define LIRC_IGOR              4
-#define LIRC_NSLU2             5
-
-/*** module parameters ***/
-static int type;
-static int io;
-static int irq;
-static int iommap;
-static int ioshift;
-static int softcarrier = 1;
-static int share_irq;
-static int debug;
-static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */
-static int txsense;    /* 0 = active high, 1 = active low */
-
-#define dprintk(fmt, args...)                                  \
-       do {                                                    \
-               if (debug)                                      \
-                       printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
-                              fmt, ## args);                   \
-       } while (0)
-
-/* forward declarations */
-static long send_pulse_irdeo(unsigned long length);
-static long send_pulse_homebrew(unsigned long length);
-static void send_space_irdeo(long length);
-static void send_space_homebrew(long length);
-
-static struct lirc_serial hardware[] = {
-       [LIRC_HOMEBREW] = {
-               .signal_pin        = UART_MSR_DCD,
-               .signal_pin_change = UART_MSR_DDCD,
-               .on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
-               .off = (UART_MCR_RTS | UART_MCR_OUT2),
-               .send_pulse = send_pulse_homebrew,
-               .send_space = send_space_homebrew,
-#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
-               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
-                               LIRC_CAN_SET_SEND_CARRIER |
-                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
-#else
-               .features    = LIRC_CAN_REC_MODE2
-#endif
-       },
-
-       [LIRC_IRDEO] = {
-               .signal_pin        = UART_MSR_DSR,
-               .signal_pin_change = UART_MSR_DDSR,
-               .on  = UART_MCR_OUT2,
-               .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
-               .send_pulse  = send_pulse_irdeo,
-               .send_space  = send_space_irdeo,
-               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
-                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
-       },
-
-       [LIRC_IRDEO_REMOTE] = {
-               .signal_pin        = UART_MSR_DSR,
-               .signal_pin_change = UART_MSR_DDSR,
-               .on  = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
-               .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
-               .send_pulse  = send_pulse_irdeo,
-               .send_space  = send_space_irdeo,
-               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
-                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
-       },
-
-       [LIRC_ANIMAX] = {
-               .signal_pin        = UART_MSR_DCD,
-               .signal_pin_change = UART_MSR_DDCD,
-               .on  = 0,
-               .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
-               .send_pulse = NULL,
-               .send_space = NULL,
-               .features   = LIRC_CAN_REC_MODE2
-       },
-
-       [LIRC_IGOR] = {
-               .signal_pin        = UART_MSR_DSR,
-               .signal_pin_change = UART_MSR_DDSR,
-               .on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
-               .off = (UART_MCR_RTS | UART_MCR_OUT2),
-               .send_pulse = send_pulse_homebrew,
-               .send_space = send_space_homebrew,
-#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
-               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
-                               LIRC_CAN_SET_SEND_CARRIER |
-                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
-#else
-               .features    = LIRC_CAN_REC_MODE2
-#endif
-       },
-
-#ifdef CONFIG_LIRC_SERIAL_NSLU2
-       /*
-        * Modified Linksys Network Storage Link USB 2.0 (NSLU2):
-        * We receive on CTS of the 2nd serial port (R142,LHS), we
-        * transmit with a IR diode between GPIO[1] (green status LED),
-        * and ground (Matthias Goebl <matthias.goebl@goebl.net>).
-        * See also http://www.nslu2-linux.org for this device
-        */
-       [LIRC_NSLU2] = {
-               .signal_pin        = UART_MSR_CTS,
-               .signal_pin_change = UART_MSR_DCTS,
-               .on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
-               .off = (UART_MCR_RTS | UART_MCR_OUT2),
-               .send_pulse = send_pulse_homebrew,
-               .send_space = send_space_homebrew,
-#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
-               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
-                               LIRC_CAN_SET_SEND_CARRIER |
-                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
-#else
-               .features    = LIRC_CAN_REC_MODE2
-#endif
-       },
-#endif
-
-};
-
-#define RS_ISR_PASS_LIMIT 256
-
-/*
- * A long pulse code from a remote might take up to 300 bytes.  The
- * daemon should read the bytes as soon as they are generated, so take
- * the number of keys you think you can push before the daemon runs
- * and multiply by 300.  The driver will warn you if you overrun this
- * buffer.  If you have a slow computer or non-busmastering IDE disks,
- * maybe you will need to increase this.
- */
-
-/* This MUST be a power of two!  It has to be larger than 1 as well. */
-
-#define RBUF_LEN 256
-
-static struct timeval lasttv = {0, 0};
-
-static struct lirc_buffer rbuf;
-
-static unsigned int freq = 38000;
-static unsigned int duty_cycle = 50;
-
-/* Initialized in init_timing_params() */
-static unsigned long period;
-static unsigned long pulse_width;
-static unsigned long space_width;
-
-#if defined(__i386__)
-/*
- * From:
- * Linux I/O port programming mini-HOWTO
- * Author: Riku Saikkonen <Riku.Saikkonen@hut.fi>
- * v, 28 December 1997
- *
- * [...]
- * Actually, a port I/O instruction on most ports in the 0-0x3ff range
- * takes almost exactly 1 microsecond, so if you're, for example, using
- * the parallel port directly, just do additional inb()s from that port
- * to delay.
- * [...]
- */
-/* transmitter latency 1.5625us 0x1.90 - this figure arrived at from
- * comment above plus trimming to match actual measured frequency.
- * This will be sensitive to cpu speed, though hopefully most of the 1.5us
- * is spent in the uart access.  Still - for reference test machine was a
- * 1.13GHz Athlon system - Steve
- */
-
-/*
- * changed from 400 to 450 as this works better on slower machines;
- * faster machines will use the rdtsc code anyway
- */
-#define LIRC_SERIAL_TRANSMITTER_LATENCY 450
-
-#else
-
-/* does anybody have information on other platforms ? */
-/* 256 = 1<<8 */
-#define LIRC_SERIAL_TRANSMITTER_LATENCY 256
-
-#endif  /* __i386__ */
-/*
- * FIXME: should we be using hrtimers instead of this
- * LIRC_SERIAL_TRANSMITTER_LATENCY nonsense?
- */
-
-/* fetch serial input packet (1 byte) from register offset */
-static u8 sinp(int offset)
-{
-       if (iommap != 0)
-               /* the register is memory-mapped */
-               offset <<= ioshift;
-
-       return inb(io + offset);
-}
-
-/* write serial output packet (1 byte) of value to register offset */
-static void soutp(int offset, u8 value)
-{
-       if (iommap != 0)
-               /* the register is memory-mapped */
-               offset <<= ioshift;
-
-       outb(value, io + offset);
-}
-
-static void on(void)
-{
-#ifdef CONFIG_LIRC_SERIAL_NSLU2
-       /*
-        * On NSLU2, we put the transmit diode between the output of the green
-        * status LED and ground
-        */
-       if (type == LIRC_NSLU2) {
-               gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_LOW);
-               return;
-       }
-#endif
-       if (txsense)
-               soutp(UART_MCR, hardware[type].off);
-       else
-               soutp(UART_MCR, hardware[type].on);
-}
-
-static void off(void)
-{
-#ifdef CONFIG_LIRC_SERIAL_NSLU2
-       if (type == LIRC_NSLU2) {
-               gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_HIGH);
-               return;
-       }
-#endif
-       if (txsense)
-               soutp(UART_MCR, hardware[type].on);
-       else
-               soutp(UART_MCR, hardware[type].off);
-}
-
-#ifndef MAX_UDELAY_MS
-#define MAX_UDELAY_US 5000
-#else
-#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
-#endif
-
-static void safe_udelay(unsigned long usecs)
-{
-       while (usecs > MAX_UDELAY_US) {
-               udelay(MAX_UDELAY_US);
-               usecs -= MAX_UDELAY_US;
-       }
-       udelay(usecs);
-}
-
-#ifdef USE_RDTSC
-/*
- * This is an overflow/precision juggle, complicated in that we can't
- * do long long divide in the kernel
- */
-
-/*
- * When we use the rdtsc instruction to measure clocks, we keep the
- * pulse and space widths as clock cycles.  As this is CPU speed
- * dependent, the widths must be calculated in init_port and ioctl
- * time
- */
-
-/* So send_pulse can quickly convert microseconds to clocks */
-static unsigned long conv_us_to_clocks;
-
-static int init_timing_params(unsigned int new_duty_cycle,
-               unsigned int new_freq)
-{
-       __u64 loops_per_sec, work;
-
-       duty_cycle = new_duty_cycle;
-       freq = new_freq;
-
-       loops_per_sec = __this_cpu_read(cpu.info.loops_per_jiffy);
-       loops_per_sec *= HZ;
-
-       /* How many clocks in a microsecond?, avoiding long long divide */
-       work = loops_per_sec;
-       work *= 4295;  /* 4295 = 2^32 / 1e6 */
-       conv_us_to_clocks = (work >> 32);
-
-       /*
-        * Carrier period in clocks, approach good up to 32GHz clock,
-        * gets carrier frequency within 8Hz
-        */
-       period = loops_per_sec >> 3;
-       period /= (freq >> 3);
-
-       /* Derive pulse and space from the period */
-       pulse_width = period * duty_cycle / 100;
-       space_width = period - pulse_width;
-       dprintk("in init_timing_params, freq=%d, duty_cycle=%d, "
-               "clk/jiffy=%ld, pulse=%ld, space=%ld, "
-               "conv_us_to_clocks=%ld\n",
-               freq, duty_cycle, __this_cpu_read(cpu_info.loops_per_jiffy),
-               pulse_width, space_width, conv_us_to_clocks);
-       return 0;
-}
-#else /* ! USE_RDTSC */
-static int init_timing_params(unsigned int new_duty_cycle,
-               unsigned int new_freq)
-{
-/*
- * period, pulse/space width are kept with 8 binary places -
- * IE multiplied by 256.
- */
-       if (256 * 1000000L / new_freq * new_duty_cycle / 100 <=
-           LIRC_SERIAL_TRANSMITTER_LATENCY)
-               return -EINVAL;
-       if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <=
-           LIRC_SERIAL_TRANSMITTER_LATENCY)
-               return -EINVAL;
-       duty_cycle = new_duty_cycle;
-       freq = new_freq;
-       period = 256 * 1000000L / freq;
-       pulse_width = period * duty_cycle / 100;
-       space_width = period - pulse_width;
-       dprintk("in init_timing_params, freq=%d pulse=%ld, "
-               "space=%ld\n", freq, pulse_width, space_width);
-       return 0;
-}
-#endif /* USE_RDTSC */
-
-
-/* return value: space length delta */
-
-static long send_pulse_irdeo(unsigned long length)
-{
-       long rawbits, ret;
-       int i;
-       unsigned char output;
-       unsigned char chunk, shifted;
-
-       /* how many bits have to be sent ? */
-       rawbits = length * 1152 / 10000;
-       if (duty_cycle > 50)
-               chunk = 3;
-       else
-               chunk = 1;
-       for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) {
-               shifted = chunk << (i * 3);
-               shifted >>= 1;
-               output &= (~shifted);
-               i++;
-               if (i == 3) {
-                       soutp(UART_TX, output);
-                       while (!(sinp(UART_LSR) & UART_LSR_THRE))
-                               ;
-                       output = 0x7f;
-                       i = 0;
-               }
-       }
-       if (i != 0) {
-               soutp(UART_TX, output);
-               while (!(sinp(UART_LSR) & UART_LSR_TEMT))
-                       ;
-       }
-
-       if (i == 0)
-               ret = (-rawbits) * 10000 / 1152;
-       else
-               ret = (3 - i) * 3 * 10000 / 1152 + (-rawbits) * 10000 / 1152;
-
-       return ret;
-}
-
-#ifdef USE_RDTSC
-/* Version that uses Pentium rdtsc instruction to measure clocks */
-
-/*
- * This version does sub-microsecond timing using rdtsc instruction,
- * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY
- * Implicitly i586 architecture...  - Steve
- */
-
-static long send_pulse_homebrew_softcarrier(unsigned long length)
-{
-       int flag;
-       unsigned long target, start, now;
-
-       /* Get going quick as we can */
-       rdtscl(start);
-       on();
-       /* Convert length from microseconds to clocks */
-       length *= conv_us_to_clocks;
-       /* And loop till time is up - flipping at right intervals */
-       now = start;
-       target = pulse_width;
-       flag = 1;
-       /*
-        * FIXME: This looks like a hard busy wait, without even an occasional,
-        * polite, cpu_relax() call.  There's got to be a better way?
-        *
-        * The i2c code has the result of a lot of bit-banging work, I wonder if
-        * there's something there which could be helpful here.
-        */
-       while ((now - start) < length) {
-               /* Delay till flip time */
-               do {
-                       rdtscl(now);
-               } while ((now - start) < target);
-
-               /* flip */
-               if (flag) {
-                       rdtscl(now);
-                       off();
-                       target += space_width;
-               } else {
-                       rdtscl(now); on();
-                       target += pulse_width;
-               }
-               flag = !flag;
-       }
-       rdtscl(now);
-       return ((now - start) - length) / conv_us_to_clocks;
-}
-#else /* ! USE_RDTSC */
-/* Version using udelay() */
-
-/*
- * here we use fixed point arithmetic, with 8
- * fractional bits.  that gets us within 0.1% or so of the right average
- * frequency, albeit with some jitter in pulse length - Steve
- */
-
-/* To match 8 fractional bits used for pulse/space length */
-
-static long send_pulse_homebrew_softcarrier(unsigned long length)
-{
-       int flag;
-       unsigned long actual, target, d;
-       length <<= 8;
-
-       actual = 0; target = 0; flag = 0;
-       while (actual < length) {
-               if (flag) {
-                       off();
-                       target += space_width;
-               } else {
-                       on();
-                       target += pulse_width;
-               }
-               d = (target - actual -
-                    LIRC_SERIAL_TRANSMITTER_LATENCY + 128) >> 8;
-               /*
-                * Note - we've checked in ioctl that the pulse/space
-                * widths are big enough so that d is > 0
-                */
-               udelay(d);
-               actual += (d << 8) + LIRC_SERIAL_TRANSMITTER_LATENCY;
-               flag = !flag;
-       }
-       return (actual-length) >> 8;
-}
-#endif /* USE_RDTSC */
-
-static long send_pulse_homebrew(unsigned long length)
-{
-       if (length <= 0)
-               return 0;
-
-       if (softcarrier)
-               return send_pulse_homebrew_softcarrier(length);
-       else {
-               on();
-               safe_udelay(length);
-               return 0;
-       }
-}
-
-static void send_space_irdeo(long length)
-{
-       if (length <= 0)
-               return;
-
-       safe_udelay(length);
-}
-
-static void send_space_homebrew(long length)
-{
-       off();
-       if (length <= 0)
-               return;
-       safe_udelay(length);
-}
-
-static void rbwrite(int l)
-{
-       if (lirc_buffer_full(&rbuf)) {
-               /* no new signals will be accepted */
-               dprintk("Buffer overrun\n");
-               return;
-       }
-       lirc_buffer_write(&rbuf, (void *)&l);
-}
-
-static void frbwrite(int l)
-{
-       /* simple noise filter */
-       static int pulse, space;
-       static unsigned int ptr;
-
-       if (ptr > 0 && (l & PULSE_BIT)) {
-               pulse += l & PULSE_MASK;
-               if (pulse > 250) {
-                       rbwrite(space);
-                       rbwrite(pulse | PULSE_BIT);
-                       ptr = 0;
-                       pulse = 0;
-               }
-               return;
-       }
-       if (!(l & PULSE_BIT)) {
-               if (ptr == 0) {
-                       if (l > 20000) {
-                               space = l;
-                               ptr++;
-                               return;
-                       }
-               } else {
-                       if (l > 20000) {
-                               space += pulse;
-                               if (space > PULSE_MASK)
-                                       space = PULSE_MASK;
-                               space += l;
-                               if (space > PULSE_MASK)
-                                       space = PULSE_MASK;
-                               pulse = 0;
-                               return;
-                       }
-                       rbwrite(space);
-                       rbwrite(pulse | PULSE_BIT);
-                       ptr = 0;
-                       pulse = 0;
-               }
-       }
-       rbwrite(l);
-}
-
-static irqreturn_t irq_handler(int i, void *blah)
-{
-       struct timeval tv;
-       int counter, dcd;
-       u8 status;
-       long deltv;
-       int data;
-       static int last_dcd = -1;
-
-       if ((sinp(UART_IIR) & UART_IIR_NO_INT)) {
-               /* not our interrupt */
-               return IRQ_NONE;
-       }
-
-       counter = 0;
-       do {
-               counter++;
-               status = sinp(UART_MSR);
-               if (counter > RS_ISR_PASS_LIMIT) {
-                       printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: "
-                              "We're caught!\n");
-                       break;
-               }
-               if ((status & hardware[type].signal_pin_change)
-                   && sense != -1) {
-                       /* get current time */
-                       do_gettimeofday(&tv);
-
-                       /* New mode, written by Trent Piepho
-                          <xyzzy@u.washington.edu>. */
-
-                       /*
-                        * The old format was not very portable.
-                        * We now use an int to pass pulses
-                        * and spaces to user space.
-                        *
-                        * If PULSE_BIT is set a pulse has been
-                        * received, otherwise a space has been
-                        * received.  The driver needs to know if your
-                        * receiver is active high or active low, or
-                        * the space/pulse sense could be
-                        * inverted. The bits denoted by PULSE_MASK are
-                        * the length in microseconds. Lengths greater
-                        * than or equal to 16 seconds are clamped to
-                        * PULSE_MASK.  All other bits are unused.
-                        * This is a much simpler interface for user
-                        * programs, as well as eliminating "out of
-                        * phase" errors with space/pulse
-                        * autodetection.
-                        */
-
-                       /* calc time since last interrupt in microseconds */
-                       dcd = (status & hardware[type].signal_pin) ? 1 : 0;
-
-                       if (dcd == last_dcd) {
-                               printk(KERN_WARNING LIRC_DRIVER_NAME
-                               ": ignoring spike: %d %d %lx %lx %lx %lx\n",
-                               dcd, sense,
-                               tv.tv_sec, lasttv.tv_sec,
-                               tv.tv_usec, lasttv.tv_usec);
-                               continue;
-                       }
-
-                       deltv = tv.tv_sec-lasttv.tv_sec;
-                       if (tv.tv_sec < lasttv.tv_sec ||
-                           (tv.tv_sec == lasttv.tv_sec &&
-                            tv.tv_usec < lasttv.tv_usec)) {
-                               printk(KERN_WARNING LIRC_DRIVER_NAME
-                                      ": AIEEEE: your clock just jumped "
-                                      "backwards\n");
-                               printk(KERN_WARNING LIRC_DRIVER_NAME
-                                      ": %d %d %lx %lx %lx %lx\n",
-                                      dcd, sense,
-                                      tv.tv_sec, lasttv.tv_sec,
-                                      tv.tv_usec, lasttv.tv_usec);
-                               data = PULSE_MASK;
-                       } else if (deltv > 15) {
-                               data = PULSE_MASK; /* really long time */
-                               if (!(dcd^sense)) {
-                                       /* sanity check */
-                                       printk(KERN_WARNING LIRC_DRIVER_NAME
-                                              ": AIEEEE: "
-                                              "%d %d %lx %lx %lx %lx\n",
-                                              dcd, sense,
-                                              tv.tv_sec, lasttv.tv_sec,
-                                              tv.tv_usec, lasttv.tv_usec);
-                                       /*
-                                        * detecting pulse while this
-                                        * MUST be a space!
-                                        */
-                                       sense = sense ? 0 : 1;
-                               }
-                       } else
-                               data = (int) (deltv*1000000 +
-                                              tv.tv_usec -
-                                              lasttv.tv_usec);
-                       frbwrite(dcd^sense ? data : (data|PULSE_BIT));
-                       lasttv = tv;
-                       last_dcd = dcd;
-                       wake_up_interruptible(&rbuf.wait_poll);
-               }
-       } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */
-       return IRQ_HANDLED;
-}
-
-
-static int hardware_init_port(void)
-{
-       u8 scratch, scratch2, scratch3;
-
-       /*
-        * This is a simple port existence test, borrowed from the autoconfig
-        * function in drivers/serial/8250.c
-        */
-       scratch = sinp(UART_IER);
-       soutp(UART_IER, 0);
-#ifdef __i386__
-       outb(0xff, 0x080);
-#endif
-       scratch2 = sinp(UART_IER) & 0x0f;
-       soutp(UART_IER, 0x0f);
-#ifdef __i386__
-       outb(0x00, 0x080);
-#endif
-       scratch3 = sinp(UART_IER) & 0x0f;
-       soutp(UART_IER, scratch);
-       if (scratch2 != 0 || scratch3 != 0x0f) {
-               /* we fail, there's nothing here */
-               printk(KERN_ERR LIRC_DRIVER_NAME ": port existence test "
-                      "failed, cannot continue\n");
-               return -EINVAL;
-       }
-
-
-
-       /* Set DLAB 0. */
-       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
-
-       /* First of all, disable all interrupts */
-       soutp(UART_IER, sinp(UART_IER) &
-             (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
-
-       /* Clear registers. */
-       sinp(UART_LSR);
-       sinp(UART_RX);
-       sinp(UART_IIR);
-       sinp(UART_MSR);
-
-#ifdef CONFIG_LIRC_SERIAL_NSLU2
-       if (type == LIRC_NSLU2) {
-               /* Setup NSLU2 UART */
-
-               /* Enable UART */
-               soutp(UART_IER, sinp(UART_IER) | UART_IE_IXP42X_UUE);
-               /* Disable Receiver data Time out interrupt */
-               soutp(UART_IER, sinp(UART_IER) & ~UART_IE_IXP42X_RTOIE);
-               /* set out2 = interrupt unmask; off() doesn't set MCR
-                  on NSLU2 */
-               soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
-       }
-#endif
-
-       /* Set line for power source */
-       off();
-
-       /* Clear registers again to be sure. */
-       sinp(UART_LSR);
-       sinp(UART_RX);
-       sinp(UART_IIR);
-       sinp(UART_MSR);
-
-       switch (type) {
-       case LIRC_IRDEO:
-       case LIRC_IRDEO_REMOTE:
-               /* setup port to 7N1 @ 115200 Baud */
-               /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */
-
-               /* Set DLAB 1. */
-               soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
-               /* Set divisor to 1 => 115200 Baud */
-               soutp(UART_DLM, 0);
-               soutp(UART_DLL, 1);
-               /* Set DLAB 0 +  7N1 */
-               soutp(UART_LCR, UART_LCR_WLEN7);
-               /* THR interrupt already disabled at this point */
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static int init_port(void)
-{
-       int i, nlow, nhigh, result;
-
-       result = request_irq(irq, irq_handler,
-                            (share_irq ? IRQF_SHARED : 0),
-                            LIRC_DRIVER_NAME, (void *)&hardware);
-
-       switch (result) {
-       case -EBUSY:
-               printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq);
-               return -EBUSY;
-       case -EINVAL:
-               printk(KERN_ERR LIRC_DRIVER_NAME
-                      ": Bad irq number or handler\n");
-               return -EINVAL;
-       default:
-               break;
-       };
-
-       /* Reserve io region. */
-       /*
-        * Future MMAP-Developers: Attention!
-        * For memory mapped I/O you *might* need to use ioremap() first,
-        * for the NSLU2 it's done in boot code.
-        */
-       if (((iommap != 0)
-            && (request_mem_region(iommap, 8 << ioshift,
-                                   LIRC_DRIVER_NAME) == NULL))
-          || ((iommap == 0)
-              && (request_region(io, 8, LIRC_DRIVER_NAME) == NULL))) {
-               printk(KERN_ERR  LIRC_DRIVER_NAME
-                      ": port %04x already in use\n", io);
-               printk(KERN_WARNING LIRC_DRIVER_NAME
-                      ": use 'setserial /dev/ttySX uart none'\n");
-               printk(KERN_WARNING LIRC_DRIVER_NAME
-                      ": or compile the serial port driver as module and\n");
-               printk(KERN_WARNING LIRC_DRIVER_NAME
-                      ": make sure this module is loaded first\n");
-               return -EBUSY;
-       }
-
-       if (hardware_init_port() < 0)
-               return -EINVAL;
-
-       /* Initialize pulse/space widths */
-       init_timing_params(duty_cycle, freq);
-
-       /* If pin is high, then this must be an active low receiver. */
-       if (sense == -1) {
-               /* wait 1/2 sec for the power supply */
-               msleep(500);
-
-               /*
-                * probe 9 times every 0.04s, collect "votes" for
-                * active high/low
-                */
-               nlow = 0;
-               nhigh = 0;
-               for (i = 0; i < 9; i++) {
-                       if (sinp(UART_MSR) & hardware[type].signal_pin)
-                               nlow++;
-                       else
-                               nhigh++;
-                       msleep(40);
-               }
-               sense = (nlow >= nhigh ? 1 : 0);
-               printk(KERN_INFO LIRC_DRIVER_NAME  ": auto-detected active "
-                      "%s receiver\n", sense ? "low" : "high");
-       } else
-               printk(KERN_INFO LIRC_DRIVER_NAME  ": Manually using active "
-                      "%s receiver\n", sense ? "low" : "high");
-
-       dprintk("Interrupt %d, port %04x obtained\n", irq, io);
-       return 0;
-}
-
-static int set_use_inc(void *data)
-{
-       unsigned long flags;
-
-       /* initialize timestamp */
-       do_gettimeofday(&lasttv);
-
-       spin_lock_irqsave(&hardware[type].lock, flags);
-
-       /* Set DLAB 0. */
-       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
-
-       soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI);
-
-       spin_unlock_irqrestore(&hardware[type].lock, flags);
-
-       return 0;
-}
-
-static void set_use_dec(void *data)
-{      unsigned long flags;
-
-       spin_lock_irqsave(&hardware[type].lock, flags);
-
-       /* Set DLAB 0. */
-       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
-
-       /* First of all, disable all interrupts */
-       soutp(UART_IER, sinp(UART_IER) &
-             (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
-       spin_unlock_irqrestore(&hardware[type].lock, flags);
-}
-
-static ssize_t lirc_write(struct file *file, const char *buf,
-                        size_t n, loff_t *ppos)
-{
-       int i, count;
-       unsigned long flags;
-       long delta = 0;
-       int *wbuf;
-
-       if (!(hardware[type].features & LIRC_CAN_SEND_PULSE))
-               return -EBADF;
-
-       count = n / sizeof(int);
-       if (n % sizeof(int) || count % 2 == 0)
-               return -EINVAL;
-       wbuf = memdup_user(buf, n);
-       if (IS_ERR(wbuf))
-               return PTR_ERR(wbuf);
-       spin_lock_irqsave(&hardware[type].lock, flags);
-       if (type == LIRC_IRDEO) {
-               /* DTR, RTS down */
-               on();
-       }
-       for (i = 0; i < count; i++) {
-               if (i%2)
-                       hardware[type].send_space(wbuf[i] - delta);
-               else
-                       delta = hardware[type].send_pulse(wbuf[i]);
-       }
-       off();
-       spin_unlock_irqrestore(&hardware[type].lock, flags);
-       kfree(wbuf);
-       return n;
-}
-
-static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
-{
-       int result;
-       __u32 value;
-
-       switch (cmd) {
-       case LIRC_GET_SEND_MODE:
-               if (!(hardware[type].features&LIRC_CAN_SEND_MASK))
-                       return -ENOIOCTLCMD;
-
-               result = put_user(LIRC_SEND2MODE
-                                 (hardware[type].features&LIRC_CAN_SEND_MASK),
-                                 (__u32 *) arg);
-               if (result)
-                       return result;
-               break;
-
-       case LIRC_SET_SEND_MODE:
-               if (!(hardware[type].features&LIRC_CAN_SEND_MASK))
-                       return -ENOIOCTLCMD;
-
-               result = get_user(value, (__u32 *) arg);
-               if (result)
-                       return result;
-               /* only LIRC_MODE_PULSE supported */
-               if (value != LIRC_MODE_PULSE)
-                       return -ENOSYS;
-               break;
-
-       case LIRC_GET_LENGTH:
-               return -ENOSYS;
-               break;
-
-       case LIRC_SET_SEND_DUTY_CYCLE:
-               dprintk("SET_SEND_DUTY_CYCLE\n");
-               if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE))
-                       return -ENOIOCTLCMD;
-
-               result = get_user(value, (__u32 *) arg);
-               if (result)
-                       return result;
-               if (value <= 0 || value > 100)
-                       return -EINVAL;
-               return init_timing_params(value, freq);
-               break;
-
-       case LIRC_SET_SEND_CARRIER:
-               dprintk("SET_SEND_CARRIER\n");
-               if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER))
-                       return -ENOIOCTLCMD;
-
-               result = get_user(value, (__u32 *) arg);
-               if (result)
-                       return result;
-               if (value > 500000 || value < 20000)
-                       return -EINVAL;
-               return init_timing_params(duty_cycle, value);
-               break;
-
-       default:
-               return lirc_dev_fop_ioctl(filep, cmd, arg);
-       }
-       return 0;
-}
-
-static const struct file_operations lirc_fops = {
-       .owner          = THIS_MODULE,
-       .write          = lirc_write,
-       .unlocked_ioctl = lirc_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl   = lirc_ioctl,
-#endif
-       .read           = lirc_dev_fop_read,
-       .poll           = lirc_dev_fop_poll,
-       .open           = lirc_dev_fop_open,
-       .release        = lirc_dev_fop_close,
-       .llseek         = no_llseek,
-};
-
-static struct lirc_driver driver = {
-       .name           = LIRC_DRIVER_NAME,
-       .minor          = -1,
-       .code_length    = 1,
-       .sample_rate    = 0,
-       .data           = NULL,
-       .add_to_buf     = NULL,
-       .rbuf           = &rbuf,
-       .set_use_inc    = set_use_inc,
-       .set_use_dec    = set_use_dec,
-       .fops           = &lirc_fops,
-       .dev            = NULL,
-       .owner          = THIS_MODULE,
-};
-
-static struct platform_device *lirc_serial_dev;
-
-static int __devinit lirc_serial_probe(struct platform_device *dev)
-{
-       return 0;
-}
-
-static int __devexit lirc_serial_remove(struct platform_device *dev)
-{
-       return 0;
-}
-
-static int lirc_serial_suspend(struct platform_device *dev,
-                              pm_message_t state)
-{
-       /* Set DLAB 0. */
-       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
-
-       /* Disable all interrupts */
-       soutp(UART_IER, sinp(UART_IER) &
-             (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
-
-       /* Clear registers. */
-       sinp(UART_LSR);
-       sinp(UART_RX);
-       sinp(UART_IIR);
-       sinp(UART_MSR);
-
-       return 0;
-}
-
-/* twisty maze... need a forward-declaration here... */
-static void lirc_serial_exit(void);
-
-static int lirc_serial_resume(struct platform_device *dev)
-{
-       unsigned long flags;
-
-       if (hardware_init_port() < 0) {
-               lirc_serial_exit();
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&hardware[type].lock, flags);
-       /* Enable Interrupt */
-       do_gettimeofday(&lasttv);
-       soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI);
-       off();
-
-       lirc_buffer_clear(&rbuf);
-
-       spin_unlock_irqrestore(&hardware[type].lock, flags);
-
-       return 0;
-}
-
-static struct platform_driver lirc_serial_driver = {
-       .probe          = lirc_serial_probe,
-       .remove         = __devexit_p(lirc_serial_remove),
-       .suspend        = lirc_serial_suspend,
-       .resume         = lirc_serial_resume,
-       .driver         = {
-               .name   = "lirc_serial",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init lirc_serial_init(void)
-{
-       int result;
-
-       /* Init read buffer. */
-       result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN);
-       if (result < 0)
-               return -ENOMEM;
-
-       result = platform_driver_register(&lirc_serial_driver);
-       if (result) {
-               printk("lirc register returned %d\n", result);
-               goto exit_buffer_free;
-       }
-
-       lirc_serial_dev = platform_device_alloc("lirc_serial", 0);
-       if (!lirc_serial_dev) {
-               result = -ENOMEM;
-               goto exit_driver_unregister;
-       }
-
-       result = platform_device_add(lirc_serial_dev);
-       if (result)
-               goto exit_device_put;
-
-       return 0;
-
-exit_device_put:
-       platform_device_put(lirc_serial_dev);
-exit_driver_unregister:
-       platform_driver_unregister(&lirc_serial_driver);
-exit_buffer_free:
-       lirc_buffer_free(&rbuf);
-       return result;
-}
-
-static void lirc_serial_exit(void)
-{
-       platform_device_unregister(lirc_serial_dev);
-       platform_driver_unregister(&lirc_serial_driver);
-       lirc_buffer_free(&rbuf);
-}
-
-static int __init lirc_serial_init_module(void)
-{
-       int result;
-
-       result = lirc_serial_init();
-       if (result)
-               return result;
-
-       switch (type) {
-       case LIRC_HOMEBREW:
-       case LIRC_IRDEO:
-       case LIRC_IRDEO_REMOTE:
-       case LIRC_ANIMAX:
-       case LIRC_IGOR:
-               /* if nothing specified, use ttyS0/com1 and irq 4 */
-               io = io ? io : 0x3f8;
-               irq = irq ? irq : 4;
-               break;
-#ifdef CONFIG_LIRC_SERIAL_NSLU2
-       case LIRC_NSLU2:
-               io = io ? io : IRQ_IXP4XX_UART2;
-               irq = irq ? irq : (IXP4XX_UART2_BASE_VIRT + REG_OFFSET);
-               iommap = iommap ? iommap : IXP4XX_UART2_BASE_PHYS;
-               ioshift = ioshift ? ioshift : 2;
-               break;
-#endif
-       default:
-               result = -EINVAL;
-               goto exit_serial_exit;
-       }
-       if (!softcarrier) {
-               switch (type) {
-               case LIRC_HOMEBREW:
-               case LIRC_IGOR:
-#ifdef CONFIG_LIRC_SERIAL_NSLU2
-               case LIRC_NSLU2:
-#endif
-                       hardware[type].features &=
-                               ~(LIRC_CAN_SET_SEND_DUTY_CYCLE|
-                                 LIRC_CAN_SET_SEND_CARRIER);
-                       break;
-               }
-       }
-
-       result = init_port();
-       if (result < 0)
-               goto exit_serial_exit;
-       driver.features = hardware[type].features;
-       driver.dev = &lirc_serial_dev->dev;
-       driver.minor = lirc_register_driver(&driver);
-       if (driver.minor < 0) {
-               printk(KERN_ERR  LIRC_DRIVER_NAME
-                      ": register_chrdev failed!\n");
-               result = -EIO;
-               goto exit_release;
-       }
-       return 0;
-exit_release:
-       release_region(io, 8);
-exit_serial_exit:
-       lirc_serial_exit();
-       return result;
-}
-
-static void __exit lirc_serial_exit_module(void)
-{
-       lirc_serial_exit();
-
-       free_irq(irq, (void *)&hardware);
-
-       if (iommap != 0)
-               release_mem_region(iommap, 8 << ioshift);
-       else
-               release_region(io, 8);
-       lirc_unregister_driver(driver.minor);
-       dprintk("cleaned up module\n");
-}
-
-
-module_init(lirc_serial_init_module);
-module_exit(lirc_serial_exit_module);
-
-MODULE_DESCRIPTION("Infra-red receiver driver for serial ports.");
-MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, "
-             "Christoph Bartelmus, Andrei Tanas");
-MODULE_LICENSE("GPL");
-
-module_param(type, int, S_IRUGO);
-MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo,"
-                " 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug,"
-                " 5 = NSLU2 RX:CTS2/TX:GreenLED)");
-
-module_param(io, int, S_IRUGO);
-MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");
-
-/* some architectures (e.g. intel xscale) have memory mapped registers */
-module_param(iommap, bool, S_IRUGO);
-MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O"
-               " (0 = no memory mapped io)");
-
-/*
- * some architectures (e.g. intel xscale) align the 8bit serial registers
- * on 32bit word boundaries.
- * See linux-kernel/serial/8250.c serial_in()/out()
- */
-module_param(ioshift, int, S_IRUGO);
-MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)");
-
-module_param(irq, int, S_IRUGO);
-MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");
-
-module_param(share_irq, bool, S_IRUGO);
-MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)");
-
-module_param(sense, bool, S_IRUGO);
-MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit"
-                " (0 = active high, 1 = active low )");
-
-#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
-module_param(txsense, bool, S_IRUGO);
-MODULE_PARM_DESC(txsense, "Sense of transmitter circuit"
-                " (0 = active high, 1 = active low )");
-#endif
-
-module_param(softcarrier, bool, S_IRUGO);
-MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/lirc/lirc_sir.c b/drivers/staging/lirc/lirc_sir.c
deleted file mode 100644 (file)
index 6903d39..0000000
+++ /dev/null
@@ -1,1279 +0,0 @@
-/*
- * LIRC SIR driver, (C) 2000 Milan Pikula <www@fornax.sk>
- *
- * lirc_sir - Device driver for use with SIR (serial infra red)
- * mode of IrDA on many notebooks.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- *
- * 2000/09/16 Frank Przybylski <mail@frankprzybylski.de> :
- *  added timeout and relaxed pulse detection, removed gap bug
- *
- * 2000/12/15 Christoph Bartelmus <lirc@bartelmus.de> :
- *   added support for Tekram Irmate 210 (sending does not work yet,
- *   kind of disappointing that nobody was able to implement that
- *   before),
- *   major clean-up
- *
- * 2001/02/27 Christoph Bartelmus <lirc@bartelmus.de> :
- *   added support for StrongARM SA1100 embedded microprocessor
- *   parts cut'n'pasted from sa1100_ir.c (C) 2000 Russell King
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fs.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/serial_reg.h>
-#include <linux/time.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/poll.h>
-#include <asm/system.h>
-#include <linux/io.h>
-#include <asm/irq.h>
-#include <linux/fcntl.h>
-#ifdef LIRC_ON_SA1100
-#include <asm/hardware.h>
-#ifdef CONFIG_SA1100_COLLIE
-#include <asm/arch/tc35143.h>
-#include <asm/ucb1200.h>
-#endif
-#endif
-
-#include <linux/timer.h>
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-/* SECTION: Definitions */
-
-/*** Tekram dongle ***/
-#ifdef LIRC_SIR_TEKRAM
-/* stolen from kernel source */
-/* definitions for Tekram dongle */
-#define TEKRAM_115200 0x00
-#define TEKRAM_57600  0x01
-#define TEKRAM_38400  0x02
-#define TEKRAM_19200  0x03
-#define TEKRAM_9600   0x04
-#define TEKRAM_2400   0x08
-
-#define TEKRAM_PW 0x10 /* Pulse select bit */
-
-/* 10bit * 1s/115200bit in milliseconds = 87ms*/
-#define TIME_CONST (10000000ul/115200ul)
-
-#endif
-
-#ifdef LIRC_SIR_ACTISYS_ACT200L
-static void init_act200(void);
-#elif defined(LIRC_SIR_ACTISYS_ACT220L)
-static void init_act220(void);
-#endif
-
-/*** SA1100 ***/
-#ifdef LIRC_ON_SA1100
-struct sa1100_ser2_registers {
-       /* HSSP control register */
-       unsigned char hscr0;
-       /* UART registers */
-       unsigned char utcr0;
-       unsigned char utcr1;
-       unsigned char utcr2;
-       unsigned char utcr3;
-       unsigned char utcr4;
-       unsigned char utdr;
-       unsigned char utsr0;
-       unsigned char utsr1;
-} sr;
-
-static int irq = IRQ_Ser2ICP;
-
-#define LIRC_ON_SA1100_TRANSMITTER_LATENCY 0
-
-/* pulse/space ratio of 50/50 */
-static unsigned long pulse_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY);
-/* 1000000/freq-pulse_width */
-static unsigned long space_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY);
-static unsigned int freq = 38000;      /* modulation frequency */
-static unsigned int duty_cycle = 50;   /* duty cycle of 50% */
-
-#endif
-
-#define RBUF_LEN 1024
-#define WBUF_LEN 1024
-
-#define LIRC_DRIVER_NAME "lirc_sir"
-
-#define PULSE '['
-
-#ifndef LIRC_SIR_TEKRAM
-/* 9bit * 1s/115200bit in milli seconds = 78.125ms*/
-#define TIME_CONST (9000000ul/115200ul)
-#endif
-
-
-/* timeout for sequences in jiffies (=5/100s), must be longer than TIME_CONST */
-#define SIR_TIMEOUT    (HZ*5/100)
-
-#ifndef LIRC_ON_SA1100
-#ifndef LIRC_IRQ
-#define LIRC_IRQ 4
-#endif
-#ifndef LIRC_PORT
-/* for external dongles, default to com1 */
-#if defined(LIRC_SIR_ACTISYS_ACT200L)         || \
-           defined(LIRC_SIR_ACTISYS_ACT220L) || \
-           defined(LIRC_SIR_TEKRAM)
-#define LIRC_PORT 0x3f8
-#else
-/* onboard sir ports are typically com3 */
-#define LIRC_PORT 0x3e8
-#endif
-#endif
-
-static int io = LIRC_PORT;
-static int irq = LIRC_IRQ;
-static int threshold = 3;
-#endif
-
-static DEFINE_SPINLOCK(timer_lock);
-static struct timer_list timerlist;
-/* time of last signal change detected */
-static struct timeval last_tv = {0, 0};
-/* time of last UART data ready interrupt */
-static struct timeval last_intr_tv = {0, 0};
-static int last_value;
-
-static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue);
-
-static DEFINE_SPINLOCK(hardware_lock);
-
-static int rx_buf[RBUF_LEN];
-static unsigned int rx_tail, rx_head;
-
-static int debug;
-#define dprintk(fmt, args...)                                          \
-       do {                                                            \
-               if (debug)                                              \
-                       printk(KERN_DEBUG LIRC_DRIVER_NAME ": "         \
-                               fmt, ## args);                          \
-       } while (0)
-
-/* SECTION: Prototypes */
-
-/* Communication with user-space */
-static unsigned int lirc_poll(struct file *file, poll_table *wait);
-static ssize_t lirc_read(struct file *file, char *buf, size_t count,
-               loff_t *ppos);
-static ssize_t lirc_write(struct file *file, const char *buf, size_t n,
-               loff_t *pos);
-static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
-static void add_read_queue(int flag, unsigned long val);
-static int init_chrdev(void);
-static void drop_chrdev(void);
-/* Hardware */
-static irqreturn_t sir_interrupt(int irq, void *dev_id);
-static void send_space(unsigned long len);
-static void send_pulse(unsigned long len);
-static int init_hardware(void);
-static void drop_hardware(void);
-/* Initialisation */
-static int init_port(void);
-static void drop_port(void);
-
-#ifdef LIRC_ON_SA1100
-static void on(void)
-{
-       PPSR |= PPC_TXD2;
-}
-
-static void off(void)
-{
-       PPSR &= ~PPC_TXD2;
-}
-#else
-static inline unsigned int sinp(int offset)
-{
-       return inb(io + offset);
-}
-
-static inline void soutp(int offset, int value)
-{
-       outb(value, io + offset);
-}
-#endif
-
-#ifndef MAX_UDELAY_MS
-#define MAX_UDELAY_US 5000
-#else
-#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
-#endif
-
-static void safe_udelay(unsigned long usecs)
-{
-       while (usecs > MAX_UDELAY_US) {
-               udelay(MAX_UDELAY_US);
-               usecs -= MAX_UDELAY_US;
-       }
-       udelay(usecs);
-}
-
-/* SECTION: Communication with user-space */
-
-static unsigned int lirc_poll(struct file *file, poll_table *wait)
-{
-       poll_wait(file, &lirc_read_queue, wait);
-       if (rx_head != rx_tail)
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-static ssize_t lirc_read(struct file *file, char *buf, size_t count,
-               loff_t *ppos)
-{
-       int n = 0;
-       int retval = 0;
-       DECLARE_WAITQUEUE(wait, current);
-
-       if (count % sizeof(int))
-               return -EINVAL;
-
-       add_wait_queue(&lirc_read_queue, &wait);
-       set_current_state(TASK_INTERRUPTIBLE);
-       while (n < count) {
-               if (rx_head != rx_tail) {
-                       if (copy_to_user((void *) buf + n,
-                                       (void *) (rx_buf + rx_head),
-                                       sizeof(int))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-                       rx_head = (rx_head + 1) & (RBUF_LEN - 1);
-                       n += sizeof(int);
-               } else {
-                       if (file->f_flags & O_NONBLOCK) {
-                               retval = -EAGAIN;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               retval = -ERESTARTSYS;
-                               break;
-                       }
-                       schedule();
-                       set_current_state(TASK_INTERRUPTIBLE);
-               }
-       }
-       remove_wait_queue(&lirc_read_queue, &wait);
-       set_current_state(TASK_RUNNING);
-       return n ? n : retval;
-}
-static ssize_t lirc_write(struct file *file, const char *buf, size_t n,
-                               loff_t *pos)
-{
-       unsigned long flags;
-       int i, count;
-       int *tx_buf;
-
-       count = n / sizeof(int);
-       if (n % sizeof(int) || count % 2 == 0)
-               return -EINVAL;
-       tx_buf = memdup_user(buf, n);
-       if (IS_ERR(tx_buf))
-               return PTR_ERR(tx_buf);
-       i = 0;
-#ifdef LIRC_ON_SA1100
-       /* disable receiver */
-       Ser2UTCR3 = 0;
-#endif
-       local_irq_save(flags);
-       while (1) {
-               if (i >= count)
-                       break;
-               if (tx_buf[i])
-                       send_pulse(tx_buf[i]);
-               i++;
-               if (i >= count)
-                       break;
-               if (tx_buf[i])
-                       send_space(tx_buf[i]);
-               i++;
-       }
-       local_irq_restore(flags);
-#ifdef LIRC_ON_SA1100
-       off();
-       udelay(1000); /* wait 1ms for IR diode to recover */
-       Ser2UTCR3 = 0;
-       /* clear status register to prevent unwanted interrupts */
-       Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
-       /* enable receiver */
-       Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE;
-#endif
-       kfree(tx_buf);
-       return count;
-}
-
-static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
-{
-       int retval = 0;
-       __u32 value = 0;
-#ifdef LIRC_ON_SA1100
-
-       if (cmd == LIRC_GET_FEATURES)
-               value = LIRC_CAN_SEND_PULSE |
-                       LIRC_CAN_SET_SEND_DUTY_CYCLE |
-                       LIRC_CAN_SET_SEND_CARRIER |
-                       LIRC_CAN_REC_MODE2;
-       else if (cmd == LIRC_GET_SEND_MODE)
-               value = LIRC_MODE_PULSE;
-       else if (cmd == LIRC_GET_REC_MODE)
-               value = LIRC_MODE_MODE2;
-#else
-       if (cmd == LIRC_GET_FEATURES)
-               value = LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
-       else if (cmd == LIRC_GET_SEND_MODE)
-               value = LIRC_MODE_PULSE;
-       else if (cmd == LIRC_GET_REC_MODE)
-               value = LIRC_MODE_MODE2;
-#endif
-
-       switch (cmd) {
-       case LIRC_GET_FEATURES:
-       case LIRC_GET_SEND_MODE:
-       case LIRC_GET_REC_MODE:
-               retval = put_user(value, (__u32 *) arg);
-               break;
-
-       case LIRC_SET_SEND_MODE:
-       case LIRC_SET_REC_MODE:
-               retval = get_user(value, (__u32 *) arg);
-               break;
-#ifdef LIRC_ON_SA1100
-       case LIRC_SET_SEND_DUTY_CYCLE:
-               retval = get_user(value, (__u32 *) arg);
-               if (retval)
-                       return retval;
-               if (value <= 0 || value > 100)
-                       return -EINVAL;
-               /* (value/100)*(1000000/freq) */
-               duty_cycle = value;
-               pulse_width = (unsigned long) duty_cycle*10000/freq;
-               space_width = (unsigned long) 1000000L/freq-pulse_width;
-               if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
-                       pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
-               if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
-                       space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
-               break;
-       case LIRC_SET_SEND_CARRIER:
-               retval = get_user(value, (__u32 *) arg);
-               if (retval)
-                       return retval;
-               if (value > 500000 || value < 20000)
-                       return -EINVAL;
-               freq = value;
-               pulse_width = (unsigned long) duty_cycle*10000/freq;
-               space_width = (unsigned long) 1000000L/freq-pulse_width;
-               if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
-                       pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
-               if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
-                       space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
-               break;
-#endif
-       default:
-               retval = -ENOIOCTLCMD;
-
-       }
-
-       if (retval)
-               return retval;
-       if (cmd == LIRC_SET_REC_MODE) {
-               if (value != LIRC_MODE_MODE2)
-                       retval = -ENOSYS;
-       } else if (cmd == LIRC_SET_SEND_MODE) {
-               if (value != LIRC_MODE_PULSE)
-                       retval = -ENOSYS;
-       }
-
-       return retval;
-}
-
-static void add_read_queue(int flag, unsigned long val)
-{
-       unsigned int new_rx_tail;
-       int newval;
-
-       dprintk("add flag %d with val %lu\n", flag, val);
-
-       newval = val & PULSE_MASK;
-
-       /*
-        * statistically, pulses are ~TIME_CONST/2 too long. we could
-        * maybe make this more exact, but this is good enough
-        */
-       if (flag) {
-               /* pulse */
-               if (newval > TIME_CONST/2)
-                       newval -= TIME_CONST/2;
-               else /* should not ever happen */
-                       newval = 1;
-               newval |= PULSE_BIT;
-       } else {
-               newval += TIME_CONST/2;
-       }
-       new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1);
-       if (new_rx_tail == rx_head) {
-               dprintk("Buffer overrun.\n");
-               return;
-       }
-       rx_buf[rx_tail] = newval;
-       rx_tail = new_rx_tail;
-       wake_up_interruptible(&lirc_read_queue);
-}
-
-static const struct file_operations lirc_fops = {
-       .owner          = THIS_MODULE,
-       .read           = lirc_read,
-       .write          = lirc_write,
-       .poll           = lirc_poll,
-       .unlocked_ioctl = lirc_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl   = lirc_ioctl,
-#endif
-       .open           = lirc_dev_fop_open,
-       .release        = lirc_dev_fop_close,
-       .llseek         = no_llseek,
-};
-
-static int set_use_inc(void *data)
-{
-       return 0;
-}
-
-static void set_use_dec(void *data)
-{
-}
-
-static struct lirc_driver driver = {
-       .name           = LIRC_DRIVER_NAME,
-       .minor          = -1,
-       .code_length    = 1,
-       .sample_rate    = 0,
-       .data           = NULL,
-       .add_to_buf     = NULL,
-       .set_use_inc    = set_use_inc,
-       .set_use_dec    = set_use_dec,
-       .fops           = &lirc_fops,
-       .dev            = NULL,
-       .owner          = THIS_MODULE,
-};
-
-
-static int init_chrdev(void)
-{
-       driver.minor = lirc_register_driver(&driver);
-       if (driver.minor < 0) {
-               printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n");
-               return -EIO;
-       }
-       return 0;
-}
-
-static void drop_chrdev(void)
-{
-       lirc_unregister_driver(driver.minor);
-}
-
-/* SECTION: Hardware */
-static long delta(struct timeval *tv1, struct timeval *tv2)
-{
-       unsigned long deltv;
-
-       deltv = tv2->tv_sec - tv1->tv_sec;
-       if (deltv > 15)
-               deltv = 0xFFFFFF;
-       else
-               deltv = deltv*1000000 +
-                       tv2->tv_usec -
-                       tv1->tv_usec;
-       return deltv;
-}
-
-static void sir_timeout(unsigned long data)
-{
-       /*
-        * if last received signal was a pulse, but receiving stopped
-        * within the 9 bit frame, we need to finish this pulse and
-        * simulate a signal change to from pulse to space. Otherwise
-        * upper layers will receive two sequences next time.
-        */
-
-       unsigned long flags;
-       unsigned long pulse_end;
-
-       /* avoid interference with interrupt */
-       spin_lock_irqsave(&timer_lock, flags);
-       if (last_value) {
-#ifndef LIRC_ON_SA1100
-               /* clear unread bits in UART and restart */
-               outb(UART_FCR_CLEAR_RCVR, io + UART_FCR);
-#endif
-               /* determine 'virtual' pulse end: */
-               pulse_end = delta(&last_tv, &last_intr_tv);
-               dprintk("timeout add %d for %lu usec\n", last_value, pulse_end);
-               add_read_queue(last_value, pulse_end);
-               last_value = 0;
-               last_tv = last_intr_tv;
-       }
-       spin_unlock_irqrestore(&timer_lock, flags);
-}
-
-static irqreturn_t sir_interrupt(int irq, void *dev_id)
-{
-       unsigned char data;
-       struct timeval curr_tv;
-       static unsigned long deltv;
-#ifdef LIRC_ON_SA1100
-       int status;
-       static int n;
-
-       status = Ser2UTSR0;
-       /*
-        * Deal with any receive errors first.  The bytes in error may be
-        * the only bytes in the receive FIFO, so we do this first.
-        */
-       while (status & UTSR0_EIF) {
-               int bstat;
-
-               if (debug) {
-                       dprintk("EIF\n");
-                       bstat = Ser2UTSR1;
-
-                       if (bstat & UTSR1_FRE)
-                               dprintk("frame error\n");
-                       if (bstat & UTSR1_ROR)
-                               dprintk("receive fifo overrun\n");
-                       if (bstat & UTSR1_PRE)
-                               dprintk("parity error\n");
-               }
-
-               bstat = Ser2UTDR;
-               n++;
-               status = Ser2UTSR0;
-       }
-
-       if (status & (UTSR0_RFS | UTSR0_RID)) {
-               do_gettimeofday(&curr_tv);
-               deltv = delta(&last_tv, &curr_tv);
-               do {
-                       data = Ser2UTDR;
-                       dprintk("%d data: %u\n", n, (unsigned int) data);
-                       n++;
-               } while (status & UTSR0_RID && /* do not empty fifo in order to
-                                               * get UTSR0_RID in any case */
-                     Ser2UTSR1 & UTSR1_RNE); /* data ready */
-
-               if (status&UTSR0_RID) {
-                       add_read_queue(0 , deltv - n * TIME_CONST); /*space*/
-                       add_read_queue(1, n * TIME_CONST); /*pulse*/
-                       n = 0;
-                       last_tv = curr_tv;
-               }
-       }
-
-       if (status & UTSR0_TFS)
-               printk(KERN_ERR "transmit fifo not full, shouldn't happen\n");
-
-       /* We must clear certain bits. */
-       status &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
-       if (status)
-               Ser2UTSR0 = status;
-#else
-       unsigned long deltintrtv;
-       unsigned long flags;
-       int iir, lsr;
-
-       while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) {
-               switch (iir&UART_IIR_ID) { /* FIXME toto treba preriedit */
-               case UART_IIR_MSI:
-                       (void) inb(io + UART_MSR);
-                       break;
-               case UART_IIR_RLSI:
-                       (void) inb(io + UART_LSR);
-                       break;
-               case UART_IIR_THRI:
-#if 0
-                       if (lsr & UART_LSR_THRE) /* FIFO is empty */
-                               outb(data, io + UART_TX)
-#endif
-                       break;
-               case UART_IIR_RDI:
-                       /* avoid interference with timer */
-                       spin_lock_irqsave(&timer_lock, flags);
-                       do {
-                               del_timer(&timerlist);
-                               data = inb(io + UART_RX);
-                               do_gettimeofday(&curr_tv);
-                               deltv = delta(&last_tv, &curr_tv);
-                               deltintrtv = delta(&last_intr_tv, &curr_tv);
-                               dprintk("t %lu, d %d\n", deltintrtv, (int)data);
-                               /*
-                                * if nothing came in last X cycles,
-                                * it was gap
-                                */
-                               if (deltintrtv > TIME_CONST * threshold) {
-                                       if (last_value) {
-                                               dprintk("GAP\n");
-                                               /* simulate signal change */
-                                               add_read_queue(last_value,
-                                                              deltv -
-                                                              deltintrtv);
-                                               last_value = 0;
-                                               last_tv.tv_sec =
-                                                       last_intr_tv.tv_sec;
-                                               last_tv.tv_usec =
-                                                       last_intr_tv.tv_usec;
-                                               deltv = deltintrtv;
-                                       }
-                               }
-                               data = 1;
-                               if (data ^ last_value) {
-                                       /*
-                                        * deltintrtv > 2*TIME_CONST, remember?
-                                        * the other case is timeout
-                                        */
-                                       add_read_queue(last_value,
-                                                      deltv-TIME_CONST);
-                                       last_value = data;
-                                       last_tv = curr_tv;
-                                       if (last_tv.tv_usec >= TIME_CONST) {
-                                               last_tv.tv_usec -= TIME_CONST;
-                                       } else {
-                                               last_tv.tv_sec--;
-                                               last_tv.tv_usec += 1000000 -
-                                                       TIME_CONST;
-                                       }
-                               }
-                               last_intr_tv = curr_tv;
-                               if (data) {
-                                       /*
-                                        * start timer for end of
-                                        * sequence detection
-                                        */
-                                       timerlist.expires = jiffies +
-                                                               SIR_TIMEOUT;
-                                       add_timer(&timerlist);
-                               }
-
-                               lsr = inb(io + UART_LSR);
-                       } while (lsr & UART_LSR_DR); /* data ready */
-                       spin_unlock_irqrestore(&timer_lock, flags);
-                       break;
-               default:
-                       break;
-               }
-       }
-#endif
-       return IRQ_RETVAL(IRQ_HANDLED);
-}
-
-#ifdef LIRC_ON_SA1100
-static void send_pulse(unsigned long length)
-{
-       unsigned long k, delay;
-       int flag;
-
-       if (length == 0)
-               return;
-       /*
-        * this won't give us the carrier frequency we really want
-        * due to integer arithmetic, but we can accept this inaccuracy
-        */
-
-       for (k = flag = 0; k < length; k += delay, flag = !flag) {
-               if (flag) {
-                       off();
-                       delay = space_width;
-               } else {
-                       on();
-                       delay = pulse_width;
-               }
-               safe_udelay(delay);
-       }
-       off();
-}
-
-static void send_space(unsigned long length)
-{
-       if (length == 0)
-               return;
-       off();
-       safe_udelay(length);
-}
-#else
-static void send_space(unsigned long len)
-{
-       safe_udelay(len);
-}
-
-static void send_pulse(unsigned long len)
-{
-       long bytes_out = len / TIME_CONST;
-
-       if (bytes_out == 0)
-               bytes_out++;
-
-       while (bytes_out--) {
-               outb(PULSE, io + UART_TX);
-               /* FIXME treba seriozne cakanie z char/serial.c */
-               while (!(inb(io + UART_LSR) & UART_LSR_THRE))
-                       ;
-       }
-}
-#endif
-
-#ifdef CONFIG_SA1100_COLLIE
-static int sa1100_irda_set_power_collie(int state)
-{
-       if (state) {
-               /*
-                *  0 - off
-                *  1 - short range, lowest power
-                *  2 - medium range, medium power
-                *  3 - maximum range, high power
-                */
-               ucb1200_set_io_direction(TC35143_GPIO_IR_ON,
-                                        TC35143_IODIR_OUTPUT);
-               ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_LOW);
-               udelay(100);
-       } else {
-               /* OFF */
-               ucb1200_set_io_direction(TC35143_GPIO_IR_ON,
-                                        TC35143_IODIR_OUTPUT);
-               ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_HIGH);
-       }
-       return 0;
-}
-#endif
-
-static int init_hardware(void)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&hardware_lock, flags);
-       /* reset UART */
-#ifdef LIRC_ON_SA1100
-#ifdef CONFIG_SA1100_BITSY
-       if (machine_is_bitsy()) {
-               printk(KERN_INFO "Power on IR module\n");
-               set_bitsy_egpio(EGPIO_BITSY_IR_ON);
-       }
-#endif
-#ifdef CONFIG_SA1100_COLLIE
-       sa1100_irda_set_power_collie(3);        /* power on */
-#endif
-       sr.hscr0 = Ser2HSCR0;
-
-       sr.utcr0 = Ser2UTCR0;
-       sr.utcr1 = Ser2UTCR1;
-       sr.utcr2 = Ser2UTCR2;
-       sr.utcr3 = Ser2UTCR3;
-       sr.utcr4 = Ser2UTCR4;
-
-       sr.utdr = Ser2UTDR;
-       sr.utsr0 = Ser2UTSR0;
-       sr.utsr1 = Ser2UTSR1;
-
-       /* configure GPIO */
-       /* output */
-       PPDR |= PPC_TXD2;
-       PSDR |= PPC_TXD2;
-       /* set output to 0 */
-       off();
-
-       /* Enable HP-SIR modulation, and ensure that the port is disabled. */
-       Ser2UTCR3 = 0;
-       Ser2HSCR0 = sr.hscr0 & (~HSCR0_HSSP);
-
-       /* clear status register to prevent unwanted interrupts */
-       Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
-
-       /* 7N1 */
-       Ser2UTCR0 = UTCR0_1StpBit|UTCR0_7BitData;
-       /* 115200 */
-       Ser2UTCR1 = 0;
-       Ser2UTCR2 = 1;
-       /* use HPSIR, 1.6 usec pulses */
-       Ser2UTCR4 = UTCR4_HPSIR|UTCR4_Z1_6us;
-
-       /* enable receiver, receive fifo interrupt */
-       Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE;
-
-       /* clear status register to prevent unwanted interrupts */
-       Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
-
-#elif defined(LIRC_SIR_TEKRAM)
-       /* disable FIFO */
-       soutp(UART_FCR,
-             UART_FCR_CLEAR_RCVR|
-             UART_FCR_CLEAR_XMIT|
-             UART_FCR_TRIGGER_1);
-
-       /* Set DLAB 0. */
-       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
-
-       /* First of all, disable all interrupts */
-       soutp(UART_IER, sinp(UART_IER) &
-             (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
-
-       /* Set DLAB 1. */
-       soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
-
-       /* Set divisor to 12 => 9600 Baud */
-       soutp(UART_DLM, 0);
-       soutp(UART_DLL, 12);
-
-       /* Set DLAB 0. */
-       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
-
-       /* power supply */
-       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
-       safe_udelay(50*1000);
-
-       /* -DTR low -> reset PIC */
-       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
-       udelay(1*1000);
-
-       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
-       udelay(100);
-
-
-       /* -RTS low -> send control byte */
-       soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
-       udelay(7);
-       soutp(UART_TX, TEKRAM_115200|TEKRAM_PW);
-
-       /* one byte takes ~1042 usec to transmit at 9600,8N1 */
-       udelay(1500);
-
-       /* back to normal operation */
-       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
-       udelay(50);
-
-       udelay(1500);
-
-       /* read previous control byte */
-       printk(KERN_INFO LIRC_DRIVER_NAME
-              ": 0x%02x\n", sinp(UART_RX));
-
-       /* Set DLAB 1. */
-       soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
-
-       /* Set divisor to 1 => 115200 Baud */
-       soutp(UART_DLM, 0);
-       soutp(UART_DLL, 1);
-
-       /* Set DLAB 0, 8 Bit */
-       soutp(UART_LCR, UART_LCR_WLEN8);
-       /* enable interrupts */
-       soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI);
-#else
-       outb(0, io + UART_MCR);
-       outb(0, io + UART_IER);
-       /* init UART */
-       /* set DLAB, speed = 115200 */
-       outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR);
-       outb(1, io + UART_DLL); outb(0, io + UART_DLM);
-       /* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */
-       outb(UART_LCR_WLEN7, io + UART_LCR);
-       /* FIFO operation */
-       outb(UART_FCR_ENABLE_FIFO, io + UART_FCR);
-       /* interrupts */
-       /* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */
-       outb(UART_IER_RDI, io + UART_IER);
-       /* turn on UART */
-       outb(UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2, io + UART_MCR);
-#ifdef LIRC_SIR_ACTISYS_ACT200L
-       init_act200();
-#elif defined(LIRC_SIR_ACTISYS_ACT220L)
-       init_act220();
-#endif
-#endif
-       spin_unlock_irqrestore(&hardware_lock, flags);
-       return 0;
-}
-
-static void drop_hardware(void)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&hardware_lock, flags);
-
-#ifdef LIRC_ON_SA1100
-       Ser2UTCR3 = 0;
-
-       Ser2UTCR0 = sr.utcr0;
-       Ser2UTCR1 = sr.utcr1;
-       Ser2UTCR2 = sr.utcr2;
-       Ser2UTCR4 = sr.utcr4;
-       Ser2UTCR3 = sr.utcr3;
-
-       Ser2HSCR0 = sr.hscr0;
-#ifdef CONFIG_SA1100_BITSY
-       if (machine_is_bitsy())
-               clr_bitsy_egpio(EGPIO_BITSY_IR_ON);
-#endif
-#ifdef CONFIG_SA1100_COLLIE
-       sa1100_irda_set_power_collie(0);        /* power off */
-#endif
-#else
-       /* turn off interrupts */
-       outb(0, io + UART_IER);
-#endif
-       spin_unlock_irqrestore(&hardware_lock, flags);
-}
-
-/* SECTION: Initialisation */
-
-static int init_port(void)
-{
-       int retval;
-
-       /* get I/O port access and IRQ line */
-#ifndef LIRC_ON_SA1100
-       if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) {
-               printk(KERN_ERR LIRC_DRIVER_NAME
-                      ": i/o port 0x%.4x already in use.\n", io);
-               return -EBUSY;
-       }
-#endif
-       retval = request_irq(irq, sir_interrupt, 0,
-                            LIRC_DRIVER_NAME, NULL);
-       if (retval < 0) {
-#               ifndef LIRC_ON_SA1100
-               release_region(io, 8);
-#               endif
-               printk(KERN_ERR LIRC_DRIVER_NAME
-                       ": IRQ %d already in use.\n",
-                       irq);
-               return retval;
-       }
-#ifndef LIRC_ON_SA1100
-       printk(KERN_INFO LIRC_DRIVER_NAME
-               ": I/O port 0x%.4x, IRQ %d.\n",
-               io, irq);
-#endif
-
-       init_timer(&timerlist);
-       timerlist.function = sir_timeout;
-       timerlist.data = 0xabadcafe;
-
-       return 0;
-}
-
-static void drop_port(void)
-{
-       free_irq(irq, NULL);
-       del_timer_sync(&timerlist);
-#ifndef LIRC_ON_SA1100
-       release_region(io, 8);
-#endif
-}
-
-#ifdef LIRC_SIR_ACTISYS_ACT200L
-/* Crystal/Cirrus CS8130 IR transceiver, used in Actisys Act200L dongle */
-/* some code borrowed from Linux IRDA driver */
-
-/* Register 0: Control register #1 */
-#define ACT200L_REG0    0x00
-#define ACT200L_TXEN    0x01 /* Enable transmitter */
-#define ACT200L_RXEN    0x02 /* Enable receiver */
-#define ACT200L_ECHO    0x08 /* Echo control chars */
-
-/* Register 1: Control register #2 */
-#define ACT200L_REG1    0x10
-#define ACT200L_LODB    0x01 /* Load new baud rate count value */
-#define ACT200L_WIDE    0x04 /* Expand the maximum allowable pulse */
-
-/* Register 3: Transmit mode register #2 */
-#define ACT200L_REG3    0x30
-#define ACT200L_B0      0x01 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P)  */
-#define ACT200L_B1      0x02 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P)  */
-#define ACT200L_CHSY    0x04 /* StartBit Synced 0=bittime, 1=startbit */
-
-/* Register 4: Output Power register */
-#define ACT200L_REG4    0x40
-#define ACT200L_OP0     0x01 /* Enable LED1C output */
-#define ACT200L_OP1     0x02 /* Enable LED2C output */
-#define ACT200L_BLKR    0x04
-
-/* Register 5: Receive Mode register */
-#define ACT200L_REG5    0x50
-#define ACT200L_RWIDL   0x01 /* fixed 1.6us pulse mode */
-    /*.. other various IRDA bit modes, and TV remote modes..*/
-
-/* Register 6: Receive Sensitivity register #1 */
-#define ACT200L_REG6    0x60
-#define ACT200L_RS0     0x01 /* receive threshold bit 0 */
-#define ACT200L_RS1     0x02 /* receive threshold bit 1 */
-
-/* Register 7: Receive Sensitivity register #2 */
-#define ACT200L_REG7    0x70
-#define ACT200L_ENPOS   0x04 /* Ignore the falling edge */
-
-/* Register 8,9: Baud Rate Divider register #1,#2 */
-#define ACT200L_REG8    0x80
-#define ACT200L_REG9    0x90
-
-#define ACT200L_2400    0x5f
-#define ACT200L_9600    0x17
-#define ACT200L_19200   0x0b
-#define ACT200L_38400   0x05
-#define ACT200L_57600   0x03
-#define ACT200L_115200  0x01
-
-/* Register 13: Control register #3 */
-#define ACT200L_REG13   0xd0
-#define ACT200L_SHDW    0x01 /* Enable access to shadow registers */
-
-/* Register 15: Status register */
-#define ACT200L_REG15   0xf0
-
-/* Register 21: Control register #4 */
-#define ACT200L_REG21   0x50
-#define ACT200L_EXCK    0x02 /* Disable clock output driver */
-#define ACT200L_OSCL    0x04 /* oscillator in low power, medium accuracy mode */
-
-static void init_act200(void)
-{
-       int i;
-       __u8 control[] = {
-               ACT200L_REG15,
-               ACT200L_REG13 | ACT200L_SHDW,
-               ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL,
-               ACT200L_REG13,
-               ACT200L_REG7  | ACT200L_ENPOS,
-               ACT200L_REG6  | ACT200L_RS0  | ACT200L_RS1,
-               ACT200L_REG5  | ACT200L_RWIDL,
-               ACT200L_REG4  | ACT200L_OP0  | ACT200L_OP1 | ACT200L_BLKR,
-               ACT200L_REG3  | ACT200L_B0,
-               ACT200L_REG0  | ACT200L_TXEN | ACT200L_RXEN,
-               ACT200L_REG8 |  (ACT200L_115200       & 0x0f),
-               ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f),
-               ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE
-       };
-
-       /* Set DLAB 1. */
-       soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8);
-
-       /* Set divisor to 12 => 9600 Baud */
-       soutp(UART_DLM, 0);
-       soutp(UART_DLL, 12);
-
-       /* Set DLAB 0. */
-       soutp(UART_LCR, UART_LCR_WLEN8);
-       /* Set divisor to 12 => 9600 Baud */
-
-       /* power supply */
-       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
-       for (i = 0; i < 50; i++)
-               safe_udelay(1000);
-
-               /* Reset the dongle : set RTS low for 25 ms */
-       soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
-       for (i = 0; i < 25; i++)
-               udelay(1000);
-
-       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
-       udelay(100);
-
-       /* Clear DTR and set RTS to enter command mode */
-       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
-       udelay(7);
-
-       /* send out the control register settings for 115K 7N1 SIR operation */
-       for (i = 0; i < sizeof(control); i++) {
-               soutp(UART_TX, control[i]);
-               /* one byte takes ~1042 usec to transmit at 9600,8N1 */
-               udelay(1500);
-       }
-
-       /* back to normal operation */
-       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
-       udelay(50);
-
-       udelay(1500);
-       soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
-
-       /* Set DLAB 1. */
-       soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7);
-
-       /* Set divisor to 1 => 115200 Baud */
-       soutp(UART_DLM, 0);
-       soutp(UART_DLL, 1);
-
-       /* Set DLAB 0. */
-       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
-
-       /* Set DLAB 0, 7 Bit */
-       soutp(UART_LCR, UART_LCR_WLEN7);
-
-       /* enable interrupts */
-       soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI);
-}
-#endif
-
-#ifdef LIRC_SIR_ACTISYS_ACT220L
-/*
- * Derived from linux IrDA driver (net/irda/actisys.c)
- * Drop me a mail for any kind of comment: maxx@spaceboyz.net
- */
-
-void init_act220(void)
-{
-       int i;
-
-       /* DLAB 1 */
-       soutp(UART_LCR, UART_LCR_DLAB|UART_LCR_WLEN7);
-
-       /* 9600 baud */
-       soutp(UART_DLM, 0);
-       soutp(UART_DLL, 12);
-
-       /* DLAB 0 */
-       soutp(UART_LCR, UART_LCR_WLEN7);
-
-       /* reset the dongle, set DTR low for 10us */
-       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
-       udelay(10);
-
-       /* back to normal (still 9600) */
-       soutp(UART_MCR, UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2);
-
-       /*
-        * send RTS pulses until we reach 115200
-        * i hope this is really the same for act220l/act220l+
-        */
-       for (i = 0; i < 3; i++) {
-               udelay(10);
-               /* set RTS low for 10 us */
-               soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
-               udelay(10);
-               /* set RTS high for 10 us */
-               soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
-       }
-
-       /* back to normal operation */
-       udelay(1500); /* better safe than sorry ;) */
-
-       /* Set DLAB 1. */
-       soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7);
-
-       /* Set divisor to 1 => 115200 Baud */
-       soutp(UART_DLM, 0);
-       soutp(UART_DLL, 1);
-
-       /* Set DLAB 0, 7 Bit */
-       /* The dongle doesn't seem to have any problems with operation at 7N1 */
-       soutp(UART_LCR, UART_LCR_WLEN7);
-
-       /* enable interrupts */
-       soutp(UART_IER, UART_IER_RDI);
-}
-#endif
-
-static int init_lirc_sir(void)
-{
-       int retval;
-
-       init_waitqueue_head(&lirc_read_queue);
-       retval = init_port();
-       if (retval < 0)
-               return retval;
-       init_hardware();
-       printk(KERN_INFO LIRC_DRIVER_NAME
-               ": Installed.\n");
-       return 0;
-}
-
-
-static int __init lirc_sir_init(void)
-{
-       int retval;
-
-       retval = init_chrdev();
-       if (retval < 0)
-               return retval;
-       retval = init_lirc_sir();
-       if (retval) {
-               drop_chrdev();
-               return retval;
-       }
-       return 0;
-}
-
-static void __exit lirc_sir_exit(void)
-{
-       drop_hardware();
-       drop_chrdev();
-       drop_port();
-       printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
-}
-
-module_init(lirc_sir_init);
-module_exit(lirc_sir_exit);
-
-#ifdef LIRC_SIR_TEKRAM
-MODULE_DESCRIPTION("Infrared receiver driver for Tekram Irmate 210");
-MODULE_AUTHOR("Christoph Bartelmus");
-#elif defined(LIRC_ON_SA1100)
-MODULE_DESCRIPTION("LIRC driver for StrongARM SA1100 embedded microprocessor");
-MODULE_AUTHOR("Christoph Bartelmus");
-#elif defined(LIRC_SIR_ACTISYS_ACT200L)
-MODULE_DESCRIPTION("LIRC driver for Actisys Act200L");
-MODULE_AUTHOR("Karl Bongers");
-#elif defined(LIRC_SIR_ACTISYS_ACT220L)
-MODULE_DESCRIPTION("LIRC driver for Actisys Act220L(+)");
-MODULE_AUTHOR("Jan Roemisch");
-#else
-MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports");
-MODULE_AUTHOR("Milan Pikula");
-#endif
-MODULE_LICENSE("GPL");
-
-#ifdef LIRC_ON_SA1100
-module_param(irq, int, S_IRUGO);
-MODULE_PARM_DESC(irq, "Interrupt (16)");
-#else
-module_param(io, int, S_IRUGO);
-MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");
-
-module_param(irq, int, S_IRUGO);
-MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");
-
-module_param(threshold, int, S_IRUGO);
-MODULE_PARM_DESC(threshold, "space detection threshold (3)");
-#endif
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/lirc/lirc_ttusbir.c b/drivers/staging/lirc/lirc_ttusbir.c
deleted file mode 100644 (file)
index e4b329b..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * lirc_ttusbir.c
- *
- * lirc_ttusbir - LIRC device driver for the TechnoTrend USB IR Receiver
- *
- * Copyright (C) 2007 Stefan Macher <st_maker-lirc@yahoo.de>
- *
- * This LIRC driver provides access to the TechnoTrend USB IR Receiver.
- * The receiver delivers the IR signal as raw sampled true/false data in
- * isochronous USB packets each of size 128 byte.
- * Currently the driver reduces the sampling rate by factor of 8 as this
- * is still more than enough to decode RC-5 - others should be analyzed.
- * But the driver does not rely on RC-5 it should be able to decode every
- * IR signal that is not too fast.
- */
-
-/*
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-MODULE_DESCRIPTION("TechnoTrend USB IR device driver for LIRC");
-MODULE_AUTHOR("Stefan Macher (st_maker-lirc@yahoo.de)");
-MODULE_LICENSE("GPL");
-
-/* #define DEBUG */
-#ifdef DEBUG
-#define DPRINTK printk
-#else
-#define DPRINTK(_x_, a...)
-#endif
-
-/* function declarations */
-static int probe(struct usb_interface *intf, const struct usb_device_id *id);
-static void disconnect(struct usb_interface *intf);
-static void urb_complete(struct urb *urb);
-static int set_use_inc(void *data);
-static void set_use_dec(void *data);
-
-static int num_urbs = 2;
-module_param(num_urbs, int, S_IRUGO);
-MODULE_PARM_DESC(num_urbs,
-                "Number of URBs in queue. Try to increase to 4 in case "
-                "of problems (default: 2; minimum: 2)");
-
-/* table of devices that work with this driver */
-static struct usb_device_id device_id_table[] = {
-       /* TechnoTrend USB IR Receiver */
-       { USB_DEVICE(0x0B48, 0x2003) },
-       /* Terminating entry */
-       { }
-};
-MODULE_DEVICE_TABLE(usb, device_id_table);
-
-/* USB driver definition */
-static struct usb_driver usb_driver = {
-       .name = "TTUSBIR",
-       .id_table = &(device_id_table[0]),
-       .probe = probe,
-       .disconnect = disconnect,
-};
-
-/* USB device definition */
-struct ttusbir_device {
-       struct usb_driver *usb_driver;
-       struct usb_device *udev;
-       struct usb_interface *interf;
-       struct usb_class_driver class_driver;
-       unsigned int ifnum; /* Interface number to use */
-       unsigned int alt_setting; /* alternate setting to use */
-       unsigned int endpoint; /* Endpoint to use */
-       struct urb **urb; /* num_urb URB pointers*/
-       char **buffer; /* 128 byte buffer for each URB */
-       struct lirc_buffer rbuf; /* Buffer towards LIRC */
-       struct lirc_driver driver;
-       int minor;
-       int last_pulse; /* remembers if last received byte was pulse or space */
-       int last_num; /* remembers how many last bytes appeared */
-       int opened;
-};
-
-/*** LIRC specific functions ***/
-static int set_use_inc(void *data)
-{
-       int i, retval;
-       struct ttusbir_device *ttusbir = data;
-
-       DPRINTK("Sending first URBs\n");
-       /* @TODO Do I need to check if I am already opened */
-       ttusbir->opened = 1;
-
-       for (i = 0; i < num_urbs; i++) {
-               retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL);
-               if (retval) {
-                       err("%s: usb_submit_urb failed on urb %d",
-                           __func__, i);
-                       return retval;
-               }
-       }
-       return 0;
-}
-
-static void set_use_dec(void *data)
-{
-       struct ttusbir_device *ttusbir = data;
-
-       DPRINTK("Device closed\n");
-
-       ttusbir->opened = 0;
-}
-
-/*** USB specific functions ***/
-
-/*
- * This mapping table is used to do a very simple filtering of the
- * input signal.
- * For a value with at least 4 bits set it returns 0xFF otherwise
- * 0x00.  For faster IR signals this can not be used. But for RC-5 we
- * still have about 14 samples per pulse/space, i.e. we sample with 14
- * times higher frequency than the signal frequency
- */
-const unsigned char map_table[] = {
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
-       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
-       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
-       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
-       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
-       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
-       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
-       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-static void urb_complete(struct urb *urb)
-{
-       struct ttusbir_device *ttusbir;
-       unsigned char *buf;
-       int i;
-       int l;
-
-       ttusbir = urb->context;
-
-       if (!ttusbir->opened)
-               return;
-
-       buf = (unsigned char *)urb->transfer_buffer;
-
-       for (i = 0; i < 128; i++) {
-               /* Here we do the filtering and some kind of down sampling */
-               buf[i] = ~map_table[buf[i]];
-               if (ttusbir->last_pulse == buf[i]) {
-                       if (ttusbir->last_num < PULSE_MASK/63)
-                               ttusbir->last_num++;
-               /*
-                * else we are in a idle period and do not need to
-                * increment any longer
-                */
-               } else {
-                       l = ttusbir->last_num * 62; /* about 62 = us/byte */
-                       if (ttusbir->last_pulse) /* pulse or space? */
-                               l |= PULSE_BIT;
-                       if (!lirc_buffer_full(&ttusbir->rbuf)) {
-                               lirc_buffer_write(&ttusbir->rbuf, (void *)&l);
-                               wake_up_interruptible(&ttusbir->rbuf.wait_poll);
-                       }
-                       ttusbir->last_num = 0;
-                       ttusbir->last_pulse = buf[i];
-               }
-       }
-       usb_submit_urb(urb, GFP_ATOMIC); /* keep data rolling :-) */
-}
-
-/*
- * Called whenever the USB subsystem thinks we could be the right driver
- * to handle this device
- */
-static int probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       int alt_set, endp;
-       int found = 0;
-       int i, j;
-       int struct_size;
-       struct usb_host_interface *host_interf;
-       struct usb_interface_descriptor *interf_desc;
-       struct usb_host_endpoint *host_endpoint;
-       struct ttusbir_device *ttusbir;
-
-       DPRINTK("Module ttusbir probe\n");
-
-       /* To reduce memory fragmentation we use only one allocation */
-       struct_size =  sizeof(struct ttusbir_device) +
-               (sizeof(struct urb *) * num_urbs) +
-               (sizeof(char *) * num_urbs) +
-               (num_urbs * 128);
-       ttusbir = kzalloc(struct_size, GFP_KERNEL);
-       if (!ttusbir)
-               return -ENOMEM;
-
-       ttusbir->urb = (struct urb **)((char *)ttusbir +
-                                     sizeof(struct ttusbir_device));
-       ttusbir->buffer = (char **)((char *)ttusbir->urb +
-                                  (sizeof(struct urb *) * num_urbs));
-       for (i = 0; i < num_urbs; i++)
-               ttusbir->buffer[i] = (char *)ttusbir->buffer +
-                       (sizeof(char *)*num_urbs) + (i * 128);
-
-       ttusbir->usb_driver = &usb_driver;
-       ttusbir->alt_setting = -1;
-       /* @TODO check if error can be returned */
-       ttusbir->udev = usb_get_dev(interface_to_usbdev(intf));
-       ttusbir->interf = intf;
-       ttusbir->last_pulse = 0x00;
-       ttusbir->last_num = 0;
-
-       /*
-        * Now look for interface setting we can handle
-        * We are searching for the alt setting where end point
-        * 0x82 has max packet size 16
-        */
-       for (alt_set = 0; alt_set < intf->num_altsetting && !found; alt_set++) {
-               host_interf = &intf->altsetting[alt_set];
-               interf_desc = &host_interf->desc;
-               for (endp = 0; endp < interf_desc->bNumEndpoints; endp++) {
-                       host_endpoint = &host_interf->endpoint[endp];
-                       if ((host_endpoint->desc.bEndpointAddress == 0x82) &&
-                           (host_endpoint->desc.wMaxPacketSize == 0x10)) {
-                               ttusbir->alt_setting = alt_set;
-                               ttusbir->endpoint = endp;
-                               found = 1;
-                               break;
-                       }
-               }
-       }
-       if (ttusbir->alt_setting != -1)
-               DPRINTK("alt setting: %d\n", ttusbir->alt_setting);
-       else {
-               err("Could not find alternate setting\n");
-               kfree(ttusbir);
-               return -EINVAL;
-       }
-
-       /* OK lets setup this interface setting */
-       usb_set_interface(ttusbir->udev, 0, ttusbir->alt_setting);
-
-       /* Store device info in interface structure */
-       usb_set_intfdata(intf, ttusbir);
-
-       /* Register as a LIRC driver */
-       if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) {
-               err("Could not get memory for LIRC data buffer\n");
-               usb_set_intfdata(intf, NULL);
-               kfree(ttusbir);
-               return -ENOMEM;
-       }
-       strcpy(ttusbir->driver.name, "TTUSBIR");
-       ttusbir->driver.minor = -1;
-       ttusbir->driver.code_length = 1;
-       ttusbir->driver.sample_rate = 0;
-       ttusbir->driver.data = ttusbir;
-       ttusbir->driver.add_to_buf = NULL;
-       ttusbir->driver.rbuf = &ttusbir->rbuf;
-       ttusbir->driver.set_use_inc = set_use_inc;
-       ttusbir->driver.set_use_dec = set_use_dec;
-       ttusbir->driver.dev = &intf->dev;
-       ttusbir->driver.owner = THIS_MODULE;
-       ttusbir->driver.features = LIRC_CAN_REC_MODE2;
-       ttusbir->minor = lirc_register_driver(&ttusbir->driver);
-       if (ttusbir->minor < 0) {
-               err("Error registering as LIRC driver\n");
-               usb_set_intfdata(intf, NULL);
-               lirc_buffer_free(&ttusbir->rbuf);
-               kfree(ttusbir);
-               return -EIO;
-       }
-
-       /* Allocate and setup the URB that we will use to talk to the device */
-       for (i = 0; i < num_urbs; i++) {
-               ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL);
-               if (!ttusbir->urb[i]) {
-                       err("Could not allocate memory for the URB\n");
-                       for (j = i - 1; j >= 0; j--)
-                               kfree(ttusbir->urb[j]);
-                       lirc_buffer_free(&ttusbir->rbuf);
-                       lirc_unregister_driver(ttusbir->minor);
-                       kfree(ttusbir);
-                       usb_set_intfdata(intf, NULL);
-                       return -ENOMEM;
-               }
-               ttusbir->urb[i]->dev = ttusbir->udev;
-               ttusbir->urb[i]->context = ttusbir;
-               ttusbir->urb[i]->pipe = usb_rcvisocpipe(ttusbir->udev,
-                                                       ttusbir->endpoint);
-               ttusbir->urb[i]->interval = 1;
-               ttusbir->urb[i]->transfer_flags = URB_ISO_ASAP;
-               ttusbir->urb[i]->transfer_buffer = &ttusbir->buffer[i][0];
-               ttusbir->urb[i]->complete = urb_complete;
-               ttusbir->urb[i]->number_of_packets = 8;
-               ttusbir->urb[i]->transfer_buffer_length = 128;
-               for (j = 0; j < 8; j++) {
-                       ttusbir->urb[i]->iso_frame_desc[j].offset = j*16;
-                       ttusbir->urb[i]->iso_frame_desc[j].length = 16;
-               }
-       }
-       return 0;
-}
-
-/**
- * Called when the driver is unloaded or the device is unplugged
- */
-static void disconnect(struct usb_interface *intf)
-{
-       int i;
-       struct ttusbir_device *ttusbir;
-
-       DPRINTK("Module ttusbir disconnect\n");
-
-       ttusbir = (struct ttusbir_device *) usb_get_intfdata(intf);
-       usb_set_intfdata(intf, NULL);
-       lirc_unregister_driver(ttusbir->minor);
-       DPRINTK("unregistered\n");
-
-       for (i = 0; i < num_urbs; i++) {
-               usb_kill_urb(ttusbir->urb[i]);
-               usb_free_urb(ttusbir->urb[i]);
-       }
-       DPRINTK("URBs killed\n");
-       lirc_buffer_free(&ttusbir->rbuf);
-       kfree(ttusbir);
-}
-
-static int ttusbir_init_module(void)
-{
-       int result;
-
-       DPRINTK(KERN_DEBUG "Module ttusbir init\n");
-
-       /* register this driver with the USB subsystem */
-       result = usb_register(&usb_driver);
-       if (result)
-               err("usb_register failed. Error number %d", result);
-       return result;
-}
-
-static void ttusbir_exit_module(void)
-{
-       printk(KERN_DEBUG "Module ttusbir exit\n");
-       usb_deregister(&usb_driver);
-}
-
-module_init(ttusbir_init_module);
-module_exit(ttusbir_exit_module);
diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c
deleted file mode 100644 (file)
index 0302d82..0000000
+++ /dev/null
@@ -1,1676 +0,0 @@
-/*
- * i2c IR lirc driver for devices with zilog IR processors
- *
- * Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
- * modified for PixelView (BT878P+W/FM) by
- *      Michal Kochanowicz <mkochano@pld.org.pl>
- *      Christoph Bartelmus <lirc@bartelmus.de>
- * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
- *      Ulrich Mueller <ulrich.mueller42@web.de>
- * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by
- *      Stefan Jahn <stefan@lkcc.org>
- * modified for inclusion into kernel sources by
- *      Jerome Brock <jbrock@users.sourceforge.net>
- * modified for Leadtek Winfast PVR2000 by
- *      Thomas Reitmayr (treitmayr@yahoo.com)
- * modified for Hauppauge PVR-150 IR TX device by
- *      Mark Weaver <mark@npsl.co.uk>
- * changed name from lirc_pvr150 to lirc_zilog, works on more than pvr-150
- *     Jarod Wilson <jarod@redhat.com>
- *
- * parts are cut&pasted from the lirc_i2c.c driver
- *
- * Numerous changes updating lirc_zilog.c in kernel 2.6.38 and later are
- * Copyright (C) 2011 Andy Walls <awalls@md.metrocast.net>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/kmod.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/completion.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/firmware.h>
-#include <linux/vmalloc.h>
-
-#include <linux/mutex.h>
-#include <linux/kthread.h>
-
-#include <media/lirc_dev.h>
-#include <media/lirc.h>
-
-struct IR;
-
-struct IR_rx {
-       struct kref ref;
-       struct IR *ir;
-
-       /* RX device */
-       struct mutex client_lock;
-       struct i2c_client *c;
-
-       /* RX polling thread data */
-       struct task_struct *task;
-
-       /* RX read data */
-       unsigned char b[3];
-       bool hdpvr_data_fmt;
-};
-
-struct IR_tx {
-       struct kref ref;
-       struct IR *ir;
-
-       /* TX device */
-       struct mutex client_lock;
-       struct i2c_client *c;
-
-       /* TX additional actions needed */
-       int need_boot;
-       bool post_tx_ready_poll;
-};
-
-struct IR {
-       struct kref ref;
-       struct list_head list;
-
-       /* FIXME spinlock access to l.features */
-       struct lirc_driver l;
-       struct lirc_buffer rbuf;
-
-       struct mutex ir_lock;
-       atomic_t open_count;
-
-       struct i2c_adapter *adapter;
-
-       spinlock_t rx_ref_lock; /* struct IR_rx kref get()/put() */
-       struct IR_rx *rx;
-
-       spinlock_t tx_ref_lock; /* struct IR_tx kref get()/put() */
-       struct IR_tx *tx;
-};
-
-/* IR transceiver instance object list */
-/*
- * This lock is used for the following:
- * a. ir_devices_list access, insertions, deletions
- * b. struct IR kref get()s and put()s
- * c. serialization of ir_probe() for the two i2c_clients for a Z8
- */
-static DEFINE_MUTEX(ir_devices_lock);
-static LIST_HEAD(ir_devices_list);
-
-/* Block size for IR transmitter */
-#define TX_BLOCK_SIZE  99
-
-/* Hauppauge IR transmitter data */
-struct tx_data_struct {
-       /* Boot block */
-       unsigned char *boot_data;
-
-       /* Start of binary data block */
-       unsigned char *datap;
-
-       /* End of binary data block */
-       unsigned char *endp;
-
-       /* Number of installed codesets */
-       unsigned int num_code_sets;
-
-       /* Pointers to codesets */
-       unsigned char **code_sets;
-
-       /* Global fixed data template */
-       int fixed[TX_BLOCK_SIZE];
-};
-
-static struct tx_data_struct *tx_data;
-static struct mutex tx_data_lock;
-
-#define zilog_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, \
-                                       ## args)
-#define zilog_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
-#define zilog_info(s, args...) printk(KERN_INFO KBUILD_MODNAME ": " s, ## args)
-
-/* module parameters */
-static int debug;      /* debug output */
-static int tx_only;    /* only handle the IR Tx function */
-static int minor = -1; /* minor number */
-
-#define dprintk(fmt, args...)                                          \
-       do {                                                            \
-               if (debug)                                              \
-                       printk(KERN_DEBUG KBUILD_MODNAME ": " fmt,      \
-                                ## args);                              \
-       } while (0)
-
-
-/* struct IR reference counting */
-static struct IR *get_ir_device(struct IR *ir, bool ir_devices_lock_held)
-{
-       if (ir_devices_lock_held) {
-               kref_get(&ir->ref);
-       } else {
-               mutex_lock(&ir_devices_lock);
-               kref_get(&ir->ref);
-               mutex_unlock(&ir_devices_lock);
-       }
-       return ir;
-}
-
-static void release_ir_device(struct kref *ref)
-{
-       struct IR *ir = container_of(ref, struct IR, ref);
-
-       /*
-        * Things should be in this state by now:
-        * ir->rx set to NULL and deallocated - happens before ir->rx->ir put()
-        * ir->rx->task kthread stopped - happens before ir->rx->ir put()
-        * ir->tx set to NULL and deallocated - happens before ir->tx->ir put()
-        * ir->open_count ==  0 - happens on final close()
-        * ir_lock, tx_ref_lock, rx_ref_lock, all released
-        */
-       if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) {
-               lirc_unregister_driver(ir->l.minor);
-               ir->l.minor = MAX_IRCTL_DEVICES;
-       }
-       if (ir->rbuf.fifo_initialized)
-               lirc_buffer_free(&ir->rbuf);
-       list_del(&ir->list);
-       kfree(ir);
-}
-
-static int put_ir_device(struct IR *ir, bool ir_devices_lock_held)
-{
-       int released;
-
-       if (ir_devices_lock_held)
-               return kref_put(&ir->ref, release_ir_device);
-
-       mutex_lock(&ir_devices_lock);
-       released = kref_put(&ir->ref, release_ir_device);
-       mutex_unlock(&ir_devices_lock);
-
-       return released;
-}
-
-/* struct IR_rx reference counting */
-static struct IR_rx *get_ir_rx(struct IR *ir)
-{
-       struct IR_rx *rx;
-
-       spin_lock(&ir->rx_ref_lock);
-       rx = ir->rx;
-       if (rx != NULL)
-               kref_get(&rx->ref);
-       spin_unlock(&ir->rx_ref_lock);
-       return rx;
-}
-
-static void destroy_rx_kthread(struct IR_rx *rx, bool ir_devices_lock_held)
-{
-       /* end up polling thread */
-       if (!IS_ERR_OR_NULL(rx->task)) {
-               kthread_stop(rx->task);
-               rx->task = NULL;
-               /* Put the ir ptr that ir_probe() gave to the rx poll thread */
-               put_ir_device(rx->ir, ir_devices_lock_held);
-       }
-}
-
-static void release_ir_rx(struct kref *ref)
-{
-       struct IR_rx *rx = container_of(ref, struct IR_rx, ref);
-       struct IR *ir = rx->ir;
-
-       /*
-        * This release function can't do all the work, as we want
-        * to keep the rx_ref_lock a spinlock, and killing the poll thread
-        * and releasing the ir reference can cause a sleep.  That work is
-        * performed by put_ir_rx()
-        */
-       ir->l.features &= ~LIRC_CAN_REC_LIRCCODE;
-       /* Don't put_ir_device(rx->ir) here; lock can't be freed yet */
-       ir->rx = NULL;
-       /* Don't do the kfree(rx) here; we still need to kill the poll thread */
-       return;
-}
-
-static int put_ir_rx(struct IR_rx *rx, bool ir_devices_lock_held)
-{
-       int released;
-       struct IR *ir = rx->ir;
-
-       spin_lock(&ir->rx_ref_lock);
-       released = kref_put(&rx->ref, release_ir_rx);
-       spin_unlock(&ir->rx_ref_lock);
-       /* Destroy the rx kthread while not holding the spinlock */
-       if (released) {
-               destroy_rx_kthread(rx, ir_devices_lock_held);
-               kfree(rx);
-               /* Make sure we're not still in a poll_table somewhere */
-               wake_up_interruptible(&ir->rbuf.wait_poll);
-       }
-       /* Do a reference put() for the rx->ir reference, if we released rx */
-       if (released)
-               put_ir_device(ir, ir_devices_lock_held);
-       return released;
-}
-
-/* struct IR_tx reference counting */
-static struct IR_tx *get_ir_tx(struct IR *ir)
-{
-       struct IR_tx *tx;
-
-       spin_lock(&ir->tx_ref_lock);
-       tx = ir->tx;
-       if (tx != NULL)
-               kref_get(&tx->ref);
-       spin_unlock(&ir->tx_ref_lock);
-       return tx;
-}
-
-static void release_ir_tx(struct kref *ref)
-{
-       struct IR_tx *tx = container_of(ref, struct IR_tx, ref);
-       struct IR *ir = tx->ir;
-
-       ir->l.features &= ~LIRC_CAN_SEND_PULSE;
-       /* Don't put_ir_device(tx->ir) here, so our lock doesn't get freed */
-       ir->tx = NULL;
-       kfree(tx);
-}
-
-static int put_ir_tx(struct IR_tx *tx, bool ir_devices_lock_held)
-{
-       int released;
-       struct IR *ir = tx->ir;
-
-       spin_lock(&ir->tx_ref_lock);
-       released = kref_put(&tx->ref, release_ir_tx);
-       spin_unlock(&ir->tx_ref_lock);
-       /* Do a reference put() for the tx->ir reference, if we released tx */
-       if (released)
-               put_ir_device(ir, ir_devices_lock_held);
-       return released;
-}
-
-static int add_to_buf(struct IR *ir)
-{
-       __u16 code;
-       unsigned char codes[2];
-       unsigned char keybuf[6];
-       int got_data = 0;
-       int ret;
-       int failures = 0;
-       unsigned char sendbuf[1] = { 0 };
-       struct lirc_buffer *rbuf = ir->l.rbuf;
-       struct IR_rx *rx;
-       struct IR_tx *tx;
-
-       if (lirc_buffer_full(rbuf)) {
-               dprintk("buffer overflow\n");
-               return -EOVERFLOW;
-       }
-
-       rx = get_ir_rx(ir);
-       if (rx == NULL)
-               return -ENXIO;
-
-       /* Ensure our rx->c i2c_client remains valid for the duration */
-       mutex_lock(&rx->client_lock);
-       if (rx->c == NULL) {
-               mutex_unlock(&rx->client_lock);
-               put_ir_rx(rx, false);
-               return -ENXIO;
-       }
-
-       tx = get_ir_tx(ir);
-
-       /*
-        * service the device as long as it is returning
-        * data and we have space
-        */
-       do {
-               if (kthread_should_stop()) {
-                       ret = -ENODATA;
-                       break;
-               }
-
-               /*
-                * Lock i2c bus for the duration.  RX/TX chips interfere so
-                * this is worth it
-                */
-               mutex_lock(&ir->ir_lock);
-
-               if (kthread_should_stop()) {
-                       mutex_unlock(&ir->ir_lock);
-                       ret = -ENODATA;
-                       break;
-               }
-
-               /*
-                * Send random "poll command" (?)  Windows driver does this
-                * and it is a good point to detect chip failure.
-                */
-               ret = i2c_master_send(rx->c, sendbuf, 1);
-               if (ret != 1) {
-                       zilog_error("i2c_master_send failed with %d\n", ret);
-                       if (failures >= 3) {
-                               mutex_unlock(&ir->ir_lock);
-                               zilog_error("unable to read from the IR chip "
-                                           "after 3 resets, giving up\n");
-                               break;
-                       }
-
-                       /* Looks like the chip crashed, reset it */
-                       zilog_error("polling the IR receiver chip failed, "
-                                   "trying reset\n");
-
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       if (kthread_should_stop()) {
-                               mutex_unlock(&ir->ir_lock);
-                               ret = -ENODATA;
-                               break;
-                       }
-                       schedule_timeout((100 * HZ + 999) / 1000);
-                       if (tx != NULL)
-                               tx->need_boot = 1;
-
-                       ++failures;
-                       mutex_unlock(&ir->ir_lock);
-                       ret = 0;
-                       continue;
-               }
-
-               if (kthread_should_stop()) {
-                       mutex_unlock(&ir->ir_lock);
-                       ret = -ENODATA;
-                       break;
-               }
-               ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf));
-               mutex_unlock(&ir->ir_lock);
-               if (ret != sizeof(keybuf)) {
-                       zilog_error("i2c_master_recv failed with %d -- "
-                                   "keeping last read buffer\n", ret);
-               } else {
-                       rx->b[0] = keybuf[3];
-                       rx->b[1] = keybuf[4];
-                       rx->b[2] = keybuf[5];
-                       dprintk("key (0x%02x/0x%02x)\n", rx->b[0], rx->b[1]);
-               }
-
-               /* key pressed ? */
-               if (rx->hdpvr_data_fmt) {
-                       if (got_data && (keybuf[0] == 0x80)) {
-                               ret = 0;
-                               break;
-                       } else if (got_data && (keybuf[0] == 0x00)) {
-                               ret = -ENODATA;
-                               break;
-                       }
-               } else if ((rx->b[0] & 0x80) == 0) {
-                       ret = got_data ? 0 : -ENODATA;
-                       break;
-               }
-
-               /* look what we have */
-               code = (((__u16)rx->b[0] & 0x7f) << 6) | (rx->b[1] >> 2);
-
-               codes[0] = (code >> 8) & 0xff;
-               codes[1] = code & 0xff;
-
-               /* return it */
-               lirc_buffer_write(rbuf, codes);
-               ++got_data;
-               ret = 0;
-       } while (!lirc_buffer_full(rbuf));
-
-       mutex_unlock(&rx->client_lock);
-       if (tx != NULL)
-               put_ir_tx(tx, false);
-       put_ir_rx(rx, false);
-       return ret;
-}
-
-/*
- * Main function of the polling thread -- from lirc_dev.
- * We don't fit the LIRC model at all anymore.  This is horrible, but
- * basically we have a single RX/TX device with a nasty failure mode
- * that needs to be accounted for across the pair.  lirc lets us provide
- * fops, but prevents us from using the internal polling, etc. if we do
- * so.  Hence the replication.  Might be neater to extend the LIRC model
- * to account for this but I'd think it's a very special case of seriously
- * messed up hardware.
- */
-static int lirc_thread(void *arg)
-{
-       struct IR *ir = arg;
-       struct lirc_buffer *rbuf = ir->l.rbuf;
-
-       dprintk("poll thread started\n");
-
-       while (!kthread_should_stop()) {
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               /* if device not opened, we can sleep half a second */
-               if (atomic_read(&ir->open_count) == 0) {
-                       schedule_timeout(HZ/2);
-                       continue;
-               }
-
-               /*
-                * This is ~113*2 + 24 + jitter (2*repeat gap + code length).
-                * We use this interval as the chip resets every time you poll
-                * it (bad!).  This is therefore just sufficient to catch all
-                * of the button presses.  It makes the remote much more
-                * responsive.  You can see the difference by running irw and
-                * holding down a button.  With 100ms, the old polling
-                * interval, you'll notice breaks in the repeat sequence
-                * corresponding to lost keypresses.
-                */
-               schedule_timeout((260 * HZ) / 1000);
-               if (kthread_should_stop())
-                       break;
-               if (!add_to_buf(ir))
-                       wake_up_interruptible(&rbuf->wait_poll);
-       }
-
-       dprintk("poll thread ended\n");
-       return 0;
-}
-
-static int set_use_inc(void *data)
-{
-       return 0;
-}
-
-static void set_use_dec(void *data)
-{
-       return;
-}
-
-/* safe read of a uint32 (always network byte order) */
-static int read_uint32(unsigned char **data,
-                                    unsigned char *endp, unsigned int *val)
-{
-       if (*data + 4 > endp)
-               return 0;
-       *val = ((*data)[0] << 24) | ((*data)[1] << 16) |
-              ((*data)[2] << 8) | (*data)[3];
-       *data += 4;
-       return 1;
-}
-
-/* safe read of a uint8 */
-static int read_uint8(unsigned char **data,
-                                   unsigned char *endp, unsigned char *val)
-{
-       if (*data + 1 > endp)
-               return 0;
-       *val = *((*data)++);
-       return 1;
-}
-
-/* safe skipping of N bytes */
-static int skip(unsigned char **data,
-                             unsigned char *endp, unsigned int distance)
-{
-       if (*data + distance > endp)
-               return 0;
-       *data += distance;
-       return 1;
-}
-
-/* decompress key data into the given buffer */
-static int get_key_data(unsigned char *buf,
-                            unsigned int codeset, unsigned int key)
-{
-       unsigned char *data, *endp, *diffs, *key_block;
-       unsigned char keys, ndiffs, id;
-       unsigned int base, lim, pos, i;
-
-       /* Binary search for the codeset */
-       for (base = 0, lim = tx_data->num_code_sets; lim; lim >>= 1) {
-               pos = base + (lim >> 1);
-               data = tx_data->code_sets[pos];
-
-               if (!read_uint32(&data, tx_data->endp, &i))
-                       goto corrupt;
-
-               if (i == codeset)
-                       break;
-               else if (codeset > i) {
-                       base = pos + 1;
-                       --lim;
-               }
-       }
-       /* Not found? */
-       if (!lim)
-               return -EPROTO;
-
-       /* Set end of data block */
-       endp = pos < tx_data->num_code_sets - 1 ?
-               tx_data->code_sets[pos + 1] : tx_data->endp;
-
-       /* Read the block header */
-       if (!read_uint8(&data, endp, &keys) ||
-           !read_uint8(&data, endp, &ndiffs) ||
-           ndiffs > TX_BLOCK_SIZE || keys == 0)
-               goto corrupt;
-
-       /* Save diffs & skip */
-       diffs = data;
-       if (!skip(&data, endp, ndiffs))
-               goto corrupt;
-
-       /* Read the id of the first key */
-       if (!read_uint8(&data, endp, &id))
-               goto corrupt;
-
-       /* Unpack the first key's data */
-       for (i = 0; i < TX_BLOCK_SIZE; ++i) {
-               if (tx_data->fixed[i] == -1) {
-                       if (!read_uint8(&data, endp, &buf[i]))
-                               goto corrupt;
-               } else {
-                       buf[i] = (unsigned char)tx_data->fixed[i];
-               }
-       }
-
-       /* Early out key found/not found */
-       if (key == id)
-               return 0;
-       if (keys == 1)
-               return -EPROTO;
-
-       /* Sanity check */
-       key_block = data;
-       if (!skip(&data, endp, (keys - 1) * (ndiffs + 1)))
-               goto corrupt;
-
-       /* Binary search for the key */
-       for (base = 0, lim = keys - 1; lim; lim >>= 1) {
-               /* Seek to block */
-               unsigned char *key_data;
-               pos = base + (lim >> 1);
-               key_data = key_block + (ndiffs + 1) * pos;
-
-               if (*key_data == key) {
-                       /* skip key id */
-                       ++key_data;
-
-                       /* found, so unpack the diffs */
-                       for (i = 0; i < ndiffs; ++i) {
-                               unsigned char val;
-                               if (!read_uint8(&key_data, endp, &val) ||
-                                   diffs[i] >= TX_BLOCK_SIZE)
-                                       goto corrupt;
-                               buf[diffs[i]] = val;
-                       }
-
-                       return 0;
-               } else if (key > *key_data) {
-                       base = pos + 1;
-                       --lim;
-               }
-       }
-       /* Key not found */
-       return -EPROTO;
-
-corrupt:
-       zilog_error("firmware is corrupt\n");
-       return -EFAULT;
-}
-
-/* send a block of data to the IR TX device */
-static int send_data_block(struct IR_tx *tx, unsigned char *data_block)
-{
-       int i, j, ret;
-       unsigned char buf[5];
-
-       for (i = 0; i < TX_BLOCK_SIZE;) {
-               int tosend = TX_BLOCK_SIZE - i;
-               if (tosend > 4)
-                       tosend = 4;
-               buf[0] = (unsigned char)(i + 1);
-               for (j = 0; j < tosend; ++j)
-                       buf[1 + j] = data_block[i + j];
-               dprintk("%02x %02x %02x %02x %02x",
-                       buf[0], buf[1], buf[2], buf[3], buf[4]);
-               ret = i2c_master_send(tx->c, buf, tosend + 1);
-               if (ret != tosend + 1) {
-                       zilog_error("i2c_master_send failed with %d\n", ret);
-                       return ret < 0 ? ret : -EFAULT;
-               }
-               i += tosend;
-       }
-       return 0;
-}
-
-/* send boot data to the IR TX device */
-static int send_boot_data(struct IR_tx *tx)
-{
-       int ret, i;
-       unsigned char buf[4];
-
-       /* send the boot block */
-       ret = send_data_block(tx, tx_data->boot_data);
-       if (ret != 0)
-               return ret;
-
-       /* Hit the go button to activate the new boot data */
-       buf[0] = 0x00;
-       buf[1] = 0x20;
-       ret = i2c_master_send(tx->c, buf, 2);
-       if (ret != 2) {
-               zilog_error("i2c_master_send failed with %d\n", ret);
-               return ret < 0 ? ret : -EFAULT;
-       }
-
-       /*
-        * Wait for zilog to settle after hitting go post boot block upload.
-        * Without this delay, the HD-PVR and HVR-1950 both return an -EIO
-        * upon attempting to get firmware revision, and tx probe thus fails.
-        */
-       for (i = 0; i < 10; i++) {
-               ret = i2c_master_send(tx->c, buf, 1);
-               if (ret == 1)
-                       break;
-               udelay(100);
-       }
-
-       if (ret != 1) {
-               zilog_error("i2c_master_send failed with %d\n", ret);
-               return ret < 0 ? ret : -EFAULT;
-       }
-
-       /* Here comes the firmware version... (hopefully) */
-       ret = i2c_master_recv(tx->c, buf, 4);
-       if (ret != 4) {
-               zilog_error("i2c_master_recv failed with %d\n", ret);
-               return 0;
-       }
-       if ((buf[0] != 0x80) && (buf[0] != 0xa0)) {
-               zilog_error("unexpected IR TX init response: %02x\n", buf[0]);
-               return 0;
-       }
-       zilog_notify("Zilog/Hauppauge IR blaster firmware version "
-                    "%d.%d.%d loaded\n", buf[1], buf[2], buf[3]);
-
-       return 0;
-}
-
-/* unload "firmware", lock held */
-static void fw_unload_locked(void)
-{
-       if (tx_data) {
-               if (tx_data->code_sets)
-                       vfree(tx_data->code_sets);
-
-               if (tx_data->datap)
-                       vfree(tx_data->datap);
-
-               vfree(tx_data);
-               tx_data = NULL;
-               dprintk("successfully unloaded IR blaster firmware\n");
-       }
-}
-
-/* unload "firmware" for the IR TX device */
-static void fw_unload(void)
-{
-       mutex_lock(&tx_data_lock);
-       fw_unload_locked();
-       mutex_unlock(&tx_data_lock);
-}
-
-/* load "firmware" for the IR TX device */
-static int fw_load(struct IR_tx *tx)
-{
-       int ret;
-       unsigned int i;
-       unsigned char *data, version, num_global_fixed;
-       const struct firmware *fw_entry;
-
-       /* Already loaded? */
-       mutex_lock(&tx_data_lock);
-       if (tx_data) {
-               ret = 0;
-               goto out;
-       }
-
-       /* Request codeset data file */
-       ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", tx->ir->l.dev);
-       if (ret != 0) {
-               zilog_error("firmware haup-ir-blaster.bin not available "
-                           "(%d)\n", ret);
-               ret = ret < 0 ? ret : -EFAULT;
-               goto out;
-       }
-       dprintk("firmware of size %zu loaded\n", fw_entry->size);
-
-       /* Parse the file */
-       tx_data = vmalloc(sizeof(*tx_data));
-       if (tx_data == NULL) {
-               zilog_error("out of memory\n");
-               release_firmware(fw_entry);
-               ret = -ENOMEM;
-               goto out;
-       }
-       tx_data->code_sets = NULL;
-
-       /* Copy the data so hotplug doesn't get confused and timeout */
-       tx_data->datap = vmalloc(fw_entry->size);
-       if (tx_data->datap == NULL) {
-               zilog_error("out of memory\n");
-               release_firmware(fw_entry);
-               vfree(tx_data);
-               ret = -ENOMEM;
-               goto out;
-       }
-       memcpy(tx_data->datap, fw_entry->data, fw_entry->size);
-       tx_data->endp = tx_data->datap + fw_entry->size;
-       release_firmware(fw_entry); fw_entry = NULL;
-
-       /* Check version */
-       data = tx_data->datap;
-       if (!read_uint8(&data, tx_data->endp, &version))
-               goto corrupt;
-       if (version != 1) {
-               zilog_error("unsupported code set file version (%u, expected"
-                           "1) -- please upgrade to a newer driver",
-                           version);
-               fw_unload_locked();
-               ret = -EFAULT;
-               goto out;
-       }
-
-       /* Save boot block for later */
-       tx_data->boot_data = data;
-       if (!skip(&data, tx_data->endp, TX_BLOCK_SIZE))
-               goto corrupt;
-
-       if (!read_uint32(&data, tx_data->endp,
-                             &tx_data->num_code_sets))
-               goto corrupt;
-
-       dprintk("%u IR blaster codesets loaded\n", tx_data->num_code_sets);
-
-       tx_data->code_sets = vmalloc(
-               tx_data->num_code_sets * sizeof(char *));
-       if (tx_data->code_sets == NULL) {
-               fw_unload_locked();
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       for (i = 0; i < TX_BLOCK_SIZE; ++i)
-               tx_data->fixed[i] = -1;
-
-       /* Read global fixed data template */
-       if (!read_uint8(&data, tx_data->endp, &num_global_fixed) ||
-           num_global_fixed > TX_BLOCK_SIZE)
-               goto corrupt;
-       for (i = 0; i < num_global_fixed; ++i) {
-               unsigned char pos, val;
-               if (!read_uint8(&data, tx_data->endp, &pos) ||
-                   !read_uint8(&data, tx_data->endp, &val) ||
-                   pos >= TX_BLOCK_SIZE)
-                       goto corrupt;
-               tx_data->fixed[pos] = (int)val;
-       }
-
-       /* Filch out the position of each code set */
-       for (i = 0; i < tx_data->num_code_sets; ++i) {
-               unsigned int id;
-               unsigned char keys;
-               unsigned char ndiffs;
-
-               /* Save the codeset position */
-               tx_data->code_sets[i] = data;
-
-               /* Read header */
-               if (!read_uint32(&data, tx_data->endp, &id) ||
-                   !read_uint8(&data, tx_data->endp, &keys) ||
-                   !read_uint8(&data, tx_data->endp, &ndiffs) ||
-                   ndiffs > TX_BLOCK_SIZE || keys == 0)
-                       goto corrupt;
-
-               /* skip diff positions */
-               if (!skip(&data, tx_data->endp, ndiffs))
-                       goto corrupt;
-
-               /*
-                * After the diffs we have the first key id + data -
-                * global fixed
-                */
-               if (!skip(&data, tx_data->endp,
-                              1 + TX_BLOCK_SIZE - num_global_fixed))
-                       goto corrupt;
-
-               /* Then we have keys-1 blocks of key id+diffs */
-               if (!skip(&data, tx_data->endp,
-                              (ndiffs + 1) * (keys - 1)))
-                       goto corrupt;
-       }
-       ret = 0;
-       goto out;
-
-corrupt:
-       zilog_error("firmware is corrupt\n");
-       fw_unload_locked();
-       ret = -EFAULT;
-
-out:
-       mutex_unlock(&tx_data_lock);
-       return ret;
-}
-
-/* copied from lirc_dev */
-static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
-{
-       struct IR *ir = filep->private_data;
-       struct IR_rx *rx;
-       struct lirc_buffer *rbuf = ir->l.rbuf;
-       int ret = 0, written = 0, retries = 0;
-       unsigned int m;
-       DECLARE_WAITQUEUE(wait, current);
-
-       dprintk("read called\n");
-       if (n % rbuf->chunk_size) {
-               dprintk("read result = -EINVAL\n");
-               return -EINVAL;
-       }
-
-       rx = get_ir_rx(ir);
-       if (rx == NULL)
-               return -ENXIO;
-
-       /*
-        * we add ourselves to the task queue before buffer check
-        * to avoid losing scan code (in case when queue is awaken somewhere
-        * between while condition checking and scheduling)
-        */
-       add_wait_queue(&rbuf->wait_poll, &wait);
-       set_current_state(TASK_INTERRUPTIBLE);
-
-       /*
-        * while we didn't provide 'length' bytes, device is opened in blocking
-        * mode and 'copy_to_user' is happy, wait for data.
-        */
-       while (written < n && ret == 0) {
-               if (lirc_buffer_empty(rbuf)) {
-                       /*
-                        * According to the read(2) man page, 'written' can be
-                        * returned as less than 'n', instead of blocking
-                        * again, returning -EWOULDBLOCK, or returning
-                        * -ERESTARTSYS
-                        */
-                       if (written)
-                               break;
-                       if (filep->f_flags & O_NONBLOCK) {
-                               ret = -EWOULDBLOCK;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               ret = -ERESTARTSYS;
-                               break;
-                       }
-                       schedule();
-                       set_current_state(TASK_INTERRUPTIBLE);
-               } else {
-                       unsigned char buf[rbuf->chunk_size];
-                       m = lirc_buffer_read(rbuf, buf);
-                       if (m == rbuf->chunk_size) {
-                               ret = copy_to_user((void *)outbuf+written, buf,
-                                                  rbuf->chunk_size);
-                               written += rbuf->chunk_size;
-                       } else {
-                               retries++;
-                       }
-                       if (retries >= 5) {
-                               zilog_error("Buffer read failed!\n");
-                               ret = -EIO;
-                       }
-               }
-       }
-
-       remove_wait_queue(&rbuf->wait_poll, &wait);
-       put_ir_rx(rx, false);
-       set_current_state(TASK_RUNNING);
-
-       dprintk("read result = %d (%s)\n", ret, ret ? "Error" : "OK");
-
-       return ret ? ret : written;
-}
-
-/* send a keypress to the IR TX device */
-static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
-{
-       unsigned char data_block[TX_BLOCK_SIZE];
-       unsigned char buf[2];
-       int i, ret;
-
-       /* Get data for the codeset/key */
-       ret = get_key_data(data_block, code, key);
-
-       if (ret == -EPROTO) {
-               zilog_error("failed to get data for code %u, key %u -- check "
-                           "lircd.conf entries\n", code, key);
-               return ret;
-       } else if (ret != 0)
-               return ret;
-
-       /* Send the data block */
-       ret = send_data_block(tx, data_block);
-       if (ret != 0)
-               return ret;
-
-       /* Send data block length? */
-       buf[0] = 0x00;
-       buf[1] = 0x40;
-       ret = i2c_master_send(tx->c, buf, 2);
-       if (ret != 2) {
-               zilog_error("i2c_master_send failed with %d\n", ret);
-               return ret < 0 ? ret : -EFAULT;
-       }
-
-       /* Give the z8 a moment to process data block */
-       for (i = 0; i < 10; i++) {
-               ret = i2c_master_send(tx->c, buf, 1);
-               if (ret == 1)
-                       break;
-               udelay(100);
-       }
-
-       if (ret != 1) {
-               zilog_error("i2c_master_send failed with %d\n", ret);
-               return ret < 0 ? ret : -EFAULT;
-       }
-
-       /* Send finished download? */
-       ret = i2c_master_recv(tx->c, buf, 1);
-       if (ret != 1) {
-               zilog_error("i2c_master_recv failed with %d\n", ret);
-               return ret < 0 ? ret : -EFAULT;
-       }
-       if (buf[0] != 0xA0) {
-               zilog_error("unexpected IR TX response #1: %02x\n",
-                       buf[0]);
-               return -EFAULT;
-       }
-
-       /* Send prepare command? */
-       buf[0] = 0x00;
-       buf[1] = 0x80;
-       ret = i2c_master_send(tx->c, buf, 2);
-       if (ret != 2) {
-               zilog_error("i2c_master_send failed with %d\n", ret);
-               return ret < 0 ? ret : -EFAULT;
-       }
-
-       /*
-        * The sleep bits aren't necessary on the HD PVR, and in fact, the
-        * last i2c_master_recv always fails with a -5, so for now, we're
-        * going to skip this whole mess and say we're done on the HD PVR
-        */
-       if (!tx->post_tx_ready_poll) {
-               dprintk("sent code %u, key %u\n", code, key);
-               return 0;
-       }
-
-       /*
-        * This bit NAKs until the device is ready, so we retry it
-        * sleeping a bit each time.  This seems to be what the windows
-        * driver does, approximately.
-        * Try for up to 1s.
-        */
-       for (i = 0; i < 20; ++i) {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout((50 * HZ + 999) / 1000);
-               ret = i2c_master_send(tx->c, buf, 1);
-               if (ret == 1)
-                       break;
-               dprintk("NAK expected: i2c_master_send "
-                       "failed with %d (try %d)\n", ret, i+1);
-       }
-       if (ret != 1) {
-               zilog_error("IR TX chip never got ready: last i2c_master_send "
-                           "failed with %d\n", ret);
-               return ret < 0 ? ret : -EFAULT;
-       }
-
-       /* Seems to be an 'ok' response */
-       i = i2c_master_recv(tx->c, buf, 1);
-       if (i != 1) {
-               zilog_error("i2c_master_recv failed with %d\n", ret);
-               return -EFAULT;
-       }
-       if (buf[0] != 0x80) {
-               zilog_error("unexpected IR TX response #2: %02x\n", buf[0]);
-               return -EFAULT;
-       }
-
-       /* Oh good, it worked */
-       dprintk("sent code %u, key %u\n", code, key);
-       return 0;
-}
-
-/*
- * Write a code to the device.  We take in a 32-bit number (an int) and then
- * decode this to a codeset/key index.  The key data is then decompressed and
- * sent to the device.  We have a spin lock as per i2c documentation to prevent
- * multiple concurrent sends which would probably cause the device to explode.
- */
-static ssize_t write(struct file *filep, const char *buf, size_t n,
-                         loff_t *ppos)
-{
-       struct IR *ir = filep->private_data;
-       struct IR_tx *tx;
-       size_t i;
-       int failures = 0;
-
-       /* Validate user parameters */
-       if (n % sizeof(int))
-               return -EINVAL;
-
-       /* Get a struct IR_tx reference */
-       tx = get_ir_tx(ir);
-       if (tx == NULL)
-               return -ENXIO;
-
-       /* Ensure our tx->c i2c_client remains valid for the duration */
-       mutex_lock(&tx->client_lock);
-       if (tx->c == NULL) {
-               mutex_unlock(&tx->client_lock);
-               put_ir_tx(tx, false);
-               return -ENXIO;
-       }
-
-       /* Lock i2c bus for the duration */
-       mutex_lock(&ir->ir_lock);
-
-       /* Send each keypress */
-       for (i = 0; i < n;) {
-               int ret = 0;
-               int command;
-
-               if (copy_from_user(&command, buf + i, sizeof(command))) {
-                       mutex_unlock(&ir->ir_lock);
-                       mutex_unlock(&tx->client_lock);
-                       put_ir_tx(tx, false);
-                       return -EFAULT;
-               }
-
-               /* Send boot data first if required */
-               if (tx->need_boot == 1) {
-                       /* Make sure we have the 'firmware' loaded, first */
-                       ret = fw_load(tx);
-                       if (ret != 0) {
-                               mutex_unlock(&ir->ir_lock);
-                               mutex_unlock(&tx->client_lock);
-                               put_ir_tx(tx, false);
-                               if (ret != -ENOMEM)
-                                       ret = -EIO;
-                               return ret;
-                       }
-                       /* Prep the chip for transmitting codes */
-                       ret = send_boot_data(tx);
-                       if (ret == 0)
-                               tx->need_boot = 0;
-               }
-
-               /* Send the code */
-               if (ret == 0) {
-                       ret = send_code(tx, (unsigned)command >> 16,
-                                           (unsigned)command & 0xFFFF);
-                       if (ret == -EPROTO) {
-                               mutex_unlock(&ir->ir_lock);
-                               mutex_unlock(&tx->client_lock);
-                               put_ir_tx(tx, false);
-                               return ret;
-                       }
-               }
-
-               /*
-                * Hmm, a failure.  If we've had a few then give up, otherwise
-                * try a reset
-                */
-               if (ret != 0) {
-                       /* Looks like the chip crashed, reset it */
-                       zilog_error("sending to the IR transmitter chip "
-                                   "failed, trying reset\n");
-
-                       if (failures >= 3) {
-                               zilog_error("unable to send to the IR chip "
-                                           "after 3 resets, giving up\n");
-                               mutex_unlock(&ir->ir_lock);
-                               mutex_unlock(&tx->client_lock);
-                               put_ir_tx(tx, false);
-                               return ret;
-                       }
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout((100 * HZ + 999) / 1000);
-                       tx->need_boot = 1;
-                       ++failures;
-               } else
-                       i += sizeof(int);
-       }
-
-       /* Release i2c bus */
-       mutex_unlock(&ir->ir_lock);
-
-       mutex_unlock(&tx->client_lock);
-
-       /* Give back our struct IR_tx reference */
-       put_ir_tx(tx, false);
-
-       /* All looks good */
-       return n;
-}
-
-/* copied from lirc_dev */
-static unsigned int poll(struct file *filep, poll_table *wait)
-{
-       struct IR *ir = filep->private_data;
-       struct IR_rx *rx;
-       struct lirc_buffer *rbuf = ir->l.rbuf;
-       unsigned int ret;
-
-       dprintk("poll called\n");
-
-       rx = get_ir_rx(ir);
-       if (rx == NULL) {
-               /*
-                * Revisit this, if our poll function ever reports writeable
-                * status for Tx
-                */
-               dprintk("poll result = POLLERR\n");
-               return POLLERR;
-       }
-
-       /*
-        * Add our lirc_buffer's wait_queue to the poll_table. A wake up on
-        * that buffer's wait queue indicates we may have a new poll status.
-        */
-       poll_wait(filep, &rbuf->wait_poll, wait);
-
-       /* Indicate what ops could happen immediately without blocking */
-       ret = lirc_buffer_empty(rbuf) ? 0 : (POLLIN|POLLRDNORM);
-
-       dprintk("poll result = %s\n", ret ? "POLLIN|POLLRDNORM" : "none");
-       return ret;
-}
-
-static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
-{
-       struct IR *ir = filep->private_data;
-       int result;
-       unsigned long mode, features;
-
-       features = ir->l.features;
-
-       switch (cmd) {
-       case LIRC_GET_LENGTH:
-               result = put_user((unsigned long)13,
-                                 (unsigned long *)arg);
-               break;
-       case LIRC_GET_FEATURES:
-               result = put_user(features, (unsigned long *) arg);
-               break;
-       case LIRC_GET_REC_MODE:
-               if (!(features&LIRC_CAN_REC_MASK))
-                       return -ENOSYS;
-
-               result = put_user(LIRC_REC2MODE
-                                 (features&LIRC_CAN_REC_MASK),
-                                 (unsigned long *)arg);
-               break;
-       case LIRC_SET_REC_MODE:
-               if (!(features&LIRC_CAN_REC_MASK))
-                       return -ENOSYS;
-
-               result = get_user(mode, (unsigned long *)arg);
-               if (!result && !(LIRC_MODE2REC(mode) & features))
-                       result = -EINVAL;
-               break;
-       case LIRC_GET_SEND_MODE:
-               if (!(features&LIRC_CAN_SEND_MASK))
-                       return -ENOSYS;
-
-               result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg);
-               break;
-       case LIRC_SET_SEND_MODE:
-               if (!(features&LIRC_CAN_SEND_MASK))
-                       return -ENOSYS;
-
-               result = get_user(mode, (unsigned long *) arg);
-               if (!result && mode != LIRC_MODE_PULSE)
-                       return -EINVAL;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return result;
-}
-
-static struct IR *get_ir_device_by_minor(unsigned int minor)
-{
-       struct IR *ir;
-       struct IR *ret = NULL;
-
-       mutex_lock(&ir_devices_lock);
-
-       if (!list_empty(&ir_devices_list)) {
-               list_for_each_entry(ir, &ir_devices_list, list) {
-                       if (ir->l.minor == minor) {
-                               ret = get_ir_device(ir, true);
-                               break;
-                       }
-               }
-       }
-
-       mutex_unlock(&ir_devices_lock);
-       return ret;
-}
-
-/*
- * Open the IR device.  Get hold of our IR structure and
- * stash it in private_data for the file
- */
-static int open(struct inode *node, struct file *filep)
-{
-       struct IR *ir;
-       unsigned int minor = MINOR(node->i_rdev);
-
-       /* find our IR struct */
-       ir = get_ir_device_by_minor(minor);
-
-       if (ir == NULL)
-               return -ENODEV;
-
-       atomic_inc(&ir->open_count);
-
-       /* stash our IR struct */
-       filep->private_data = ir;
-
-       nonseekable_open(node, filep);
-       return 0;
-}
-
-/* Close the IR device */
-static int close(struct inode *node, struct file *filep)
-{
-       /* find our IR struct */
-       struct IR *ir = filep->private_data;
-       if (ir == NULL) {
-               zilog_error("close: no private_data attached to the file!\n");
-               return -ENODEV;
-       }
-
-       atomic_dec(&ir->open_count);
-
-       put_ir_device(ir, false);
-       return 0;
-}
-
-static int ir_remove(struct i2c_client *client);
-static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id);
-
-#define ID_FLAG_TX     0x01
-#define ID_FLAG_HDPVR  0x02
-
-static const struct i2c_device_id ir_transceiver_id[] = {
-       { "ir_tx_z8f0811_haup",  ID_FLAG_TX                 },
-       { "ir_rx_z8f0811_haup",  0                          },
-       { "ir_tx_z8f0811_hdpvr", ID_FLAG_HDPVR | ID_FLAG_TX },
-       { "ir_rx_z8f0811_hdpvr", ID_FLAG_HDPVR              },
-       { }
-};
-
-static struct i2c_driver driver = {
-       .driver = {
-               .owner  = THIS_MODULE,
-               .name   = "Zilog/Hauppauge i2c IR",
-       },
-       .probe          = ir_probe,
-       .remove         = ir_remove,
-       .id_table       = ir_transceiver_id,
-};
-
-static const struct file_operations lirc_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .read           = read,
-       .write          = write,
-       .poll           = poll,
-       .unlocked_ioctl = ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl   = ioctl,
-#endif
-       .open           = open,
-       .release        = close
-};
-
-static struct lirc_driver lirc_template = {
-       .name           = "lirc_zilog",
-       .minor          = -1,
-       .code_length    = 13,
-       .buffer_size    = BUFLEN / 2,
-       .sample_rate    = 0, /* tell lirc_dev to not start its own kthread */
-       .chunk_size     = 2,
-       .set_use_inc    = set_use_inc,
-       .set_use_dec    = set_use_dec,
-       .fops           = &lirc_fops,
-       .owner          = THIS_MODULE,
-};
-
-static int ir_remove(struct i2c_client *client)
-{
-       if (strncmp("ir_tx_z8", client->name, 8) == 0) {
-               struct IR_tx *tx = i2c_get_clientdata(client);
-               if (tx != NULL) {
-                       mutex_lock(&tx->client_lock);
-                       tx->c = NULL;
-                       mutex_unlock(&tx->client_lock);
-                       put_ir_tx(tx, false);
-               }
-       } else if (strncmp("ir_rx_z8", client->name, 8) == 0) {
-               struct IR_rx *rx = i2c_get_clientdata(client);
-               if (rx != NULL) {
-                       mutex_lock(&rx->client_lock);
-                       rx->c = NULL;
-                       mutex_unlock(&rx->client_lock);
-                       put_ir_rx(rx, false);
-               }
-       }
-       return 0;
-}
-
-
-/* ir_devices_lock must be held */
-static struct IR *get_ir_device_by_adapter(struct i2c_adapter *adapter)
-{
-       struct IR *ir;
-
-       if (list_empty(&ir_devices_list))
-               return NULL;
-
-       list_for_each_entry(ir, &ir_devices_list, list)
-               if (ir->adapter == adapter) {
-                       get_ir_device(ir, true);
-                       return ir;
-               }
-
-       return NULL;
-}
-
-static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
-{
-       struct IR *ir;
-       struct IR_tx *tx;
-       struct IR_rx *rx;
-       struct i2c_adapter *adap = client->adapter;
-       int ret;
-       bool tx_probe = false;
-
-       dprintk("%s: %s on i2c-%d (%s), client addr=0x%02x\n",
-               __func__, id->name, adap->nr, adap->name, client->addr);
-
-       /*
-        * The IR receiver    is at i2c address 0x71.
-        * The IR transmitter is at i2c address 0x70.
-        */
-
-       if (id->driver_data & ID_FLAG_TX)
-               tx_probe = true;
-       else if (tx_only) /* module option */
-               return -ENXIO;
-
-       zilog_info("probing IR %s on %s (i2c-%d)\n",
-                  tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
-
-       mutex_lock(&ir_devices_lock);
-
-       /* Use a single struct IR instance for both the Rx and Tx functions */
-       ir = get_ir_device_by_adapter(adap);
-       if (ir == NULL) {
-               ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
-               if (ir == NULL) {
-                       ret = -ENOMEM;
-                       goto out_no_ir;
-               }
-               kref_init(&ir->ref);
-
-               /* store for use in ir_probe() again, and open() later on */
-               INIT_LIST_HEAD(&ir->list);
-               list_add_tail(&ir->list, &ir_devices_list);
-
-               ir->adapter = adap;
-               mutex_init(&ir->ir_lock);
-               atomic_set(&ir->open_count, 0);
-               spin_lock_init(&ir->tx_ref_lock);
-               spin_lock_init(&ir->rx_ref_lock);
-
-               /* set lirc_dev stuff */
-               memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
-               /*
-                * FIXME this is a pointer reference to us, but no refcount.
-                *
-                * This OK for now, since lirc_dev currently won't touch this
-                * buffer as we provide our own lirc_fops.
-                *
-                * Currently our own lirc_fops rely on this ir->l.rbuf pointer
-                */
-               ir->l.rbuf = &ir->rbuf;
-               ir->l.dev  = &adap->dev;
-               ret = lirc_buffer_init(ir->l.rbuf,
-                                      ir->l.chunk_size, ir->l.buffer_size);
-               if (ret)
-                       goto out_put_ir;
-       }
-
-       if (tx_probe) {
-               /* Get the IR_rx instance for later, if already allocated */
-               rx = get_ir_rx(ir);
-
-               /* Set up a struct IR_tx instance */
-               tx = kzalloc(sizeof(struct IR_tx), GFP_KERNEL);
-               if (tx == NULL) {
-                       ret = -ENOMEM;
-                       goto out_put_xx;
-               }
-               kref_init(&tx->ref);
-               ir->tx = tx;
-
-               ir->l.features |= LIRC_CAN_SEND_PULSE;
-               mutex_init(&tx->client_lock);
-               tx->c = client;
-               tx->need_boot = 1;
-               tx->post_tx_ready_poll =
-                              (id->driver_data & ID_FLAG_HDPVR) ? false : true;
-
-               /* An ir ref goes to the struct IR_tx instance */
-               tx->ir = get_ir_device(ir, true);
-
-               /* A tx ref goes to the i2c_client */
-               i2c_set_clientdata(client, get_ir_tx(ir));
-
-               /*
-                * Load the 'firmware'.  We do this before registering with
-                * lirc_dev, so the first firmware load attempt does not happen
-                * after a open() or write() call on the device.
-                *
-                * Failure here is not deemed catastrophic, so the receiver will
-                * still be usable.  Firmware load will be retried in write(),
-                * if it is needed.
-                */
-               fw_load(tx);
-
-               /* Proceed only if the Rx client is also ready or not needed */
-               if (rx == NULL && !tx_only) {
-                       zilog_info("probe of IR Tx on %s (i2c-%d) done. Waiting"
-                                  " on IR Rx.\n", adap->name, adap->nr);
-                       goto out_ok;
-               }
-       } else {
-               /* Get the IR_tx instance for later, if already allocated */
-               tx = get_ir_tx(ir);
-
-               /* Set up a struct IR_rx instance */
-               rx = kzalloc(sizeof(struct IR_rx), GFP_KERNEL);
-               if (rx == NULL) {
-                       ret = -ENOMEM;
-                       goto out_put_xx;
-               }
-               kref_init(&rx->ref);
-               ir->rx = rx;
-
-               ir->l.features |= LIRC_CAN_REC_LIRCCODE;
-               mutex_init(&rx->client_lock);
-               rx->c = client;
-               rx->hdpvr_data_fmt =
-                              (id->driver_data & ID_FLAG_HDPVR) ? true : false;
-
-               /* An ir ref goes to the struct IR_rx instance */
-               rx->ir = get_ir_device(ir, true);
-
-               /* An rx ref goes to the i2c_client */
-               i2c_set_clientdata(client, get_ir_rx(ir));
-
-               /*
-                * Start the polling thread.
-                * It will only perform an empty loop around schedule_timeout()
-                * until we register with lirc_dev and the first user open()
-                */
-               /* An ir ref goes to the new rx polling kthread */
-               rx->task = kthread_run(lirc_thread, get_ir_device(ir, true),
-                                      "zilog-rx-i2c-%d", adap->nr);
-               if (IS_ERR(rx->task)) {
-                       ret = PTR_ERR(rx->task);
-                       zilog_error("%s: could not start IR Rx polling thread"
-                                   "\n", __func__);
-                       /* Failed kthread, so put back the ir ref */
-                       put_ir_device(ir, true);
-                       /* Failure exit, so put back rx ref from i2c_client */
-                       i2c_set_clientdata(client, NULL);
-                       put_ir_rx(rx, true);
-                       ir->l.features &= ~LIRC_CAN_REC_LIRCCODE;
-                       goto out_put_xx;
-               }
-
-               /* Proceed only if the Tx client is also ready */
-               if (tx == NULL) {
-                       zilog_info("probe of IR Rx on %s (i2c-%d) done. Waiting"
-                                  " on IR Tx.\n", adap->name, adap->nr);
-                       goto out_ok;
-               }
-       }
-
-       /* register with lirc */
-       ir->l.minor = minor; /* module option: user requested minor number */
-       ir->l.minor = lirc_register_driver(&ir->l);
-       if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) {
-               zilog_error("%s: \"minor\" must be between 0 and %d (%d)!\n",
-                           __func__, MAX_IRCTL_DEVICES-1, ir->l.minor);
-               ret = -EBADRQC;
-               goto out_put_xx;
-       }
-       zilog_info("IR unit on %s (i2c-%d) registered as lirc%d and ready\n",
-                  adap->name, adap->nr, ir->l.minor);
-
-out_ok:
-       if (rx != NULL)
-               put_ir_rx(rx, true);
-       if (tx != NULL)
-               put_ir_tx(tx, true);
-       put_ir_device(ir, true);
-       zilog_info("probe of IR %s on %s (i2c-%d) done\n",
-                  tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
-       mutex_unlock(&ir_devices_lock);
-       return 0;
-
-out_put_xx:
-       if (rx != NULL)
-               put_ir_rx(rx, true);
-       if (tx != NULL)
-               put_ir_tx(tx, true);
-out_put_ir:
-       put_ir_device(ir, true);
-out_no_ir:
-       zilog_error("%s: probing IR %s on %s (i2c-%d) failed with %d\n",
-                   __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr,
-                  ret);
-       mutex_unlock(&ir_devices_lock);
-       return ret;
-}
-
-static int __init zilog_init(void)
-{
-       int ret;
-
-       zilog_notify("Zilog/Hauppauge IR driver initializing\n");
-
-       mutex_init(&tx_data_lock);
-
-       request_module("firmware_class");
-
-       ret = i2c_add_driver(&driver);
-       if (ret)
-               zilog_error("initialization failed\n");
-       else
-               zilog_notify("initialization complete\n");
-
-       return ret;
-}
-
-static void __exit zilog_exit(void)
-{
-       i2c_del_driver(&driver);
-       /* if loaded */
-       fw_unload();
-       zilog_notify("Zilog/Hauppauge IR driver unloaded\n");
-}
-
-module_init(zilog_init);
-module_exit(zilog_exit);
-
-MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)");
-MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, "
-             "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver, "
-             "Andy Walls");
-MODULE_LICENSE("GPL");
-/* for compat with old name, which isn't all that accurate anymore */
-MODULE_ALIAS("lirc_pvr150");
-
-module_param(minor, int, 0444);
-MODULE_PARM_DESC(minor, "Preferred minor device number");
-
-module_param(debug, bool, 0644);
-MODULE_PARM_DESC(debug, "Enable debugging messages");
-
-module_param(tx_only, bool, 0644);
-MODULE_PARM_DESC(tx_only, "Only handle the IR transmit function");
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
new file mode 100644 (file)
index 0000000..7e5caa3
--- /dev/null
@@ -0,0 +1,37 @@
+menuconfig STAGING_MEDIA
+        bool "Media staging drivers"
+        default n
+        ---help---
+          This option allows you to select a number of media drivers that
+         don't have the "normal" Linux kernel quality level.
+         Most of them don't follow properly the V4L, DVB and/or RC API's,
+         so, they won't likely work fine with the existing applications.
+         That also means that, one fixed, their API's will change to match
+         the existing ones.
+
+          If you wish to work on these drivers, to help improve them, or
+          to report problems you have with them, please use the
+         linux-media@vger.kernel.org mailing list.
+
+          If in doubt, say N here.
+
+
+if STAGING_MEDIA
+
+# Please keep them in alphabetic order
+source "drivers/staging/media/as102/Kconfig"
+
+source "drivers/staging/media/cxd2099/Kconfig"
+
+source "drivers/staging/media/dt3155v4l/Kconfig"
+
+source "drivers/staging/media/easycap/Kconfig"
+
+source "drivers/staging/media/go7007/Kconfig"
+
+source "drivers/staging/media/solo6x10/Kconfig"
+
+# Keep LIRC at the end, as it has sub-menus
+source "drivers/staging/media/lirc/Kconfig"
+
+endif
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
new file mode 100644 (file)
index 0000000..c69124c
--- /dev/null
@@ -0,0 +1,7 @@
+obj-$(CONFIG_DVB_AS102)                += as102/
+obj-$(CONFIG_DVB_CXD2099)      += cxd2099/
+obj-$(CONFIG_EASYCAP)          += easycap/
+obj-$(CONFIG_LIRC_STAGING)     += lirc/
+obj-$(CONFIG_SOLO6X10)         += solo6x10/
+obj-$(CONFIG_VIDEO_DT3155)     += dt3155v4l/
+obj-$(CONFIG_VIDEO_GO7007)     += go7007/
diff --git a/drivers/staging/media/cxd2099/Kconfig b/drivers/staging/media/cxd2099/Kconfig
new file mode 100644 (file)
index 0000000..b48aefd
--- /dev/null
@@ -0,0 +1,12 @@
+config DVB_CXD2099
+       tristate "CXD2099AR Common Interface driver"
+       depends on DVB_CORE && PCI && I2C
+       ---help---
+         Support for the CI module found on cards based on
+         - Micronas ngene PCIe bridge: cineS2 etc.
+         - Digital Devices PCIe bridge: Octopus series
+
+         For now, data is passed through '/dev/dvb/adapterX/sec0':
+           - Encrypted data must be written to 'sec0'.
+           - Decrypted data can be read from 'sec0'.
+           - Setup the CAM using device 'ca0'.
diff --git a/drivers/staging/media/cxd2099/Makefile b/drivers/staging/media/cxd2099/Makefile
new file mode 100644 (file)
index 0000000..64cfc77
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_DVB_CXD2099) += cxd2099.o
+
+ccflags-y += -Idrivers/media/dvb/dvb-core/
+ccflags-y += -Idrivers/media/dvb/frontends/
+ccflags-y += -Idrivers/media/common/tuners/
diff --git a/drivers/staging/media/cxd2099/TODO b/drivers/staging/media/cxd2099/TODO
new file mode 100644 (file)
index 0000000..375bb6f
--- /dev/null
@@ -0,0 +1,12 @@
+For now, data is passed through '/dev/dvb/adapterX/sec0':
+ - Encrypted data must be written to 'sec0'.
+ - Decrypted data can be read from 'sec0'.
+ - Setup the CAM using device 'ca0'.
+
+But this is wrong. There are some discussions about the proper way for
+doing it, as seen at:
+       http://www.mail-archive.com/linux-media@vger.kernel.org/msg22196.html
+
+While there's no proper fix for it, the driver should be kept in staging.
+
+Patches should be submitted to: linux-media@vger.kernel.org.
diff --git a/drivers/staging/media/cxd2099/cxd2099.c b/drivers/staging/media/cxd2099/cxd2099.c
new file mode 100644 (file)
index 0000000..1c04185
--- /dev/null
@@ -0,0 +1,716 @@
+/*
+ * cxd2099.c: Driver for the CXD2099AR Common Interface Controller
+ *
+ * Copyright (C) 2010-2011 Digital Devices GmbH
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include "cxd2099.h"
+
+#define MAX_BUFFER_SIZE 248
+
+struct cxd {
+       struct dvb_ca_en50221 en;
+
+       struct i2c_adapter *i2c;
+       struct cxd2099_cfg cfg;
+
+       u8     regs[0x23];
+       u8     lastaddress;
+       u8     clk_reg_f;
+       u8     clk_reg_b;
+       int    mode;
+       int    ready;
+       int    dr;
+       int    slot_stat;
+
+       u8     amem[1024];
+       int    amem_read;
+
+       int    cammode;
+       struct mutex lock;
+};
+
+static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr,
+                        u8 reg, u8 data)
+{
+       u8 m[2] = {reg, data};
+       struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = 2};
+
+       if (i2c_transfer(adapter, &msg, 1) != 1) {
+               printk(KERN_ERR "Failed to write to I2C register %02x@%02x!\n",
+                      reg, adr);
+               return -1;
+       }
+       return 0;
+}
+
+static int i2c_write(struct i2c_adapter *adapter, u8 adr,
+                    u8 *data, u8 len)
+{
+       struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len};
+
+       if (i2c_transfer(adapter, &msg, 1) != 1) {
+               printk(KERN_ERR "Failed to write to I2C!\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr,
+                       u8 reg, u8 *val)
+{
+       struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+                                  .buf = &reg, .len = 1},
+                                 {.addr = adr, .flags = I2C_M_RD,
+                                  .buf = val, .len = 1} };
+
+       if (i2c_transfer(adapter, msgs, 2) != 2) {
+               printk(KERN_ERR "error in i2c_read_reg\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int i2c_read(struct i2c_adapter *adapter, u8 adr,
+                   u8 reg, u8 *data, u8 n)
+{
+       struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+                                .buf = &reg, .len = 1},
+                               {.addr = adr, .flags = I2C_M_RD,
+                                .buf = data, .len = n} };
+
+       if (i2c_transfer(adapter, msgs, 2) != 2) {
+               printk(KERN_ERR "error in i2c_read\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int read_block(struct cxd *ci, u8 adr, u8 *data, u8 n)
+{
+       int status;
+
+       status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
+       if (!status) {
+               ci->lastaddress = adr;
+               status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, n);
+       }
+       return status;
+}
+
+static int read_reg(struct cxd *ci, u8 reg, u8 *val)
+{
+       return read_block(ci, reg, val, 1);
+}
+
+
+static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
+{
+       int status;
+       u8 addr[3] = {2, address & 0xff, address >> 8};
+
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
+       if (!status)
+               status = i2c_read(ci->i2c, ci->cfg.adr, 3, data, n);
+       return status;
+}
+
+static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
+{
+       int status;
+       u8 addr[3] = {2, address & 0xff, address >> 8};
+
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
+       if (!status) {
+               u8 buf[256] = {3};
+               memcpy(buf+1, data, n);
+               status = i2c_write(ci->i2c, ci->cfg.adr, buf, n+1);
+       }
+       return status;
+}
+
+static int read_io(struct cxd *ci, u16 address, u8 *val)
+{
+       int status;
+       u8 addr[3] = {2, address & 0xff, address >> 8};
+
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
+       if (!status)
+               status = i2c_read(ci->i2c, ci->cfg.adr, 3, val, 1);
+       return status;
+}
+
+static int write_io(struct cxd *ci, u16 address, u8 val)
+{
+       int status;
+       u8 addr[3] = {2, address & 0xff, address >> 8};
+       u8 buf[2] = {3, val};
+
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
+       if (!status)
+               status = i2c_write(ci->i2c, ci->cfg.adr, buf, 2);
+       return status;
+}
+
+#if 0
+static int read_io_data(struct cxd *ci, u8 *data, u8 n)
+{
+       int status;
+       u8 addr[3] = { 2, 0, 0 };
+
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
+       if (!status)
+               status = i2c_read(ci->i2c, ci->cfg.adr, 3, data, n);
+       return 0;
+}
+
+static int write_io_data(struct cxd *ci, u8 *data, u8 n)
+{
+       int status;
+       u8 addr[3] = {2, 0, 0};
+
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
+       if (!status) {
+               u8 buf[256] = {3};
+               memcpy(buf+1, data, n);
+               status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
+       }
+       return 0;
+}
+#endif
+
+static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask)
+{
+       int status;
+
+       status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, reg);
+       if (!status && reg >= 6 && reg <= 8 && mask != 0xff)
+               status = i2c_read_reg(ci->i2c, ci->cfg.adr, 1, &ci->regs[reg]);
+       ci->regs[reg] = (ci->regs[reg] & (~mask)) | val;
+       if (!status) {
+               ci->lastaddress = reg;
+               status = i2c_write_reg(ci->i2c, ci->cfg.adr, 1, ci->regs[reg]);
+       }
+       if (reg == 0x20)
+               ci->regs[reg] &= 0x7f;
+       return status;
+}
+
+static int write_reg(struct cxd *ci, u8 reg, u8 val)
+{
+       return write_regm(ci, reg, val, 0xff);
+}
+
+#ifdef BUFFER_MODE
+static int write_block(struct cxd *ci, u8 adr, u8 *data, int n)
+{
+       int status;
+       u8 buf[256] = {1};
+
+       status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
+       if (!status) {
+               ci->lastaddress = adr;
+               memcpy(buf + 1, data, n);
+               status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
+       }
+       return status;
+}
+#endif
+
+static void set_mode(struct cxd *ci, int mode)
+{
+       if (mode == ci->mode)
+               return;
+
+       switch (mode) {
+       case 0x00: /* IO mem */
+               write_regm(ci, 0x06, 0x00, 0x07);
+               break;
+       case 0x01: /* ATT mem */
+               write_regm(ci, 0x06, 0x02, 0x07);
+               break;
+       default:
+               break;
+       }
+       ci->mode = mode;
+}
+
+static void cam_mode(struct cxd *ci, int mode)
+{
+       if (mode == ci->cammode)
+               return;
+
+       switch (mode) {
+       case 0x00:
+               write_regm(ci, 0x20, 0x80, 0x80);
+               break;
+       case 0x01:
+#ifdef BUFFER_MODE
+               if (!ci->en.read_data)
+                       return;
+               printk(KERN_INFO "enable cam buffer mode\n");
+               /* write_reg(ci, 0x0d, 0x00); */
+               /* write_reg(ci, 0x0e, 0x01); */
+               write_regm(ci, 0x08, 0x40, 0x40);
+               /* read_reg(ci, 0x12, &dummy); */
+               write_regm(ci, 0x08, 0x80, 0x80);
+#endif
+               break;
+       default:
+               break;
+       }
+       ci->cammode = mode;
+}
+
+
+
+static int init(struct cxd *ci)
+{
+       int status;
+
+       mutex_lock(&ci->lock);
+       ci->mode = -1;
+       do {
+               status = write_reg(ci, 0x00, 0x00);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x01, 0x00);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x02, 0x10);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x03, 0x00);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x05, 0xFF);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x06, 0x1F);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x07, 0x1F);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x08, 0x28);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x14, 0x20);
+               if (status < 0)
+                       break;
+
+#if 0
+               status = write_reg(ci, 0x09, 0x4D); /* Input Mode C, BYPass Serial, TIVAL = low, MSB */
+               if (status < 0)
+                       break;
+#endif
+               status = write_reg(ci, 0x0A, 0xA7); /* TOSTRT = 8, Mode B (gated clock), falling Edge, Serial, POL=HIGH, MSB */
+               if (status < 0)
+                       break;
+
+               status = write_reg(ci, 0x0B, 0x33);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x0C, 0x33);
+               if (status < 0)
+                       break;
+
+               status = write_regm(ci, 0x14, 0x00, 0x0F);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x15, ci->clk_reg_b);
+               if (status < 0)
+                       break;
+               status = write_regm(ci, 0x16, 0x00, 0x0F);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x17, ci->clk_reg_f);
+               if (status < 0)
+                       break;
+
+               if (ci->cfg.clock_mode) {
+                       if (ci->cfg.polarity) {
+                               status = write_reg(ci, 0x09, 0x6f);
+                               if (status < 0)
+                                       break;
+                       } else {
+                               status = write_reg(ci, 0x09, 0x6d);
+                               if (status < 0)
+                                       break;
+                       }
+                       status = write_reg(ci, 0x20, 0x68);
+                       if (status < 0)
+                               break;
+                       status = write_reg(ci, 0x21, 0x00);
+                       if (status < 0)
+                               break;
+                       status = write_reg(ci, 0x22, 0x02);
+                       if (status < 0)
+                               break;
+               } else {
+                       if (ci->cfg.polarity) {
+                               status = write_reg(ci, 0x09, 0x4f);
+                               if (status < 0)
+                                       break;
+                       } else {
+                               status = write_reg(ci, 0x09, 0x4d);
+                               if (status < 0)
+                                       break;
+                       }
+
+                       status = write_reg(ci, 0x20, 0x28);
+                       if (status < 0)
+                               break;
+                       status = write_reg(ci, 0x21, 0x00);
+                       if (status < 0)
+                               break;
+                       status = write_reg(ci, 0x22, 0x07);
+                       if (status < 0)
+                               break;
+               }
+
+               status = write_regm(ci, 0x20, 0x80, 0x80);
+               if (status < 0)
+                       break;
+               status = write_regm(ci, 0x03, 0x02, 0x02);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x01, 0x04);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x00, 0x31);
+               if (status < 0)
+                       break;
+
+               /* Put TS in bypass */
+               status = write_regm(ci, 0x09, 0x08, 0x08);
+               if (status < 0)
+                       break;
+               ci->cammode = -1;
+               cam_mode(ci, 0);
+       } while (0);
+       mutex_unlock(&ci->lock);
+
+       return 0;
+}
+
+static int read_attribute_mem(struct dvb_ca_en50221 *ca,
+                             int slot, int address)
+{
+       struct cxd *ci = ca->data;
+#if 0
+       if (ci->amem_read) {
+               if (address <= 0 || address > 1024)
+                       return -EIO;
+               return ci->amem[address];
+       }
+
+       mutex_lock(&ci->lock);
+       write_regm(ci, 0x06, 0x00, 0x05);
+       read_pccard(ci, 0, &ci->amem[0], 128);
+       read_pccard(ci, 128, &ci->amem[0], 128);
+       read_pccard(ci, 256, &ci->amem[0], 128);
+       read_pccard(ci, 384, &ci->amem[0], 128);
+       write_regm(ci, 0x06, 0x05, 0x05);
+       mutex_unlock(&ci->lock);
+       return ci->amem[address];
+#else
+       u8 val;
+       mutex_lock(&ci->lock);
+       set_mode(ci, 1);
+       read_pccard(ci, address, &val, 1);
+       mutex_unlock(&ci->lock);
+       /* printk(KERN_INFO "%02x:%02x\n", address,val); */
+       return val;
+#endif
+}
+
+static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot,
+                              int address, u8 value)
+{
+       struct cxd *ci = ca->data;
+
+       mutex_lock(&ci->lock);
+       set_mode(ci, 1);
+       write_pccard(ci, address, &value, 1);
+       mutex_unlock(&ci->lock);
+       return 0;
+}
+
+static int read_cam_control(struct dvb_ca_en50221 *ca,
+                           int slot, u8 address)
+{
+       struct cxd *ci = ca->data;
+       u8 val;
+
+       mutex_lock(&ci->lock);
+       set_mode(ci, 0);
+       read_io(ci, address, &val);
+       mutex_unlock(&ci->lock);
+       return val;
+}
+
+static int write_cam_control(struct dvb_ca_en50221 *ca, int slot,
+                            u8 address, u8 value)
+{
+       struct cxd *ci = ca->data;
+
+       mutex_lock(&ci->lock);
+       set_mode(ci, 0);
+       write_io(ci, address, value);
+       mutex_unlock(&ci->lock);
+       return 0;
+}
+
+static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
+{
+       struct cxd *ci = ca->data;
+
+       mutex_lock(&ci->lock);
+#if 0
+       write_reg(ci, 0x00, 0x21);
+       write_reg(ci, 0x06, 0x1F);
+       write_reg(ci, 0x00, 0x31);
+#else
+#if 0
+       write_reg(ci, 0x06, 0x1F);
+       write_reg(ci, 0x06, 0x2F);
+#else
+       cam_mode(ci, 0);
+       write_reg(ci, 0x00, 0x21);
+       write_reg(ci, 0x06, 0x1F);
+       write_reg(ci, 0x00, 0x31);
+       write_regm(ci, 0x20, 0x80, 0x80);
+       write_reg(ci, 0x03, 0x02);
+       ci->ready = 0;
+#endif
+#endif
+       ci->mode = -1;
+       {
+               int i;
+#if 0
+               u8 val;
+#endif
+               for (i = 0; i < 100; i++) {
+                       msleep(10);
+#if 0
+                       read_reg(ci, 0x06, &val);
+                       printk(KERN_INFO "%d:%02x\n", i, val);
+                       if (!(val&0x10))
+                               break;
+#else
+                       if (ci->ready)
+                               break;
+#endif
+               }
+       }
+       mutex_unlock(&ci->lock);
+       /* msleep(500); */
+       return 0;
+}
+
+static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
+{
+       struct cxd *ci = ca->data;
+
+       printk(KERN_INFO "slot_shutdown\n");
+       mutex_lock(&ci->lock);
+       write_regm(ci, 0x09, 0x08, 0x08);
+       write_regm(ci, 0x20, 0x80, 0x80); /* Reset CAM Mode */
+       write_regm(ci, 0x06, 0x07, 0x07); /* Clear IO Mode */
+       ci->mode = -1;
+       mutex_unlock(&ci->lock);
+       return 0;
+}
+
+static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
+{
+       struct cxd *ci = ca->data;
+
+       mutex_lock(&ci->lock);
+       write_regm(ci, 0x09, 0x00, 0x08);
+       set_mode(ci, 0);
+#ifdef BUFFER_MODE
+       cam_mode(ci, 1);
+#endif
+       mutex_unlock(&ci->lock);
+       return 0;
+}
+
+
+static int campoll(struct cxd *ci)
+{
+       u8 istat;
+
+       read_reg(ci, 0x04, &istat);
+       if (!istat)
+               return 0;
+       write_reg(ci, 0x05, istat);
+
+       if (istat&0x40) {
+               ci->dr = 1;
+               printk(KERN_INFO "DR\n");
+       }
+       if (istat&0x20)
+               printk(KERN_INFO "WC\n");
+
+       if (istat&2) {
+               u8 slotstat;
+
+               read_reg(ci, 0x01, &slotstat);
+               if (!(2&slotstat)) {
+                       if (!ci->slot_stat) {
+                               ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_PRESENT;
+                               write_regm(ci, 0x03, 0x08, 0x08);
+                       }
+
+               } else {
+                       if (ci->slot_stat) {
+                               ci->slot_stat = 0;
+                               write_regm(ci, 0x03, 0x00, 0x08);
+                               printk(KERN_INFO "NO CAM\n");
+                               ci->ready = 0;
+                       }
+               }
+               if (istat&8 && ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) {
+                       ci->ready = 1;
+                       ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY;
+               }
+       }
+       return 0;
+}
+
+
+static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
+{
+       struct cxd *ci = ca->data;
+       u8 slotstat;
+
+       mutex_lock(&ci->lock);
+       campoll(ci);
+       read_reg(ci, 0x01, &slotstat);
+       mutex_unlock(&ci->lock);
+
+       return ci->slot_stat;
+}
+
+#ifdef BUFFER_MODE
+static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
+{
+       struct cxd *ci = ca->data;
+       u8 msb, lsb;
+       u16 len;
+
+       mutex_lock(&ci->lock);
+       campoll(ci);
+       mutex_unlock(&ci->lock);
+
+       printk(KERN_INFO "read_data\n");
+       if (!ci->dr)
+               return 0;
+
+       mutex_lock(&ci->lock);
+       read_reg(ci, 0x0f, &msb);
+       read_reg(ci, 0x10, &lsb);
+       len = (msb<<8)|lsb;
+       read_block(ci, 0x12, ebuf, len);
+       ci->dr = 0;
+       mutex_unlock(&ci->lock);
+
+       return len;
+}
+
+static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
+{
+       struct cxd *ci = ca->data;
+
+       mutex_lock(&ci->lock);
+       printk(kern_INFO "write_data %d\n", ecount);
+       write_reg(ci, 0x0d, ecount>>8);
+       write_reg(ci, 0x0e, ecount&0xff);
+       write_block(ci, 0x11, ebuf, ecount);
+       mutex_unlock(&ci->lock);
+       return ecount;
+}
+#endif
+
+static struct dvb_ca_en50221 en_templ = {
+       .read_attribute_mem  = read_attribute_mem,
+       .write_attribute_mem = write_attribute_mem,
+       .read_cam_control    = read_cam_control,
+       .write_cam_control   = write_cam_control,
+       .slot_reset          = slot_reset,
+       .slot_shutdown       = slot_shutdown,
+       .slot_ts_enable      = slot_ts_enable,
+       .poll_slot_status    = poll_slot_status,
+#ifdef BUFFER_MODE
+       .read_data           = read_data,
+       .write_data          = write_data,
+#endif
+
+};
+
+struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
+                                     void *priv,
+                                     struct i2c_adapter *i2c)
+{
+       struct cxd *ci = 0;
+       u8 val;
+
+       if (i2c_read_reg(i2c, cfg->adr, 0, &val) < 0) {
+               printk(KERN_INFO "No CXD2099 detected at %02x\n", cfg->adr);
+               return 0;
+       }
+
+       ci = kmalloc(sizeof(struct cxd), GFP_KERNEL);
+       if (!ci)
+               return 0;
+       memset(ci, 0, sizeof(*ci));
+
+       mutex_init(&ci->lock);
+       memcpy(&ci->cfg, cfg, sizeof(struct cxd2099_cfg));
+       ci->i2c = i2c;
+       ci->lastaddress = 0xff;
+       ci->clk_reg_b = 0x4a;
+       ci->clk_reg_f = 0x1b;
+
+       memcpy(&ci->en, &en_templ, sizeof(en_templ));
+       ci->en.data = ci;
+       init(ci);
+       printk(KERN_INFO "Attached CXD2099AR at %02x\n", ci->cfg.adr);
+       return &ci->en;
+}
+EXPORT_SYMBOL(cxd2099_attach);
+
+MODULE_DESCRIPTION("cxd2099");
+MODULE_AUTHOR("Ralph Metzler");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/cxd2099/cxd2099.h b/drivers/staging/media/cxd2099/cxd2099.h
new file mode 100644 (file)
index 0000000..19c588a
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * cxd2099.h: Driver for the CXD2099AR Common Interface Controller
+ *
+ * Copyright (C) 2010-2011 Digital Devices GmbH
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _CXD2099_H_
+#define _CXD2099_H_
+
+#include <dvb_ca_en50221.h>
+
+struct cxd2099_cfg {
+       u32 bitrate;
+       u8  adr;
+       u8  polarity:1;
+       u8  clock_mode:1;
+};
+
+#if defined(CONFIG_DVB_CXD2099) || \
+       (defined(CONFIG_DVB_CXD2099_MODULE) && defined(MODULE))
+struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
+                                     void *priv, struct i2c_adapter *i2c);
+#else
+
+static inline struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
+                                       void *priv, struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/staging/media/dt3155v4l/Kconfig b/drivers/staging/media/dt3155v4l/Kconfig
new file mode 100644 (file)
index 0000000..226a1ca
--- /dev/null
@@ -0,0 +1,28 @@
+config VIDEO_DT3155
+       tristate "DT3155 frame grabber, Video4Linux interface"
+       depends on PCI && VIDEO_DEV && VIDEO_V4L2
+       select VIDEOBUF2_DMA_CONTIG
+       default n
+       ---help---
+         Enables dt3155 device driver for the DataTranslation DT3155 frame grabber.
+         Say Y here if you have this hardware.
+         In doubt, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called dt3155v4l.
+
+config DT3155_CCIR
+       bool "Selects CCIR/50Hz vertical refresh"
+       depends on VIDEO_DT3155
+       default y
+       ---help---
+         Select it for CCIR/50Hz (European region),
+         or leave it unselected for RS-170/60Hz (North America).
+
+config DT3155_STREAMING
+       bool "Selects streaming capture method"
+       depends on VIDEO_DT3155
+       default y
+       ---help---
+         Select it if you want to use streaming of memory mapped buffers
+         or leave it unselected if you want to use read method (one copy more).
diff --git a/drivers/staging/media/dt3155v4l/Makefile b/drivers/staging/media/dt3155v4l/Makefile
new file mode 100644 (file)
index 0000000..ce7a3ec
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_DT3155)     += dt3155v4l.o
diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c
new file mode 100644 (file)
index 0000000..04e93c4
--- /dev/null
@@ -0,0 +1,993 @@
+/***************************************************************************
+ *   Copyright (C) 2006-2010 by Marin Mitov                                *
+ *   mitov@issp.bas.bg                                                     *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/stringify.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "dt3155v4l.h"
+
+#define DT3155_VENDOR_ID 0x8086
+#define DT3155_DEVICE_ID 0x1223
+
+/* DT3155_CHUNK_SIZE is 4M (2^22) 8 full size buffers */
+#define DT3155_CHUNK_SIZE (1U << 22)
+
+#define DT3155_COH_FLAGS (GFP_KERNEL | GFP_DMA32 | __GFP_COLD | __GFP_NOWARN)
+
+#define DT3155_BUF_SIZE (768 * 576)
+
+#ifdef CONFIG_DT3155_STREAMING
+#define DT3155_CAPTURE_METHOD V4L2_CAP_STREAMING
+#else
+#define DT3155_CAPTURE_METHOD V4L2_CAP_READWRITE
+#endif
+
+/*  global initializers (for all boards)  */
+#ifdef CONFIG_DT3155_CCIR
+static const u8 csr2_init = VT_50HZ;
+#define DT3155_CURRENT_NORM V4L2_STD_625_50
+static const unsigned int img_width = 768;
+static const unsigned int img_height = 576;
+static const unsigned int frames_per_sec = 25;
+static const struct v4l2_fmtdesc frame_std[] = {
+       {
+       .index = 0,
+       .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+       .flags = 0,
+       .description = "CCIR/50Hz 8 bits gray",
+       .pixelformat = V4L2_PIX_FMT_GREY,
+       },
+};
+#else
+static const u8 csr2_init = VT_60HZ;
+#define DT3155_CURRENT_NORM V4L2_STD_525_60
+static const unsigned int img_width = 640;
+static const unsigned int img_height = 480;
+static const unsigned int frames_per_sec = 30;
+static const struct v4l2_fmtdesc frame_std[] = {
+       {
+       .index = 0,
+       .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+       .flags = 0,
+       .description = "RS-170/60Hz 8 bits gray",
+       .pixelformat = V4L2_PIX_FMT_GREY,
+       },
+};
+#endif
+
+#define NUM_OF_FORMATS ARRAY_SIZE(frame_std)
+
+static u8 config_init = ACQ_MODE_EVEN;
+
+/**
+ * read_i2c_reg - reads an internal i2c register
+ *
+ * @addr:      dt3155 mmio base address
+ * @index:     index (internal address) of register to read
+ * @data:      pointer to byte the read data will be placed in
+ *
+ * returns:    zero on success or error code
+ *
+ * This function starts reading the specified (by index) register
+ * and busy waits for the process to finish. The result is placed
+ * in a byte pointed by data.
+ */
+static int
+read_i2c_reg(void __iomem *addr, u8 index, u8 *data)
+{
+       u32 tmp = index;
+
+       iowrite32((tmp<<17) | IIC_READ, addr + IIC_CSR2);
+       mmiowb();
+       udelay(45); /* wait at least 43 usec for NEW_CYCLE to clear */
+       if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
+               return -EIO; /* error: NEW_CYCLE not cleared */
+       tmp = ioread32(addr + IIC_CSR1);
+       if (tmp & DIRECT_ABORT) {
+               /* reset DIRECT_ABORT bit */
+               iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
+               return -EIO; /* error: DIRECT_ABORT set */
+       }
+       *data = tmp>>24;
+       return 0;
+}
+
+/**
+ * write_i2c_reg - writes to an internal i2c register
+ *
+ * @addr:      dt3155 mmio base address
+ * @index:     index (internal address) of register to read
+ * @data:      data to be written
+ *
+ * returns:    zero on success or error code
+ *
+ * This function starts writting the specified (by index) register
+ * and busy waits for the process to finish.
+ */
+static int
+write_i2c_reg(void __iomem *addr, u8 index, u8 data)
+{
+       u32 tmp = index;
+
+       iowrite32((tmp<<17) | IIC_WRITE | data, addr + IIC_CSR2);
+       mmiowb();
+       udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */
+       if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
+               return -EIO; /* error: NEW_CYCLE not cleared */
+       if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
+               /* reset DIRECT_ABORT bit */
+               iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
+               return -EIO; /* error: DIRECT_ABORT set */
+       }
+       return 0;
+}
+
+/**
+ * write_i2c_reg_nowait - writes to an internal i2c register
+ *
+ * @addr:      dt3155 mmio base address
+ * @index:     index (internal address) of register to read
+ * @data:      data to be written
+ *
+ * This function starts writting the specified (by index) register
+ * and then returns.
+ */
+static void write_i2c_reg_nowait(void __iomem *addr, u8 index, u8 data)
+{
+       u32 tmp = index;
+
+       iowrite32((tmp<<17) | IIC_WRITE | data, addr + IIC_CSR2);
+       mmiowb();
+}
+
+/**
+ * wait_i2c_reg - waits the read/write to finish
+ *
+ * @addr:      dt3155 mmio base address
+ *
+ * returns:    zero on success or error code
+ *
+ * This function waits reading/writting to finish.
+ */
+static int wait_i2c_reg(void __iomem *addr)
+{
+       if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
+               udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */
+       if (ioread32(addr + IIC_CSR2) & NEW_CYCLE)
+               return -EIO; /* error: NEW_CYCLE not cleared */
+       if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) {
+               /* reset DIRECT_ABORT bit */
+               iowrite32(DIRECT_ABORT, addr + IIC_CSR1);
+               return -EIO; /* error: DIRECT_ABORT set */
+       }
+       return 0;
+}
+
+static int
+dt3155_start_acq(struct dt3155_priv *pd)
+{
+       struct vb2_buffer *vb = pd->curr_buf;
+       dma_addr_t dma_addr;
+
+       dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+       iowrite32(dma_addr, pd->regs + EVEN_DMA_START);
+       iowrite32(dma_addr + img_width, pd->regs + ODD_DMA_START);
+       iowrite32(img_width, pd->regs + EVEN_DMA_STRIDE);
+       iowrite32(img_width, pd->regs + ODD_DMA_STRIDE);
+       /* enable interrupts, clear all irq flags */
+       iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
+                       FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR);
+       iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
+                 FLD_DN_ODD | FLD_DN_EVEN | CAP_CONT_EVEN | CAP_CONT_ODD,
+                                                       pd->regs + CSR1);
+       wait_i2c_reg(pd->regs);
+       write_i2c_reg(pd->regs, CONFIG, pd->config);
+       write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE);
+       write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_DONE);
+
+       /*  start the board  */
+       write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | BUSY_ODD);
+       return 0; /* success  */
+}
+
+/*
+ *     driver-specific callbacks (vb2_ops)
+ */
+static int
+dt3155_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+                       unsigned int *num_planes, unsigned long sizes[],
+                                               void *alloc_ctxs[])
+{
+       struct dt3155_priv *pd = vb2_get_drv_priv(q);
+       void *ret;
+
+       if (*num_buffers == 0)
+               *num_buffers = 1;
+       *num_planes = 1;
+       sizes[0] = img_width * img_height;
+       if (pd->q->alloc_ctx[0])
+               return 0;
+       ret = vb2_dma_contig_init_ctx(&pd->pdev->dev);
+       if (IS_ERR(ret))
+               return PTR_ERR(ret);
+       pd->q->alloc_ctx[0] = ret;
+       return 0;
+}
+
+static void
+dt3155_wait_prepare(struct vb2_queue *q)
+{
+       struct dt3155_priv *pd = vb2_get_drv_priv(q);
+
+       mutex_unlock(pd->vdev->lock);
+}
+
+static void
+dt3155_wait_finish(struct vb2_queue *q)
+{
+       struct dt3155_priv *pd = vb2_get_drv_priv(q);
+
+       mutex_lock(pd->vdev->lock);
+}
+
+static int
+dt3155_buf_prepare(struct vb2_buffer *vb)
+{
+       vb2_set_plane_payload(vb, 0, img_width * img_height);
+       return 0;
+}
+
+static int
+dt3155_start_streaming(struct vb2_queue *q)
+{
+       return 0;
+}
+
+static int
+dt3155_stop_streaming(struct vb2_queue *q)
+{
+       struct dt3155_priv *pd = vb2_get_drv_priv(q);
+       struct vb2_buffer *vb;
+
+       spin_lock_irq(&pd->lock);
+       while (!list_empty(&pd->dmaq)) {
+               vb = list_first_entry(&pd->dmaq, typeof(*vb), done_entry);
+               list_del(&vb->done_entry);
+               vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+       }
+       spin_unlock_irq(&pd->lock);
+       msleep(45); /* irq hendler will stop the hardware */
+       return 0;
+}
+
+static void
+dt3155_buf_queue(struct vb2_buffer *vb)
+{
+       struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue);
+
+       /*  pd->q->streaming = 1 when dt3155_buf_queue() is invoked  */
+       spin_lock_irq(&pd->lock);
+       if (pd->curr_buf)
+               list_add_tail(&vb->done_entry, &pd->dmaq);
+       else {
+               pd->curr_buf = vb;
+               dt3155_start_acq(pd);
+       }
+       spin_unlock_irq(&pd->lock);
+}
+/*
+ *     end driver-specific callbacks
+ */
+
+const struct vb2_ops q_ops = {
+       .queue_setup = dt3155_queue_setup,
+       .wait_prepare = dt3155_wait_prepare,
+       .wait_finish = dt3155_wait_finish,
+       .buf_prepare = dt3155_buf_prepare,
+       .start_streaming = dt3155_start_streaming,
+       .stop_streaming = dt3155_stop_streaming,
+       .buf_queue = dt3155_buf_queue,
+};
+
+static irqreturn_t
+dt3155_irq_handler_even(int irq, void *dev_id)
+{
+       struct dt3155_priv *ipd = dev_id;
+       struct vb2_buffer *ivb;
+       dma_addr_t dma_addr;
+       u32 tmp;
+
+       tmp = ioread32(ipd->regs + INT_CSR) & (FLD_START | FLD_END_ODD);
+       if (!tmp)
+               return IRQ_NONE;  /* not our irq */
+       if ((tmp & FLD_START) && !(tmp & FLD_END_ODD)) {
+               iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START,
+                                                       ipd->regs + INT_CSR);
+               ipd->field_count++;
+               return IRQ_HANDLED; /* start of field irq */
+       }
+       if ((tmp & FLD_START) && (tmp & FLD_END_ODD))
+               ipd->stats.start_before_end++;
+       /*      check for corrupted fields     */
+/*     write_i2c_reg(ipd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE);       */
+/*     write_i2c_reg(ipd->regs, ODD_CSR, CSR_ERROR | CSR_DONE);        */
+       tmp = ioread32(ipd->regs + CSR1) & (FLD_CRPT_EVEN | FLD_CRPT_ODD);
+       if (tmp) {
+               ipd->stats.corrupted_fields++;
+               iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
+                                               FLD_DN_ODD | FLD_DN_EVEN |
+                                               CAP_CONT_EVEN | CAP_CONT_ODD,
+                                                       ipd->regs + CSR1);
+               mmiowb();
+       }
+
+       spin_lock(&ipd->lock);
+       if (ipd->curr_buf) {
+               do_gettimeofday(&ipd->curr_buf->v4l2_buf.timestamp);
+               ipd->curr_buf->v4l2_buf.sequence = (ipd->field_count) >> 1;
+               vb2_buffer_done(ipd->curr_buf, VB2_BUF_STATE_DONE);
+       }
+
+       if (!ipd->q->streaming || list_empty(&ipd->dmaq))
+               goto stop_dma;
+       ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), done_entry);
+       list_del(&ivb->done_entry);
+       ipd->curr_buf = ivb;
+       dma_addr = vb2_dma_contig_plane_dma_addr(ivb, 0);
+       iowrite32(dma_addr, ipd->regs + EVEN_DMA_START);
+       iowrite32(dma_addr + img_width, ipd->regs + ODD_DMA_START);
+       iowrite32(img_width, ipd->regs + EVEN_DMA_STRIDE);
+       iowrite32(img_width, ipd->regs + ODD_DMA_STRIDE);
+       mmiowb();
+       /* enable interrupts, clear all irq flags */
+       iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START |
+                       FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR);
+       spin_unlock(&ipd->lock);
+       return IRQ_HANDLED;
+
+stop_dma:
+       ipd->curr_buf = NULL;
+       /* stop the board */
+       write_i2c_reg_nowait(ipd->regs, CSR2, ipd->csr2);
+       iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN |
+                 FLD_DN_ODD | FLD_DN_EVEN, ipd->regs + CSR1);
+       /* disable interrupts, clear all irq flags */
+       iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR);
+       spin_unlock(&ipd->lock);
+       return IRQ_HANDLED;
+}
+
+static int
+dt3155_open(struct file *filp)
+{
+       int ret = 0;
+       struct dt3155_priv *pd = video_drvdata(filp);
+
+       if (!pd->users) {
+               pd->q = kzalloc(sizeof(*pd->q), GFP_KERNEL);
+               if (!pd->q) {
+                       ret = -ENOMEM;
+                       goto err_alloc_queue;
+               }
+               pd->q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               pd->q->io_modes = VB2_READ | VB2_MMAP;
+               pd->q->ops = &q_ops;
+               pd->q->mem_ops = &vb2_dma_contig_memops;
+               pd->q->drv_priv = pd;
+               pd->curr_buf = NULL;
+               pd->field_count = 0;
+               vb2_queue_init(pd->q); /* cannot fail */
+               INIT_LIST_HEAD(&pd->dmaq);
+               spin_lock_init(&pd->lock);
+               /* disable all irqs, clear all irq flags */
+               iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD,
+                                               pd->regs + INT_CSR);
+               ret = request_irq(pd->pdev->irq, dt3155_irq_handler_even,
+                                               IRQF_SHARED, DT3155_NAME, pd);
+               if (ret)
+                       goto err_request_irq;
+       }
+       pd->users++;
+       return 0; /* success */
+err_request_irq:
+       kfree(pd->q);
+       pd->q = NULL;
+err_alloc_queue:
+       return ret;
+}
+
+static int
+dt3155_release(struct file *filp)
+{
+       struct dt3155_priv *pd = video_drvdata(filp);
+
+       pd->users--;
+       BUG_ON(pd->users < 0);
+       if (!pd->users) {
+               vb2_queue_release(pd->q);
+               free_irq(pd->pdev->irq, pd);
+               if (pd->q->alloc_ctx[0])
+                       vb2_dma_contig_cleanup_ctx(pd->q->alloc_ctx[0]);
+               kfree(pd->q);
+               pd->q = NULL;
+       }
+       return 0;
+}
+
+static ssize_t
+dt3155_read(struct file *filp, char __user *user, size_t size, loff_t *loff)
+{
+       struct dt3155_priv *pd = video_drvdata(filp);
+
+       return vb2_read(pd->q, user, size, loff, filp->f_flags & O_NONBLOCK);
+}
+
+static unsigned int
+dt3155_poll(struct file *filp, struct poll_table_struct *polltbl)
+{
+       struct dt3155_priv *pd = video_drvdata(filp);
+
+       return vb2_poll(pd->q, filp, polltbl);
+}
+
+static int
+dt3155_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct dt3155_priv *pd = video_drvdata(filp);
+
+       return vb2_mmap(pd->q, vma);
+}
+
+static const struct v4l2_file_operations dt3155_fops = {
+       .owner = THIS_MODULE,
+       .open = dt3155_open,
+       .release = dt3155_release,
+       .read = dt3155_read,
+       .poll = dt3155_poll,
+       .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+       .mmap = dt3155_mmap,
+};
+
+static int
+dt3155_ioc_streamon(struct file *filp, void *p, enum v4l2_buf_type type)
+{
+       struct dt3155_priv *pd = video_drvdata(filp);
+
+       return vb2_streamon(pd->q, type);
+}
+
+static int
+dt3155_ioc_streamoff(struct file *filp, void *p, enum v4l2_buf_type type)
+{
+       struct dt3155_priv *pd = video_drvdata(filp);
+
+       return vb2_streamoff(pd->q, type);
+}
+
+static int
+dt3155_ioc_querycap(struct file *filp, void *p, struct v4l2_capability *cap)
+{
+       struct dt3155_priv *pd = video_drvdata(filp);
+
+       strcpy(cap->driver, DT3155_NAME);
+       strcpy(cap->card, DT3155_NAME " frame grabber");
+       sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev));
+       cap->version =
+              KERNEL_VERSION(DT3155_VER_MAJ, DT3155_VER_MIN, DT3155_VER_EXT);
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+                               DT3155_CAPTURE_METHOD;
+       return 0;
+}
+
+static int
+dt3155_ioc_enum_fmt_vid_cap(struct file *filp, void *p, struct v4l2_fmtdesc *f)
+{
+       if (f->index >= NUM_OF_FORMATS)
+               return -EINVAL;
+       *f = frame_std[f->index];
+       return 0;
+}
+
+static int
+dt3155_ioc_g_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
+{
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       f->fmt.pix.width = img_width;
+       f->fmt.pix.height = img_height;
+       f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY;
+       f->fmt.pix.field = V4L2_FIELD_NONE;
+       f->fmt.pix.bytesperline = f->fmt.pix.width;
+       f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height;
+       f->fmt.pix.colorspace = 0;
+       f->fmt.pix.priv = 0;
+       return 0;
+}
+
+static int
+dt3155_ioc_try_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
+{
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (f->fmt.pix.width == img_width &&
+               f->fmt.pix.height == img_height &&
+               f->fmt.pix.pixelformat == V4L2_PIX_FMT_GREY &&
+               f->fmt.pix.field == V4L2_FIELD_NONE &&
+               f->fmt.pix.bytesperline == f->fmt.pix.width &&
+               f->fmt.pix.sizeimage == f->fmt.pix.width * f->fmt.pix.height)
+                       return 0;
+       else
+               return -EINVAL;
+}
+
+static int
+dt3155_ioc_s_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
+{
+       return dt3155_ioc_g_fmt_vid_cap(filp, p, f);
+}
+
+static int
+dt3155_ioc_reqbufs(struct file *filp, void *p, struct v4l2_requestbuffers *b)
+{
+       struct dt3155_priv *pd = video_drvdata(filp);
+
+       return vb2_reqbufs(pd->q, b);
+}
+
+static int
+dt3155_ioc_querybuf(struct file *filp, void *p, struct v4l2_buffer *b)
+{
+       struct dt3155_priv *pd = video_drvdata(filp);
+
+       return vb2_querybuf(pd->q, b);
+}
+
+static int
+dt3155_ioc_qbuf(struct file *filp, void *p, struct v4l2_buffer *b)
+{
+       struct dt3155_priv *pd = video_drvdata(filp);
+
+       return vb2_qbuf(pd->q, b);
+}
+
+static int
+dt3155_ioc_dqbuf(struct file *filp, void *p, struct v4l2_buffer *b)
+{
+       struct dt3155_priv *pd = video_drvdata(filp);
+
+       return vb2_dqbuf(pd->q, b, filp->f_flags & O_NONBLOCK);
+}
+
+static int
+dt3155_ioc_querystd(struct file *filp, void *p, v4l2_std_id *norm)
+{
+       *norm = DT3155_CURRENT_NORM;
+       return 0;
+}
+
+static int
+dt3155_ioc_g_std(struct file *filp, void *p, v4l2_std_id *norm)
+{
+       *norm = DT3155_CURRENT_NORM;
+       return 0;
+}
+
+static int
+dt3155_ioc_s_std(struct file *filp, void *p, v4l2_std_id *norm)
+{
+       if (*norm & DT3155_CURRENT_NORM)
+               return 0;
+       return -EINVAL;
+}
+
+static int
+dt3155_ioc_enum_input(struct file *filp, void *p, struct v4l2_input *input)
+{
+       if (input->index)
+               return -EINVAL;
+       strcpy(input->name, "Coax in");
+       input->type = V4L2_INPUT_TYPE_CAMERA;
+       /*
+        * FIXME: input->std = 0 according to v4l2 API
+        * VIDIOC_G_STD, VIDIOC_S_STD, VIDIOC_QUERYSTD and VIDIOC_ENUMSTD
+        * should return -EINVAL
+        */
+       input->std = DT3155_CURRENT_NORM;
+       input->status = 0;/* FIXME: add sync detection & V4L2_IN_ST_NO_H_LOCK */
+       return 0;
+}
+
+static int
+dt3155_ioc_g_input(struct file *filp, void *p, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
+
+static int
+dt3155_ioc_s_input(struct file *filp, void *p, unsigned int i)
+{
+       if (i)
+               return -EINVAL;
+       return 0;
+}
+
+static int
+dt3155_ioc_g_parm(struct file *filp, void *p, struct v4l2_streamparm *parms)
+{
+       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       parms->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+       parms->parm.capture.capturemode = 0;
+       parms->parm.capture.timeperframe.numerator = 1001;
+       parms->parm.capture.timeperframe.denominator = frames_per_sec * 1000;
+       parms->parm.capture.extendedmode = 0;
+       parms->parm.capture.readbuffers = 1; /* FIXME: 2 buffers? */
+       return 0;
+}
+
+static int
+dt3155_ioc_s_parm(struct file *filp, void *p, struct v4l2_streamparm *parms)
+{
+       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       parms->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+       parms->parm.capture.capturemode = 0;
+       parms->parm.capture.timeperframe.numerator = 1001;
+       parms->parm.capture.timeperframe.denominator = frames_per_sec * 1000;
+       parms->parm.capture.extendedmode = 0;
+       parms->parm.capture.readbuffers = 1; /* FIXME: 2 buffers? */
+       return 0;
+}
+
+static const struct v4l2_ioctl_ops dt3155_ioctl_ops = {
+       .vidioc_streamon = dt3155_ioc_streamon,
+       .vidioc_streamoff = dt3155_ioc_streamoff,
+       .vidioc_querycap = dt3155_ioc_querycap,
+/*
+       .vidioc_g_priority = dt3155_ioc_g_priority,
+       .vidioc_s_priority = dt3155_ioc_s_priority,
+*/
+       .vidioc_enum_fmt_vid_cap = dt3155_ioc_enum_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap = dt3155_ioc_try_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap = dt3155_ioc_g_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap = dt3155_ioc_s_fmt_vid_cap,
+       .vidioc_reqbufs = dt3155_ioc_reqbufs,
+       .vidioc_querybuf = dt3155_ioc_querybuf,
+       .vidioc_qbuf = dt3155_ioc_qbuf,
+       .vidioc_dqbuf = dt3155_ioc_dqbuf,
+       .vidioc_querystd = dt3155_ioc_querystd,
+       .vidioc_g_std = dt3155_ioc_g_std,
+       .vidioc_s_std = dt3155_ioc_s_std,
+       .vidioc_enum_input = dt3155_ioc_enum_input,
+       .vidioc_g_input = dt3155_ioc_g_input,
+       .vidioc_s_input = dt3155_ioc_s_input,
+/*
+       .vidioc_queryctrl = dt3155_ioc_queryctrl,
+       .vidioc_g_ctrl = dt3155_ioc_g_ctrl,
+       .vidioc_s_ctrl = dt3155_ioc_s_ctrl,
+       .vidioc_querymenu = dt3155_ioc_querymenu,
+       .vidioc_g_ext_ctrls = dt3155_ioc_g_ext_ctrls,
+       .vidioc_s_ext_ctrls = dt3155_ioc_s_ext_ctrls,
+*/
+       .vidioc_g_parm = dt3155_ioc_g_parm,
+       .vidioc_s_parm = dt3155_ioc_s_parm,
+/*
+       .vidioc_cropcap = dt3155_ioc_cropcap,
+       .vidioc_g_crop = dt3155_ioc_g_crop,
+       .vidioc_s_crop = dt3155_ioc_s_crop,
+       .vidioc_enum_framesizes = dt3155_ioc_enum_framesizes,
+       .vidioc_enum_frameintervals = dt3155_ioc_enum_frameintervals,
+*/
+};
+
+static int __devinit
+dt3155_init_board(struct pci_dev *pdev)
+{
+       struct dt3155_priv *pd = pci_get_drvdata(pdev);
+       void *buf_cpu;
+       dma_addr_t buf_dma;
+       int i;
+       u8 tmp;
+
+       pci_set_master(pdev); /* dt3155 needs it */
+
+       /*  resetting the adapter  */
+       iowrite32(FLD_CRPT_ODD | FLD_CRPT_EVEN | FLD_DN_ODD | FLD_DN_EVEN,
+                                                       pd->regs + CSR1);
+       mmiowb();
+       msleep(20);
+
+       /*  initializing adaper registers  */
+       iowrite32(FIFO_EN | SRST, pd->regs + CSR1);
+       mmiowb();
+       iowrite32(0xEEEEEE01, pd->regs + EVEN_PIXEL_FMT);
+       iowrite32(0xEEEEEE01, pd->regs + ODD_PIXEL_FMT);
+       iowrite32(0x00000020, pd->regs + FIFO_TRIGER);
+       iowrite32(0x00000103, pd->regs + XFER_MODE);
+       iowrite32(0, pd->regs + RETRY_WAIT_CNT);
+       iowrite32(0, pd->regs + INT_CSR);
+       iowrite32(1, pd->regs + EVEN_FLD_MASK);
+       iowrite32(1, pd->regs + ODD_FLD_MASK);
+       iowrite32(0, pd->regs + MASK_LENGTH);
+       iowrite32(0x0005007C, pd->regs + FIFO_FLAG_CNT);
+       iowrite32(0x01010101, pd->regs + IIC_CLK_DUR);
+       mmiowb();
+
+       /* verifying that we have a DT3155 board (not just a SAA7116 chip) */
+       read_i2c_reg(pd->regs, DT_ID, &tmp);
+       if (tmp != DT3155_ID)
+               return -ENODEV;
+
+       /* initialize AD LUT */
+       write_i2c_reg(pd->regs, AD_ADDR, 0);
+       for (i = 0; i < 256; i++)
+               write_i2c_reg(pd->regs, AD_LUT, i);
+
+       /* initialize ADC references */
+       /* FIXME: pos_ref & neg_ref depend on VT_50HZ */
+       write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
+       write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
+       write_i2c_reg(pd->regs, AD_ADDR, AD_POS_REF);
+       write_i2c_reg(pd->regs, AD_CMD, 34);
+       write_i2c_reg(pd->regs, AD_ADDR, AD_NEG_REF);
+       write_i2c_reg(pd->regs, AD_CMD, 0);
+
+       /* initialize PM LUT */
+       write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM);
+       for (i = 0; i < 256; i++) {
+               write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
+               write_i2c_reg(pd->regs, PM_LUT_DATA, i);
+       }
+       write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM | PM_LUT_SEL);
+       for (i = 0; i < 256; i++) {
+               write_i2c_reg(pd->regs, PM_LUT_ADDR, i);
+               write_i2c_reg(pd->regs, PM_LUT_DATA, i);
+       }
+       write_i2c_reg(pd->regs, CONFIG, pd->config); /*  ACQ_MODE_EVEN  */
+
+       /* select chanel 1 for input and set sync level */
+       write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG);
+       write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3);
+
+       /* allocate memory, and initialize the DMA machine */
+       buf_cpu = dma_alloc_coherent(&pdev->dev, DT3155_BUF_SIZE, &buf_dma,
+                                                               GFP_KERNEL);
+       if (!buf_cpu)
+               return -ENOMEM;
+       iowrite32(buf_dma, pd->regs + EVEN_DMA_START);
+       iowrite32(buf_dma, pd->regs + ODD_DMA_START);
+       iowrite32(0, pd->regs + EVEN_DMA_STRIDE);
+       iowrite32(0, pd->regs + ODD_DMA_STRIDE);
+
+       /*  Perform a pseudo even field acquire    */
+       iowrite32(FIFO_EN | SRST | CAP_CONT_ODD, pd->regs + CSR1);
+       write_i2c_reg(pd->regs, CSR2, pd->csr2 | SYNC_SNTL);
+       write_i2c_reg(pd->regs, CONFIG, pd->config);
+       write_i2c_reg(pd->regs, EVEN_CSR, CSR_SNGL);
+       write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | SYNC_SNTL);
+       msleep(100);
+       read_i2c_reg(pd->regs, CSR2, &tmp);
+       write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_SNGL | CSR_DONE);
+       write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_SNGL | CSR_DONE);
+       write_i2c_reg(pd->regs, CSR2, pd->csr2);
+       iowrite32(FIFO_EN | SRST | FLD_DN_EVEN | FLD_DN_ODD, pd->regs + CSR1);
+
+       /*  deallocate memory  */
+       dma_free_coherent(&pdev->dev, DT3155_BUF_SIZE, buf_cpu, buf_dma);
+       if (tmp & BUSY_EVEN)
+               return -EIO;
+       return 0;
+}
+
+static struct video_device dt3155_vdev = {
+       .name = DT3155_NAME,
+       .fops = &dt3155_fops,
+       .ioctl_ops = &dt3155_ioctl_ops,
+       .minor = -1,
+       .release = video_device_release,
+       .tvnorms = DT3155_CURRENT_NORM,
+       .current_norm = DT3155_CURRENT_NORM,
+};
+
+/* same as in drivers/base/dma-coherent.c */
+struct dma_coherent_mem {
+       void            *virt_base;
+       dma_addr_t      device_base;
+       int             size;
+       int             flags;
+       unsigned long   *bitmap;
+};
+
+static int __devinit
+dt3155_alloc_coherent(struct device *dev, size_t size, int flags)
+{
+       struct dma_coherent_mem *mem;
+       dma_addr_t dev_base;
+       int pages = size >> PAGE_SHIFT;
+       int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
+
+       if ((flags & DMA_MEMORY_MAP) == 0)
+               goto out;
+       if (!size)
+               goto out;
+       if (dev->dma_mem)
+               goto out;
+
+       mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+       if (!mem)
+               goto out;
+       mem->virt_base = dma_alloc_coherent(dev, size, &dev_base,
+                                                       DT3155_COH_FLAGS);
+       if (!mem->virt_base)
+               goto err_alloc_coherent;
+       mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+       if (!mem->bitmap)
+               goto err_bitmap;
+
+       /* coherent_dma_mask is already set to 32 bits */
+       mem->device_base = dev_base;
+       mem->size = pages;
+       mem->flags = flags;
+       dev->dma_mem = mem;
+       return DMA_MEMORY_MAP;
+
+err_bitmap:
+       dma_free_coherent(dev, size, mem->virt_base, dev_base);
+err_alloc_coherent:
+       kfree(mem);
+out:
+       return 0;
+}
+
+static void __devexit
+dt3155_free_coherent(struct device *dev)
+{
+       struct dma_coherent_mem *mem = dev->dma_mem;
+
+       if (!mem)
+               return;
+       dev->dma_mem = NULL;
+       dma_free_coherent(dev, mem->size << PAGE_SHIFT,
+                                       mem->virt_base, mem->device_base);
+       kfree(mem->bitmap);
+       kfree(mem);
+}
+
+static int __devinit
+dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       int err;
+       struct dt3155_priv *pd;
+
+       err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+       if (err)
+               return -ENODEV;
+       err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+       if (err)
+               return -ENODEV;
+       pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+       if (!pd)
+               return -ENOMEM;
+       pd->vdev = video_device_alloc();
+       if (!pd->vdev)
+               goto err_video_device_alloc;
+       *pd->vdev = dt3155_vdev;
+       pci_set_drvdata(pdev, pd);    /* for use in dt3155_remove() */
+       video_set_drvdata(pd->vdev, pd);  /* for use in video_fops */
+       pd->users = 0;
+       pd->pdev = pdev;
+       INIT_LIST_HEAD(&pd->dmaq);
+       mutex_init(&pd->mux);
+       pd->vdev->lock = &pd->mux; /* for locking v4l2_file_operations */
+       spin_lock_init(&pd->lock);
+       pd->csr2 = csr2_init;
+       pd->config = config_init;
+       err = pci_enable_device(pdev);
+       if (err)
+               goto err_enable_dev;
+       err = pci_request_region(pdev, 0, pci_name(pdev));
+       if (err)
+               goto err_req_region;
+       pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0));
+       if (!pd->regs)
+               err = -ENOMEM;
+               goto err_pci_iomap;
+       err = dt3155_init_board(pdev);
+       if (err)
+               goto err_init_board;
+       err = video_register_device(pd->vdev, VFL_TYPE_GRABBER, -1);
+       if (err)
+               goto err_init_board;
+       if (dt3155_alloc_coherent(&pdev->dev, DT3155_CHUNK_SIZE,
+                                                       DMA_MEMORY_MAP))
+               dev_info(&pdev->dev, "preallocated 8 buffers\n");
+       dev_info(&pdev->dev, "/dev/video%i is ready\n", pd->vdev->minor);
+       return 0;  /*   success   */
+
+err_init_board:
+       pci_iounmap(pdev, pd->regs);
+err_pci_iomap:
+       pci_release_region(pdev, 0);
+err_req_region:
+       pci_disable_device(pdev);
+err_enable_dev:
+       video_device_release(pd->vdev);
+err_video_device_alloc:
+       kfree(pd);
+       return err;
+}
+
+static void __devexit
+dt3155_remove(struct pci_dev *pdev)
+{
+       struct dt3155_priv *pd = pci_get_drvdata(pdev);
+
+       dt3155_free_coherent(&pdev->dev);
+       video_unregister_device(pd->vdev);
+       pci_iounmap(pdev, pd->regs);
+       pci_release_region(pdev, 0);
+       pci_disable_device(pdev);
+       /*
+        * video_device_release() is invoked automatically
+        * see: struct video_device dt3155_vdev
+        */
+       kfree(pd);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
+       { PCI_DEVICE(DT3155_VENDOR_ID, DT3155_DEVICE_ID) },
+       { 0, /* zero marks the end */ },
+};
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static struct pci_driver pci_driver = {
+       .name = DT3155_NAME,
+       .id_table = pci_ids,
+       .probe = dt3155_probe,
+       .remove = __devexit_p(dt3155_remove),
+};
+
+static int __init
+dt3155_init_module(void)
+{
+       return pci_register_driver(&pci_driver);
+}
+
+static void __exit
+dt3155_exit_module(void)
+{
+       pci_unregister_driver(&pci_driver);
+}
+
+module_init(dt3155_init_module);
+module_exit(dt3155_exit_module);
+
+MODULE_DESCRIPTION("video4linux pci-driver for dt3155 frame grabber");
+MODULE_AUTHOR("Marin Mitov <mitov@issp.bas.bg>");
+MODULE_VERSION(DT3155_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.h b/drivers/staging/media/dt3155v4l/dt3155v4l.h
new file mode 100644 (file)
index 0000000..2e4f89d
--- /dev/null
@@ -0,0 +1,212 @@
+/***************************************************************************
+ *   Copyright (C) 2006-2010 by Marin Mitov                                *
+ *   mitov@issp.bas.bg                                                     *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+/*    DT3155 header file    */
+#ifndef _DT3155_H_
+#define _DT3155_H_
+
+#ifdef __KERNEL__
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+#define DT3155_NAME "dt3155"
+#define DT3155_VER_MAJ 1
+#define DT3155_VER_MIN 1
+#define DT3155_VER_EXT 0
+#define DT3155_VERSION  __stringify(DT3155_VER_MAJ)    "."             \
+                       __stringify(DT3155_VER_MIN)     "."             \
+                       __stringify(DT3155_VER_EXT)
+
+/* DT3155 Base Register offsets (memory mapped) */
+#define EVEN_DMA_START  0x00
+#define ODD_DMA_START   0x0C
+#define EVEN_DMA_STRIDE  0x18
+#define ODD_DMA_STRIDE  0x24
+#define EVEN_PIXEL_FMT  0x30
+#define ODD_PIXEL_FMT   0x34
+#define FIFO_TRIGER     0x38
+#define XFER_MODE       0x3C
+#define CSR1            0x40
+#define RETRY_WAIT_CNT  0x44
+#define INT_CSR                 0x48
+#define EVEN_FLD_MASK   0x4C
+#define ODD_FLD_MASK    0x50
+#define MASK_LENGTH     0x54
+#define FIFO_FLAG_CNT   0x58
+#define IIC_CLK_DUR     0x5C
+#define IIC_CSR1        0x60
+#define IIC_CSR2        0x64
+
+/*  DT3155 Internal Registers indexes (i2c/IIC mapped) */
+#define CSR2        0x10
+#define EVEN_CSR     0x11
+#define ODD_CSR      0x12
+#define CONFIG      0x13
+#define DT_ID       0x1F
+#define X_CLIP_START 0x20
+#define Y_CLIP_START 0x22
+#define X_CLIP_END   0x24
+#define Y_CLIP_END   0x26
+#define AD_ADDR      0x30
+#define AD_LUT      0x31
+#define AD_CMD      0x32
+#define DIG_OUT      0x40
+#define PM_LUT_ADDR  0x50
+#define PM_LUT_DATA  0x51
+
+/* AD command register values  */
+#define AD_CMD_REG   0x00
+#define AD_POS_REF   0x01
+#define AD_NEG_REF   0x02
+
+/* CSR1 bit masks */
+#define CRPT_DIS       0x00004000
+#define FLD_CRPT_ODD   0x00000200
+#define FLD_CRPT_EVEN  0x00000100
+#define FIFO_EN        0x00000080
+#define SRST          0x00000040
+#define FLD_DN_ODD     0x00000020
+#define FLD_DN_EVEN    0x00000010
+/*   These should not be used.
+ *   Use CAP_CONT_ODD/EVEN instead
+#define CAP_SNGL_ODD   0x00000008
+#define CAP_SNGL_EVEN  0x00000004
+*/
+#define CAP_CONT_ODD   0x00000002
+#define CAP_CONT_EVEN  0x00000001
+
+/*  INT_CSR bit masks */
+#define FLD_START_EN    0x00000400
+#define FLD_END_ODD_EN  0x00000200
+#define FLD_END_EVEN_EN  0x00000100
+#define FLD_START       0x00000004
+#define FLD_END_ODD     0x00000002
+#define FLD_END_EVEN    0x00000001
+
+/* IIC_CSR1 bit masks */
+#define DIRECT_ABORT    0x00000200
+
+/* IIC_CSR2 bit masks */
+#define NEW_CYCLE   0x01000000
+#define DIR_RD     0x00010000
+#define IIC_READ    0x01010000
+#define IIC_WRITE   0x01000000
+
+/* CSR2 bit masks */
+#define DISP_PASS     0x40
+#define BUSY_ODD      0x20
+#define BUSY_EVEN     0x10
+#define SYNC_PRESENT  0x08
+#define VT_50HZ       0x04
+#define SYNC_SNTL     0x02
+#define CHROM_FILT    0x01
+#define VT_60HZ       0x00
+
+/* CSR_EVEN/ODD bit masks */
+#define CSR_ERROR      0x04
+#define CSR_SNGL       0x02
+#define CSR_DONE       0x01
+
+/* CONFIG bit masks */
+#define PM_LUT_PGM     0x80
+#define PM_LUT_SEL     0x40
+#define CLIP_EN        0x20
+#define HSCALE_EN      0x10
+#define EXT_TRIG_UP    0x0C
+#define EXT_TRIG_DOWN  0x04
+#define ACQ_MODE_NEXT  0x02
+#define ACQ_MODE_ODD   0x01
+#define ACQ_MODE_EVEN  0x00
+
+/* AD_CMD bit masks */
+#define VIDEO_CNL_1  0x00
+#define VIDEO_CNL_2  0x40
+#define VIDEO_CNL_3  0x80
+#define VIDEO_CNL_4  0xC0
+#define SYNC_CNL_1   0x00
+#define SYNC_CNL_2   0x10
+#define SYNC_CNL_3   0x20
+#define SYNC_CNL_4   0x30
+#define SYNC_LVL_1   0x00
+#define SYNC_LVL_2   0x04
+#define SYNC_LVL_3   0x08
+#define SYNC_LVL_4   0x0C
+
+/* DT3155 identificator */
+#define DT3155_ID   0x20
+
+#ifdef CONFIG_DT3155_CCIR
+#define DMA_STRIDE 768
+#else
+#define DMA_STRIDE 640
+#endif
+
+/**
+ * struct dt3155_stats - statistics structure
+ *
+ * @free_bufs_empty:   no free image buffers
+ * @corrupted_fields:  corrupted fields
+ * @dma_map_failed:    dma mapping failed
+ * @start_before_end:  new started before old ended
+ */
+struct dt3155_stats {
+       int free_bufs_empty;
+       int corrupted_fields;
+       int dma_map_failed;
+       int start_before_end;
+};
+
+/*    per board private data structure   */
+/**
+ * struct dt3155_priv - private data structure
+ *
+ * @vdev:              pointer to video_device structure
+ * @pdev:              pointer to pci_dev structure
+ * @q                  pointer to vb2_queue structure
+ * @curr_buf:          pointer to curren buffer
+ * @mux:               mutex to protect the instance
+ * @dmaq               queue for dma buffers
+ * @lock               spinlock for dma queue
+ * @field_count                fields counter
+ * @stats:             statistics structure
+ * @users              open count
+ * @regs:              local copy of mmio base register
+ * @csr2:              local copy of csr2 register
+ * @config:            local copy of config register
+ */
+struct dt3155_priv {
+       struct video_device *vdev;
+       struct pci_dev *pdev;
+       struct vb2_queue *q;
+       struct vb2_buffer *curr_buf;
+       struct mutex mux;
+       struct list_head dmaq;
+       spinlock_t lock;
+       unsigned int field_count;
+       struct dt3155_stats stats;
+       void __iomem *regs;
+       int users;
+       u8 csr2, config;
+};
+
+#endif /*  __KERNEL__  */
+
+#endif /*  _DT3155_H_  */
diff --git a/drivers/staging/media/easycap/Kconfig b/drivers/staging/media/easycap/Kconfig
new file mode 100644 (file)
index 0000000..a425a6f
--- /dev/null
@@ -0,0 +1,30 @@
+config EASYCAP
+       tristate "EasyCAP USB ID 05e1:0408 support"
+       depends on USB && VIDEO_DEV && SND
+       select SND_PCM
+
+       ---help---
+         This is an integrated audio/video driver for EasyCAP cards with
+         USB ID 05e1:0408.  It supports two hardware variants:
+
+         *  EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,
+            having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)
+
+         *  EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled
+            1, 2, 3, 4 and an unlabelled input cable for a microphone.
+
+         To compile this driver as a module, choose M here: the
+         module will be called easycap
+
+config EASYCAP_DEBUG
+       bool "Enable EasyCAP driver debugging"
+       depends on EASYCAP
+
+       ---help---
+         This option enables debug printouts
+
+         To enable debug, pass the debug level to the debug module
+          parameter:
+
+          modprobe easycap debug=[0..9]
+
diff --git a/drivers/staging/media/easycap/Makefile b/drivers/staging/media/easycap/Makefile
new file mode 100644 (file)
index 0000000..a34e75f
--- /dev/null
@@ -0,0 +1,10 @@
+easycap-objs := easycap_main.o
+easycap-objs += easycap_low.o
+easycap-objs += easycap_ioctl.o
+easycap-objs += easycap_settings.o
+easycap-objs += easycap_testcard.o
+easycap-objs += easycap_sound.o
+obj-$(CONFIG_EASYCAP) += easycap.o
+
+ccflags-y := -Wall
+
diff --git a/drivers/staging/media/easycap/README b/drivers/staging/media/easycap/README
new file mode 100644 (file)
index 0000000..796b032
--- /dev/null
@@ -0,0 +1,141 @@
+
+        ***********************************************************
+        *   EasyCAP USB 2.0 Video Adapter with Audio, Model DC60  *
+        *                            and                          *
+        *             EasyCAP002 4-Channel USB 2.0 DVR            *
+        ***********************************************************
+                     Mike Thomas  <rmthomas@sciolus.org>
+
+
+
+SUPPORTED HARDWARE
+------------------
+
+This driver is intended for use with hardware having USB ID 05e1:0408.
+Two kinds of EasyCAP have this USB ID, namely:
+
+    *  EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,
+       having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)
+
+    *  EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled
+       1, 2, 3, 4 and an unlabelled input cable for a microphone.
+
+
+BUILD OPTIONS AND DEPENDENCIES
+------------------------------
+
+Unless EASYCAP_DEBUG is defined during compilation it will not be possible
+to select a debug level at the time of module installation.
+
+
+KNOWN RUNTIME ISSUES
+--------------------
+
+(1) Intentionally, this driver will not stream material which is unambiguously
+identified by the hardware as copy-protected.  Normal video output will be
+present for about a minute but will then freeze when this situation arises.
+
+(2) The controls for luminance, contrast, saturation, hue and volume may not
+always work properly.
+
+(3) Reduced-resolution S-Video seems to suffer from moire artefacts.
+
+
+INPUT NUMBERING
+---------------
+
+For the EasyCAP with S-VIDEO input cable the driver regards a request for
+inputs numbered 0 or 1 as referring to CVBS and a request for input
+numbered 5 as referring to S-VIDEO.
+
+For the EasyCAP with four CVBS inputs the driver expects to be asked for
+any one of inputs numbered 1,2,3,4.  If input 0 is asked for, it is
+interpreted as input 1.
+
+
+MODULE PARAMETERS
+-----------------
+
+Three module parameters are defined:
+
+debug      the easycap module is configured at diagnostic level n (0 to 9)
+gain       audio gain level n (0 to 31, default is 16)
+bars       whether to display testcard bars when incoming video signal is lost
+           0 => no, 1 => yes (default)
+
+
+SUPPORTED TV STANDARDS AND RESOLUTIONS
+--------------------------------------
+
+The following TV standards are natively supported by the hardware and are
+usable as (for example) the "norm=" parameter in the mplayer command:
+
+    PAL_BGHIN,    NTSC_N_443,
+    PAL_Nc,       NTSC_N,
+    SECAM,        NTSC_M,        NTSC_M_JP,
+    PAL_60,       NTSC_443,
+    PAL_M.
+
+In addition, the driver offers "custom" pseudo-standards with a framerate
+which is 20% of the usual framerate.  These pseudo-standards are named:
+
+    PAL_BGHIN_SLOW,    NTSC_N_443_SLOW,
+    PAL_Nc_SLOW,       NTSC_N_SLOW,
+    SECAM_SLOW,        NTSC_M_SLOW,        NTSC_M_JP_SLOW,
+    PAL_60_SLOW,       NTSC_443_SLOW,
+    PAL_M_SLOW.
+
+
+The available picture sizes are:
+
+     at 25 frames per second:   720x576, 704x576, 640x480, 360x288, 320x240;
+     at 30 frames per second:   720x480, 640x480, 360x240, 320x240.
+
+
+WHAT'S TESTED AND WHAT'S NOT
+----------------------------
+
+This driver is known to work with mplayer, mencoder, tvtime, zoneminder,
+xawtv, gstreamer and sufficiently recent versions of vlc.  An interface
+to ffmpeg is implemented, but serious audio-video synchronization problems
+remain.
+
+The driver is designed to support all the TV standards accepted by the
+hardware, but as yet it has actually been tested on only a few of these.
+
+I have been unable to test and calibrate the S-video input myself because I
+do not possess any equipment with S-video output.
+
+
+UDEV RULES
+----------
+
+In order that the special files /dev/easycap0 and /dev/easysnd1 are created
+with conveniently relaxed permissions when the EasyCAP is plugged in, a file
+is preferably to be provided in directory /etc/udev/rules.d with content:
+
+ACTION!="add|change", GOTO="easycap_rules_end"
+ATTRS{idVendor}=="05e1", ATTRS{idProduct}=="0408", \
+       MODE="0666", OWNER="root", GROUP="root"
+LABEL="easycap_rules_end"
+
+
+MODPROBE CONFIGURATION
+----------------------
+
+The easycap module is in competition with the module snd-usb-audio for the
+EasyCAP's audio channel, and its installation can be aided by providing a
+file in directory /etc/modprobe.d with content:
+
+options easycap  gain=16 bars=1
+install easycap /sbin/rmmod snd-usb-audio; /sbin/modprobe --ignore-install easycap
+
+
+ACKNOWLEGEMENTS AND REFERENCES
+------------------------------
+This driver makes use of information contained in the Syntek Semicon DC-1125
+Driver, presently maintained at http://sourceforge.net/projects/syntekdriver/
+by Nicolas Vivien.  Particularly useful has been a patch to the latter driver
+provided by Ivor Hewitt in January 2009.  The NTSC implementation is taken
+from the work of Ben Trask.
+
diff --git a/drivers/staging/media/easycap/easycap.h b/drivers/staging/media/easycap/easycap.h
new file mode 100644 (file)
index 0000000..7b256a9
--- /dev/null
@@ -0,0 +1,594 @@
+/*****************************************************************************
+*                                                                            *
+*  easycap.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
+ *
+*/
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  THE FOLLOWING PARAMETERS ARE UNDEFINED:
+ *
+ *                EASYCAP_DEBUG
+ *
+ *  IF REQUIRED THEY MUST BE EXTERNALLY DEFINED, FOR EXAMPLE AS COMPILER
+ *  OPTIONS.
+ */
+/*---------------------------------------------------------------------------*/
+
+#ifndef __EASYCAP_H__
+#define __EASYCAP_H__
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  THESE ARE NORMALLY DEFINED
+ */
+/*---------------------------------------------------------------------------*/
+#define  PATIENCE  500
+#define  PERSEVERE
+/*---------------------------------------------------------------------------*/
+/*
+ *  THESE ARE FOR MAINTENANCE ONLY - NORMALLY UNDEFINED:
+ */
+/*---------------------------------------------------------------------------*/
+#undef  EASYCAP_TESTCARD
+/*---------------------------------------------------------------------------*/
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/uaccess.h>
+
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+
+#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>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <linux/videodev2.h>
+#include <linux/soundcard.h>
+
+/*---------------------------------------------------------------------------*/
+/*  VENDOR, PRODUCT:  Syntek Semiconductor Co., Ltd
+ *
+ *      EITHER        EasyCAP USB 2.0 Video Adapter with Audio, Model No. DC60
+ *               with input cabling:  AUDIO(L), AUDIO(R), CVBS, S-VIDEO.
+ *
+ *          OR        EasyCAP 4CHANNEL USB 2.0 DVR, Model No. EasyCAP002
+ *               with input cabling:  MICROPHONE, CVBS1, CVBS2, CVBS3, CVBS4.
+ */
+/*---------------------------------------------------------------------------*/
+#define USB_EASYCAP_VENDOR_ID  0x05e1
+#define USB_EASYCAP_PRODUCT_ID 0x0408
+
+#define EASYCAP_DRIVER_VERSION "0.9.01"
+#define EASYCAP_DRIVER_DESCRIPTION "easycapdc60"
+
+#define USB_SKEL_MINOR_BASE     192
+#define DONGLE_MANY 8
+#define INPUT_MANY 6
+/*---------------------------------------------------------------------------*/
+/*
+ *  DEFAULT LUMINANCE, CONTRAST, SATURATION AND HUE
+ */
+/*---------------------------------------------------------------------------*/
+#define SAA_0A_DEFAULT 0x7F
+#define SAA_0B_DEFAULT 0x3F
+#define SAA_0C_DEFAULT 0x2F
+#define SAA_0D_DEFAULT 0x00
+/*---------------------------------------------------------------------------*/
+/*
+ *  VIDEO STREAMING PARAMETERS:
+ *  USB 2.0 PROVIDES FOR HIGH-BANDWIDTH ENDPOINTS WITH AN UPPER LIMIT
+ *  OF 3072 BYTES PER MICROFRAME for wMaxPacketSize.
+ */
+/*---------------------------------------------------------------------------*/
+#define VIDEO_ISOC_BUFFER_MANY 16
+#define VIDEO_ISOC_ORDER 3
+#define VIDEO_ISOC_FRAMESPERDESC ((unsigned int) 1 << VIDEO_ISOC_ORDER)
+#define USB_2_0_MAXPACKETSIZE 3072
+#if (USB_2_0_MAXPACKETSIZE > PAGE_SIZE)
+#error video_isoc_buffer[.] will not be big enough
+#endif
+#define VIDEO_JUNK_TOLERATE VIDEO_ISOC_BUFFER_MANY
+#define VIDEO_LOST_TOLERATE 50
+/*---------------------------------------------------------------------------*/
+/*
+ *  VIDEO BUFFERS
+ */
+/*---------------------------------------------------------------------------*/
+#define FIELD_BUFFER_SIZE (203 * PAGE_SIZE)
+#define FRAME_BUFFER_SIZE (405 * PAGE_SIZE)
+#define FIELD_BUFFER_MANY 4
+#define FRAME_BUFFER_MANY 6
+/*---------------------------------------------------------------------------*/
+/*
+ *  AUDIO STREAMING PARAMETERS
+ */
+/*---------------------------------------------------------------------------*/
+#define AUDIO_ISOC_BUFFER_MANY 16
+#define AUDIO_ISOC_ORDER 1
+#define AUDIO_ISOC_FRAMESPERDESC 32
+#define AUDIO_ISOC_BUFFER_SIZE (PAGE_SIZE << AUDIO_ISOC_ORDER)
+/*---------------------------------------------------------------------------*/
+/*
+ *  AUDIO BUFFERS
+ */
+/*---------------------------------------------------------------------------*/
+#define AUDIO_FRAGMENT_MANY 32
+#define PAGES_PER_AUDIO_FRAGMENT 4
+/*---------------------------------------------------------------------------*/
+/*
+ *  IT IS ESSENTIAL THAT EVEN-NUMBERED STANDARDS ARE 25 FRAMES PER SECOND,
+ *                        ODD-NUMBERED STANDARDS ARE 30 FRAMES PER SECOND.
+ *  THE NUMBERING OF STANDARDS MUST NOT BE CHANGED WITHOUT DUE CARE.  NOT
+ *  ONLY MUST THE PARAMETER
+ *                             STANDARD_MANY
+ *  BE CHANGED TO CORRESPOND TO THE NEW NUMBER OF STANDARDS, BUT ALSO THE
+ *  NUMBERING MUST REMAIN AN UNBROKEN ASCENDING SEQUENCE:  DUMMY STANDARDS
+ *  MAY NEED TO BE ADDED.   APPROPRIATE CHANGES WILL ALWAYS BE REQUIRED IN
+ *  ROUTINE fillin_formats() AND POSSIBLY ELSEWHERE.  BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+#define  PAL_BGHIN      0
+#define  PAL_Nc         2
+#define  SECAM          4
+#define  NTSC_N         6
+#define  NTSC_N_443     8
+#define  NTSC_M         1
+#define  NTSC_443       3
+#define  NTSC_M_JP      5
+#define  PAL_60         7
+#define  PAL_M          9
+#define  PAL_BGHIN_SLOW    10
+#define  PAL_Nc_SLOW       12
+#define  SECAM_SLOW        14
+#define  NTSC_N_SLOW       16
+#define  NTSC_N_443_SLOW   18
+#define  NTSC_M_SLOW       11
+#define  NTSC_443_SLOW     13
+#define  NTSC_M_JP_SLOW    15
+#define  PAL_60_SLOW       17
+#define  PAL_M_SLOW        19
+#define  STANDARD_MANY 20
+/*---------------------------------------------------------------------------*/
+/*
+ *  ENUMS
+ */
+/*---------------------------------------------------------------------------*/
+enum {
+       AT_720x576,
+       AT_704x576,
+       AT_640x480,
+       AT_720x480,
+       AT_360x288,
+       AT_320x240,
+       AT_360x240,
+       RESOLUTION_MANY
+};
+enum {
+       FMT_UYVY,
+       FMT_YUY2,
+       FMT_RGB24,
+       FMT_RGB32,
+       FMT_BGR24,
+       FMT_BGR32,
+       PIXELFORMAT_MANY
+};
+enum {
+       FIELD_NONE,
+       FIELD_INTERLACED,
+       INTERLACE_MANY
+};
+#define SETTINGS_MANY  (STANDARD_MANY * \
+                       RESOLUTION_MANY * \
+                       2 * \
+                       PIXELFORMAT_MANY * \
+                       INTERLACE_MANY)
+/*---------------------------------------------------------------------------*/
+/*
+ *  STRUCTURE DEFINITIONS
+ */
+/*---------------------------------------------------------------------------*/
+struct easycap_dongle {
+       struct easycap *peasycap;
+       struct mutex mutex_video;
+       struct mutex mutex_audio;
+};
+/*---------------------------------------------------------------------------*/
+struct data_buffer {
+       struct list_head list_head;
+       void *pgo;
+       void *pto;
+       u16 kount;
+       u16 input;
+};
+/*---------------------------------------------------------------------------*/
+struct data_urb {
+       struct list_head list_head;
+       struct urb *purb;
+       int isbuf;
+       int length;
+};
+/*---------------------------------------------------------------------------*/
+struct easycap_standard {
+       u16 mask;
+struct v4l2_standard v4l2_standard;
+};
+struct easycap_format {
+       u16 mask;
+       char name[128];
+struct v4l2_format v4l2_format;
+};
+struct inputset {
+       int input;
+       int input_ok;
+       int standard_offset;
+       int standard_offset_ok;
+       int format_offset;
+       int format_offset_ok;
+       int brightness;
+       int brightness_ok;
+       int contrast;
+       int contrast_ok;
+       int saturation;
+       int saturation_ok;
+       int hue;
+       int hue_ok;
+};
+/*---------------------------------------------------------------------------*/
+/*
+ *   easycap.ilk == 0   =>  CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=256
+ *   easycap.ilk == 2   =>  CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=9
+ *   easycap.ilk == 3   =>     FOUR-CVBS HARDWARE, AUDIO wMaxPacketSize=9
+ */
+/*---------------------------------------------------------------------------*/
+struct easycap {
+       int isdongle;
+       int minor;
+
+       struct video_device video_device;
+       struct v4l2_device v4l2_device;
+
+       int status;
+       unsigned int audio_pages_per_fragment;
+       unsigned int audio_bytes_per_fragment;
+       unsigned int audio_buffer_page_many;
+
+#define UPSAMPLE
+#ifdef UPSAMPLE
+       s16 oldaudio;
+#endif /*UPSAMPLE*/
+
+       int ilk;
+       bool microphone;
+
+       struct usb_device *pusb_device;
+       struct usb_interface *pusb_interface;
+
+       struct kref kref;
+
+       int queued[FRAME_BUFFER_MANY];
+       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;
+       int standard_offset;
+       int format_offset;
+       struct inputset inputset[INPUT_MANY];
+
+       bool ntsc;
+       int fps;
+       int usec;
+       int tolerate;
+       int skip;
+       int skipped;
+       int lost[INPUT_MANY];
+       int merit[180];
+
+       long long int dnbydt;
+
+       int    video_interface;
+       int    video_altsetting_on;
+       int    video_altsetting_off;
+       int    video_endpointnumber;
+       int    video_isoc_maxframesize;
+       int    video_isoc_buffer_size;
+       int    video_isoc_framesperdesc;
+
+       int    video_isoc_streaming;
+       int    video_isoc_sequence;
+       int    video_idle;
+       int    video_eof;
+       int    video_junk;
+
+       struct data_buffer video_isoc_buffer[VIDEO_ISOC_BUFFER_MANY];
+       struct data_buffer field_buffer[FIELD_BUFFER_MANY]
+                                       [(FIELD_BUFFER_SIZE/PAGE_SIZE)];
+       struct data_buffer frame_buffer[FRAME_BUFFER_MANY]
+                                       [(FRAME_BUFFER_SIZE/PAGE_SIZE)];
+
+       struct list_head urb_video_head;
+       struct list_head *purb_video_head;
+
+       u8 cache[8];
+       u8 *pcache;
+       int video_mt;
+       int audio_mt;
+       long long audio_bytes;
+       u32 isequence;
+
+       int vma_many;
+/*---------------------------------------------------------------------------*/
+/*
+ *  BUFFER INDICATORS
+ */
+/*---------------------------------------------------------------------------*/
+       int field_fill; /* Field buffer being filled by easycap_complete().  */
+                       /*   Bumped only by easycap_complete().              */
+       int field_page; /* Page of field buffer page being filled by         */
+                       /*   easycap_complete().                             */
+       int field_read; /* Field buffer to be read by field2frame().         */
+                       /*   Bumped only by easycap_complete().              */
+       int frame_fill; /* Frame buffer being filled by field2frame().       */
+                       /*   Bumped only by easycap_dqbuf() when             */
+                       /*   field2frame() has created a complete frame.     */
+       int frame_read; /* Frame buffer offered to user by DQBUF.            */
+                       /*   Set only by easycap_dqbuf() to trail frame_fill.*/
+       int frame_lock; /* Flag set to 1 by DQBUF and cleared by QBUF        */
+/*---------------------------------------------------------------------------*/
+/*
+ *  IMAGE PROPERTIES
+ */
+/*---------------------------------------------------------------------------*/
+       u32                   pixelformat;
+       int                     width;
+       int                     height;
+       int                     bytesperpixel;
+       bool                    byteswaporder;
+       bool                    decimatepixel;
+       bool                    offerfields;
+       int                     frame_buffer_used;
+       int                     frame_buffer_many;
+       int                     videofieldamount;
+
+       int                     brightness;
+       int                     contrast;
+       int                     saturation;
+       int                     hue;
+
+       int allocation_video_urb;
+       int allocation_video_page;
+       int allocation_video_struct;
+       int registered_video;
+/*---------------------------------------------------------------------------*/
+/*
+ *  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;
+/*---------------------------------------------------------------------------*/
+/*
+ *  SOUND PROPERTIES
+ */
+/*---------------------------------------------------------------------------*/
+       int audio_interface;
+       int audio_altsetting_on;
+       int audio_altsetting_off;
+       int audio_endpointnumber;
+       int audio_isoc_maxframesize;
+       int audio_isoc_buffer_size;
+       int audio_isoc_framesperdesc;
+
+       int audio_isoc_streaming;
+       int audio_idle;
+       int audio_eof;
+       int volume;
+       int mute;
+       s8 gain;
+
+       struct data_buffer audio_isoc_buffer[AUDIO_ISOC_BUFFER_MANY];
+
+       struct list_head urb_audio_head;
+       struct list_head *purb_audio_head;
+/*---------------------------------------------------------------------------*/
+/*
+ *  BUFFER INDICATORS
+ */
+/*---------------------------------------------------------------------------*/
+       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.                                   */
+/*---------------------------------------------------------------------------*/
+/*
+ *  SOUND PROPERTIES
+ */
+/*---------------------------------------------------------------------------*/
+
+       int audio_buffer_many;
+
+       int allocation_audio_urb;
+       int allocation_audio_page;
+       int allocation_audio_struct;
+       int registered_audio;
+
+       long long int audio_sample;
+       long long int audio_niveau;
+       long long int audio_square;
+
+       struct data_buffer audio_buffer[];
+};
+/*---------------------------------------------------------------------------*/
+/*
+ *  VIDEO FUNCTION PROTOTYPES
+ */
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+long easycap_unlocked_ioctl(struct file *, unsigned int, unsigned long);
+int              easycap_dqbuf(struct easycap *, int);
+int              submit_video_urbs(struct easycap *);
+int              kill_video_urbs(struct easycap *);
+int              field2frame(struct easycap *);
+int              redaub(struct easycap *, void *, void *,
+                                               int, int, u8, u8, bool);
+void             easycap_testcard(struct easycap *, int);
+int              fillin_formats(void);
+int              newinput(struct easycap *, int);
+int              adjust_standard(struct easycap *, v4l2_std_id);
+int              adjust_format(struct easycap *, u32, u32, u32,
+                                                               int, bool);
+int              adjust_brightness(struct easycap *, int);
+int              adjust_contrast(struct easycap *, int);
+int              adjust_saturation(struct easycap *, int);
+int              adjust_hue(struct easycap *, int);
+int              adjust_volume(struct easycap *, int);
+/*---------------------------------------------------------------------------*/
+/*
+ *  AUDIO FUNCTION PROTOTYPES
+ */
+/*---------------------------------------------------------------------------*/
+int            easycap_alsa_probe(struct easycap *);
+void            easycap_alsa_complete(struct urb *);
+
+int              easycap_sound_setup(struct easycap *);
+int              submit_audio_urbs(struct easycap *);
+int              kill_audio_urbs(struct easycap *);
+void             easyoss_testtone(struct easycap *, int);
+int              audio_setup(struct easycap *);
+/*---------------------------------------------------------------------------*/
+/*
+ *  LOW-LEVEL FUNCTION PROTOTYPES
+ */
+/*---------------------------------------------------------------------------*/
+int              audio_gainget(struct usb_device *);
+int              audio_gainset(struct usb_device *, s8);
+
+int              set_interface(struct usb_device *, u16);
+int              wakeup_device(struct usb_device *);
+int              confirm_resolution(struct usb_device *);
+int              confirm_stream(struct usb_device *);
+
+int              setup_stk(struct usb_device *, bool);
+int              setup_saa(struct usb_device *, bool);
+int              setup_vt(struct usb_device *);
+int              check_stk(struct usb_device *, bool);
+int              check_saa(struct usb_device *, bool);
+int              ready_saa(struct usb_device *);
+int              merit_saa(struct usb_device *);
+int              check_vt(struct usb_device *);
+int              select_input(struct usb_device *, int, int);
+int              set_resolution(struct usb_device *,
+                                               u16, u16, u16, u16);
+
+int              read_saa(struct usb_device *, u16);
+int              read_stk(struct usb_device *, u32);
+int              write_saa(struct usb_device *, u16, u16);
+int              write_000(struct usb_device *, u16, u16);
+int              start_100(struct usb_device *);
+int              stop_100(struct usb_device *);
+int              write_300(struct usb_device *);
+int              read_vt(struct usb_device *, u16);
+int              write_vt(struct usb_device *, u16, u16);
+int            isdongle(struct easycap *);
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  MACROS SAM(...) AND JOM(...) ALLOW DIAGNOSTIC OUTPUT TO BE TAGGED WITH
+ *  THE IDENTITY OF THE DONGLE TO WHICH IT APPLIES, BUT IF INVOKED WHEN THE
+ *  POINTER peasycap IS INVALID AN Oops IS LIKELY, AND ITS CAUSE MAY NOT BE
+ *  IMMEDIATELY OBVIOUS FROM A CASUAL READING OF THE SOURCE CODE.  BEWARE.
+*/
+/*---------------------------------------------------------------------------*/
+const char *strerror(int err);
+
+#define SAY(format, args...) do { \
+       printk(KERN_DEBUG "easycap:: %s: " \
+                       format, __func__, ##args); \
+} while (0)
+#define SAM(format, args...) do { \
+       printk(KERN_DEBUG "easycap::%i%s: " \
+                       format, peasycap->isdongle, __func__, ##args);\
+} while (0)
+
+#ifdef CONFIG_EASYCAP_DEBUG
+extern int easycap_debug;
+#define JOT(n, format, args...) do { \
+       if (n <= easycap_debug) { \
+               printk(KERN_DEBUG "easycap:: %s: " \
+                       format, __func__, ##args);\
+       } \
+} while (0)
+#define JOM(n, format, args...) do { \
+       if (n <= easycap_debug) { \
+               printk(KERN_DEBUG "easycap::%i%s: " \
+                       format, peasycap->isdongle, __func__, ##args);\
+       } \
+} while (0)
+
+#else
+#define JOT(n, format, args...) do {} while (0)
+#define JOM(n, format, args...) do {} while (0)
+#endif /* CONFIG_EASYCAP_DEBUG */
+
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* globals
+ */
+/*---------------------------------------------------------------------------*/
+
+extern bool easycap_readback;
+extern const struct easycap_standard easycap_standard[];
+extern struct easycap_format easycap_format[];
+extern struct v4l2_queryctrl easycap_control[];
+extern struct usb_driver easycap_usb_driver;
+extern struct easycap_dongle easycapdc60_dongle[];
+
+#endif /* !__EASYCAP_H__  */
diff --git a/drivers/staging/media/easycap/easycap_ioctl.c b/drivers/staging/media/easycap/easycap_ioctl.c
new file mode 100644 (file)
index 0000000..c99addf
--- /dev/null
@@ -0,0 +1,2450 @@
+/******************************************************************************
+*                                                                             *
+*  easycap_ioctl.c                                                            *
+*                                                                             *
+******************************************************************************/
+/*
+ *
+ *  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
+ *
+*/
+/*****************************************************************************/
+
+#include <linux/version.h>
+#include "easycap.h"
+
+/*--------------------------------------------------------------------------*/
+/*
+ *  UNLESS THERE IS A PREMATURE ERROR RETURN THIS ROUTINE UPDATES THE
+ *  FOLLOWING:
+ *          peasycap->standard_offset
+ *          peasycap->inputset[peasycap->input].standard_offset
+ *          peasycap->fps
+ *          peasycap->usec
+ *          peasycap->tolerate
+ *          peasycap->skip
+ */
+/*---------------------------------------------------------------------------*/
+int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id)
+{
+       struct easycap_standard const *peasycap_standard;
+       u16 reg, set;
+       int ir, rc, need, k;
+       unsigned int itwas, isnow;
+       bool resubmit;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+       if (!peasycap->pusb_device) {
+               SAM("ERROR: peasycap->pusb_device is NULL\n");
+               return -EFAULT;
+       }
+       peasycap_standard = &easycap_standard[0];
+       while (0xFFFF != peasycap_standard->mask) {
+               if (std_id == peasycap_standard->v4l2_standard.id)
+                       break;
+               peasycap_standard++;
+       }
+       if (0xFFFF == peasycap_standard->mask) {
+               peasycap_standard = &easycap_standard[0];
+               while (0xFFFF != peasycap_standard->mask) {
+                       if (std_id & peasycap_standard->v4l2_standard.id)
+                               break;
+                       peasycap_standard++;
+               }
+       }
+       if (0xFFFF == peasycap_standard->mask) {
+               SAM("ERROR: 0x%08X=std_id: standard not found\n",
+                   (unsigned int)std_id);
+               return -EINVAL;
+       }
+       SAM("selected standard: %s\n",
+           &(peasycap_standard->v4l2_standard.name[0]));
+       if (peasycap->standard_offset == peasycap_standard - easycap_standard) {
+               SAM("requested standard already in effect\n");
+               return 0;
+       }
+       peasycap->standard_offset = peasycap_standard - easycap_standard;
+       for (k = 0; k < INPUT_MANY;  k++) {
+               if (!peasycap->inputset[k].standard_offset_ok) {
+                       peasycap->inputset[k].standard_offset =
+                               peasycap->standard_offset;
+               }
+       }
+       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
+               peasycap->inputset[peasycap->input].standard_offset =
+                       peasycap->standard_offset;
+               peasycap->inputset[peasycap->input].standard_offset_ok = 1;
+       } else
+               JOM(8, "%i=peasycap->input\n", peasycap->input);
+
+       peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator /
+                       peasycap_standard->v4l2_standard.frameperiod.numerator;
+       switch (peasycap->fps) {
+       case 6:
+       case 30: {
+               peasycap->ntsc = true;
+               break;
+       }
+       case 5:
+       case 25: {
+               peasycap->ntsc = false;
+               break;
+       }
+       default: {
+               SAM("MISTAKE: %i=frames-per-second\n", peasycap->fps);
+               return -ENOENT;
+       }
+       }
+       JOM(8, "%i frames-per-second\n", peasycap->fps);
+       if (0x8000 & peasycap_standard->mask) {
+               peasycap->skip = 5;
+               peasycap->usec = 1000000 / (2 * (5 * peasycap->fps));
+               peasycap->tolerate = 1000 * (25 / (5 * peasycap->fps));
+       } else {
+               peasycap->skip = 0;
+               peasycap->usec = 1000000 / (2 * peasycap->fps);
+               peasycap->tolerate = 1000 * (25 / peasycap->fps);
+       }
+       if (peasycap->video_isoc_streaming) {
+               resubmit = true;
+               kill_video_urbs(peasycap);
+       } else
+               resubmit = false;
+/*--------------------------------------------------------------------------*/
+/*
+ *  SAA7113H DATASHEET PAGE 44, TABLE 42
+ */
+/*--------------------------------------------------------------------------*/
+       need = 0;
+       itwas = 0;
+       reg = 0x00;
+       set = 0x00;
+       switch (peasycap_standard->mask & 0x000F) {
+       case NTSC_M_JP: {
+               reg = 0x0A;
+               set = 0x95;
+               ir = read_saa(peasycap->pusb_device, reg);
+               if (0 > ir)
+                       SAM("ERROR: cannot read SAA register 0x%02X\n", reg);
+               else
+                       itwas = (unsigned int)ir;
+               rc = write_saa(peasycap->pusb_device, reg, set);
+               if (rc)
+                       SAM("ERROR: failed to set SAA register "
+                           "0x%02X to 0x%02X for JP standard\n", reg, set);
+               else {
+                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+                       if (0 > ir)
+                               JOM(8, "SAA register 0x%02X changed "
+                                   "to 0x%02X\n", reg, isnow);
+                       else
+                               JOM(8, "SAA register 0x%02X changed "
+                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+               }
+
+               reg = 0x0B;
+               set = 0x48;
+               ir = read_saa(peasycap->pusb_device, reg);
+               if (0 > ir)
+                       SAM("ERROR: cannot read SAA register 0x%02X\n", reg);
+               else
+                       itwas = (unsigned int)ir;
+               rc = write_saa(peasycap->pusb_device, reg, set);
+               if (rc)
+                       SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X "
+                           "for JP standard\n", reg, set);
+               else {
+                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+                       if (0 > ir)
+                               JOM(8, "SAA register 0x%02X changed "
+                                   "to 0x%02X\n", reg, isnow);
+                       else
+                               JOM(8, "SAA register 0x%02X changed "
+                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+               }
+/*--------------------------------------------------------------------------*/
+/*
+ *  NOTE:  NO break HERE:  RUN ON TO NEXT CASE
+ */
+/*--------------------------------------------------------------------------*/
+       }
+       case NTSC_M:
+       case PAL_BGHIN: {
+               reg = 0x0E;
+               set = 0x01;
+               need = 1;
+               break;
+       }
+       case NTSC_N_443:
+       case PAL_60: {
+               reg = 0x0E;
+               set = 0x11;
+               need = 1;
+               break;
+       }
+       case NTSC_443:
+       case PAL_Nc: {
+               reg = 0x0E;
+               set = 0x21;
+               need = 1;
+               break;
+       }
+       case NTSC_N:
+       case PAL_M: {
+               reg = 0x0E;
+               set = 0x31;
+               need = 1;
+               break;
+       }
+       case SECAM: {
+               reg = 0x0E;
+               set = 0x51;
+               need = 1;
+               break;
+       }
+       default:
+               break;
+       }
+/*--------------------------------------------------------------------------*/
+       if (need) {
+               ir = read_saa(peasycap->pusb_device, reg);
+               if (0 > ir)
+                       SAM("ERROR: failed to read SAA register 0x%02X\n", reg);
+               else
+                       itwas = (unsigned int)ir;
+               rc = write_saa(peasycap->pusb_device, reg, set);
+               if (0 != write_saa(peasycap->pusb_device, reg, set)) {
+                       SAM("ERROR: failed to set SAA register "
+                           "0x%02X to 0x%02X for table 42\n", reg, set);
+               } else {
+                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+                       if (0 > ir)
+                               JOM(8, "SAA register 0x%02X changed "
+                                   "to 0x%02X\n", reg, isnow);
+                       else
+                               JOM(8, "SAA register 0x%02X changed "
+                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+               }
+       }
+/*--------------------------------------------------------------------------*/
+/*
+        *  SAA7113H DATASHEET PAGE 41
+        */
+/*--------------------------------------------------------------------------*/
+       reg = 0x08;
+       ir = read_saa(peasycap->pusb_device, reg);
+       if (0 > ir)
+               SAM("ERROR: failed to read SAA register 0x%02X "
+                   "so cannot reset\n", reg);
+       else {
+               itwas = (unsigned int)ir;
+               if (peasycap_standard->mask & 0x0001)
+                       set = itwas | 0x40 ;
+               else
+                       set = itwas & ~0x40 ;
+               rc  = write_saa(peasycap->pusb_device, reg, set);
+               if (rc)
+                       SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
+                           reg, set);
+               else {
+                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+                       if (0 > ir)
+                               JOM(8, "SAA register 0x%02X changed to 0x%02X\n",
+                                   reg, isnow);
+                       else
+                               JOM(8, "SAA register 0x%02X changed "
+                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+               }
+       }
+/*--------------------------------------------------------------------------*/
+/*
+ *  SAA7113H DATASHEET PAGE 51, TABLE 57
+ */
+/*---------------------------------------------------------------------------*/
+       reg = 0x40;
+       ir = read_saa(peasycap->pusb_device, reg);
+       if (0 > ir)
+               SAM("ERROR: failed to read SAA register 0x%02X "
+                   "so cannot reset\n", reg);
+       else {
+               itwas = (unsigned int)ir;
+               if (peasycap_standard->mask & 0x0001)
+                       set = itwas | 0x80 ;
+               else
+                       set = itwas & ~0x80 ;
+               rc = write_saa(peasycap->pusb_device, reg, set);
+               if (rc)
+                       SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
+                           reg, set);
+               else {
+                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+                       if (0 > ir)
+                               JOM(8, "SAA register 0x%02X changed to 0x%02X\n",
+                                   reg, isnow);
+                       else
+                               JOM(8, "SAA register 0x%02X changed "
+                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+               }
+       }
+/*--------------------------------------------------------------------------*/
+/*
+        *  SAA7113H DATASHEET PAGE 53, TABLE 66
+        */
+/*--------------------------------------------------------------------------*/
+       reg = 0x5A;
+       ir = read_saa(peasycap->pusb_device, reg);
+       if (0 > ir)
+               SAM("ERROR: failed to read SAA register 0x%02X but continuing\n", reg);
+       itwas = (unsigned int)ir;
+       if (peasycap_standard->mask & 0x0001)
+               set = 0x0A ;
+       else
+               set = 0x07 ;
+       if (0 != write_saa(peasycap->pusb_device, reg, set))
+               SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
+                   reg, set);
+       else {
+               isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+               if (0 > ir)
+                       JOM(8, "SAA register 0x%02X changed "
+                           "to 0x%02X\n", reg, isnow);
+               else
+                       JOM(8, "SAA register 0x%02X changed "
+                           "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+       }
+       if (resubmit)
+               submit_video_urbs(peasycap);
+       return 0;
+}
+/*****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL REQUIRES
+ *  A VALID VALUE OF peasycap->standard_offset, OTHERWISE -EBUSY IS RETURNED.
+ *
+ *  PROVIDED THE ARGUMENT try IS false AND THERE IS NO PREMATURE ERROR RETURN
+ *  THIS ROUTINE UPDATES THE FOLLOWING:
+ *          peasycap->format_offset
+ *          peasycap->inputset[peasycap->input].format_offset
+ *          peasycap->pixelformat
+ *          peasycap->height
+ *          peasycap->width
+ *          peasycap->bytesperpixel
+ *          peasycap->byteswaporder
+ *          peasycap->decimatepixel
+ *          peasycap->frame_buffer_used
+ *          peasycap->videofieldamount
+ *          peasycap->offerfields
+ *
+ *  IF SUCCESSFUL THE FUNCTION RETURNS THE OFFSET IN easycap_format[]
+ *  IDENTIFYING THE FORMAT WHICH IS TO RETURNED TO THE USER.
+ *  ERRORS RETURN A NEGATIVE NUMBER.
+ */
+/*--------------------------------------------------------------------------*/
+int adjust_format(struct easycap *peasycap,
+                 u32 width, u32 height, u32 pixelformat, int field, bool try)
+{
+       struct easycap_format *peasycap_format, *peasycap_best_format;
+       u16 mask;
+       struct usb_device *p;
+       int miss, multiplier, best, k;
+       char bf[5], fo[32], *pc;
+       u32 uc;
+       bool resubmit;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+       if (0 > peasycap->standard_offset) {
+               JOM(8, "%i=peasycap->standard_offset\n", peasycap->standard_offset);
+               return -EBUSY;
+       }
+       p = peasycap->pusb_device;
+       if (!p) {
+               SAM("ERROR: peaycap->pusb_device is NULL\n");
+               return -EFAULT;
+       }
+       pc = &bf[0];
+       uc = pixelformat;
+       memcpy((void *)pc, (void *)(&uc), 4);
+       bf[4] = 0;
+       mask = 0xFF & easycap_standard[peasycap->standard_offset].mask;
+       SAM("sought:    %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n",
+           width, height, pc, pixelformat, field, mask);
+       switch (field) {
+       case V4L2_FIELD_ANY: {
+               strcpy(&fo[0], "V4L2_FIELD_ANY ");
+               break;
+       }
+       case V4L2_FIELD_NONE: {
+               strcpy(&fo[0], "V4L2_FIELD_NONE");
+               break;
+       }
+       case V4L2_FIELD_TOP: {
+               strcpy(&fo[0], "V4L2_FIELD_TOP");
+               break;
+       }
+       case V4L2_FIELD_BOTTOM: {
+               strcpy(&fo[0], "V4L2_FIELD_BOTTOM");
+               break;
+       }
+       case V4L2_FIELD_INTERLACED: {
+               strcpy(&fo[0], "V4L2_FIELD_INTERLACED");
+               break;
+       }
+       case V4L2_FIELD_SEQ_TB: {
+               strcpy(&fo[0], "V4L2_FIELD_SEQ_TB");
+               break;
+       }
+       case V4L2_FIELD_SEQ_BT: {
+               strcpy(&fo[0], "V4L2_FIELD_SEQ_BT");
+               break;
+       }
+       case V4L2_FIELD_ALTERNATE: {
+               strcpy(&fo[0], "V4L2_FIELD_ALTERNATE");
+               break;
+       }
+       case V4L2_FIELD_INTERLACED_TB: {
+               strcpy(&fo[0], "V4L2_FIELD_INTERLACED_TB");
+               break;
+       }
+       case V4L2_FIELD_INTERLACED_BT: {
+               strcpy(&fo[0], "V4L2_FIELD_INTERLACED_BT");
+               break;
+       }
+       default: {
+               strcpy(&fo[0], "V4L2_FIELD_... UNKNOWN  ");
+               break;
+       }
+       }
+       SAM("sought:    %s\n", &fo[0]);
+       if (V4L2_FIELD_ANY == field) {
+               field = V4L2_FIELD_NONE;
+               SAM("prefer:    V4L2_FIELD_NONE=field, was V4L2_FIELD_ANY\n");
+       }
+       peasycap_best_format = NULL;
+       peasycap_format = &easycap_format[0];
+       while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
+               JOM(16, ".> %i %i 0x%08X %ix%i\n",
+                   peasycap_format->mask & 0x01,
+                   peasycap_format->v4l2_format.fmt.pix.field,
+                   peasycap_format->v4l2_format.fmt.pix.pixelformat,
+                   peasycap_format->v4l2_format.fmt.pix.width,
+                   peasycap_format->v4l2_format.fmt.pix.height);
+
+               if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) &&
+                   (peasycap_format->v4l2_format.fmt.pix.field == field) &&
+                   (peasycap_format->v4l2_format.fmt.pix.pixelformat == pixelformat) &&
+                   (peasycap_format->v4l2_format.fmt.pix.width  == width) &&
+                   (peasycap_format->v4l2_format.fmt.pix.height == height)) {
+
+                       peasycap_best_format = peasycap_format;
+                       break;
+               }
+               peasycap_format++;
+       }
+       if (0 == peasycap_format->v4l2_format.fmt.pix.width) {
+               SAM("cannot do: %ix%i with standard mask 0x%02X\n",
+                   width, height, mask);
+               peasycap_format = &easycap_format[0];
+               best = -1;
+               while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
+                       if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) &&
+                           (peasycap_format->v4l2_format.fmt.pix.field == field) &&
+                           (peasycap_format->v4l2_format.fmt.pix.pixelformat == pixelformat)) {
+
+                               miss = abs(peasycap_format->v4l2_format.fmt.pix.width  - width);
+                               if ((best > miss) || (best < 0)) {
+                                       best = miss;
+                                       peasycap_best_format = peasycap_format;
+                                       if (!miss)
+                                               break;
+                               }
+                       }
+                       peasycap_format++;
+               }
+               if (-1 == best) {
+                       SAM("cannot do %ix... with standard mask 0x%02X\n",
+                           width, mask);
+                       SAM("cannot do ...x%i with standard mask 0x%02X\n",
+                           height, mask);
+                       SAM("           %ix%i unmatched\n", width, height);
+                       return peasycap->format_offset;
+               }
+       }
+       if (!peasycap_best_format) {
+               SAM("MISTAKE: peasycap_best_format is NULL");
+               return -EINVAL;
+       }
+       peasycap_format = peasycap_best_format;
+
+/*...........................................................................*/
+       if (try)
+               return peasycap_best_format - easycap_format;
+/*...........................................................................*/
+
+       if (false != try) {
+               SAM("MISTAKE: true==try where is should be false\n");
+               return -EINVAL;
+       }
+       SAM("actioning: %ix%i %s\n",
+           peasycap_format->v4l2_format.fmt.pix.width,
+           peasycap_format->v4l2_format.fmt.pix.height,
+           &peasycap_format->name[0]);
+       peasycap->height        = peasycap_format->v4l2_format.fmt.pix.height;
+       peasycap->width         = peasycap_format->v4l2_format.fmt.pix.width;
+       peasycap->pixelformat   = peasycap_format->v4l2_format.fmt.pix.pixelformat;
+       peasycap->format_offset = peasycap_format - easycap_format;
+
+
+       for (k = 0; k < INPUT_MANY; k++) {
+               if (!peasycap->inputset[k].format_offset_ok) {
+                       peasycap->inputset[k].format_offset =
+                               peasycap->format_offset;
+               }
+       }
+       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
+               peasycap->inputset[peasycap->input].format_offset =
+                       peasycap->format_offset;
+               peasycap->inputset[peasycap->input].format_offset_ok = 1;
+       } else
+               JOM(8, "%i=peasycap->input\n", peasycap->input);
+
+
+
+       peasycap->bytesperpixel = (0x00E0 & peasycap_format->mask) >> 5 ;
+       if (0x0100 & peasycap_format->mask)
+               peasycap->byteswaporder = true;
+       else
+               peasycap->byteswaporder = false;
+       if (0x0200 & peasycap_format->mask)
+               peasycap->skip = 5;
+       else
+               peasycap->skip = 0;
+       if (0x0800 & peasycap_format->mask)
+               peasycap->decimatepixel = true;
+       else
+               peasycap->decimatepixel = false;
+       if (0x1000 & peasycap_format->mask)
+               peasycap->offerfields = true;
+       else
+               peasycap->offerfields = false;
+       if (peasycap->decimatepixel)
+               multiplier = 2;
+       else
+               multiplier = 1;
+       peasycap->videofieldamount =
+               multiplier * peasycap->width * multiplier * peasycap->height;
+       peasycap->frame_buffer_used =
+               peasycap->bytesperpixel * peasycap->width * peasycap->height;
+       if (peasycap->video_isoc_streaming) {
+               resubmit = true;
+               kill_video_urbs(peasycap);
+       } else
+               resubmit = false;
+/*---------------------------------------------------------------------------*/
+/*
+        *  PAL
+        */
+/*---------------------------------------------------------------------------*/
+       if (0 == (0x01 & peasycap_format->mask)) {
+               if (((720 == peasycap_format->v4l2_format.fmt.pix.width) &&
+                    (576 == peasycap_format->v4l2_format.fmt.pix.height)) ||
+                   ((360 == peasycap_format->v4l2_format.fmt.pix.width) &&
+                    (288 == peasycap_format->v4l2_format.fmt.pix.height))) {
+                       if (set_resolution(p, 0x0000, 0x0001, 0x05A0, 0x0121)) {
+                               SAM("ERROR: set_resolution() failed\n");
+                               return -EINVAL;
+                       }
+               } else if ((704 == peasycap_format->v4l2_format.fmt.pix.width) &&
+                          (576 == peasycap_format->v4l2_format.fmt.pix.height)) {
+                       if (set_resolution(p, 0x0004, 0x0001, 0x0584, 0x0121)) {
+                               SAM("ERROR: set_resolution() failed\n");
+                               return -EINVAL;
+                       }
+               } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) &&
+                           (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
+                          ((320 == peasycap_format->v4l2_format.fmt.pix.width) &&
+                           (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
+                       if (set_resolution(p, 0x0014, 0x0020, 0x0514, 0x0110)) {
+                               SAM("ERROR: set_resolution() failed\n");
+                               return -EINVAL;
+                       }
+               } else {
+                       SAM("MISTAKE: bad format, cannot set resolution\n");
+                       return -EINVAL;
+               }
+/*---------------------------------------------------------------------------*/
+/*
+ *  NTSC
+ */
+/*---------------------------------------------------------------------------*/
+       } else {
+               if (((720 == peasycap_format->v4l2_format.fmt.pix.width) &&
+                    (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
+                   ((360 == peasycap_format->v4l2_format.fmt.pix.width) &&
+                    (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
+                       if (set_resolution(p, 0x0000, 0x0003, 0x05A0, 0x00F3)) {
+                               SAM("ERROR: set_resolution() failed\n");
+                               return -EINVAL;
+                       }
+               } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) &&
+                           (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
+                          ((320 == peasycap_format->v4l2_format.fmt.pix.width) &&
+                           (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
+                       if (set_resolution(p, 0x0014, 0x0003, 0x0514, 0x00F3)) {
+                               SAM("ERROR: set_resolution() failed\n");
+                               return -EINVAL;
+                       }
+               } else {
+                       SAM("MISTAKE: bad format, cannot set resolution\n");
+                       return -EINVAL;
+               }
+       }
+/*---------------------------------------------------------------------------*/
+       if (resubmit)
+               submit_video_urbs(peasycap);
+
+       return peasycap_best_format - easycap_format;
+}
+/*****************************************************************************/
+int adjust_brightness(struct easycap *peasycap, int value)
+{
+       unsigned int mood;
+       int i1, k;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+       if (!peasycap->pusb_device) {
+               SAM("ERROR: peasycap->pusb_device is NULL\n");
+               return -EFAULT;
+       }
+       i1 = 0;
+       while (0xFFFFFFFF != easycap_control[i1].id) {
+               if (V4L2_CID_BRIGHTNESS == easycap_control[i1].id) {
+                       if ((easycap_control[i1].minimum > value) ||
+                           (easycap_control[i1].maximum < value))
+                               value = easycap_control[i1].default_value;
+
+                       if ((easycap_control[i1].minimum <= peasycap->brightness) &&
+                           (easycap_control[i1].maximum >= peasycap->brightness)) {
+                               if (peasycap->brightness == value) {
+                                       SAM("unchanged brightness at  0x%02X\n",
+                                           value);
+                                       return 0;
+                               }
+                       }
+                       peasycap->brightness = value;
+                       for (k = 0; k < INPUT_MANY; k++) {
+                               if (!peasycap->inputset[k].brightness_ok)
+                                       peasycap->inputset[k].brightness =
+                                               peasycap->brightness;
+                       }
+                       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
+                               peasycap->inputset[peasycap->input].brightness =
+                                       peasycap->brightness;
+                               peasycap->inputset[peasycap->input].brightness_ok = 1;
+                       } else
+                               JOM(8, "%i=peasycap->input\n", peasycap->input);
+                       mood = 0x00FF & (unsigned int)peasycap->brightness;
+                       if (!write_saa(peasycap->pusb_device, 0x0A, mood)) {
+                               SAM("adjusting brightness to  0x%02X\n", mood);
+                               return 0;
+                       } else {
+                               SAM("WARNING: failed to adjust brightness "
+                                   "to 0x%02X\n", mood);
+                               return -ENOENT;
+                       }
+                       break;
+               }
+               i1++;
+       }
+       SAM("WARNING: failed to adjust brightness: control not found\n");
+       return -ENOENT;
+}
+/*****************************************************************************/
+int adjust_contrast(struct easycap *peasycap, int value)
+{
+       unsigned int mood;
+       int i1, k;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+       if (!peasycap->pusb_device) {
+               SAM("ERROR: peasycap->pusb_device is NULL\n");
+               return -EFAULT;
+       }
+       i1 = 0;
+       while (0xFFFFFFFF != easycap_control[i1].id) {
+               if (V4L2_CID_CONTRAST == easycap_control[i1].id) {
+                       if ((easycap_control[i1].minimum > value) ||
+                           (easycap_control[i1].maximum < value))
+                               value = easycap_control[i1].default_value;
+
+
+                       if ((easycap_control[i1].minimum <= peasycap->contrast) &&
+                           (easycap_control[i1].maximum >= peasycap->contrast)) {
+                               if (peasycap->contrast == value) {
+                                       SAM("unchanged contrast at  0x%02X\n", value);
+                                       return 0;
+                               }
+                       }
+                       peasycap->contrast = value;
+                       for (k = 0; k < INPUT_MANY; k++) {
+                               if (!peasycap->inputset[k].contrast_ok)
+                                       peasycap->inputset[k].contrast = peasycap->contrast;
+                       }
+
+                       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
+                               peasycap->inputset[peasycap->input].contrast =
+                                               peasycap->contrast;
+                               peasycap->inputset[peasycap->input].contrast_ok = 1;
+                       } else
+                               JOM(8, "%i=peasycap->input\n", peasycap->input);
+
+                       mood = 0x00FF & (unsigned int) (peasycap->contrast - 128);
+                       if (!write_saa(peasycap->pusb_device, 0x0B, mood)) {
+                               SAM("adjusting contrast to  0x%02X\n", mood);
+                               return 0;
+                       } else {
+                               SAM("WARNING: failed to adjust contrast to "
+                                   "0x%02X\n", mood);
+                               return -ENOENT;
+                       }
+                       break;
+               }
+               i1++;
+       }
+       SAM("WARNING: failed to adjust contrast: control not found\n");
+       return -ENOENT;
+}
+/*****************************************************************************/
+int adjust_saturation(struct easycap *peasycap, int value)
+{
+       unsigned int mood;
+       int i1, k;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+       if (!peasycap->pusb_device) {
+               SAM("ERROR: peasycap->pusb_device is NULL\n");
+               return -EFAULT;
+       }
+       i1 = 0;
+       while (0xFFFFFFFF != easycap_control[i1].id) {
+               if (V4L2_CID_SATURATION == easycap_control[i1].id) {
+                       if ((easycap_control[i1].minimum > value) ||
+                           (easycap_control[i1].maximum < value))
+                               value = easycap_control[i1].default_value;
+
+
+                       if ((easycap_control[i1].minimum <= peasycap->saturation) &&
+                           (easycap_control[i1].maximum >= peasycap->saturation)) {
+                               if (peasycap->saturation == value) {
+                                       SAM("unchanged saturation at  0x%02X\n",
+                                           value);
+                                       return 0;
+                               }
+                       }
+                       peasycap->saturation = value;
+                       for (k = 0; k < INPUT_MANY; k++) {
+                               if (!peasycap->inputset[k].saturation_ok)
+                                       peasycap->inputset[k].saturation =
+                                               peasycap->saturation;
+                       }
+                       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
+                               peasycap->inputset[peasycap->input].saturation =
+                                       peasycap->saturation;
+                               peasycap->inputset[peasycap->input].saturation_ok = 1;
+                       } else
+                               JOM(8, "%i=peasycap->input\n", peasycap->input);
+                       mood = 0x00FF & (unsigned int) (peasycap->saturation - 128);
+                       if (!write_saa(peasycap->pusb_device, 0x0C, mood)) {
+                               SAM("adjusting saturation to  0x%02X\n", mood);
+                               return 0;
+                       } else {
+                               SAM("WARNING: failed to adjust saturation to "
+                                   "0x%02X\n", mood);
+                               return -ENOENT;
+                       }
+                       break;
+               }
+               i1++;
+       }
+       SAM("WARNING: failed to adjust saturation: control not found\n");
+       return -ENOENT;
+}
+/*****************************************************************************/
+int adjust_hue(struct easycap *peasycap, int value)
+{
+       unsigned int mood;
+       int i1, i2, k;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+       if (!peasycap->pusb_device) {
+               SAM("ERROR: peasycap->pusb_device is NULL\n");
+               return -EFAULT;
+       }
+       i1 = 0;
+       while (0xFFFFFFFF != easycap_control[i1].id) {
+               if (V4L2_CID_HUE == easycap_control[i1].id) {
+                       if ((easycap_control[i1].minimum > value) ||
+                           (easycap_control[i1].maximum < value))
+                               value = easycap_control[i1].default_value;
+
+                       if ((easycap_control[i1].minimum <= peasycap->hue) &&
+                           (easycap_control[i1].maximum >= peasycap->hue)) {
+                               if (peasycap->hue == value) {
+                                       SAM("unchanged hue at  0x%02X\n", value);
+                                       return 0;
+                               }
+                       }
+                       peasycap->hue = value;
+                       for (k = 0; k < INPUT_MANY; k++) {
+                               if (!peasycap->inputset[k].hue_ok)
+                                       peasycap->inputset[k].hue = peasycap->hue;
+                       }
+                       if (0 <= peasycap->input && INPUT_MANY > peasycap->input) {
+                               peasycap->inputset[peasycap->input].hue = peasycap->hue;
+                               peasycap->inputset[peasycap->input].hue_ok = 1;
+                       } else
+                               JOM(8, "%i=peasycap->input\n", peasycap->input);
+                       i2 = peasycap->hue - 128;
+                       mood = 0x00FF & ((int) i2);
+                       if (!write_saa(peasycap->pusb_device, 0x0D, mood)) {
+                               SAM("adjusting hue to  0x%02X\n", mood);
+                               return 0;
+                       } else {
+                               SAM("WARNING: failed to adjust hue to 0x%02X\n", mood);
+                               return -ENOENT;
+                       }
+                       break;
+               }
+               i1++;
+       }
+       SAM("WARNING: failed to adjust hue: control not found\n");
+       return -ENOENT;
+}
+/*****************************************************************************/
+int adjust_volume(struct easycap *peasycap, int value)
+{
+       s8 mood;
+       int i1;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+       if (!peasycap->pusb_device) {
+               SAM("ERROR: peasycap->pusb_device is NULL\n");
+               return -EFAULT;
+       }
+       i1 = 0;
+       while (0xFFFFFFFF != easycap_control[i1].id) {
+               if (V4L2_CID_AUDIO_VOLUME == easycap_control[i1].id) {
+                       if ((easycap_control[i1].minimum > value) ||
+                           (easycap_control[i1].maximum < value))
+                               value = easycap_control[i1].default_value;
+
+                       if ((easycap_control[i1].minimum <= peasycap->volume) &&
+                           (easycap_control[i1].maximum >= peasycap->volume)) {
+                               if (peasycap->volume == value) {
+                                       SAM("unchanged volume at  0x%02X\n", value);
+                                       return 0;
+                               }
+                       }
+                       peasycap->volume = value;
+                       mood = (16 > peasycap->volume) ? 16 :
+                               ((31 < peasycap->volume) ? 31 :
+                                 (s8) peasycap->volume);
+                       if (!audio_gainset(peasycap->pusb_device, mood)) {
+                               SAM("adjusting volume to 0x%02X\n", mood);
+                               return 0;
+                       } else {
+                               SAM("WARNING: failed to adjust volume to "
+                                   "0x%2X\n", mood);
+                               return -ENOENT;
+                       }
+                       break;
+               }
+               i1++;
+       }
+       SAM("WARNING: failed to adjust volume: control not found\n");
+       return -ENOENT;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  AN ALTERNATIVE METHOD OF MUTING MIGHT SEEM TO BE:
+ *            usb_set_interface(peasycap->pusb_device,
+ *                              peasycap->audio_interface,
+ *                              peasycap->audio_altsetting_off);
+ *  HOWEVER, AFTER THIS COMMAND IS ISSUED ALL SUBSEQUENT URBS RECEIVE STATUS
+ *  -ESHUTDOWN.  THE HANDLER ROUTINE easyxxx_complete() DECLINES TO RESUBMIT
+ *  THE URB AND THE PIPELINE COLLAPSES IRRETRIEVABLY.  BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+static int adjust_mute(struct easycap *peasycap, int value)
+{
+       int i1;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+       if (!peasycap->pusb_device) {
+               SAM("ERROR: peasycap->pusb_device is NULL\n");
+               return -EFAULT;
+       }
+       i1 = 0;
+       while (0xFFFFFFFF != easycap_control[i1].id) {
+               if (V4L2_CID_AUDIO_MUTE == easycap_control[i1].id) {
+                       peasycap->mute = value;
+                       switch (peasycap->mute) {
+                       case 1: {
+                               peasycap->audio_idle = 1;
+                               SAM("adjusting mute: %i=peasycap->audio_idle\n",
+                                   peasycap->audio_idle);
+                               return 0;
+                       }
+                       default: {
+                               peasycap->audio_idle = 0;
+                               SAM("adjusting mute: %i=peasycap->audio_idle\n",
+                                   peasycap->audio_idle);
+                               return 0;
+                       }
+                       }
+                       break;
+               }
+               i1++;
+       }
+       SAM("WARNING: failed to adjust mute: control not found\n");
+       return -ENOENT;
+}
+/*---------------------------------------------------------------------------*/
+long easycap_unlocked_ioctl(struct file *file,
+                           unsigned int cmd, unsigned long arg)
+{
+       struct easycap *peasycap;
+       struct usb_device *p;
+       int kd;
+
+       if (!file) {
+               SAY("ERROR:  file is NULL\n");
+               return -ERESTARTSYS;
+       }
+       peasycap = file->private_data;
+       if (!peasycap) {
+               SAY("ERROR:  peasycap is NULL\n");
+               return -1;
+       }
+       p = peasycap->pusb_device;
+       if (!p) {
+               SAM("ERROR: peasycap->pusb_device is NULL\n");
+               return -EFAULT;
+       }
+       kd = isdongle(peasycap);
+       if (0 <= kd && DONGLE_MANY > 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 easycapdc60_dongle[%i].mutex_video\n", kd);
+/*---------------------------------------------------------------------------*/
+/*
+ *  MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
+ *  IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
+ *  IF NECESSARY, BAIL OUT.
+ */
+/*---------------------------------------------------------------------------*/
+               if (kd != isdongle(peasycap))
+                       return -ERESTARTSYS;
+               if (!file) {
+                       SAY("ERROR:  file is NULL\n");
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -ERESTARTSYS;
+               }
+               peasycap = file->private_data;
+               if (!peasycap) {
+                       SAY("ERROR:  peasycap is NULL\n");
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -ERESTARTSYS;
+               }
+               if (!peasycap->pusb_device) {
+                       SAM("ERROR: peasycap->pusb_device is NULL\n");
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -ERESTARTSYS;
+               }
+       } else {
+/*---------------------------------------------------------------------------*/
+/*
+ *  IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
+ *  ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED.  BAIL OUT.
+ */
+/*---------------------------------------------------------------------------*/
+               return -ERESTARTSYS;
+       }
+/*---------------------------------------------------------------------------*/
+       switch (cmd) {
+       case VIDIOC_QUERYCAP: {
+               struct v4l2_capability v4l2_capability;
+               char version[16], *p1, *p2;
+               int i, rc, k[3];
+               long lng;
+
+               JOM(8, "VIDIOC_QUERYCAP\n");
+
+               if (16 <= strlen(EASYCAP_DRIVER_VERSION)) {
+                       SAM("ERROR: bad driver version string\n");
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               strcpy(&version[0], EASYCAP_DRIVER_VERSION);
+               for (i = 0; i < 3; i++)
+                       k[i] = 0;
+               p2 = &version[0];
+               i = 0;
+               while (*p2) {
+                       p1 = p2;
+                       while (*p2 && ('.' != *p2))
+                               p2++;
+                       if (*p2)
+                               *p2++ = 0;
+                       if (3 > i) {
+                               rc = (int) strict_strtol(p1, 10, &lng);
+                               if (rc) {
+                                       SAM("ERROR: %i=strict_strtol(%s,.,,)\n",
+                                           rc, p1);
+                                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                                       return -EINVAL;
+                               }
+                               k[i] = (int)lng;
+                       }
+                       i++;
+               }
+
+               memset(&v4l2_capability, 0, sizeof(struct v4l2_capability));
+               strlcpy(&v4l2_capability.driver[0],
+                       "easycap", sizeof(v4l2_capability.driver));
+
+               v4l2_capability.capabilities = V4L2_CAP_VIDEO_CAPTURE |
+                                               V4L2_CAP_STREAMING |
+                                               V4L2_CAP_AUDIO |
+                                               V4L2_CAP_READWRITE;
+
+               v4l2_capability.version = KERNEL_VERSION(k[0], k[1], k[2]);
+               JOM(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]);
+
+               strlcpy(&v4l2_capability.card[0],
+                       "EasyCAP DC60", sizeof(v4l2_capability.card));
+
+               if (usb_make_path(peasycap->pusb_device,
+                               &v4l2_capability.bus_info[0],
+                               sizeof(v4l2_capability.bus_info)) < 0) {
+
+                       strlcpy(&v4l2_capability.bus_info[0], "EasyCAP bus_info",
+                               sizeof(v4l2_capability.bus_info));
+                       JOM(8, "%s=v4l2_capability.bus_info\n",
+                               &v4l2_capability.bus_info[0]);
+               }
+               if (copy_to_user((void __user *)arg, &v4l2_capability,
+                               sizeof(struct v4l2_capability))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_ENUMINPUT: {
+               struct v4l2_input v4l2_input;
+               u32 index;
+
+               JOM(8, "VIDIOC_ENUMINPUT\n");
+
+               if (copy_from_user(&v4l2_input, (void __user *)arg,
+                                       sizeof(struct v4l2_input))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               index = v4l2_input.index;
+               memset(&v4l2_input, 0, sizeof(struct v4l2_input));
+
+               switch (index) {
+               case 0: {
+                       v4l2_input.index = index;
+                       strcpy(&v4l2_input.name[0], "CVBS0");
+                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+                       v4l2_input.audioset = 0x01;
+                       v4l2_input.tuner = 0;
+                       v4l2_input.std = V4L2_STD_PAL |
+                                       V4L2_STD_SECAM |
+                                       V4L2_STD_NTSC ;
+                       v4l2_input.status = 0;
+                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+                       break;
+               }
+               case 1: {
+                       v4l2_input.index = index;
+                       strcpy(&v4l2_input.name[0], "CVBS1");
+                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+                       v4l2_input.audioset = 0x01;
+                       v4l2_input.tuner = 0;
+                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
+                                       V4L2_STD_NTSC;
+                       v4l2_input.status = 0;
+                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+                       break;
+               }
+               case 2: {
+                       v4l2_input.index = index;
+                       strcpy(&v4l2_input.name[0], "CVBS2");
+                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+                       v4l2_input.audioset = 0x01;
+                       v4l2_input.tuner = 0;
+                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
+                                       V4L2_STD_NTSC ;
+                       v4l2_input.status = 0;
+                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+                       break;
+               }
+               case 3: {
+                       v4l2_input.index = index;
+                       strcpy(&v4l2_input.name[0], "CVBS3");
+                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+                       v4l2_input.audioset = 0x01;
+                       v4l2_input.tuner = 0;
+                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
+                                       V4L2_STD_NTSC ;
+                       v4l2_input.status = 0;
+                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+                       break;
+               }
+               case 4: {
+                       v4l2_input.index = index;
+                       strcpy(&v4l2_input.name[0], "CVBS4");
+                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+                       v4l2_input.audioset = 0x01;
+                       v4l2_input.tuner = 0;
+                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
+                                       V4L2_STD_NTSC ;
+                       v4l2_input.status = 0;
+                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+                       break;
+               }
+               case 5: {
+                       v4l2_input.index = index;
+                       strcpy(&v4l2_input.name[0], "S-VIDEO");
+                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+                       v4l2_input.audioset = 0x01;
+                       v4l2_input.tuner = 0;
+                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
+                                       V4L2_STD_NTSC ;
+                       v4l2_input.status = 0;
+                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+                       break;
+               }
+               default: {
+                       JOM(8, "%i=index: exhausts inputs\n", index);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               }
+
+               if (copy_to_user((void __user *)arg, &v4l2_input,
+                               sizeof(struct v4l2_input))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_G_INPUT: {
+               u32 index;
+
+               JOM(8, "VIDIOC_G_INPUT\n");
+               index = (u32)peasycap->input;
+               JOM(8, "user is told: %i\n", index);
+               if (copy_to_user((void __user *)arg, &index, sizeof(u32))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_S_INPUT:
+       {
+               u32 index;
+               int rc;
+
+               JOM(8, "VIDIOC_S_INPUT\n");
+
+               if (0 != copy_from_user(&index, (void __user *)arg, sizeof(u32))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               JOM(8, "user requests input %i\n", index);
+
+               if ((int)index == peasycap->input) {
+                       SAM("requested input already in effect\n");
+                       break;
+               }
+
+               if ((0 > index) || (INPUT_MANY <= index)) {
+                       JOM(8, "ERROR:  bad requested input: %i\n", index);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+
+               rc = newinput(peasycap, (int)index);
+               if (0 == rc) {
+                       JOM(8, "newinput(.,%i) OK\n", (int)index);
+               } else {
+                       SAM("ERROR: newinput(.,%i) returned %i\n", (int)index, rc);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_ENUMAUDIO: {
+               JOM(8, "VIDIOC_ENUMAUDIO\n");
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+               return -EINVAL;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_ENUMAUDOUT: {
+               struct v4l2_audioout v4l2_audioout;
+
+               JOM(8, "VIDIOC_ENUMAUDOUT\n");
+
+               if (copy_from_user(&v4l2_audioout, (void __user *)arg,
+                                       sizeof(struct v4l2_audioout))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               if (0 != v4l2_audioout.index) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout));
+               v4l2_audioout.index = 0;
+               strcpy(&v4l2_audioout.name[0], "Soundtrack");
+
+               if (copy_to_user((void __user *)arg, &v4l2_audioout,
+                               sizeof(struct v4l2_audioout))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_QUERYCTRL: {
+               int i1;
+               struct v4l2_queryctrl v4l2_queryctrl;
+
+               JOM(8, "VIDIOC_QUERYCTRL\n");
+
+               if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg,
+                               sizeof(struct v4l2_queryctrl))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               i1 = 0;
+               while (0xFFFFFFFF != easycap_control[i1].id) {
+                       if (easycap_control[i1].id == v4l2_queryctrl.id) {
+                               JOM(8, "VIDIOC_QUERYCTRL  %s=easycap_control[%i]"
+                                   ".name\n", &easycap_control[i1].name[0], i1);
+                               memcpy(&v4l2_queryctrl, &easycap_control[i1],
+                                      sizeof(struct v4l2_queryctrl));
+                               break;
+                       }
+                       i1++;
+               }
+               if (0xFFFFFFFF == easycap_control[i1].id) {
+                       JOM(8, "%i=index: exhausts controls\n", i1);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               if (copy_to_user((void __user *)arg, &v4l2_queryctrl,
+                               sizeof(struct v4l2_queryctrl))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_QUERYMENU: {
+               JOM(8, "VIDIOC_QUERYMENU unsupported\n");
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+               return -EINVAL;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_G_CTRL: {
+               struct v4l2_control *pv4l2_control;
+
+               JOM(8, "VIDIOC_G_CTRL\n");
+               pv4l2_control = memdup_user((void __user *)arg,
+                                           sizeof(struct v4l2_control));
+               if (IS_ERR(pv4l2_control)) {
+                       SAM("ERROR: copy from user failed\n");
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return PTR_ERR(pv4l2_control);
+               }
+
+               switch (pv4l2_control->id) {
+               case V4L2_CID_BRIGHTNESS: {
+                       pv4l2_control->value = peasycap->brightness;
+                       JOM(8, "user enquires brightness: %i\n", pv4l2_control->value);
+                       break;
+               }
+               case V4L2_CID_CONTRAST: {
+                       pv4l2_control->value = peasycap->contrast;
+                       JOM(8, "user enquires contrast: %i\n", pv4l2_control->value);
+                       break;
+               }
+               case V4L2_CID_SATURATION: {
+                       pv4l2_control->value = peasycap->saturation;
+                       JOM(8, "user enquires saturation: %i\n", pv4l2_control->value);
+                       break;
+               }
+               case V4L2_CID_HUE: {
+                       pv4l2_control->value = peasycap->hue;
+                       JOM(8, "user enquires hue: %i\n", pv4l2_control->value);
+                       break;
+               }
+               case V4L2_CID_AUDIO_VOLUME: {
+                       pv4l2_control->value = peasycap->volume;
+                       JOM(8, "user enquires volume: %i\n", pv4l2_control->value);
+                       break;
+               }
+               case V4L2_CID_AUDIO_MUTE: {
+                       if (1 == peasycap->mute)
+                               pv4l2_control->value = true;
+                       else
+                               pv4l2_control->value = false;
+                       JOM(8, "user enquires mute: %i\n", pv4l2_control->value);
+                       break;
+               }
+               default: {
+                       SAM("ERROR: unknown V4L2 control: 0x%08X=id\n",
+                           pv4l2_control->id);
+                       kfree(pv4l2_control);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               }
+               if (copy_to_user((void __user *)arg, pv4l2_control,
+                               sizeof(struct v4l2_control))) {
+                       kfree(pv4l2_control);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               kfree(pv4l2_control);
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_S_CTRL: {
+               struct v4l2_control v4l2_control;
+
+               JOM(8, "VIDIOC_S_CTRL\n");
+
+               if (0 != copy_from_user(&v4l2_control, (void __user *)arg,
+                               sizeof(struct v4l2_control))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               switch (v4l2_control.id) {
+               case V4L2_CID_BRIGHTNESS: {
+                       JOM(8, "user requests brightness %i\n", v4l2_control.value);
+                       if (0 != adjust_brightness(peasycap, v4l2_control.value))
+                               ;
+                       break;
+               }
+               case V4L2_CID_CONTRAST: {
+                       JOM(8, "user requests contrast %i\n", v4l2_control.value);
+                       if (0 != adjust_contrast(peasycap, v4l2_control.value))
+                               ;
+                       break;
+               }
+               case V4L2_CID_SATURATION: {
+                       JOM(8, "user requests saturation %i\n", v4l2_control.value);
+                       if (0 != adjust_saturation(peasycap, v4l2_control.value))
+                               ;
+                       break;
+               }
+               case V4L2_CID_HUE: {
+                       JOM(8, "user requests hue %i\n", v4l2_control.value);
+                       if (0 != adjust_hue(peasycap, v4l2_control.value))
+                               ;
+                       break;
+               }
+               case V4L2_CID_AUDIO_VOLUME: {
+                       JOM(8, "user requests volume %i\n", v4l2_control.value);
+                       if (0 != adjust_volume(peasycap, v4l2_control.value))
+                               ;
+                       break;
+               }
+               case V4L2_CID_AUDIO_MUTE: {
+                       int mute;
+
+                       JOM(8, "user requests mute %i\n", v4l2_control.value);
+                       if (v4l2_control.value)
+                               mute = 1;
+                       else
+                               mute = 0;
+
+                       if (0 != adjust_mute(peasycap, mute))
+                               SAM("WARNING: failed to adjust mute to %i\n", mute);
+                       break;
+               }
+               default: {
+                       SAM("ERROR: unknown V4L2 control: 0x%08X=id\n",
+                           v4l2_control.id);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_S_EXT_CTRLS: {
+               JOM(8, "VIDIOC_S_EXT_CTRLS unsupported\n");
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+               return -EINVAL;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_ENUM_FMT: {
+               u32 index;
+               struct v4l2_fmtdesc v4l2_fmtdesc;
+
+               JOM(8, "VIDIOC_ENUM_FMT\n");
+
+               if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg,
+                               sizeof(struct v4l2_fmtdesc))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               index = v4l2_fmtdesc.index;
+               memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc));
+
+               v4l2_fmtdesc.index = index;
+               v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+               switch (index) {
+               case 0: {
+                       v4l2_fmtdesc.flags = 0;
+                       strcpy(&v4l2_fmtdesc.description[0], "uyvy");
+                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_UYVY;
+                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+                       break;
+               }
+               case 1: {
+                       v4l2_fmtdesc.flags = 0;
+                       strcpy(&v4l2_fmtdesc.description[0], "yuy2");
+                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_YUYV;
+                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+                       break;
+               }
+               case 2: {
+                       v4l2_fmtdesc.flags = 0;
+                       strcpy(&v4l2_fmtdesc.description[0], "rgb24");
+                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB24;
+                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+                       break;
+               }
+               case 3: {
+                       v4l2_fmtdesc.flags = 0;
+                       strcpy(&v4l2_fmtdesc.description[0], "rgb32");
+                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB32;
+                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+                       break;
+               }
+               case 4: {
+                       v4l2_fmtdesc.flags = 0;
+                       strcpy(&v4l2_fmtdesc.description[0], "bgr24");
+                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR24;
+                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+                       break;
+               }
+               case 5: {
+                       v4l2_fmtdesc.flags = 0;
+                       strcpy(&v4l2_fmtdesc.description[0], "bgr32");
+                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR32;
+                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+                       break;
+               }
+               default: {
+                       JOM(8, "%i=index: exhausts formats\n", index);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               }
+               if (copy_to_user((void __user *)arg, &v4l2_fmtdesc,
+                               sizeof(struct v4l2_fmtdesc))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+        *  THE RESPONSE TO VIDIOC_ENUM_FRAMESIZES MUST BE CONDITIONED ON THE
+        *  THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS.  BEWARE.
+       */
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_ENUM_FRAMESIZES: {
+               u32 index;
+               struct v4l2_frmsizeenum v4l2_frmsizeenum;
+
+               JOM(8, "VIDIOC_ENUM_FRAMESIZES\n");
+
+               if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg,
+                               sizeof(struct v4l2_frmsizeenum))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               index = v4l2_frmsizeenum.index;
+
+               v4l2_frmsizeenum.type = (u32) V4L2_FRMSIZE_TYPE_DISCRETE;
+
+               if (peasycap->ntsc) {
+                       switch (index) {
+                       case 0: {
+                               v4l2_frmsizeenum.discrete.width = 640;
+                               v4l2_frmsizeenum.discrete.height = 480;
+                               JOM(8, "%i=index: %ix%i\n", index,
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.width),
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.height));
+                               break;
+                       }
+                       case 1: {
+                               v4l2_frmsizeenum.discrete.width = 320;
+                               v4l2_frmsizeenum.discrete.height = 240;
+                               JOM(8, "%i=index: %ix%i\n", index,
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.width),
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.height));
+                               break;
+                       }
+                       case 2: {
+                               v4l2_frmsizeenum.discrete.width = 720;
+                               v4l2_frmsizeenum.discrete.height = 480;
+                               JOM(8, "%i=index: %ix%i\n", index,
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.width),
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.height));
+                               break;
+                       }
+                       case 3: {
+                               v4l2_frmsizeenum.discrete.width = 360;
+                               v4l2_frmsizeenum.discrete.height = 240;
+                               JOM(8, "%i=index: %ix%i\n", index,
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.width),
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.height));
+                               break;
+                       }
+                       default: {
+                               JOM(8, "%i=index: exhausts framesizes\n", index);
+                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                               return -EINVAL;
+                       }
+                       }
+               } else {
+                       switch (index) {
+                       case 0: {
+                               v4l2_frmsizeenum.discrete.width = 640;
+                               v4l2_frmsizeenum.discrete.height = 480;
+                               JOM(8, "%i=index: %ix%i\n", index,
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.width),
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.height));
+                               break;
+                       }
+                       case 1: {
+                               v4l2_frmsizeenum.discrete.width = 320;
+                               v4l2_frmsizeenum.discrete.height = 240;
+                               JOM(8, "%i=index: %ix%i\n", index,
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.width),
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.height));
+                               break;
+                       }
+                       case 2: {
+                               v4l2_frmsizeenum.discrete.width = 704;
+                               v4l2_frmsizeenum.discrete.height = 576;
+                               JOM(8, "%i=index: %ix%i\n", index,
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.width),
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.height));
+                               break;
+                       }
+                       case 3: {
+                               v4l2_frmsizeenum.discrete.width = 720;
+                               v4l2_frmsizeenum.discrete.height = 576;
+                               JOM(8, "%i=index: %ix%i\n", index,
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.width),
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.height));
+                               break;
+                       }
+                       case 4: {
+                               v4l2_frmsizeenum.discrete.width = 360;
+                               v4l2_frmsizeenum.discrete.height = 288;
+                               JOM(8, "%i=index: %ix%i\n", index,
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.width),
+                                   (int)(v4l2_frmsizeenum.
+                                         discrete.height));
+                               break;
+                       }
+                       default: {
+                               JOM(8, "%i=index: exhausts framesizes\n", index);
+                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                               return -EINVAL;
+                       }
+                       }
+               }
+               if (copy_to_user((void __user *)arg, &v4l2_frmsizeenum,
+                               sizeof(struct v4l2_frmsizeenum))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+        *  THE RESPONSE TO VIDIOC_ENUM_FRAMEINTERVALS MUST BE CONDITIONED ON THE
+        *  THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS.  BEWARE.
+       */
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_ENUM_FRAMEINTERVALS: {
+               u32 index;
+               int denominator;
+               struct v4l2_frmivalenum v4l2_frmivalenum;
+
+               JOM(8, "VIDIOC_ENUM_FRAMEINTERVALS\n");
+
+               if (peasycap->fps)
+                       denominator = peasycap->fps;
+               else {
+                       if (peasycap->ntsc)
+                               denominator = 30;
+                       else
+                               denominator = 25;
+               }
+
+               if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg,
+                               sizeof(struct v4l2_frmivalenum))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               index = v4l2_frmivalenum.index;
+
+               v4l2_frmivalenum.type = (u32) V4L2_FRMIVAL_TYPE_DISCRETE;
+
+               switch (index) {
+               case 0: {
+                       v4l2_frmivalenum.discrete.numerator = 1;
+                       v4l2_frmivalenum.discrete.denominator = denominator;
+                       JOM(8, "%i=index: %i/%i\n", index,
+                           (int)(v4l2_frmivalenum.discrete.numerator),
+                           (int)(v4l2_frmivalenum.discrete.denominator));
+                       break;
+               }
+               case 1: {
+                       v4l2_frmivalenum.discrete.numerator = 1;
+                       v4l2_frmivalenum.discrete.denominator = denominator/5;
+                       JOM(8, "%i=index: %i/%i\n", index,
+                           (int)(v4l2_frmivalenum.discrete.numerator),
+                           (int)(v4l2_frmivalenum.discrete.denominator));
+                       break;
+               }
+               default: {
+                       JOM(8, "%i=index: exhausts frameintervals\n", index);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               }
+               if (copy_to_user((void __user *)arg, &v4l2_frmivalenum,
+                                       sizeof(struct v4l2_frmivalenum))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_G_FMT: {
+               struct v4l2_format *pv4l2_format;
+               struct v4l2_pix_format *pv4l2_pix_format;
+
+               JOM(8, "VIDIOC_G_FMT\n");
+               pv4l2_format = kzalloc(sizeof(struct v4l2_format), GFP_KERNEL);
+               if (!pv4l2_format) {
+                       SAM("ERROR: out of memory\n");
+                       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(&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(&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(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+
+               memset(pv4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
+               pv4l2_format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               memcpy(&pv4l2_format->fmt.pix,
+                      &easycap_format[peasycap->format_offset]
+                      .v4l2_format.fmt.pix, sizeof(struct v4l2_pix_format));
+               JOM(8, "user is told: %s\n",
+                   &easycap_format[peasycap->format_offset].name[0]);
+
+               if (copy_to_user((void __user *)arg, pv4l2_format,
+                                       sizeof(struct v4l2_format))) {
+                       kfree(pv4l2_format);
+                       kfree(pv4l2_pix_format);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               kfree(pv4l2_format);
+               kfree(pv4l2_pix_format);
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_TRY_FMT:
+       case VIDIOC_S_FMT: {
+               struct v4l2_format v4l2_format;
+               struct v4l2_pix_format v4l2_pix_format;
+               bool try;
+               int best_format;
+
+               if (VIDIOC_TRY_FMT == cmd) {
+                       JOM(8, "VIDIOC_TRY_FMT\n");
+                       try = true;
+               } else {
+                       JOM(8, "VIDIOC_S_FMT\n");
+                       try = false;
+               }
+
+               if (0 != copy_from_user(&v4l2_format, (void __user *)arg,
+                                       sizeof(struct v4l2_format))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               best_format = adjust_format(peasycap,
+                                       v4l2_format.fmt.pix.width,
+                                       v4l2_format.fmt.pix.height,
+                                       v4l2_format.fmt.pix.pixelformat,
+                                       v4l2_format.fmt.pix.field,
+                                       try);
+               if (0 > best_format) {
+                       if (-EBUSY == best_format) {
+                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                               return -EBUSY;
+                       }
+                       JOM(8, "WARNING: adjust_format() returned %i\n", best_format);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -ENOENT;
+               }
+/*...........................................................................*/
+               memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
+               v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+               memcpy(&(v4l2_format.fmt.pix),
+                       &(easycap_format[best_format].v4l2_format.fmt.pix),
+                       sizeof(v4l2_pix_format));
+               JOM(8, "user is told: %s\n", &easycap_format[best_format].name[0]);
+
+               if (copy_to_user((void __user *)arg, &v4l2_format,
+                                       sizeof(struct v4l2_format))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_CROPCAP: {
+               struct v4l2_cropcap v4l2_cropcap;
+
+               JOM(8, "VIDIOC_CROPCAP\n");
+
+               if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg,
+                                       sizeof(struct v4l2_cropcap))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       JOM(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+
+               memset(&v4l2_cropcap, 0, sizeof(struct v4l2_cropcap));
+               v4l2_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               v4l2_cropcap.bounds.left      = 0;
+               v4l2_cropcap.bounds.top       = 0;
+               v4l2_cropcap.bounds.width     = peasycap->width;
+               v4l2_cropcap.bounds.height    = peasycap->height;
+               v4l2_cropcap.defrect.left     = 0;
+               v4l2_cropcap.defrect.top      = 0;
+               v4l2_cropcap.defrect.width    = peasycap->width;
+               v4l2_cropcap.defrect.height   = peasycap->height;
+               v4l2_cropcap.pixelaspect.numerator = 1;
+               v4l2_cropcap.pixelaspect.denominator = 1;
+
+               JOM(8, "user is told: %ix%i\n", peasycap->width, peasycap->height);
+
+               if (copy_to_user((void __user *)arg, &v4l2_cropcap,
+                                       sizeof(struct v4l2_cropcap))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_G_CROP:
+       case VIDIOC_S_CROP: {
+               JOM(8, "VIDIOC_G_CROP|VIDIOC_S_CROP  unsupported\n");
+               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(&easycapdc60_dongle[kd].mutex_video);
+               return -EINVAL;
+               break;
+       }
+       /*-------------------------------------------------------------------*/
+       /*
+        *  THE MANIPULATIONS INVOLVING last0,last1,last2,last3
+        *  CONSTITUTE A WORKAROUND *  FOR WHAT APPEARS TO BE
+        *  A BUG IN 64-BIT mplayer.
+        *  NOT NEEDED, BUT HOPEFULLY HARMLESS, FOR 32-BIT mplayer.
+        */
+       /*------------------------------------------------------------------*/
+       case VIDIOC_ENUMSTD: {
+               int last0 = -1, last1 = -1, last2 = -1, last3 = -1;
+               struct v4l2_standard v4l2_standard;
+               u32 index;
+               struct easycap_standard const *peasycap_standard;
+
+               JOM(8, "VIDIOC_ENUMSTD\n");
+
+               if (0 != copy_from_user(&v4l2_standard, (void __user *)arg,
+                                       sizeof(struct v4l2_standard))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               index = v4l2_standard.index;
+
+               last3 = last2;
+               last2 = last1;
+               last1 = last0;
+               last0 = index;
+               if ((index == last3) && (index == last2) &&
+                   (index == last1) && (index == last0)) {
+                       index++;
+                       last3 = last2;
+                       last2 = last1;
+                       last1 = last0;
+                       last0 = index;
+               }
+
+               memset(&v4l2_standard, 0, sizeof(struct v4l2_standard));
+
+               peasycap_standard = &easycap_standard[0];
+               while (0xFFFF != peasycap_standard->mask) {
+                       if ((int)(peasycap_standard - &easycap_standard[0]) == index)
+                               break;
+                       peasycap_standard++;
+               }
+               if (0xFFFF == peasycap_standard->mask) {
+                       JOM(8, "%i=index: exhausts standards\n", index);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               JOM(8, "%i=index: %s\n", index,
+                   &(peasycap_standard->v4l2_standard.name[0]));
+               memcpy(&v4l2_standard, &(peasycap_standard->v4l2_standard),
+                      sizeof(struct v4l2_standard));
+
+               v4l2_standard.index = index;
+
+               if (copy_to_user((void __user *)arg, &v4l2_standard,
+                               sizeof(struct v4l2_standard))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_G_STD: {
+               v4l2_std_id std_id;
+               struct easycap_standard const *peasycap_standard;
+
+               JOM(8, "VIDIOC_G_STD\n");
+
+               if (0 > peasycap->standard_offset) {
+                       JOM(8, "%i=peasycap->standard_offset\n",
+                           peasycap->standard_offset);
+                       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(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               peasycap_standard = &easycap_standard[peasycap->standard_offset];
+               std_id = peasycap_standard->v4l2_standard.id;
+
+               JOM(8, "user is told: %s\n",
+                   &peasycap_standard->v4l2_standard.name[0]);
+
+               if (copy_to_user((void __user *)arg, &std_id,
+                                       sizeof(v4l2_std_id))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_S_STD: {
+               v4l2_std_id std_id;
+               int rc;
+
+               JOM(8, "VIDIOC_S_STD\n");
+
+               if (0 != copy_from_user(&std_id, (void __user *)arg,
+                                       sizeof(v4l2_std_id))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               JOM(8, "User requests standard: 0x%08X%08X\n",
+                   (int)((std_id & (((v4l2_std_id)0xFFFFFFFF) << 32)) >> 32),
+                   (int)(std_id & ((v4l2_std_id)0xFFFFFFFF)));
+
+               rc = adjust_standard(peasycap, std_id);
+               if (0 > rc) {
+                       JOM(8, "WARNING: adjust_standard() returned %i\n", rc);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -ENOENT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_REQBUFS: {
+               int nbuffers;
+               struct v4l2_requestbuffers v4l2_requestbuffers;
+
+               JOM(8, "VIDIOC_REQBUFS\n");
+
+               if (0 != copy_from_user(&v4l2_requestbuffers,
+                                       (void __user *)arg,
+                                       sizeof(struct v4l2_requestbuffers))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               nbuffers = v4l2_requestbuffers.count;
+               JOM(8, "                   User requests %i buffers ...\n", nbuffers);
+               if (nbuffers < 2)
+                       nbuffers = 2;
+               if (nbuffers > FRAME_BUFFER_MANY)
+                       nbuffers = FRAME_BUFFER_MANY;
+               if (v4l2_requestbuffers.count == nbuffers) {
+                       JOM(8, "                   ... agree to  %i buffers\n",
+                           nbuffers);
+               } else {
+                       JOM(8, "                  ... insist on  %i buffers\n",
+                           nbuffers);
+                       v4l2_requestbuffers.count = nbuffers;
+               }
+               peasycap->frame_buffer_many = nbuffers;
+
+               if (copy_to_user((void __user *)arg, &v4l2_requestbuffers,
+                                       sizeof(struct v4l2_requestbuffers))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_QUERYBUF: {
+               u32 index;
+               struct v4l2_buffer v4l2_buffer;
+
+               JOM(8, "VIDIOC_QUERYBUF\n");
+
+               if (peasycap->video_eof) {
+                       JOM(8, "returning -EIO because  %i=video_eof\n",
+                           peasycap->video_eof);
+                       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(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               index = v4l2_buffer.index;
+               if (index < 0 || index >= peasycap->frame_buffer_many)
+                       return -EINVAL;
+               memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer));
+               v4l2_buffer.index = index;
+               v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               v4l2_buffer.bytesused = peasycap->frame_buffer_used;
+               v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED |
+                                       peasycap->done[index] |
+                                       peasycap->queued[index];
+               v4l2_buffer.field = V4L2_FIELD_NONE;
+               v4l2_buffer.memory = V4L2_MEMORY_MMAP;
+               v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE;
+               v4l2_buffer.length = FRAME_BUFFER_SIZE;
+
+               JOM(16, "  %10i=index\n", v4l2_buffer.index);
+               JOM(16, "  0x%08X=type\n", v4l2_buffer.type);
+               JOM(16, "  %10i=bytesused\n", v4l2_buffer.bytesused);
+               JOM(16, "  0x%08X=flags\n", v4l2_buffer.flags);
+               JOM(16, "  %10i=field\n", v4l2_buffer.field);
+               JOM(16, "  %10li=timestamp.tv_usec\n",
+                   (long)v4l2_buffer.timestamp.tv_usec);
+               JOM(16, "  %10i=sequence\n", v4l2_buffer.sequence);
+               JOM(16, "  0x%08X=memory\n", v4l2_buffer.memory);
+               JOM(16, "  %10i=m.offset\n", v4l2_buffer.m.offset);
+               JOM(16, "  %10i=length\n", v4l2_buffer.length);
+
+               if (copy_to_user((void __user *)arg, &v4l2_buffer,
+                                       sizeof(struct v4l2_buffer))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_QBUF: {
+               struct v4l2_buffer v4l2_buffer;
+
+               JOM(8, "VIDIOC_QBUF\n");
+
+               if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg,
+                                       sizeof(struct v4l2_buffer))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               if (v4l2_buffer.index < 0 ||
+                   v4l2_buffer.index >= peasycap->frame_buffer_many) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
+
+               peasycap->done[v4l2_buffer.index]   = 0;
+               peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED;
+
+               if (copy_to_user((void __user *)arg, &v4l2_buffer,
+                                       sizeof(struct v4l2_buffer))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               JOM(8, ".....   user queueing frame buffer %i\n",
+                   (int)v4l2_buffer.index);
+
+               peasycap->frame_lock = 0;
+
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_DQBUF:
+       {
+               struct timeval timeval, timeval2;
+               int i, j;
+               struct v4l2_buffer v4l2_buffer;
+               int rcdq;
+               u16 input;
+
+               JOM(8, "VIDIOC_DQBUF\n");
+
+               if ((peasycap->video_idle) || (peasycap->video_eof)) {
+                       JOM(8, "returning -EIO because  "
+                           "%i=video_idle  %i=video_eof\n",
+                           peasycap->video_idle, peasycap->video_eof);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EIO;
+               }
+
+               if (copy_from_user(&v4l2_buffer, (void __user *)arg,
+                                 sizeof(struct v4l2_buffer))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+
+               if (peasycap->offerfields) {
+                       /*---------------------------------------------------*/
+                       /*
+                        *  IN ITS 50 "fps" MODE tvtime SEEMS ALWAYS TO REQUEST
+                        *  V4L2_FIELD_BOTTOM
+                        */
+                       /*---------------------------------------------------*/
+                       if (V4L2_FIELD_TOP == v4l2_buffer.field)
+                               JOM(8, "user wants V4L2_FIELD_TOP\n");
+                       else if (V4L2_FIELD_BOTTOM == v4l2_buffer.field)
+                               JOM(8, "user wants V4L2_FIELD_BOTTOM\n");
+                       else if (V4L2_FIELD_ANY == v4l2_buffer.field)
+                               JOM(8, "user wants V4L2_FIELD_ANY\n");
+                       else
+                               JOM(8, "user wants V4L2_FIELD_...UNKNOWN: %i\n",
+                                   v4l2_buffer.field);
+               }
+
+               if (!peasycap->video_isoc_streaming) {
+                       JOM(16, "returning -EIO because video urbs not streaming\n");
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EIO;
+               }
+       /*-------------------------------------------------------------------*/
+       /*
+        *  IF THE USER HAS PREVIOUSLY CALLED easycap_poll(),
+        *  AS DETERMINED BY FINDING
+        *  THE FLAG peasycap->polled SET, THERE MUST BE
+        *  NO FURTHER WAIT HERE.  IN THIS
+        *  CASE, JUST CHOOSE THE FRAME INDICATED BY peasycap->frame_read
+        */
+       /*-------------------------------------------------------------------*/
+
+               if (!peasycap->polled) {
+                       do {
+                               rcdq = easycap_dqbuf(peasycap, 0);
+                               if (-EIO == rcdq) {
+                                       JOM(8, "returning -EIO because "
+                                           "dqbuf() returned -EIO\n");
+                                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                                       return -EIO;
+                               }
+                       } while (0 != rcdq);
+               } else {
+                       if (peasycap->video_eof) {
+                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                               return -EIO;
+                       }
+               }
+               if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) {
+                       JOM(8, "V4L2_BUF_FLAG_DONE != 0x%08X\n",
+                           peasycap->done[peasycap->frame_read]);
+               }
+               peasycap->polled = 0;
+
+               if (!(peasycap->isequence % 10)) {
+                       for (i = 0; i < 179; i++)
+                               peasycap->merit[i] = peasycap->merit[i+1];
+                       peasycap->merit[179] = merit_saa(peasycap->pusb_device);
+                       j = 0;
+                       for (i = 0; i < 180; i++)
+                               j += peasycap->merit[i];
+                       if (90 < j) {
+                               SAM("easycap driver shutting down "
+                                   "on condition blue\n");
+                               peasycap->video_eof = 1;
+                               peasycap->audio_eof = 1;
+                       }
+               }
+
+               v4l2_buffer.index = peasycap->frame_read;
+               v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               v4l2_buffer.bytesused = peasycap->frame_buffer_used;
+               v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
+               if (peasycap->offerfields)
+                       v4l2_buffer.field = V4L2_FIELD_BOTTOM;
+               else
+                       v4l2_buffer.field = V4L2_FIELD_NONE;
+               do_gettimeofday(&timeval);
+               timeval2 = timeval;
+
+               v4l2_buffer.timestamp = timeval2;
+               v4l2_buffer.sequence = peasycap->isequence++;
+               v4l2_buffer.memory = V4L2_MEMORY_MMAP;
+               v4l2_buffer.m.offset = v4l2_buffer.index * FRAME_BUFFER_SIZE;
+               v4l2_buffer.length = FRAME_BUFFER_SIZE;
+
+               JOM(16, "  %10i=index\n", v4l2_buffer.index);
+               JOM(16, "  0x%08X=type\n", v4l2_buffer.type);
+               JOM(16, "  %10i=bytesused\n", v4l2_buffer.bytesused);
+               JOM(16, "  0x%08X=flags\n", v4l2_buffer.flags);
+               JOM(16, "  %10i=field\n", v4l2_buffer.field);
+               JOM(16, "  %10li=timestamp.tv_sec\n",
+                   (long)v4l2_buffer.timestamp.tv_sec);
+               JOM(16, "  %10li=timestamp.tv_usec\n",
+                   (long)v4l2_buffer.timestamp.tv_usec);
+               JOM(16, "  %10i=sequence\n", v4l2_buffer.sequence);
+               JOM(16, "  0x%08X=memory\n", v4l2_buffer.memory);
+               JOM(16, "  %10i=m.offset\n", v4l2_buffer.m.offset);
+               JOM(16, "  %10i=length\n", v4l2_buffer.length);
+
+               if (copy_to_user((void __user *)arg, &v4l2_buffer,
+                                       sizeof(struct v4l2_buffer))) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               input = peasycap->frame_buffer[peasycap->frame_read][0].input;
+               if (0x08 & input) {
+                       JOM(8, "user is offered frame buffer %i, input %i\n",
+                           peasycap->frame_read, (0x07 & input));
+               } else {
+                       JOM(8, "user is offered frame buffer %i\n",
+                           peasycap->frame_read);
+               }
+               peasycap->frame_lock = 1;
+               JOM(8, "%i=peasycap->frame_fill\n", peasycap->frame_fill);
+               if (peasycap->frame_read == peasycap->frame_fill) {
+                       if (peasycap->frame_lock) {
+                               JOM(8, "WORRY:  filling frame buffer "
+                                   "while offered to user\n");
+                       }
+               }
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_STREAMON: {
+               int i;
+
+               JOM(8, "VIDIOC_STREAMON\n");
+
+               peasycap->isequence = 0;
+               for (i = 0; i < 180; i++)
+                       peasycap->merit[i] = 0;
+               if (!peasycap->pusb_device) {
+                       SAM("ERROR: peasycap->pusb_device is NULL\n");
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               submit_video_urbs(peasycap);
+               peasycap->video_idle = 0;
+               peasycap->audio_idle = 0;
+               peasycap->video_eof = 0;
+               peasycap->audio_eof = 0;
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_STREAMOFF: {
+               JOM(8, "VIDIOC_STREAMOFF\n");
+
+               if (!peasycap->pusb_device) {
+                       SAM("ERROR: peasycap->pusb_device is NULL\n");
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+
+               peasycap->video_idle = 1;
+               peasycap->audio_idle = 1;
+/*---------------------------------------------------------------------------*/
+/*
+ *  IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO THE STREAMOFF COMMAND
+ *  THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT.   BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+               JOM(8, "calling wake_up on wq_video and wq_audio\n");
+               wake_up_interruptible(&(peasycap->wq_video));
+               if (peasycap->psubstream)
+                       snd_pcm_period_elapsed(peasycap->psubstream);
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_G_PARM: {
+               struct v4l2_streamparm *pv4l2_streamparm;
+
+               JOM(8, "VIDIOC_G_PARM\n");
+               pv4l2_streamparm = memdup_user((void __user *)arg,
+                                              sizeof(struct v4l2_streamparm));
+               if (IS_ERR(pv4l2_streamparm)) {
+                       SAM("ERROR: copy from user failed\n");
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return PTR_ERR(pv4l2_streamparm);
+               }
+
+               if (pv4l2_streamparm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                       kfree(pv4l2_streamparm);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EINVAL;
+               }
+               pv4l2_streamparm->parm.capture.capability = 0;
+               pv4l2_streamparm->parm.capture.capturemode = 0;
+               pv4l2_streamparm->parm.capture.timeperframe.numerator = 1;
+
+               if (peasycap->fps) {
+                       pv4l2_streamparm->parm.capture.timeperframe.
+                       denominator = peasycap->fps;
+               } else {
+                       if (peasycap->ntsc) {
+                               pv4l2_streamparm->parm.capture.timeperframe.
+                               denominator = 30;
+                       } else {
+                               pv4l2_streamparm->parm.capture.timeperframe.
+                               denominator = 25;
+                       }
+               }
+
+               pv4l2_streamparm->parm.capture.readbuffers =
+                       peasycap->frame_buffer_many;
+               pv4l2_streamparm->parm.capture.extendedmode = 0;
+               if (copy_to_user((void __user *)arg,
+                               pv4l2_streamparm,
+                               sizeof(struct v4l2_streamparm))) {
+                       kfree(pv4l2_streamparm);
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -EFAULT;
+               }
+               kfree(pv4l2_streamparm);
+               break;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_S_PARM: {
+               JOM(8, "VIDIOC_S_PARM unsupported\n");
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+               return -EINVAL;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_G_AUDIO: {
+               JOM(8, "VIDIOC_G_AUDIO unsupported\n");
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+               return -EINVAL;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_S_AUDIO: {
+               JOM(8, "VIDIOC_S_AUDIO unsupported\n");
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+               return -EINVAL;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_S_TUNER: {
+               JOM(8, "VIDIOC_S_TUNER unsupported\n");
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+               return -EINVAL;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       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(&easycapdc60_dongle[kd].mutex_video);
+               return -EINVAL;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       case VIDIOC_G_TUNER: {
+               JOM(8, "VIDIOC_G_TUNER unsupported\n");
+               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(&easycapdc60_dongle[kd].mutex_video);
+               return -EINVAL;
+       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       default: {
+               JOM(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+               return -ENOIOCTLCMD;
+       }
+       }
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+       JOM(4, "unlocked easycapdc60_dongle[%i].mutex_video\n", kd);
+       return 0;
+}
+/*****************************************************************************/
diff --git a/drivers/staging/media/easycap/easycap_low.c b/drivers/staging/media/easycap/easycap_low.c
new file mode 100644 (file)
index 0000000..0385735
--- /dev/null
@@ -0,0 +1,1129 @@
+/*****************************************************************************
+*                                                                            *
+*                                                                            *
+*  easycap_low.c                                                             *
+*                                                                            *
+*                                                                            *
+*****************************************************************************/
+/*
+ *
+ *  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
+ *
+*/
+/*****************************************************************************/
+/*
+ *  ACKNOWLEGEMENTS AND REFERENCES
+ *  ------------------------------
+ *  This driver makes use of register information contained in the Syntek
+ *  Semicon DC-1125 driver hosted at
+ *               http://sourceforge.net/projects/syntekdriver/.
+ *  Particularly useful has been a patch to the latter driver provided by
+ *  Ivor Hewitt in January 2009.  The NTSC implementation is taken from the
+ *  work of Ben Trask.
+*/
+/****************************************************************************/
+
+#include "easycap.h"
+
+#define GET(X, Y, Z) do { \
+       int __rc; \
+       *(Z) = (u16)0; \
+       __rc = regget(X, Y, Z, sizeof(u8)); \
+       if (0 > __rc) { \
+               JOT(8, ":-(%i\n", __LINE__);  return __rc; \
+       } \
+} while (0)
+
+#define SET(X, Y, Z) do { \
+       int __rc; \
+       __rc = regset(X, Y, Z); \
+       if (0 > __rc) { \
+               JOT(8, ":-(%i\n", __LINE__);  return __rc; \
+       } \
+} while (0)
+
+/*--------------------------------------------------------------------------*/
+static const struct stk1160config {
+       int reg;
+       int set;
+} stk1160configPAL[256] = {
+               {0x000, 0x0098},
+               {0x002, 0x0093},
+
+               {0x001, 0x0003},
+               {0x003, 0x0080},
+               {0x00D, 0x0000},
+               {0x00F, 0x0002},
+               {0x018, 0x0010},
+               {0x019, 0x0000},
+               {0x01A, 0x0014},
+               {0x01B, 0x000E},
+               {0x01C, 0x0046},
+
+               {0x100, 0x0033},
+               {0x103, 0x0000},
+               {0x104, 0x0000},
+               {0x105, 0x0000},
+               {0x106, 0x0000},
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+ *  RESOLUTION 640x480
+*/
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+               {0x110, 0x0008},
+               {0x111, 0x0000},
+               {0x112, 0x0020},
+               {0x113, 0x0000},
+               {0x114, 0x0508},
+               {0x115, 0x0005},
+               {0x116, 0x0110},
+               {0x117, 0x0001},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+               {0x202, 0x000F},
+               {0x203, 0x004A},
+               {0x2FF, 0x0000},
+
+               {0xFFF, 0xFFFF}
+};
+/*--------------------------------------------------------------------------*/
+static const struct stk1160config stk1160configNTSC[256] = {
+               {0x000, 0x0098},
+               {0x002, 0x0093},
+
+               {0x001, 0x0003},
+               {0x003, 0x0080},
+               {0x00D, 0x0000},
+               {0x00F, 0x0002},
+               {0x018, 0x0010},
+               {0x019, 0x0000},
+               {0x01A, 0x0014},
+               {0x01B, 0x000E},
+               {0x01C, 0x0046},
+
+               {0x100, 0x0033},
+               {0x103, 0x0000},
+               {0x104, 0x0000},
+               {0x105, 0x0000},
+               {0x106, 0x0000},
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+ *  RESOLUTION 640x480
+*/
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+               {0x110, 0x0008},
+               {0x111, 0x0000},
+               {0x112, 0x0003},
+               {0x113, 0x0000},
+               {0x114, 0x0508},
+               {0x115, 0x0005},
+               {0x116, 0x00F3},
+               {0x117, 0x0000},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+               {0x202, 0x000F},
+               {0x203, 0x004A},
+               {0x2FF, 0x0000},
+
+               {0xFFF, 0xFFFF}
+};
+/*--------------------------------------------------------------------------*/
+static const struct saa7113config {
+       int reg;
+       int set;
+} saa7113configPAL[256] = {
+               {0x01, 0x08},
+               {0x02, 0x80},
+               {0x03, 0x33},
+               {0x04, 0x00},
+               {0x05, 0x00},
+               {0x06, 0xE9},
+               {0x07, 0x0D},
+               {0x08, 0x38},
+               {0x09, 0x00},
+               {0x0A, SAA_0A_DEFAULT},
+               {0x0B, SAA_0B_DEFAULT},
+               {0x0C, SAA_0C_DEFAULT},
+               {0x0D, SAA_0D_DEFAULT},
+               {0x0E, 0x01},
+               {0x0F, 0x36},
+               {0x10, 0x00},
+               {0x11, 0x0C},
+               {0x12, 0xE7},
+               {0x13, 0x00},
+               {0x15, 0x00},
+               {0x16, 0x00},
+               {0x40, 0x02},
+               {0x41, 0xFF},
+               {0x42, 0xFF},
+               {0x43, 0xFF},
+               {0x44, 0xFF},
+               {0x45, 0xFF},
+               {0x46, 0xFF},
+               {0x47, 0xFF},
+               {0x48, 0xFF},
+               {0x49, 0xFF},
+               {0x4A, 0xFF},
+               {0x4B, 0xFF},
+               {0x4C, 0xFF},
+               {0x4D, 0xFF},
+               {0x4E, 0xFF},
+               {0x4F, 0xFF},
+               {0x50, 0xFF},
+               {0x51, 0xFF},
+               {0x52, 0xFF},
+               {0x53, 0xFF},
+               {0x54, 0xFF},
+               {0x55, 0xFF},
+               {0x56, 0xFF},
+               {0x57, 0xFF},
+               {0x58, 0x40},
+               {0x59, 0x54},
+               {0x5A, 0x07},
+               {0x5B, 0x83},
+
+               {0xFF, 0xFF}
+};
+/*--------------------------------------------------------------------------*/
+static const struct saa7113config saa7113configNTSC[256] = {
+               {0x01, 0x08},
+               {0x02, 0x80},
+               {0x03, 0x33},
+               {0x04, 0x00},
+               {0x05, 0x00},
+               {0x06, 0xE9},
+               {0x07, 0x0D},
+               {0x08, 0x78},
+               {0x09, 0x00},
+               {0x0A, SAA_0A_DEFAULT},
+               {0x0B, SAA_0B_DEFAULT},
+               {0x0C, SAA_0C_DEFAULT},
+               {0x0D, SAA_0D_DEFAULT},
+               {0x0E, 0x01},
+               {0x0F, 0x36},
+               {0x10, 0x00},
+               {0x11, 0x0C},
+               {0x12, 0xE7},
+               {0x13, 0x00},
+               {0x15, 0x00},
+               {0x16, 0x00},
+               {0x40, 0x82},
+               {0x41, 0xFF},
+               {0x42, 0xFF},
+               {0x43, 0xFF},
+               {0x44, 0xFF},
+               {0x45, 0xFF},
+               {0x46, 0xFF},
+               {0x47, 0xFF},
+               {0x48, 0xFF},
+               {0x49, 0xFF},
+               {0x4A, 0xFF},
+               {0x4B, 0xFF},
+               {0x4C, 0xFF},
+               {0x4D, 0xFF},
+               {0x4E, 0xFF},
+               {0x4F, 0xFF},
+               {0x50, 0xFF},
+               {0x51, 0xFF},
+               {0x52, 0xFF},
+               {0x53, 0xFF},
+               {0x54, 0xFF},
+               {0x55, 0xFF},
+               {0x56, 0xFF},
+               {0x57, 0xFF},
+               {0x58, 0x40},
+               {0x59, 0x54},
+               {0x5A, 0x0A},
+               {0x5B, 0x83},
+
+               {0xFF, 0xFF}
+};
+
+static int regget(struct usb_device *pusb_device,
+               u16 index, void *reg, int reg_size)
+{
+       int rc;
+
+       if (!pusb_device)
+               return -ENODEV;
+
+       rc = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0),
+                       0x00,
+                       (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
+                       0x00,
+                       index, reg, reg_size, 50000);
+
+       return rc;
+}
+
+static int regset(struct usb_device *pusb_device, u16 index, u16 value)
+{
+       int rc;
+
+       if (!pusb_device)
+               return -ENODEV;
+
+       rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
+                       0x01,
+                       (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
+                       value, index, NULL, 0, 500);
+
+       if (rc < 0)
+               return rc;
+
+       if (easycap_readback) {
+               u16 igot = 0;
+               rc = regget(pusb_device, index, &igot, sizeof(igot));
+               igot = 0xFF & igot;
+               switch (index) {
+               case 0x000:
+               case 0x500:
+               case 0x502:
+               case 0x503:
+               case 0x504:
+               case 0x506:
+               case 0x507:
+                       break;
+
+               case 0x204:
+               case 0x205:
+               case 0x350:
+               case 0x351:
+                       if (igot)
+                               JOT(8, "unexpected 0x%02X "
+                                       "for STK register 0x%03X\n",
+                                       igot, index);
+                       break;
+
+               default:
+                       if ((0xFF & value) != igot)
+                               JOT(8, "unexpected 0x%02X != 0x%02X "
+                                       "for STK register 0x%03X\n",
+                                               igot, value, index);
+                       break;
+               }
+       }
+
+       return rc;
+}
+/*--------------------------------------------------------------------------*/
+/*
+ *  FUNCTION wait_i2c() RETURNS 0 ON SUCCESS
+*/
+/*--------------------------------------------------------------------------*/
+static int wait_i2c(struct usb_device *p)
+{
+       u16 get0;
+       u8 igot;
+       const int max = 2;
+       int k;
+
+       if (!p)
+               return -ENODEV;
+
+       for (k = 0;  k < max;  k++) {
+               GET(p, 0x0201, &igot);  get0 = igot;
+               switch (get0) {
+               case 0x04:
+               case 0x01:
+                       return 0;
+               case 0x00:
+                       msleep(20);
+                       continue;
+               default:
+                       return get0 - 1;
+               }
+       }
+       return -1;
+}
+
+/****************************************************************************/
+int confirm_resolution(struct usb_device *p)
+{
+       u8 get0, get1, get2, get3, get4, get5, get6, get7;
+
+       if (!p)
+               return -ENODEV;
+       GET(p, 0x0110, &get0);
+       GET(p, 0x0111, &get1);
+       GET(p, 0x0112, &get2);
+       GET(p, 0x0113, &get3);
+       GET(p, 0x0114, &get4);
+       GET(p, 0x0115, &get5);
+       GET(p, 0x0116, &get6);
+       GET(p, 0x0117, &get7);
+       JOT(8,  "0x%03X, 0x%03X, "
+               "0x%03X, 0x%03X, "
+               "0x%03X, 0x%03X, "
+               "0x%03X, 0x%03X\n",
+               get0, get1, get2, get3, get4, get5, get6, get7);
+       JOT(8,  "....cf PAL_720x526: "
+               "0x%03X, 0x%03X, "
+               "0x%03X, 0x%03X, "
+               "0x%03X, 0x%03X, "
+               "0x%03X, 0x%03X\n",
+               0x000, 0x000, 0x001, 0x000, 0x5A0, 0x005, 0x121, 0x001);
+       JOT(8,  "....cf PAL_704x526: "
+               "0x%03X, 0x%03X, "
+               "0x%03X, 0x%03X, "
+               "0x%03X, 0x%03X, "
+               "0x%03X, 0x%03X\n",
+               0x004, 0x000, 0x001, 0x000, 0x584, 0x005, 0x121, 0x001);
+       JOT(8,  "....cf VGA_640x480: "
+               "0x%03X, 0x%03X, "
+               "0x%03X, 0x%03X, "
+               "0x%03X, 0x%03X, "
+               "0x%03X, 0x%03X\n",
+               0x008, 0x000, 0x020, 0x000, 0x508, 0x005, 0x110, 0x001);
+       return 0;
+}
+/****************************************************************************/
+int confirm_stream(struct usb_device *p)
+{
+       u16 get2;
+       u8 igot;
+
+       if (!p)
+               return -ENODEV;
+       GET(p, 0x0100, &igot);  get2 = 0x80 & igot;
+       if (0x80 == get2)
+               JOT(8, "confirm_stream:  OK\n");
+       else
+               JOT(8, "confirm_stream:  STUCK\n");
+       return 0;
+}
+/****************************************************************************/
+int setup_stk(struct usb_device *p, bool ntsc)
+{
+       int i;
+       const struct stk1160config *cfg;
+       if (!p)
+               return -ENODEV;
+       cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL;
+       for (i = 0; cfg[i].reg != 0xFFF; i++)
+               SET(p, cfg[i].reg, cfg[i].set);
+
+       write_300(p);
+
+       return 0;
+}
+/****************************************************************************/
+int setup_saa(struct usb_device *p, bool ntsc)
+{
+       int i, ir;
+       const struct saa7113config *cfg;
+       if (!p)
+               return -ENODEV;
+       cfg = (ntsc) ?  saa7113configNTSC : saa7113configPAL;
+       for (i = 0; cfg[i].reg != 0xFF; i++)
+               ir = write_saa(p, cfg[i].reg, cfg[i].set);
+       return 0;
+}
+/****************************************************************************/
+int write_000(struct usb_device *p, u16 set2, u16 set0)
+{
+       u8 igot0, igot2;
+
+       if (!p)
+               return -ENODEV;
+       GET(p, 0x0002, &igot2);
+       GET(p, 0x0000, &igot0);
+       SET(p, 0x0002, set2);
+       SET(p, 0x0000, set0);
+       return 0;
+}
+/****************************************************************************/
+int write_saa(struct usb_device *p, u16 reg0, u16 set0)
+{
+       if (!p)
+               return -ENODEV;
+       SET(p, 0x200, 0x00);
+       SET(p, 0x204, reg0);
+       SET(p, 0x205, set0);
+       SET(p, 0x200, 0x01);
+       return wait_i2c(p);
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  REGISTER 500:  SETTING VALUE TO 0x008B READS FROM VT1612A (?)
+ *  REGISTER 500:  SETTING VALUE TO 0x008C WRITES TO  VT1612A
+ *  REGISTER 502:  LEAST SIGNIFICANT BYTE OF VALUE TO SET
+ *  REGISTER 503:  MOST SIGNIFICANT BYTE OF VALUE TO SET
+ *  REGISTER 504:  TARGET ADDRESS ON VT1612A
+ */
+/*--------------------------------------------------------------------------*/
+int
+write_vt(struct usb_device *p, u16 reg0, u16 set0)
+{
+       u8 igot;
+       u16 got502, got503;
+       u16 set502, set503;
+
+       if (!p)
+               return -ENODEV;
+       SET(p, 0x0504, reg0);
+       SET(p, 0x0500, 0x008B);
+
+       GET(p, 0x0502, &igot);  got502 = (0xFF & igot);
+       GET(p, 0x0503, &igot);  got503 = (0xFF & igot);
+
+       JOT(16, "write_vt(., 0x%04X, 0x%04X): was 0x%04X\n",
+                               reg0, set0, ((got503 << 8) | got502));
+
+       set502 =  (0x00FF & set0);
+       set503 = ((0xFF00 & set0) >> 8);
+
+       SET(p, 0x0504, reg0);
+       SET(p, 0x0502, set502);
+       SET(p, 0x0503, set503);
+       SET(p, 0x0500, 0x008C);
+
+       return 0;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  REGISTER 500:  SETTING VALUE TO 0x008B READS FROM VT1612A (?)
+ *  REGISTER 500:  SETTING VALUE TO 0x008C WRITES TO  VT1612A
+ *  REGISTER 502:  LEAST SIGNIFICANT BYTE OF VALUE TO GET
+ *  REGISTER 503:  MOST SIGNIFICANT BYTE OF VALUE TO GET
+ *  REGISTER 504:  TARGET ADDRESS ON VT1612A
+ */
+/*--------------------------------------------------------------------------*/
+int read_vt(struct usb_device *p, u16 reg0)
+{
+       u8 igot;
+       u16 got502, got503;
+
+       if (!p)
+               return -ENODEV;
+       SET(p, 0x0504, reg0);
+       SET(p, 0x0500, 0x008B);
+
+       GET(p, 0x0502, &igot);  got502 = (0xFF & igot);
+       GET(p, 0x0503, &igot);  got503 = (0xFF & igot);
+
+       JOT(16, "read_vt(., 0x%04X): has 0x%04X\n",
+                       reg0, ((got503 << 8) | got502));
+
+       return (got503 << 8) | got502;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  THESE APPEAR TO HAVE NO EFFECT ON EITHER VIDEO OR AUDIO.
+ */
+/*--------------------------------------------------------------------------*/
+int write_300(struct usb_device *p)
+{
+       if (!p)
+               return -ENODEV;
+       SET(p, 0x300, 0x0012);
+       SET(p, 0x350, 0x002D);
+       SET(p, 0x351, 0x0001);
+       SET(p, 0x352, 0x0000);
+       SET(p, 0x353, 0x0000);
+       SET(p, 0x300, 0x0080);
+       return 0;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  NOTE: THE FOLLOWING IS NOT CHECKED:
+ *  REGISTER 0x0F, WHICH IS INVOLVED IN CHROMINANCE AUTOMATIC GAIN CONTROL.
+ */
+/*--------------------------------------------------------------------------*/
+int check_saa(struct usb_device *p, bool ntsc)
+{
+       int i, ir, rc = 0;
+       struct saa7113config const *cfg;
+       if (!p)
+               return -ENODEV;
+
+       cfg = (ntsc) ? saa7113configNTSC : saa7113configPAL;
+       for (i = 0; cfg[i].reg != 0xFF; i++) {
+               if (0x0F == cfg[i].reg)
+                       continue;
+               ir = read_saa(p, cfg[i].reg);
+               if (ir != cfg[i].set) {
+                       SAY("SAA register 0x%02X has 0x%02X, expected 0x%02X\n",
+                               cfg[i].reg, ir, cfg[i].set);
+                               rc--;
+               }
+       }
+
+       return (rc < -8) ? rc : 0;
+}
+/****************************************************************************/
+int merit_saa(struct usb_device *p)
+{
+       int rc;
+
+       if (!p)
+               return -ENODEV;
+       rc = read_saa(p, 0x1F);
+       return ((0 > rc) || (0x02 & rc)) ? 1 : 0;
+}
+/****************************************************************************/
+int ready_saa(struct usb_device *p)
+{
+       int j, rc, rate;
+       const int max = 5, marktime = PATIENCE/5;
+/*--------------------------------------------------------------------------*/
+/*
+ *   RETURNS    0     FOR INTERLACED       50 Hz
+ *              1     FOR NON-INTERLACED   50 Hz
+ *              2     FOR INTERLACED       60 Hz
+ *              3     FOR NON-INTERLACED   60 Hz
+*/
+/*--------------------------------------------------------------------------*/
+       if (!p)
+               return -ENODEV;
+       j = 0;
+       while (max > j) {
+               rc = read_saa(p, 0x1F);
+               if (0 <= rc) {
+                       if (0 == (0x40 & rc))
+                               break;
+                       if (1 == (0x01 & rc))
+                               break;
+               }
+               msleep(marktime);
+               j++;
+       }
+       if (max == j)
+               return -1;
+       else {
+               if (0x20 & rc) {
+                       rate = 2;
+                       JOT(8, "hardware detects 60 Hz\n");
+               } else {
+                       rate = 0;
+                       JOT(8, "hardware detects 50 Hz\n");
+               }
+               if (0x80 & rc)
+                       JOT(8, "hardware detects interlacing\n");
+               else {
+                       rate++;
+                       JOT(8, "hardware detects no interlacing\n");
+               }
+       }
+       return 0;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  NOTE: THE FOLLOWING ARE NOT CHECKED:
+ *  REGISTERS 0x000, 0x002:  FUNCTIONALITY IS NOT KNOWN
+ *  REGISTER  0x100:  ACCEPT ALSO (0x80 | stk1160config....[.].set)
+ */
+/*--------------------------------------------------------------------------*/
+int check_stk(struct usb_device *p, bool ntsc)
+{
+       int i, ir;
+       const struct stk1160config *cfg;
+
+       if (!p)
+               return -ENODEV;
+       cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL;
+
+       for (i = 0; 0xFFF != cfg[i].reg; i++) {
+               if (0x000 == cfg[i].reg || 0x002 == cfg[i].reg)
+                       continue;
+
+
+               ir = read_stk(p, cfg[i].reg);
+               if (0x100 == cfg[i].reg) {
+                       if ((ir != (0xFF & cfg[i].set)) &&
+                           (ir != (0x80 | (0xFF & cfg[i].set))) &&
+                           (0xFFFF != cfg[i].set)) {
+                               SAY("STK reg[0x%03X]=0x%02X expected 0x%02X\n",
+                                       cfg[i].reg, ir, cfg[i].set);
+                       }
+                       continue;
+               }
+               if ((ir != (0xFF & cfg[i].set)) && (0xFFFF != cfg[i].set))
+                       SAY("STK register 0x%03X has 0x%02X,expected 0x%02X\n",
+                               cfg[i].reg, ir, cfg[i].set);
+       }
+       return 0;
+}
+/****************************************************************************/
+int read_saa(struct usb_device *p, u16 reg0)
+{
+       u8 igot;
+
+       if (!p)
+               return -ENODEV;
+       SET(p, 0x208, reg0);
+       SET(p, 0x200, 0x20);
+       if (0 != wait_i2c(p))
+               return -1;
+       igot = 0;
+       GET(p, 0x0209, &igot);
+       return igot;
+}
+/****************************************************************************/
+int read_stk(struct usb_device *p, u32 reg0)
+{
+       u8 igot;
+
+       if (!p)
+               return -ENODEV;
+       igot = 0;
+       GET(p, reg0, &igot);
+       return igot;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *    HARDWARE    USERSPACE INPUT NUMBER   PHYSICAL INPUT   DRIVER input VALUE
+ *
+ *  CVBS+S-VIDEO           0 or 1              CVBS                 1
+ *   FOUR-CVBS             0 or 1              CVBS1                1
+ *   FOUR-CVBS                2                CVBS2                2
+ *   FOUR-CVBS                3                CVBS3                3
+ *   FOUR-CVBS                4                CVBS4                4
+ *  CVBS+S-VIDEO              5               S-VIDEO               5
+ *
+ *  WHEN 5==input THE ARGUMENT mode MUST ALSO BE SUPPLIED:
+ *
+ *     mode  7   => GAIN TO BE SET EXPLICITLY USING REGISTER 0x05 (UNTESTED)
+ *     mode  9   => USE AUTOMATIC GAIN CONTROL (DEFAULT)
+ *
+*/
+/*---------------------------------------------------------------------------*/
+int
+select_input(struct usb_device *p, int input, int mode)
+{
+       int ir;
+
+       if (!p)
+               return -ENODEV;
+       stop_100(p);
+       switch (input) {
+       case 0:
+       case 1: {
+               if (0 != write_saa(p, 0x02, 0x80))
+                       SAY("ERROR: failed to set SAA register 0x02 "
+                                               "for input %i\n", input);
+
+               SET(p, 0x0000, 0x0098);
+               SET(p, 0x0002, 0x0078);
+               break;
+       }
+       case 2: {
+               if (0 != write_saa(p, 0x02, 0x80))
+                       SAY("ERROR: failed to set SAA register 0x02 "
+                                               "for input %i\n", input);
+
+               SET(p, 0x0000, 0x0090);
+               SET(p, 0x0002, 0x0078);
+               break;
+       }
+       case 3: {
+               if (0 != write_saa(p, 0x02, 0x80))
+                       SAY("ERROR: failed to set SAA register 0x02 "
+                                       " for input %i\n", input);
+
+               SET(p, 0x0000, 0x0088);
+               SET(p, 0x0002, 0x0078);
+               break;
+       }
+       case 4: {
+               if (0 != write_saa(p, 0x02, 0x80)) {
+                       SAY("ERROR: failed to set SAA register 0x02 "
+                                               "for input %i\n", input);
+               }
+               SET(p, 0x0000, 0x0080);
+               SET(p, 0x0002, 0x0078);
+               break;
+       }
+       case 5: {
+               if (9 != mode)
+                       mode = 7;
+               switch (mode) {
+               case 7: {
+                       if (0 != write_saa(p, 0x02, 0x87))
+                               SAY("ERROR: failed to set SAA register 0x02 "
+                                               "for input %i\n", input);
+
+                       if (0 != write_saa(p, 0x05, 0xFF))
+                               SAY("ERROR: failed to set SAA register 0x05 "
+                                               "for input %i\n", input);
+
+                       break;
+               }
+               case 9: {
+                       if (0 != write_saa(p, 0x02, 0x89))
+                               SAY("ERROR: failed to set SAA register 0x02 "
+                                               "for input %i\n", input);
+
+                       if (0 != write_saa(p, 0x05, 0x00))
+                               SAY("ERROR: failed to set SAA register 0x05 "
+                                               "for input %i\n", input);
+
+                       break;
+               }
+               default:
+                       SAY("MISTAKE:  bad mode: %i\n", mode);
+                       return -1;
+               }
+
+               if (0 != write_saa(p, 0x04, 0x00))
+                       SAY("ERROR: failed to set SAA register 0x04 "
+                                       "for input %i\n", input);
+
+               if (0 != write_saa(p, 0x09, 0x80))
+                       SAY("ERROR: failed to set SAA register 0x09 "
+                                               "for input %i\n", input);
+
+               SET(p, 0x0002, 0x0093);
+               break;
+       }
+       default:
+               SAY("ERROR:  bad input: %i\n", input);
+               return -1;
+       }
+
+       ir = read_stk(p, 0x00);
+       JOT(8, "STK register 0x00 has 0x%02X\n", ir);
+       ir = read_saa(p, 0x02);
+       JOT(8, "SAA register 0x02 has 0x%02X\n", ir);
+
+       start_100(p);
+
+       return 0;
+}
+/****************************************************************************/
+int set_resolution(struct usb_device *p,
+                  u16 set0, u16 set1, u16 set2, u16 set3)
+{
+       u16 u0x0111, u0x0113, u0x0115, u0x0117;
+
+       if (!p)
+               return -ENODEV;
+       u0x0111 = ((0xFF00 & set0) >> 8);
+       u0x0113 = ((0xFF00 & set1) >> 8);
+       u0x0115 = ((0xFF00 & set2) >> 8);
+       u0x0117 = ((0xFF00 & set3) >> 8);
+
+       SET(p, 0x0110, (0x00FF & set0));
+       SET(p, 0x0111, u0x0111);
+       SET(p, 0x0112, (0x00FF & set1));
+       SET(p, 0x0113, u0x0113);
+       SET(p, 0x0114, (0x00FF & set2));
+       SET(p, 0x0115, u0x0115);
+       SET(p, 0x0116, (0x00FF & set3));
+       SET(p, 0x0117, u0x0117);
+
+       return 0;
+}
+/****************************************************************************/
+int start_100(struct usb_device *p)
+{
+       u16 get116, get117, get0;
+       u8 igot116, igot117, igot;
+
+       if (!p)
+               return -ENODEV;
+       GET(p, 0x0116, &igot116);
+       get116 = igot116;
+       GET(p, 0x0117, &igot117);
+       get117 = igot117;
+       SET(p, 0x0116, 0x0000);
+       SET(p, 0x0117, 0x0000);
+
+       GET(p, 0x0100, &igot);
+       get0 = igot;
+       SET(p, 0x0100, (0x80 | get0));
+
+       SET(p, 0x0116, get116);
+       SET(p, 0x0117, get117);
+
+       return 0;
+}
+/****************************************************************************/
+int stop_100(struct usb_device *p)
+{
+       u16 get0;
+       u8 igot;
+
+       if (!p)
+               return -ENODEV;
+       GET(p, 0x0100, &igot);
+       get0 = igot;
+       SET(p, 0x0100, (0x7F & get0));
+       return 0;
+}
+/****************************************************************************/
+/****************************************************************************/
+/*****************************************************************************/
+int wakeup_device(struct usb_device *pusb_device)
+{
+       if (!pusb_device)
+               return -ENODEV;
+       return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
+                       USB_REQ_SET_FEATURE,
+                       USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+                       USB_DEVICE_REMOTE_WAKEUP,
+                       0, NULL, 0, 50000);
+}
+/*****************************************************************************/
+int
+audio_setup(struct easycap *peasycap)
+{
+       struct usb_device *pusb_device;
+       u8 buffer[1];
+       int rc, id1, id2;
+/*---------------------------------------------------------------------------*/
+/*
+ *                                IMPORTANT:
+ *  THE MESSAGE OF TYPE (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
+ *  CAUSES MUTING IF THE VALUE 0x0100 IS SENT.
+ *  TO ENABLE AUDIO  THE VALUE 0x0200 MUST BE SENT.
+ */
+/*---------------------------------------------------------------------------*/
+       const u8 request = 0x01;
+       const u8 requesttype = USB_DIR_OUT |
+                              USB_TYPE_CLASS |
+                              USB_RECIP_INTERFACE;
+       const u16 value_unmute = 0x0200;
+       const u16 index = 0x0301;
+       const u16 length = 1;
+
+       if (!peasycap)
+               return -EFAULT;
+
+       pusb_device = peasycap->pusb_device;
+       if (!pusb_device)
+               return -ENODEV;
+
+       JOM(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n",
+                               requesttype, request,
+                               (0x00FF & value_unmute),
+                               (0xFF00 & value_unmute) >> 8,
+                               (0x00FF & index),
+                               (0xFF00 & index) >> 8,
+                               (0x00FF & length),
+                               (0xFF00 & length) >> 8);
+
+       buffer[0] = 0x01;
+
+       rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
+                               request, requesttype, value_unmute,
+                               index, &buffer[0], length, 50000);
+
+       JOT(8, "0x%02X=buffer\n", buffer[0]);
+       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 ???
+ *  REGISTER 506:  ANALOGUE AUDIO ATTENTUATOR ???
+ *                 FOR THE CVBS+S-VIDEO HARDWARE:
+ *                    SETTING VALUE TO 0x0000 GIVES QUIET SOUND.
+ *                    THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
+ *                 FOR THE FOUR-CVBS HARDWARE:
+ *                    SETTING VALUE TO 0x0000 SEEMS TO HAVE NO EFFECT.
+ *  REGISTER 507:  ANALOGUE AUDIO PREAMPLIFIER ON/OFF ???
+ *                 FOR THE CVBS-S-VIDEO HARDWARE:
+ *                    SETTING VALUE TO 0x0001 GIVES VERY LOUD, DISTORTED SOUND.
+ *                    THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
+ */
+/*--------------------------------------------------------------------------*/
+       SET(pusb_device, 0x0500, 0x0094);
+       SET(pusb_device, 0x0500, 0x008C);
+       SET(pusb_device, 0x0506, 0x0001);
+       SET(pusb_device, 0x0507, 0x0000);
+       id1 = read_vt(pusb_device, 0x007C);
+       id2 = read_vt(pusb_device, 0x007E);
+       SAM("0x%04X:0x%04X is audio vendor id\n", id1, id2);
+/*---------------------------------------------------------------------------*/
+/*
+ *  SELECT AUDIO SOURCE "LINE IN" AND SET THE AUDIO GAIN.
+*/
+/*---------------------------------------------------------------------------*/
+       if (0 != audio_gainset(pusb_device, peasycap->gain))
+               SAY("ERROR: audio_gainset() failed\n");
+       check_vt(pusb_device);
+       return 0;
+}
+/*****************************************************************************/
+int check_vt(struct usb_device *pusb_device)
+{
+       int igot;
+
+       if (!pusb_device)
+               return -ENODEV;
+       igot = read_vt(pusb_device, 0x0002);
+       if (0 > igot)
+               SAY("ERROR: failed to read VT1612A register 0x02\n");
+       if (0x8000 & igot)
+               SAY("register 0x%02X muted\n", 0x02);
+
+       igot = read_vt(pusb_device, 0x000E);
+       if (0 > igot)
+               SAY("ERROR: failed to read VT1612A register 0x0E\n");
+       if (0x8000 & igot)
+               SAY("register 0x%02X muted\n", 0x0E);
+
+       igot = read_vt(pusb_device, 0x0010);
+       if (0 > igot)
+               SAY("ERROR: failed to read VT1612A register 0x10\n");
+       if (0x8000 & igot)
+               SAY("register 0x%02X muted\n", 0x10);
+
+       igot = read_vt(pusb_device, 0x0012);
+       if (0 > igot)
+               SAY("ERROR: failed to read VT1612A register 0x12\n");
+       if (0x8000 & igot)
+               SAY("register 0x%02X muted\n", 0x12);
+
+       igot = read_vt(pusb_device, 0x0014);
+       if (0 > igot)
+               SAY("ERROR: failed to read VT1612A register 0x14\n");
+       if (0x8000 & igot)
+               SAY("register 0x%02X muted\n", 0x14);
+
+       igot = read_vt(pusb_device, 0x0016);
+       if (0 > igot)
+               SAY("ERROR: failed to read VT1612A register 0x16\n");
+       if (0x8000 & igot)
+               SAY("register 0x%02X muted\n", 0x16);
+
+       igot = read_vt(pusb_device, 0x0018);
+       if (0 > igot)
+               SAY("ERROR: failed to read VT1612A register 0x18\n");
+       if (0x8000 & igot)
+               SAY("register 0x%02X muted\n", 0x18);
+
+       igot = read_vt(pusb_device, 0x001C);
+       if (0 > igot)
+               SAY("ERROR: failed to read VT1612A register 0x1C\n");
+       if (0x8000 & igot)
+               SAY("register 0x%02X muted\n", 0x1C);
+
+       return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*  NOTE:  THIS DOES INCREASE THE VOLUME DRAMATICALLY:
+ *                      audio_gainset(pusb_device, 0x000F);
+ *
+ *       loud        dB  register 0x10      dB register 0x1C    dB total
+ *         0               -34.5                   0             -34.5
+ *        ..                ....                   .              ....
+ *        15                10.5                   0              10.5
+ *        16                12.0                   0              12.0
+ *        17                12.0                   1.5            13.5
+ *        ..                ....                  ....            ....
+ *        31                12.0                  22.5            34.5
+*/
+/*---------------------------------------------------------------------------*/
+int audio_gainset(struct usb_device *pusb_device, s8 loud)
+{
+       int igot;
+       u8 tmp;
+       u16 mute;
+
+       if (!pusb_device)
+               return -ENODEV;
+       if (0 > loud)
+               loud = 0;
+       if (31 < loud)
+               loud = 31;
+
+       write_vt(pusb_device, 0x0002, 0x8000);
+/*---------------------------------------------------------------------------*/
+       igot = read_vt(pusb_device, 0x000E);
+       if (0 > igot) {
+               SAY("ERROR: failed to read VT1612A register 0x0E\n");
+               mute = 0x0000;
+       } else
+               mute = 0x8000 & ((unsigned int)igot);
+       mute = 0;
+
+       if (16 > loud)
+               tmp = 0x01 | (0x001F & (((u8)(15 - loud)) << 1));
+       else
+               tmp = 0;
+
+       JOT(8, "0x%04X=(mute|tmp) for VT1612A register 0x0E\n", mute | tmp);
+       write_vt(pusb_device, 0x000E, (mute | tmp));
+/*---------------------------------------------------------------------------*/
+       igot = read_vt(pusb_device, 0x0010);
+       if (0 > igot) {
+               SAY("ERROR: failed to read VT1612A register 0x10\n");
+               mute = 0x0000;
+       } else
+               mute = 0x8000 & ((unsigned int)igot);
+       mute = 0;
+
+       JOT(8, "0x%04X=(mute|tmp|(tmp<<8)) for VT1612A register 0x10,...0x18\n",
+                                               mute | tmp | (tmp << 8));
+       write_vt(pusb_device, 0x0010, (mute | tmp | (tmp << 8)));
+       write_vt(pusb_device, 0x0012, (mute | tmp | (tmp << 8)));
+       write_vt(pusb_device, 0x0014, (mute | tmp | (tmp << 8)));
+       write_vt(pusb_device, 0x0016, (mute | tmp | (tmp << 8)));
+       write_vt(pusb_device, 0x0018, (mute | tmp | (tmp << 8)));
+/*---------------------------------------------------------------------------*/
+       igot = read_vt(pusb_device, 0x001C);
+       if (0 > igot) {
+               SAY("ERROR: failed to read VT1612A register 0x1C\n");
+               mute = 0x0000;
+       } else
+               mute = 0x8000 & ((unsigned int)igot);
+       mute = 0;
+
+       if (16 <= loud)
+               tmp = 0x000F & (u8)(loud - 16);
+       else
+               tmp = 0;
+
+       JOT(8, "0x%04X=(mute|tmp|(tmp<<8)) for VT1612A register 0x1C\n",
+                                               mute | tmp | (tmp << 8));
+       write_vt(pusb_device, 0x001C, (mute | tmp | (tmp << 8)));
+       write_vt(pusb_device, 0x001A, 0x0404);
+       write_vt(pusb_device, 0x0002, 0x0000);
+       return 0;
+}
+/*****************************************************************************/
+int audio_gainget(struct usb_device *pusb_device)
+{
+       int igot;
+
+       if (!pusb_device)
+               return -ENODEV;
+       igot = read_vt(pusb_device, 0x001C);
+       if (0 > igot)
+               SAY("ERROR: failed to read VT1612A register 0x1C\n");
+       return igot;
+}
+/*****************************************************************************/
diff --git a/drivers/staging/media/easycap/easycap_main.c b/drivers/staging/media/easycap/easycap_main.c
new file mode 100644 (file)
index 0000000..a45c0b5
--- /dev/null
@@ -0,0 +1,4253 @@
+/******************************************************************************
+*                                                                             *
+*  easycap_main.c                                                             *
+*                                                                             *
+*  Video driver for EasyCAP USB2.0 Video Capture Device DC60                  *
+*                                                                             *
+*                                                                             *
+******************************************************************************/
+/*
+ *
+ *  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
+ *
+*/
+/*****************************************************************************/
+
+#include "easycap.h"
+#include <linux/usb/audio.h>
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("R.M. Thomas <rmthomas@sciolus.org>");
+MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION);
+MODULE_VERSION(EASYCAP_DRIVER_VERSION);
+
+#ifdef CONFIG_EASYCAP_DEBUG
+int easycap_debug;
+module_param_named(debug, easycap_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level: 0(default),1,2,...,9");
+#endif /* CONFIG_EASYCAP_DEBUG */
+
+bool easycap_readback;
+module_param_named(readback, easycap_readback, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(readback, "read back written registers: (default false)");
+
+static int easycap_bars = 1;
+module_param_named(bars, easycap_bars, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(bars,
+       "Testcard bars on input signal failure: 0=>no, 1=>yes(default)");
+
+static int easycap_gain = 16;
+module_param_named(gain, easycap_gain, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(gain, "Audio gain: 0,...,16(default),...31");
+
+static bool easycap_ntsc;
+module_param_named(ntsc, easycap_ntsc, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ntsc, "NTSC default encoding (default PAL)");
+
+
+
+struct easycap_dongle easycapdc60_dongle[DONGLE_MANY];
+static struct mutex mutex_dongle;
+static void easycap_complete(struct urb *purb);
+static int reset(struct easycap *peasycap);
+
+const char *strerror(int err)
+{
+#define ERRNOSTR(_e) case _e: return # _e
+       switch (err) {
+       case 0: return "OK";
+       ERRNOSTR(ENOMEM);
+       ERRNOSTR(ENODEV);
+       ERRNOSTR(ENXIO);
+       ERRNOSTR(EINVAL);
+       ERRNOSTR(EAGAIN);
+       ERRNOSTR(EFBIG);
+       ERRNOSTR(EPIPE);
+       ERRNOSTR(EMSGSIZE);
+       ERRNOSTR(ENOSPC);
+       ERRNOSTR(EINPROGRESS);
+       ERRNOSTR(ENOSR);
+       ERRNOSTR(EOVERFLOW);
+       ERRNOSTR(EPROTO);
+       ERRNOSTR(EILSEQ);
+       ERRNOSTR(ETIMEDOUT);
+       ERRNOSTR(EOPNOTSUPP);
+       ERRNOSTR(EPFNOSUPPORT);
+       ERRNOSTR(EAFNOSUPPORT);
+       ERRNOSTR(EADDRINUSE);
+       ERRNOSTR(EADDRNOTAVAIL);
+       ERRNOSTR(ENOBUFS);
+       ERRNOSTR(EISCONN);
+       ERRNOSTR(ENOTCONN);
+       ERRNOSTR(ESHUTDOWN);
+       ERRNOSTR(ENOENT);
+       ERRNOSTR(ECONNRESET);
+       ERRNOSTR(ETIME);
+       ERRNOSTR(ECOMM);
+       ERRNOSTR(EREMOTEIO);
+       ERRNOSTR(EXDEV);
+       ERRNOSTR(EPERM);
+       default: return "unknown";
+       }
+
+#undef ERRNOSTR
+}
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  PARAMETERS USED WHEN REGISTERING THE VIDEO INTERFACE
+ *
+ *  NOTE: SOME KERNELS IGNORE usb_class_driver.minor_base, AS MENTIONED BY
+ *        CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGE 253.
+ *        THIS IS THE CASE FOR OpenSUSE.
+ */
+/*---------------------------------------------------------------------------*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  THIS ROUTINE DOES NOT DETECT DUPLICATE OCCURRENCES OF POINTER peasycap
+*/
+/*---------------------------------------------------------------------------*/
+int isdongle(struct easycap *peasycap)
+{
+       int k;
+       if (!peasycap)
+               return -2;
+       for (k = 0; k < DONGLE_MANY; k++) {
+               if (easycapdc60_dongle[k].peasycap == peasycap) {
+                       peasycap->isdongle = k;
+                       return k;
+               }
+       }
+       return -1;
+}
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+static int easycap_open(struct inode *inode, struct file *file)
+{
+       struct video_device *pvideo_device;
+       struct easycap *peasycap;
+       int rc;
+
+       JOT(4, "\n");
+       SAY("==========OPEN=========\n");
+
+       pvideo_device = video_devdata(file);
+       if (!pvideo_device) {
+               SAY("ERROR: pvideo_device is NULL.\n");
+               return -EFAULT;
+       }
+       peasycap = (struct easycap *)video_get_drvdata(pvideo_device);
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+       if (!peasycap->pusb_device) {
+               SAM("ERROR: peasycap->pusb_device is NULL\n");
+               return -EFAULT;
+       } else {
+               JOM(16, "peasycap->pusb_device=%p\n", peasycap->pusb_device);
+       }
+       file->private_data = peasycap;
+       rc = wakeup_device(peasycap->pusb_device);
+       if (0 == rc)
+               JOM(8, "wakeup_device() OK\n");
+       else {
+               SAM("ERROR: wakeup_device() rc = %i\n", rc);
+               if (-ENODEV == rc)
+                       SAM("ERROR: wakeup_device() returned -ENODEV\n");
+               else
+                       SAM("ERROR: wakeup_device() rc = %i\n", rc);
+               return rc;
+       }
+       peasycap->input = 0;
+       rc = reset(peasycap);
+       if (rc) {
+               SAM("ERROR: reset() rc = %i\n", rc);
+               return -EFAULT;
+       }
+       return 0;
+}
+
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  RESET THE HARDWARE TO ITS REFERENCE STATE.
+ *
+ *  THIS ROUTINE MAY BE CALLED REPEATEDLY IF easycap_complete() DETECTS
+ *  A BAD VIDEO FRAME SIZE.
+*/
+/*---------------------------------------------------------------------------*/
+static int reset(struct easycap *peasycap)
+{
+       struct easycap_standard const *peasycap_standard;
+       int fmtidx, input, rate;
+       bool ntsc, other;
+       int rc;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+       input = peasycap->input;
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  IF THE SAA7113H HAS ALREADY ACQUIRED SYNC, USE ITS HARDWARE-DETECTED
+ *  FIELD FREQUENCY TO DISTINGUISH NTSC FROM PAL.  THIS IS ESSENTIAL FOR
+ *  gstreamer AND OTHER USERSPACE PROGRAMS WHICH MAY NOT ATTEMPT TO INITIATE
+ *  A SWITCH BETWEEN PAL AND NTSC.
+ *
+ *  FUNCTION ready_saa() MAY REQUIRE A SUBSTANTIAL FRACTION OF A SECOND TO
+ *  COMPLETE, SO SHOULD NOT BE INVOKED WITHOUT GOOD REASON.
+*/
+/*---------------------------------------------------------------------------*/
+       other = false;
+       JOM(8, "peasycap->ntsc=%d\n", peasycap->ntsc);
+
+       rate = ready_saa(peasycap->pusb_device);
+       if (rate < 0) {
+               JOM(8, "not ready to capture after %i ms ...\n", PATIENCE);
+               ntsc = !peasycap->ntsc;
+               JOM(8, "... trying  %s ..\n", ntsc ? "NTSC" : "PAL");
+               rc = setup_stk(peasycap->pusb_device, ntsc);
+               if (rc) {
+                       SAM("ERROR: setup_stk() rc = %i\n", rc);
+                       return -EFAULT;
+               }
+               rc = setup_saa(peasycap->pusb_device, ntsc);
+               if (rc) {
+                       SAM("ERROR: setup_saa() rc = %i\n", rc);
+                       return -EFAULT;
+               }
+
+               rate = ready_saa(peasycap->pusb_device);
+               if (rate < 0) {
+                       JOM(8, "not ready to capture after %i ms\n", PATIENCE);
+                       JOM(8, "... saa register 0x1F has 0x%02X\n",
+                                       read_saa(peasycap->pusb_device, 0x1F));
+                       ntsc = peasycap->ntsc;
+               } else {
+                       JOM(8, "... success at second try:  %i=rate\n", rate);
+                       ntsc = (0 < (rate/2)) ? true : false ;
+                       other = true;
+               }
+       } else {
+               JOM(8, "... success at first try:  %i=rate\n", rate);
+               ntsc = (0 < rate/2) ? true : false ;
+       }
+       JOM(8, "ntsc=%d\n", ntsc);
+/*---------------------------------------------------------------------------*/
+
+       rc = setup_stk(peasycap->pusb_device, ntsc);
+       if (rc) {
+               SAM("ERROR: setup_stk() rc = %i\n", rc);
+               return -EFAULT;
+       }
+       rc = setup_saa(peasycap->pusb_device, ntsc);
+       if (rc) {
+               SAM("ERROR: setup_saa() rc = %i\n", rc);
+               return -EFAULT;
+       }
+
+       memset(peasycap->merit, 0, sizeof(peasycap->merit));
+
+       peasycap->video_eof = 0;
+       peasycap->audio_eof = 0;
+/*---------------------------------------------------------------------------*/
+/*
+ * RESTORE INPUT AND FORCE REFRESH OF STANDARD, FORMAT, ETC.
+ *
+ * WHILE THIS PROCEDURE IS IN PROGRESS, SOME IOCTL COMMANDS WILL RETURN -EBUSY.
+*/
+/*---------------------------------------------------------------------------*/
+       peasycap->input = -8192;
+       peasycap->standard_offset = -8192;
+       fmtidx = ntsc ? NTSC_M : PAL_BGHIN;
+       if (other) {
+               peasycap_standard = &easycap_standard[0];
+               while (0xFFFF != peasycap_standard->mask) {
+                       if (fmtidx == peasycap_standard->v4l2_standard.index) {
+                               peasycap->inputset[input].standard_offset =
+                                       peasycap_standard - easycap_standard;
+                               break;
+                       }
+                       peasycap_standard++;
+               }
+               if (0xFFFF == peasycap_standard->mask) {
+                       SAM("ERROR: standard not found\n");
+                       return -EINVAL;
+               }
+               JOM(8, "%i=peasycap->inputset[%i].standard_offset\n",
+                       peasycap->inputset[input].standard_offset, input);
+       }
+       peasycap->format_offset = -8192;
+       peasycap->brightness = -8192;
+       peasycap->contrast = -8192;
+       peasycap->saturation = -8192;
+       peasycap->hue = -8192;
+
+       rc = newinput(peasycap, input);
+
+       if (rc) {
+               SAM("ERROR: newinput(.,%i) rc = %i\n", rc, input);
+               return -EFAULT;
+       }
+       JOM(4, "restored input, standard and format\n");
+
+       JOM(8, "true=peasycap->ntsc %d\n", peasycap->ntsc);
+
+       if (0 > peasycap->input) {
+               SAM("MISTAKE:  %i=peasycap->input\n", peasycap->input);
+               return -ENOENT;
+       }
+       if (0 > peasycap->standard_offset) {
+               SAM("MISTAKE:  %i=peasycap->standard_offset\n",
+                               peasycap->standard_offset);
+               return -ENOENT;
+       }
+       if (0 > peasycap->format_offset) {
+               SAM("MISTAKE:  %i=peasycap->format_offset\n",
+                               peasycap->format_offset);
+               return -ENOENT;
+       }
+       if (0 > peasycap->brightness) {
+               SAM("MISTAKE:  %i=peasycap->brightness\n",
+                               peasycap->brightness);
+               return -ENOENT;
+       }
+       if (0 > peasycap->contrast) {
+               SAM("MISTAKE:  %i=peasycap->contrast\n", peasycap->contrast);
+               return -ENOENT;
+       }
+       if (0 > peasycap->saturation) {
+               SAM("MISTAKE:  %i=peasycap->saturation\n",
+                               peasycap->saturation);
+               return -ENOENT;
+       }
+       if (0 > peasycap->hue) {
+               SAM("MISTAKE:  %i=peasycap->hue\n", peasycap->hue);
+               return -ENOENT;
+       }
+       return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  IF THE REQUESTED INPUT IS THE SAME AS THE EXISTING INPUT, DO NOTHING.
+ *  OTHERWISE:
+ *      KILL URBS, CLEAR FIELD AND FRAME BUFFERS AND RESET THEIR
+ *           _read AND _fill POINTERS.
+ *      SELECT THE NEW INPUT.
+ *      ADJUST THE STANDARD, FORMAT, BRIGHTNESS, CONTRAST, SATURATION AND HUE
+ *          ON THE BASIS OF INFORMATION IN STRUCTURE easycap.inputset[input].
+ *      RESUBMIT THE URBS IF STREAMING WAS ALREADY IN PROGRESS.
+ *
+ *  NOTE:
+ *      THIS ROUTINE MAY BE CALLED FREQUENTLY BY ZONEMINDER VIA IOCTL,
+ *      SO IT SHOULD WRITE ONLY SPARINGLY TO THE LOGFILE.
+*/
+/*---------------------------------------------------------------------------*/
+int
+newinput(struct easycap *peasycap, int input)
+{
+       int rc, k, m, mood, off;
+       int inputnow, video_idlenow, audio_idlenow;
+       bool resubmit;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+       JOM(8, "%i=input sought\n", input);
+
+       if (0 > input && INPUT_MANY <= input)
+               return -ENOENT;
+       inputnow = peasycap->input;
+       if (input == inputnow)
+               return 0;
+/*---------------------------------------------------------------------------*/
+/*
+ *  IF STREAMING IS IN PROGRESS THE URBS ARE KILLED AT THIS
+ *  STAGE AND WILL BE RESUBMITTED PRIOR TO EXIT FROM THE ROUTINE.
+ *  IF NO STREAMING IS IN PROGRESS NO URBS WILL BE SUBMITTED BY THE
+ *  ROUTINE.
+*/
+/*---------------------------------------------------------------------------*/
+       video_idlenow = peasycap->video_idle;
+       audio_idlenow = peasycap->audio_idle;
+
+       peasycap->video_idle = 1;
+       peasycap->audio_idle = 1;
+       if (peasycap->video_isoc_streaming) {
+               resubmit = true;
+               kill_video_urbs(peasycap);
+       } else {
+               resubmit = false;
+       }
+/*---------------------------------------------------------------------------*/
+       if (!peasycap->pusb_device) {
+               SAM("ERROR: peasycap->pusb_device is NULL\n");
+               return -ENODEV;
+       }
+       rc = usb_set_interface(peasycap->pusb_device,
+                               peasycap->video_interface,
+                               peasycap->video_altsetting_off);
+       if (rc) {
+               SAM("ERROR: usb_set_interface() rc = %i\n", rc);
+               return -EFAULT;
+       }
+       rc = stop_100(peasycap->pusb_device);
+       if (rc) {
+               SAM("ERROR: stop_100() rc = %i\n", rc);
+               return -EFAULT;
+       }
+       for (k = 0; k < FIELD_BUFFER_MANY; k++) {
+               for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++)
+                       memset(peasycap->field_buffer[k][m].pgo, 0, PAGE_SIZE);
+       }
+       for (k = 0; k < FRAME_BUFFER_MANY; k++) {
+               for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++)
+                       memset(peasycap->frame_buffer[k][m].pgo, 0, PAGE_SIZE);
+       }
+       peasycap->field_page = 0;
+       peasycap->field_read = 0;
+       peasycap->field_fill = 0;
+
+       peasycap->frame_read = 0;
+       peasycap->frame_fill = 0;
+       for (k = 0; k < peasycap->input; k++) {
+               (peasycap->frame_fill)++;
+               if (peasycap->frame_buffer_many <= peasycap->frame_fill)
+                       peasycap->frame_fill = 0;
+       }
+       peasycap->input = input;
+       select_input(peasycap->pusb_device, peasycap->input, 9);
+/*---------------------------------------------------------------------------*/
+       if (input == peasycap->inputset[input].input) {
+               off = peasycap->inputset[input].standard_offset;
+               if (off != peasycap->standard_offset) {
+                       rc = adjust_standard(peasycap,
+                               easycap_standard[off].v4l2_standard.id);
+                       if (rc) {
+                               SAM("ERROR: adjust_standard() rc = %i\n", rc);
+                               return -EFAULT;
+                       }
+                       JOM(8, "%i=peasycap->standard_offset\n",
+                               peasycap->standard_offset);
+               } else {
+                       JOM(8, "%i=peasycap->standard_offset unchanged\n",
+                                               peasycap->standard_offset);
+               }
+               off = peasycap->inputset[input].format_offset;
+               if (off != peasycap->format_offset) {
+                       struct v4l2_pix_format *pix =
+                               &easycap_format[off].v4l2_format.fmt.pix;
+                       rc = adjust_format(peasycap,
+                               pix->width, pix->height,
+                               pix->pixelformat, pix->field, false);
+                       if (0 > rc) {
+                               SAM("ERROR: adjust_format() rc = %i\n", rc);
+                               return -EFAULT;
+                       }
+                       JOM(8, "%i=peasycap->format_offset\n",
+                                       peasycap->format_offset);
+               } else {
+                       JOM(8, "%i=peasycap->format_offset unchanged\n",
+                                       peasycap->format_offset);
+               }
+               mood = peasycap->inputset[input].brightness;
+               if (mood != peasycap->brightness) {
+                       rc = adjust_brightness(peasycap, mood);
+                       if (rc) {
+                               SAM("ERROR: adjust_brightness rc = %i\n", rc);
+                               return -EFAULT;
+                       }
+                       JOM(8, "%i=peasycap->brightness\n",
+                                       peasycap->brightness);
+               }
+               mood = peasycap->inputset[input].contrast;
+               if (mood != peasycap->contrast) {
+                       rc = adjust_contrast(peasycap, mood);
+                       if (rc) {
+                               SAM("ERROR: adjust_contrast rc = %i\n", rc);
+                               return -EFAULT;
+                       }
+                       JOM(8, "%i=peasycap->contrast\n", peasycap->contrast);
+               }
+               mood = peasycap->inputset[input].saturation;
+               if (mood != peasycap->saturation) {
+                       rc = adjust_saturation(peasycap, mood);
+                       if (rc) {
+                               SAM("ERROR: adjust_saturation rc = %i\n", rc);
+                               return -EFAULT;
+                       }
+                       JOM(8, "%i=peasycap->saturation\n",
+                                       peasycap->saturation);
+               }
+               mood = peasycap->inputset[input].hue;
+               if (mood != peasycap->hue) {
+                       rc = adjust_hue(peasycap, mood);
+                       if (rc) {
+                               SAM("ERROR: adjust_hue rc = %i\n", rc);
+                               return -EFAULT;
+                       }
+                       JOM(8, "%i=peasycap->hue\n", peasycap->hue);
+               }
+       } else {
+               SAM("MISTAKE: easycap.inputset[%i] unpopulated\n", input);
+               return -ENOENT;
+       }
+/*---------------------------------------------------------------------------*/
+       if (!peasycap->pusb_device) {
+               SAM("ERROR: peasycap->pusb_device is NULL\n");
+               return -ENODEV;
+       }
+       rc = usb_set_interface(peasycap->pusb_device,
+                               peasycap->video_interface,
+                               peasycap->video_altsetting_on);
+       if (rc) {
+               SAM("ERROR: usb_set_interface() rc = %i\n", rc);
+               return -EFAULT;
+       }
+       rc = start_100(peasycap->pusb_device);
+       if (rc) {
+               SAM("ERROR: start_100() rc = %i\n", rc);
+               return -EFAULT;
+       }
+       if (resubmit)
+               submit_video_urbs(peasycap);
+
+       peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1;
+       peasycap->video_idle = video_idlenow;
+       peasycap->audio_idle = audio_idlenow;
+       peasycap->video_junk = 0;
+
+       return 0;
+}
+/*****************************************************************************/
+int submit_video_urbs(struct easycap *peasycap)
+{
+       struct data_urb *pdata_urb;
+       struct urb *purb;
+       struct list_head *plist_head;
+       int j, isbad, nospc, m, rc;
+       int isbuf;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+
+       if (!peasycap->purb_video_head) {
+               SAY("ERROR: peasycap->urb_video_head uninitialized\n");
+               return -EFAULT;
+       }
+       if (!peasycap->pusb_device) {
+               SAY("ERROR: peasycap->pusb_device is NULL\n");
+               return -ENODEV;
+       }
+       if (!peasycap->video_isoc_streaming) {
+               JOM(4, "submission of all video urbs\n");
+               isbad = 0;  nospc = 0;  m = 0;
+               list_for_each(plist_head, (peasycap->purb_video_head)) {
+                       pdata_urb = list_entry(plist_head,
+                                               struct data_urb, list_head);
+                       if (pdata_urb && pdata_urb->purb) {
+                               purb = pdata_urb->purb;
+                               isbuf = pdata_urb->isbuf;
+                               purb->interval = 1;
+                               purb->dev = peasycap->pusb_device;
+                               purb->pipe =
+                                       usb_rcvisocpipe(peasycap->pusb_device,
+                                       peasycap->video_endpointnumber);
+                               purb->transfer_flags = URB_ISO_ASAP;
+                               purb->transfer_buffer =
+                                       peasycap->video_isoc_buffer[isbuf].pgo;
+                               purb->transfer_buffer_length =
+                                       peasycap->video_isoc_buffer_size;
+                               purb->complete = easycap_complete;
+                               purb->context = peasycap;
+                               purb->start_frame = 0;
+                               purb->number_of_packets =
+                                       peasycap->video_isoc_framesperdesc;
+
+                               for (j = 0;  j < peasycap->video_isoc_framesperdesc; j++) {
+                                       purb->iso_frame_desc[j]. offset =
+                                               j * peasycap->video_isoc_maxframesize;
+                                       purb->iso_frame_desc[j]. length =
+                                               peasycap->video_isoc_maxframesize;
+                               }
+
+                               rc = usb_submit_urb(purb, GFP_KERNEL);
+                               if (rc) {
+                                       isbad++;
+                                       SAM("ERROR: usb_submit_urb() failed "
+                                               "for urb with rc:-%s\n",
+                                                       strerror(rc));
+                                       if (rc == -ENOSPC)
+                                               nospc++;
+                               } else {
+                                       m++;
+                               }
+                       } else {
+                               isbad++;
+                       }
+               }
+               if (nospc) {
+                       SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
+                       SAM(".....  possibly inadequate USB bandwidth\n");
+                       peasycap->video_eof = 1;
+               }
+
+               if (isbad) {
+                       JOM(4, "attempting cleanup instead of submitting\n");
+                       list_for_each(plist_head, (peasycap->purb_video_head)) {
+                               pdata_urb = list_entry(plist_head,
+                                               struct data_urb, list_head);
+                               if (pdata_urb) {
+                                       purb = pdata_urb->purb;
+                                       if (purb)
+                                               usb_kill_urb(purb);
+                               }
+                       }
+                       peasycap->video_isoc_streaming = 0;
+               } else {
+                       peasycap->video_isoc_streaming = 1;
+                       JOM(4, "submitted %i video urbs\n", m);
+               }
+       } else {
+               JOM(4, "already streaming video urbs\n");
+       }
+       return 0;
+}
+/*****************************************************************************/
+int kill_video_urbs(struct easycap *peasycap)
+{
+       int m;
+       struct list_head *plist_head;
+       struct data_urb *pdata_urb;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+       if (!peasycap->video_isoc_streaming) {
+               JOM(8, "%i=video_isoc_streaming, no video urbs killed\n",
+                       peasycap->video_isoc_streaming);
+               return 0;
+       }
+       if (!peasycap->purb_video_head) {
+               SAM("ERROR: peasycap->purb_video_head is NULL\n");
+               return -EFAULT;
+       }
+
+       peasycap->video_isoc_streaming = 0;
+       JOM(4, "killing video urbs\n");
+       m = 0;
+       list_for_each(plist_head, (peasycap->purb_video_head)) {
+               pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+               if (pdata_urb && pdata_urb->purb) {
+                       usb_kill_urb(pdata_urb->purb);
+                       m++;
+               }
+       }
+       JOM(4, "%i video urbs killed\n", m);
+
+       return 0;
+}
+/****************************************************************************/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*--------------------------------------------------------------------------*/
+static int easycap_open_noinode(struct file *file)
+{
+       return easycap_open(NULL, file);
+}
+
+static int videodev_release(struct video_device *pvideo_device)
+{
+       struct easycap *peasycap;
+
+       peasycap = video_get_drvdata(pvideo_device);
+       if (!peasycap) {
+               SAY("ERROR:  peasycap is NULL\n");
+               SAY("ending unsuccessfully\n");
+               return -EFAULT;
+       }
+       if (0 != kill_video_urbs(peasycap)) {
+               SAM("ERROR: kill_video_urbs() failed\n");
+               return -EFAULT;
+       }
+       JOM(4, "ending successfully\n");
+       return 0;
+}
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect() AND IS
+ *  PROTECTED BY SEMAPHORES SET AND CLEARED BY easycap_usb_disconnect().
+ *
+ *  BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED, SO
+ *  peasycap->pusb_device IS NO LONGER VALID.
+ */
+/*---------------------------------------------------------------------------*/
+static void easycap_delete(struct kref *pkref)
+{
+       struct easycap *peasycap;
+       struct data_urb *pdata_urb;
+       struct list_head *plist_head, *plist_next;
+       int k, m, gone, kd;
+       int allocation_video_urb;
+       int allocation_video_page;
+       int allocation_video_struct;
+       int allocation_audio_urb;
+       int allocation_audio_page;
+       int allocation_audio_struct;
+       int registered_video, registered_audio;
+
+       peasycap = container_of(pkref, struct easycap, kref);
+       if (!peasycap) {
+               SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
+               return;
+       }
+       kd = isdongle(peasycap);
+/*---------------------------------------------------------------------------*/
+/*
+ *  FREE VIDEO.
+ */
+/*---------------------------------------------------------------------------*/
+       if (peasycap->purb_video_head) {
+               JOM(4, "freeing video urbs\n");
+               m = 0;
+               list_for_each(plist_head, (peasycap->purb_video_head)) {
+                       pdata_urb = list_entry(plist_head,
+                                               struct data_urb, list_head);
+                       if (!pdata_urb) {
+                               JOM(4, "ERROR: pdata_urb is NULL\n");
+                       } else {
+                               if (pdata_urb->purb) {
+                                       usb_free_urb(pdata_urb->purb);
+                                       pdata_urb->purb = NULL;
+                                       peasycap->allocation_video_urb -= 1;
+                                       m++;
+                               }
+                       }
+               }
+
+               JOM(4, "%i video urbs freed\n", m);
+/*---------------------------------------------------------------------------*/
+               JOM(4, "freeing video data_urb structures.\n");
+               m = 0;
+               list_for_each_safe(plist_head, plist_next,
+                                       peasycap->purb_video_head) {
+                       pdata_urb = list_entry(plist_head,
+                                               struct data_urb, list_head);
+                       if (pdata_urb) {
+                               peasycap->allocation_video_struct -=
+                                               sizeof(struct data_urb);
+                               kfree(pdata_urb);
+                               pdata_urb = NULL;
+                               m++;
+                       }
+               }
+               JOM(4, "%i video data_urb structures freed\n", m);
+               JOM(4, "setting peasycap->purb_video_head=NULL\n");
+               peasycap->purb_video_head = NULL;
+       }
+/*---------------------------------------------------------------------------*/
+       JOM(4, "freeing video isoc buffers.\n");
+       m = 0;
+       for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY;  k++) {
+               if (peasycap->video_isoc_buffer[k].pgo) {
+                       free_pages((unsigned long)
+                                  peasycap->video_isoc_buffer[k].pgo,
+                                       VIDEO_ISOC_ORDER);
+                       peasycap->video_isoc_buffer[k].pgo = NULL;
+                       peasycap->allocation_video_page -=
+                                               BIT(VIDEO_ISOC_ORDER);
+                       m++;
+               }
+       }
+       JOM(4, "isoc video buffers freed: %i pages\n",
+                       m * (0x01 << VIDEO_ISOC_ORDER));
+/*---------------------------------------------------------------------------*/
+       JOM(4, "freeing video field buffers.\n");
+       gone = 0;
+       for (k = 0;  k < FIELD_BUFFER_MANY;  k++) {
+               for (m = 0;  m < FIELD_BUFFER_SIZE/PAGE_SIZE;  m++) {
+                       if (peasycap->field_buffer[k][m].pgo) {
+                               free_page((unsigned long)
+                                         peasycap->field_buffer[k][m].pgo);
+                               peasycap->field_buffer[k][m].pgo = NULL;
+                               peasycap->allocation_video_page -= 1;
+                               gone++;
+                       }
+               }
+       }
+       JOM(4, "video field buffers freed: %i pages\n", gone);
+/*---------------------------------------------------------------------------*/
+       JOM(4, "freeing video frame buffers.\n");
+       gone = 0;
+       for (k = 0;  k < FRAME_BUFFER_MANY;  k++) {
+               for (m = 0;  m < FRAME_BUFFER_SIZE/PAGE_SIZE;  m++) {
+                       if (peasycap->frame_buffer[k][m].pgo) {
+                               free_page((unsigned long)
+                                         peasycap->frame_buffer[k][m].pgo);
+                               peasycap->frame_buffer[k][m].pgo = NULL;
+                               peasycap->allocation_video_page -= 1;
+                               gone++;
+                       }
+               }
+       }
+       JOM(4, "video frame buffers freed: %i pages\n", gone);
+/*---------------------------------------------------------------------------*/
+/*
+ *  FREE AUDIO.
+ */
+/*---------------------------------------------------------------------------*/
+       if (peasycap->purb_audio_head) {
+               JOM(4, "freeing audio urbs\n");
+               m = 0;
+               list_for_each(plist_head, (peasycap->purb_audio_head)) {
+                       pdata_urb = list_entry(plist_head,
+                                       struct data_urb, list_head);
+                       if (!pdata_urb)
+                               JOM(4, "ERROR: pdata_urb is NULL\n");
+                       else {
+                               if (pdata_urb->purb) {
+                                       usb_free_urb(pdata_urb->purb);
+                                       pdata_urb->purb = NULL;
+                                       peasycap->allocation_audio_urb -= 1;
+                                       m++;
+                               }
+                       }
+               }
+               JOM(4, "%i audio urbs freed\n", m);
+/*---------------------------------------------------------------------------*/
+               JOM(4, "freeing audio data_urb structures.\n");
+               m = 0;
+               list_for_each_safe(plist_head, plist_next,
+                                       peasycap->purb_audio_head) {
+                       pdata_urb = list_entry(plist_head,
+                                       struct data_urb, list_head);
+                       if (pdata_urb) {
+                               peasycap->allocation_audio_struct -=
+                                                       sizeof(struct data_urb);
+                               kfree(pdata_urb);
+                               pdata_urb = NULL;
+                               m++;
+                       }
+               }
+               JOM(4, "%i audio data_urb structures freed\n", m);
+               JOM(4, "setting peasycap->purb_audio_head=NULL\n");
+               peasycap->purb_audio_head = NULL;
+       }
+/*---------------------------------------------------------------------------*/
+       JOM(4, "freeing audio isoc buffers.\n");
+       m = 0;
+       for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY;  k++) {
+               if (peasycap->audio_isoc_buffer[k].pgo) {
+                       free_pages((unsigned long)
+                                       (peasycap->audio_isoc_buffer[k].pgo),
+                                       AUDIO_ISOC_ORDER);
+                       peasycap->audio_isoc_buffer[k].pgo = NULL;
+                       peasycap->allocation_audio_page -=
+                                       BIT(AUDIO_ISOC_ORDER);
+                       m++;
+               }
+       }
+       JOM(4, "easyoss_delete(): isoc audio buffers freed: %i pages\n",
+                                       m * (0x01 << AUDIO_ISOC_ORDER));
+/*---------------------------------------------------------------------------*/
+       JOM(4, "freeing easycap structure.\n");
+       allocation_video_urb    = peasycap->allocation_video_urb;
+       allocation_video_page   = peasycap->allocation_video_page;
+       allocation_video_struct = peasycap->allocation_video_struct;
+       registered_video        = peasycap->registered_video;
+       allocation_audio_urb    = peasycap->allocation_audio_urb;
+       allocation_audio_page   = peasycap->allocation_audio_page;
+       allocation_audio_struct = peasycap->allocation_audio_struct;
+       registered_audio        = peasycap->registered_audio;
+
+       if (0 <= kd && DONGLE_MANY > kd) {
+               if (mutex_lock_interruptible(&mutex_dongle)) {
+                       SAY("ERROR: cannot down mutex_dongle\n");
+               } else {
+                       JOM(4, "locked mutex_dongle\n");
+                       easycapdc60_dongle[kd].peasycap = NULL;
+                       mutex_unlock(&mutex_dongle);
+                       JOM(4, "unlocked mutex_dongle\n");
+                       JOT(4, "   null-->dongle[%i].peasycap\n", kd);
+                       allocation_video_struct -= sizeof(struct easycap);
+               }
+       } else {
+               SAY("ERROR: cannot purge dongle[].peasycap");
+       }
+
+       kfree(peasycap);
+
+/*---------------------------------------------------------------------------*/
+       SAY("%8i=video urbs    after all deletions\n", allocation_video_urb);
+       SAY("%8i=video pages   after all deletions\n", allocation_video_page);
+       SAY("%8i=video structs after all deletions\n", allocation_video_struct);
+       SAY("%8i=video devices after all deletions\n", registered_video);
+       SAY("%8i=audio urbs    after all deletions\n", allocation_audio_urb);
+       SAY("%8i=audio pages   after all deletions\n", allocation_audio_page);
+       SAY("%8i=audio structs after all deletions\n", allocation_audio_struct);
+       SAY("%8i=audio devices after all deletions\n", registered_audio);
+
+       JOT(4, "ending.\n");
+       return;
+}
+/*****************************************************************************/
+static unsigned int easycap_poll(struct file *file, poll_table *wait)
+{
+       struct easycap *peasycap;
+       int rc, kd;
+
+       JOT(8, "\n");
+
+       if (NULL == ((poll_table *)wait))
+               JOT(8, "WARNING:  poll table pointer is NULL ... continuing\n");
+       if (!file) {
+               SAY("ERROR:  file pointer is NULL\n");
+               return -ERESTARTSYS;
+       }
+       peasycap = file->private_data;
+       if (!peasycap) {
+               SAY("ERROR:  peasycap is NULL\n");
+               return -EFAULT;
+       }
+       if (!peasycap->pusb_device) {
+               SAY("ERROR:  peasycap->pusb_device is NULL\n");
+               return -EFAULT;
+       }
+/*---------------------------------------------------------------------------*/
+       kd = isdongle(peasycap);
+       if (0 <= kd && DONGLE_MANY > kd) {
+               if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
+                       SAY("ERROR: cannot down dongle[%i].mutex_video\n", kd);
+                       return -ERESTARTSYS;
+               }
+               JOM(4, "locked dongle[%i].mutex_video\n", kd);
+       /*
+        *  MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER
+        *  peasycap, IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
+        *  IF NECESSARY, BAIL OUT.
+        */
+               if (kd != isdongle(peasycap)) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -ERESTARTSYS;
+               }
+               if (!file) {
+                       SAY("ERROR:  file is NULL\n");
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -ERESTARTSYS;
+               }
+               peasycap = file->private_data;
+               if (!peasycap) {
+                       SAY("ERROR:  peasycap is NULL\n");
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -ERESTARTSYS;
+               }
+               if (!peasycap->pusb_device) {
+                       SAM("ERROR: peasycap->pusb_device is NULL\n");
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return -ERESTARTSYS;
+               }
+       } else
+       /*
+        *  IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap
+        *  BEFORE THE ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL
+        *  HAVE FAILED.  BAIL OUT.
+       */
+               return -ERESTARTSYS;
+/*---------------------------------------------------------------------------*/
+       rc = easycap_dqbuf(peasycap, 0);
+       peasycap->polled = 1;
+       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+       if (0 == rc)
+               return POLLIN | POLLRDNORM;
+       else
+               return POLLERR;
+       }
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  IF mode IS NONZERO THIS ROUTINE RETURNS -EAGAIN RATHER THAN BLOCKING.
+ */
+/*---------------------------------------------------------------------------*/
+int easycap_dqbuf(struct easycap *peasycap, int mode)
+{
+       int input, ifield, miss, rc;
+
+
+       if (!peasycap) {
+               SAY("ERROR:  peasycap is NULL\n");
+               return -EFAULT;
+       }
+       if (!peasycap->pusb_device) {
+               SAY("ERROR:  peasycap->pusb_device is NULL\n");
+               return -EFAULT;
+       }
+       ifield = 0;
+       JOM(8, "%i=ifield\n", ifield);
+/*---------------------------------------------------------------------------*/
+/*
+ *  CHECK FOR LOST INPUT SIGNAL.
+ *
+ *  FOR THE FOUR-CVBS EasyCAP, THIS DOES NOT WORK AS EXPECTED.
+ *  IF INPUT 0 IS PRESENT AND SYNC ACQUIRED, UNPLUGGING INPUT 4 DOES NOT
+ *  RESULT IN SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE
+ *  IS FLYWHEELING ON INPUT 0.  THE UPSHOT IS:
+ *
+ *    INPUT 0   PLUGGED, INPUT 4   PLUGGED => SCREEN 0 OK,   SCREEN 4 OK
+ *    INPUT 0   PLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 OK,   SCREEN 4 BLACK
+ *    INPUT 0 UNPLUGGED, INPUT 4   PLUGGED => SCREEN 0 BARS, SCREEN 4 OK
+ *    INPUT 0 UNPLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 BARS, SCREEN 4 BARS
+*/
+/*---------------------------------------------------------------------------*/
+       input = peasycap->input;
+       if (0 <= input && INPUT_MANY > input) {
+               rc = read_saa(peasycap->pusb_device, 0x1F);
+               if (0 <= rc) {
+                       if (rc & 0x40)
+                               peasycap->lost[input] += 1;
+                       else
+                               peasycap->lost[input] -= 2;
+
+               if (0 > peasycap->lost[input])
+                       peasycap->lost[input] = 0;
+               else if ((2 * VIDEO_LOST_TOLERATE) < peasycap->lost[input])
+                       peasycap->lost[input] = (2 * VIDEO_LOST_TOLERATE);
+               }
+       }
+/*---------------------------------------------------------------------------*/
+/*
+ *  WAIT FOR FIELD ifield  (0 => TOP, 1 => BOTTOM)
+ */
+/*---------------------------------------------------------------------------*/
+       miss = 0;
+       while ((peasycap->field_read == peasycap->field_fill) ||
+              (0 != (0xFF00 & peasycap->field_buffer
+                                       [peasycap->field_read][0].kount)) ||
+             (ifield != (0x00FF & peasycap->field_buffer
+                                       [peasycap->field_read][0].kount))) {
+               if (mode)
+                       return -EAGAIN;
+
+               JOM(8, "first wait  on wq_video, %i=field_read %i=field_fill\n",
+                               peasycap->field_read, peasycap->field_fill);
+
+               if (0 != (wait_event_interruptible(peasycap->wq_video,
+                               (peasycap->video_idle || peasycap->video_eof  ||
+                               ((peasycap->field_read != peasycap->field_fill) &&
+                               (0 == (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) &&
+                               (ifield == (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))))))) {
+                       SAM("aborted by signal\n");
+                       return -EIO;
+               }
+               if (peasycap->video_idle) {
+                       JOM(8, "%i=peasycap->video_idle returning -EAGAIN\n",
+                                                       peasycap->video_idle);
+                       return -EAGAIN;
+               }
+               if (peasycap->video_eof) {
+                       JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
+                       #if defined(PERSEVERE)
+                       if (1 == peasycap->status) {
+                               JOM(8, "persevering ...\n");
+                               peasycap->video_eof = 0;
+                               peasycap->audio_eof = 0;
+                               if (0 != reset(peasycap)) {
+                                       JOM(8, " ... failed  returning -EIO\n");
+                                       peasycap->video_eof = 1;
+                                       peasycap->audio_eof = 1;
+                                       kill_video_urbs(peasycap);
+                                       return -EIO;
+                               }
+                               peasycap->status = 0;
+                               JOM(8, " ... OK  returning -EAGAIN\n");
+                               return -EAGAIN;
+                       }
+                       #endif /*PERSEVERE*/
+                       peasycap->video_eof = 1;
+                       peasycap->audio_eof = 1;
+                       kill_video_urbs(peasycap);
+                       JOM(8, "returning -EIO\n");
+                       return -EIO;
+               }
+               miss++;
+       }
+       JOM(8, "first awakening on wq_video after %i waits\n", miss);
+
+       rc = field2frame(peasycap);
+       if (rc)
+               SAM("ERROR: field2frame() rc = %i\n", rc);
+/*---------------------------------------------------------------------------*/
+/*
+ *  WAIT FOR THE OTHER FIELD
+ */
+/*---------------------------------------------------------------------------*/
+       if (ifield)
+               ifield = 0;
+       else
+               ifield = 1;
+       miss = 0;
+       while ((peasycap->field_read == peasycap->field_fill) ||
+              (0 != (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) ||
+              (ifield != (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))) {
+               if (mode)
+                       return -EAGAIN;
+
+               JOM(8, "second wait on wq_video %i=field_read  %i=field_fill\n",
+                               peasycap->field_read, peasycap->field_fill);
+               if (0 != (wait_event_interruptible(peasycap->wq_video,
+                       (peasycap->video_idle || peasycap->video_eof  ||
+                       ((peasycap->field_read != peasycap->field_fill) &&
+                        (0 == (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) &&
+                        (ifield == (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))))))) {
+                       SAM("aborted by signal\n");
+                       return -EIO;
+               }
+               if (peasycap->video_idle) {
+                       JOM(8, "%i=peasycap->video_idle returning -EAGAIN\n",
+                                                       peasycap->video_idle);
+                       return -EAGAIN;
+               }
+               if (peasycap->video_eof) {
+                       JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
+#if defined(PERSEVERE)
+                       if (1 == peasycap->status) {
+                               JOM(8, "persevering ...\n");
+                               peasycap->video_eof = 0;
+                               peasycap->audio_eof = 0;
+                               if (0 != reset(peasycap)) {
+                                       JOM(8, " ... failed returning -EIO\n");
+                                       peasycap->video_eof = 1;
+                                       peasycap->audio_eof = 1;
+                                       kill_video_urbs(peasycap);
+                                       return -EIO;
+                               }
+                               peasycap->status = 0;
+                               JOM(8, " ... OK ... returning -EAGAIN\n");
+                               return -EAGAIN;
+                       }
+#endif /*PERSEVERE*/
+                       peasycap->video_eof = 1;
+                       peasycap->audio_eof = 1;
+                       kill_video_urbs(peasycap);
+                       JOM(8, "returning -EIO\n");
+                       return -EIO;
+               }
+               miss++;
+       }
+       JOM(8, "second awakening on wq_video after %i waits\n", miss);
+
+       rc = field2frame(peasycap);
+       if (rc)
+               SAM("ERROR: field2frame() rc = %i\n", rc);
+/*---------------------------------------------------------------------------*/
+/*
+ *  WASTE THIS FRAME
+*/
+/*---------------------------------------------------------------------------*/
+       if (peasycap->skip) {
+               peasycap->skipped++;
+               if (peasycap->skip != peasycap->skipped)
+                       return peasycap->skip - peasycap->skipped;
+               else
+                       peasycap->skipped = 0;
+       }
+/*---------------------------------------------------------------------------*/
+       peasycap->frame_read = peasycap->frame_fill;
+       peasycap->queued[peasycap->frame_read] = 0;
+       peasycap->done[peasycap->frame_read]   = V4L2_BUF_FLAG_DONE;
+
+       peasycap->frame_fill++;
+       if (peasycap->frame_buffer_many <= peasycap->frame_fill)
+               peasycap->frame_fill = 0;
+
+       if (0x01 & easycap_standard[peasycap->standard_offset].mask)
+               peasycap->frame_buffer[peasycap->frame_read][0].kount =
+                                                       V4L2_FIELD_TOP;
+       else
+               peasycap->frame_buffer[peasycap->frame_read][0].kount =
+                                                       V4L2_FIELD_BOTTOM;
+
+
+       JOM(8, "setting:    %i=peasycap->frame_read\n", peasycap->frame_read);
+       JOM(8, "bumped to:  %i=peasycap->frame_fill\n", peasycap->frame_fill);
+
+       return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  BY DEFINITION, odd IS true  FOR THE FIELD OCCUPYING LINES 1,3,5,...,479
+ *                 odd IS false FOR THE FIELD OCCUPYING LINES 0,2,4,...,478
+ *
+ *  WHEN BOOLEAN PARAMETER decimatepixel IS true, ONLY THE FIELD FOR WHICH
+ *  odd==false IS TRANSFERRED TO THE FRAME BUFFER.
+ *
+ *  THE BOOLEAN PARAMETER offerfields IS true ONLY WHEN THE USER PROGRAM
+ *  CHOOSES THE OPTION V4L2_FIELD_INTERLACED.
+ */
+/*---------------------------------------------------------------------------*/
+int
+field2frame(struct easycap *peasycap)
+{
+
+       void *pex, *pad;
+       int kex, kad, mex, mad, rex, rad, rad2;
+       int c2, c3, w2, w3, cz, wz;
+       int rc, bytesperpixel, multiplier;
+       int  much, more, over, rump, caches, input;
+       u8 mask, margin;
+       bool odd, isuy, decimatepixel, offerfields, badinput;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+
+       badinput = false;
+       input = 0x07 & peasycap->field_buffer[peasycap->field_read][0].input;
+
+       JOM(8, "=====  parity %i, input 0x%02X, field buffer %i --> "
+                                                       "frame buffer %i\n",
+                       peasycap->field_buffer[peasycap->field_read][0].kount,
+                       peasycap->field_buffer[peasycap->field_read][0].input,
+                       peasycap->field_read, peasycap->frame_fill);
+       JOM(8, "=====  %i=bytesperpixel\n", peasycap->bytesperpixel);
+       if (peasycap->offerfields)
+               JOM(8, "===== offerfields\n");
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  REJECT OR CLEAN BAD FIELDS
+ */
+/*---------------------------------------------------------------------------*/
+       if (peasycap->field_read == peasycap->field_fill) {
+               SAM("ERROR: on entry, still filling field buffer %i\n",
+                                               peasycap->field_read);
+               return 0;
+       }
+#ifdef EASYCAP_TESTCARD
+       easycap_testcard(peasycap, peasycap->field_read);
+#else
+       if (0 <= input && INPUT_MANY > input) {
+               if (easycap_bars && VIDEO_LOST_TOLERATE <= peasycap->lost[input])
+                       easycap_testcard(peasycap, peasycap->field_read);
+       }
+#endif /*EASYCAP_TESTCARD*/
+/*---------------------------------------------------------------------------*/
+
+       offerfields = peasycap->offerfields;
+       bytesperpixel = peasycap->bytesperpixel;
+       decimatepixel = peasycap->decimatepixel;
+
+       if ((2 != bytesperpixel) &&
+           (3 != bytesperpixel) &&
+           (4 != bytesperpixel)) {
+               SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
+               return -EFAULT;
+       }
+       if (decimatepixel)
+               multiplier = 2;
+       else
+               multiplier = 1;
+
+       w2 = 2 * multiplier * (peasycap->width);
+       w3 = bytesperpixel * multiplier * (peasycap->width);
+       wz = multiplier * (peasycap->height) *
+               multiplier * (peasycap->width);
+
+       kex = peasycap->field_read;  mex = 0;
+       kad = peasycap->frame_fill;  mad = 0;
+
+       pex = peasycap->field_buffer[kex][0].pgo;  rex = PAGE_SIZE;
+       pad = peasycap->frame_buffer[kad][0].pgo;  rad = PAGE_SIZE;
+       odd = !!(peasycap->field_buffer[kex][0].kount);
+
+       if (odd && (!decimatepixel)) {
+               JOM(8, "initial skipping %4i bytes p.%4i\n",
+                                       w3/multiplier, mad);
+               pad += (w3 / multiplier); rad -= (w3 / multiplier);
+       }
+       isuy = true;
+       mask = 0;  rump = 0;  caches = 0;
+
+       cz = 0;
+       while (cz < wz) {
+               /*
+                *  PROCESS ONE LINE OF FRAME AT FULL RESOLUTION:
+                *  READ   w2   BYTES FROM FIELD BUFFER,
+                *  WRITE  w3   BYTES TO FRAME BUFFER
+                */
+               if (!decimatepixel) {
+                       over = w2;
+                       do {
+                               much = over;  more = 0;
+                               margin = 0;  mask = 0x00;
+                               if (rex < much)
+                                       much = rex;
+                               rump = 0;
+
+                               if (much % 2) {
+                                       SAM("MISTAKE: much is odd\n");
+                                       return -EFAULT;
+                               }
+
+                               more = (bytesperpixel *
+                                               much) / 2;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+                               if (1 < bytesperpixel) {
+                                       if (rad * 2 < much * bytesperpixel) {
+                                               /*
+                                                * INJUDICIOUS ALTERATION OF
+                                                * THIS STATEMENT BLOCK WILL
+                                                * CAUSE BREAKAGE.  BEWARE.
+                                                */
+                                               rad2 = rad + bytesperpixel - 1;
+                                               much = ((((2 * rad2)/bytesperpixel)/2) * 2);
+                                               rump = ((bytesperpixel * much) / 2) - rad;
+                                               more = rad;
+                                       }
+                                       mask = (u8)rump;
+                                       margin = 0;
+                                       if (much == rex) {
+                                               mask |= 0x04;
+                                               if ((mex + 1) < FIELD_BUFFER_SIZE / PAGE_SIZE)
+                                                       margin = *((u8 *)(peasycap->field_buffer[kex][mex + 1].pgo));
+                                               else
+                                                       mask |= 0x08;
+                                       }
+                               } else {
+                                       SAM("MISTAKE: %i=bytesperpixel\n",
+                                                       bytesperpixel);
+                                       return -EFAULT;
+                               }
+                               if (rump)
+                                       caches++;
+                                       if (badinput) {
+                                               JOM(8, "ERROR: 0x%02X=->field_buffer"
+                                                       "[%i][%i].input, "
+                                                       "0x%02X=(0x08|->input)\n",
+                                                       peasycap->field_buffer
+                                                       [kex][mex].input, kex, mex,
+                                                       (0x08|peasycap->input));
+                                       }
+                               rc = redaub(peasycap, pad, pex, much, more,
+                                                               mask, margin, isuy);
+                               if (0 > rc) {
+                                       SAM("ERROR: redaub() failed\n");
+                                       return -EFAULT;
+                               }
+                               if (much % 4)
+                                       isuy = !isuy;
+
+                               over -= much;   cz += much;
+                               pex  += much;  rex -= much;
+                               if (!rex) {
+                                       mex++;
+                                       pex = peasycap->field_buffer[kex][mex].pgo;
+                                       rex = PAGE_SIZE;
+                                       if (peasycap->field_buffer[kex][mex].input != (0x08|peasycap->input))
+                                               badinput = true;
+                               }
+                               pad  += more;
+                               rad -= more;
+                               if (!rad) {
+                                       mad++;
+                                       pad = peasycap->frame_buffer[kad][mad].pgo;
+                                       rad = PAGE_SIZE;
+                                       if (rump) {
+                                               pad += rump;
+                                               rad -= rump;
+                                       }
+                               }
+                       } while (over);
+/*---------------------------------------------------------------------------*/
+/*
+ *  SKIP  w3 BYTES IN TARGET FRAME BUFFER,
+ *  UNLESS IT IS THE LAST LINE OF AN ODD FRAME
+ */
+/*---------------------------------------------------------------------------*/
+                       if (!odd || (cz != wz)) {
+                               over = w3;
+                               do {
+                                       if (!rad) {
+                                               mad++;
+                                               pad = peasycap->frame_buffer
+                                                       [kad][mad].pgo;
+                                               rad = PAGE_SIZE;
+                                       }
+                                       more = over;
+                                       if (rad < more)
+                                               more = rad;
+                                       over -= more;
+                                       pad  += more;
+                                       rad  -= more;
+                               } while (over);
+                       }
+/*---------------------------------------------------------------------------*/
+/*
+ *  PROCESS ONE LINE OF FRAME AT REDUCED RESOLUTION:
+ *  ONLY IF false==odd,
+ *  READ   w2   BYTES FROM FIELD BUFFER,
+ *  WRITE  w3 / 2  BYTES TO FRAME BUFFER
+ */
+/*---------------------------------------------------------------------------*/
+               } else if (!odd) {
+                       over = w2;
+                       do {
+                               much = over;  more = 0;  margin = 0;  mask = 0x00;
+                               if (rex < much)
+                                       much = rex;
+                               rump = 0;
+
+                               if (much % 2) {
+                                       SAM("MISTAKE: much is odd\n");
+                                       return -EFAULT;
+                               }
+
+                               more = (bytesperpixel * much) / 4;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+                               if (1 < bytesperpixel) {
+                                       if (rad * 4 < much * bytesperpixel) {
+                                               /*
+                                                * INJUDICIOUS ALTERATION OF
+                                                * THIS STATEMENT BLOCK
+                                                * WILL CAUSE BREAKAGE.
+                                                * BEWARE.
+                                                */
+                                               rad2 = rad + bytesperpixel - 1;
+                                               much = ((((2 * rad2) / bytesperpixel) / 2) * 4);
+                                               rump = ((bytesperpixel * much) / 4) - rad;
+                                               more = rad;
+                                       }
+                                       mask = (u8)rump;
+                                       margin = 0;
+                                       if (much == rex) {
+                                               mask |= 0x04;
+                                               if ((mex + 1) < FIELD_BUFFER_SIZE / PAGE_SIZE)
+                                                       margin = *((u8 *)(peasycap->field_buffer[kex][mex + 1].pgo));
+                                               else
+                                                       mask |= 0x08;
+                                       }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+                               } else {
+                                       SAM("MISTAKE: %i=bytesperpixel\n",
+                                               bytesperpixel);
+                                       return -EFAULT;
+                               }
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+                               if (rump)
+                                       caches++;
+
+                                       if (badinput) {
+                                               JOM(8, "ERROR: 0x%02X=->field_buffer"
+                                                       "[%i][%i].input, "
+                                                       "0x%02X=(0x08|->input)\n",
+                                                       peasycap->field_buffer
+                                                       [kex][mex].input, kex, mex,
+                                                       (0x08|peasycap->input));
+                                       }
+                               rc = redaub(peasycap, pad, pex, much, more,
+                                                       mask, margin, isuy);
+                               if (0 > rc) {
+                                       SAM("ERROR: redaub() failed\n");
+                                       return -EFAULT;
+                               }
+                               over -= much;   cz += much;
+                               pex  += much;  rex -= much;
+                               if (!rex) {
+                                       mex++;
+                                       pex = peasycap->field_buffer[kex][mex].pgo;
+                                       rex = PAGE_SIZE;
+                                       if (peasycap->field_buffer[kex][mex].input !=
+                                                       (0x08|peasycap->input))
+                                               badinput = true;
+                               }
+                               pad  += more;
+                               rad -= more;
+                               if (!rad) {
+                                       mad++;
+                                       pad = peasycap->frame_buffer[kad][mad].pgo;
+                                       rad = PAGE_SIZE;
+                                       if (rump) {
+                                               pad += rump;
+                                               rad -= rump;
+                                       }
+                               }
+                       } while (over);
+/*---------------------------------------------------------------------------*/
+/*
+ *  OTHERWISE JUST
+ *  READ   w2   BYTES FROM FIELD BUFFER AND DISCARD THEM
+ */
+/*---------------------------------------------------------------------------*/
+               } else {
+                       over = w2;
+                       do {
+                               if (!rex) {
+                                       mex++;
+                                       pex = peasycap->field_buffer[kex][mex].pgo;
+                                       rex = PAGE_SIZE;
+                                       if (peasycap->field_buffer[kex][mex].input !=
+                                                       (0x08|peasycap->input)) {
+                                               JOM(8, "ERROR: 0x%02X=->field_buffer"
+                                                       "[%i][%i].input, "
+                                                       "0x%02X=(0x08|->input)\n",
+                                                       peasycap->field_buffer
+                                                       [kex][mex].input, kex, mex,
+                                                       (0x08|peasycap->input));
+                                               badinput = true;
+                                       }
+                               }
+                               much = over;
+                               if (rex < much)
+                                       much = rex;
+                               over -= much;
+                               cz += much;
+                               pex  += much;
+                               rex -= much;
+                       } while (over);
+               }
+       }
+/*---------------------------------------------------------------------------*/
+/*
+ *  SANITY CHECKS
+ */
+/*---------------------------------------------------------------------------*/
+       c2 = (mex + 1)*PAGE_SIZE - rex;
+       if (cz != c2)
+               SAM("ERROR: discrepancy %i in bytes read\n", c2 - cz);
+       c3 = (mad + 1)*PAGE_SIZE - rad;
+
+       if (!decimatepixel) {
+               if (bytesperpixel * cz != c3)
+                       SAM("ERROR: discrepancy %i in bytes written\n",
+                                       c3 - (bytesperpixel * cz));
+       } else {
+               if (!odd) {
+                       if (bytesperpixel *
+                               cz != (4 * c3))
+                               SAM("ERROR: discrepancy %i in bytes written\n",
+                                       (2*c3)-(bytesperpixel * cz));
+                       } else {
+                               if (0 != c3)
+                                       SAM("ERROR: discrepancy %i "
+                                           "in bytes written\n", c3);
+                       }
+       }
+       if (rump)
+               SAM("WORRY: undischarged cache at end of line in frame buffer\n");
+
+       JOM(8, "===== field2frame(): %i bytes --> %i bytes (incl skip)\n", c2, c3);
+       JOM(8, "===== field2frame(): %i=mad  %i=rad\n", mad, rad);
+
+       if (odd)
+               JOM(8, "+++++ field2frame():  frame buffer %i is full\n", kad);
+
+       if (peasycap->field_read == peasycap->field_fill)
+               SAM("WARNING: on exit, filling field buffer %i\n",
+                                               peasycap->field_read);
+
+       if (caches)
+               JOM(8, "%i=caches\n", caches);
+       return 0;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  DECIMATION AND COLOURSPACE CONVERSION.
+ *
+ *  THIS ROUTINE REQUIRES THAT ALL THE DATA TO BE READ RESIDES ON ONE PAGE
+ *  AND THAT ALL THE DATA TO BE WRITTEN RESIDES ON ONE (DIFFERENT) PAGE.
+ *  THE CALLING ROUTINE MUST ENSURE THAT THIS REQUIREMENT IS MET, AND MUST
+ *  ALSO ENSURE THAT much IS EVEN.
+ *
+ *  much BYTES ARE READ, AT LEAST (bytesperpixel * much)/2 BYTES ARE WRITTEN
+ *  IF THERE IS NO DECIMATION, HALF THIS AMOUNT IF THERE IS DECIMATION.
+ *
+ *  mask IS ZERO WHEN NO SPECIAL BEHAVIOUR REQUIRED. OTHERWISE IT IS SET THUS:
+ *     0x03 & mask =  number of bytes to be written to cache instead of to
+ *                    frame buffer
+ *     0x04 & mask => use argument margin to set the chrominance for last pixel
+ *     0x08 & mask => do not set the chrominance for last pixel
+ *
+ *  YUV to RGB CONVERSION IS (OR SHOULD BE) ITU-R BT 601.
+ *
+ *  THERE IS A LOT OF CODE REPETITION IN THIS ROUTINE IN ORDER TO AVOID
+ *  INEFFICIENT SWITCHING INSIDE INNER LOOPS.  REARRANGING THE LOGIC TO
+ *  REDUCE CODE LENGTH WILL GENERALLY IMPAIR RUNTIME PERFORMANCE.  BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+int
+redaub(struct easycap *peasycap, void *pad, void *pex, int much, int more,
+                                       u8 mask, u8 margin, bool isuy)
+{
+       static s32 ay[256], bu[256], rv[256], gu[256], gv[256];
+       u8 *pcache;
+       u8 r, g, b, y, u, v, c, *p2, *p3, *pz, *pr;
+       int  bytesperpixel;
+       bool byteswaporder, decimatepixel, last;
+       int j, rump;
+       s32 tmp;
+
+       if (much % 2) {
+               SAM("MISTAKE: much is odd\n");
+               return -EFAULT;
+       }
+       bytesperpixel = peasycap->bytesperpixel;
+       byteswaporder = peasycap->byteswaporder;
+       decimatepixel = peasycap->decimatepixel;
+
+/*---------------------------------------------------------------------------*/
+       if (!bu[255]) {
+               for (j = 0; j < 112; j++) {
+                       tmp = (0xFF00 & (453 * j)) >> 8;
+                       bu[j + 128] =  tmp; bu[127 - j] = -tmp;
+                       tmp = (0xFF00 & (359 * j)) >> 8;
+                       rv[j + 128] =  tmp; rv[127 - j] = -tmp;
+                       tmp = (0xFF00 & (88 * j)) >> 8;
+                       gu[j + 128] =  tmp; gu[127 - j] = -tmp;
+                       tmp = (0xFF00 & (183 * j)) >> 8;
+                       gv[j + 128] =  tmp; gv[127 - j] = -tmp;
+               }
+               for (j = 0; j < 16; j++) {
+                       bu[j] = bu[16]; rv[j] = rv[16];
+                       gu[j] = gu[16]; gv[j] = gv[16];
+               }
+               for (j = 240; j < 256; j++) {
+                       bu[j] = bu[239]; rv[j] = rv[239];
+                       gu[j] = gu[239]; gv[j] = gv[239];
+               }
+               for (j =  16; j < 236; j++)
+                       ay[j] = j;
+               for (j =   0; j <  16; j++)
+                       ay[j] = ay[16];
+               for (j = 236; j < 256; j++)
+                       ay[j] = ay[235];
+               JOM(8, "lookup tables are prepared\n");
+       }
+       pcache = peasycap->pcache;
+       if (!pcache)
+               pcache = &peasycap->cache[0];
+/*---------------------------------------------------------------------------*/
+/*
+ *  TRANSFER CONTENTS OF CACHE TO THE FRAME BUFFER
+ */
+/*---------------------------------------------------------------------------*/
+       if (!pcache) {
+               SAM("MISTAKE: pcache is NULL\n");
+               return -EFAULT;
+       }
+
+       if (pcache != &peasycap->cache[0])
+               JOM(16, "cache has %i bytes\n", (int)(pcache - &peasycap->cache[0]));
+       p2 = &peasycap->cache[0];
+       p3 = (u8 *)pad - (int)(pcache - &peasycap->cache[0]);
+       while (p2 < pcache) {
+               *p3++ = *p2;  p2++;
+       }
+       pcache = &peasycap->cache[0];
+       if (p3 != pad) {
+               SAM("MISTAKE: pointer misalignment\n");
+               return -EFAULT;
+       }
+/*---------------------------------------------------------------------------*/
+       rump = (int)(0x03 & mask);
+       u = 0; v = 0;
+       p2 = (u8 *)pex;  pz = p2 + much;  pr = p3 + more;  last = false;
+       p2++;
+
+       if (isuy)
+               u = *(p2 - 1);
+       else
+               v = *(p2 - 1);
+
+       if (rump)
+               JOM(16, "%4i=much  %4i=more  %i=rump\n", much, more, rump);
+
+/*---------------------------------------------------------------------------*/
+       switch (bytesperpixel) {
+       case 2: {
+               if (!decimatepixel) {
+                       memcpy(pad, pex, (size_t)much);
+                       if (!byteswaporder) {
+                               /* UYVY */
+                               return 0;
+                       } else {
+                               /* YUYV */
+                               p3 = (u8 *)pad;  pz = p3 + much;
+                               while  (pz > p3) {
+                                       c = *p3;
+                                       *p3 = *(p3 + 1);
+                                       *(p3 + 1) = c;
+                                       p3 += 2;
+                               }
+                               return 0;
+                       }
+               } else {
+                       if (!byteswaporder) {
+                               /*  UYVY DECIMATED */
+                               p2 = (u8 *)pex;  p3 = (u8 *)pad;  pz = p2 + much;
+                               while (pz > p2) {
+                                       *p3 = *p2;
+                                       *(p3 + 1) = *(p2 + 1);
+                                       *(p3 + 2) = *(p2 + 2);
+                                       *(p3 + 3) = *(p2 + 3);
+                                       p3 += 4;  p2 += 8;
+                               }
+                               return 0;
+                       } else {
+                               /* YUYV DECIMATED */
+                               p2 = (u8 *)pex;  p3 = (u8 *)pad;  pz = p2 + much;
+                               while (pz > p2) {
+                                       *p3 = *(p2 + 1);
+                                       *(p3 + 1) = *p2;
+                                       *(p3 + 2) = *(p2 + 3);
+                                       *(p3 + 3) = *(p2 + 2);
+                                       p3 += 4;  p2 += 8;
+                               }
+                               return 0;
+                       }
+               }
+               break;
+               }
+       case 3:
+               {
+               if (!decimatepixel) {
+                       if (!byteswaporder) {
+                               /* RGB */
+                               while (pz > p2) {
+                                       if (pr <= (p3 + bytesperpixel))
+                                               last = true;
+                                       else
+                                               last = false;
+                                       y = *p2;
+                                       if (last && (0x0C & mask)) {
+                                               if (0x04 & mask) {
+                                                       if (isuy)
+                                                               v = margin;
+                                                       else
+                                                               u = margin;
+                                               } else
+                                                       if (0x08 & mask)
+                                                               ;
+                                       } else {
+                                               if (isuy)
+                                                       v = *(p2 + 1);
+                                               else
+                                                       u = *(p2 + 1);
+                                       }
+
+                                       tmp = ay[(int)y] + rv[(int)v];
+                                       r = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                               0 : (u8)tmp);
+                                       tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
+                                       g = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                               0 : (u8)tmp);
+                                       tmp = ay[(int)y] + bu[(int)u];
+                                       b = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                               0 : (u8)tmp);
+
+                                       if (last && rump) {
+                                               pcache = &peasycap->cache[0];
+                                               switch (bytesperpixel - rump) {
+                                               case 1: {
+                                                       *p3 = r;
+                                                       *pcache++ = g;
+                                                       *pcache++ = b;
+                                                       break;
+                                               }
+                                               case 2: {
+                                                       *p3 = r;
+                                                       *(p3 + 1) = g;
+                                                       *pcache++ = b;
+                                                       break;
+                                               }
+                                               default: {
+                                                       SAM("MISTAKE: %i=rump\n",
+                                                               bytesperpixel - rump);
+                                                       return -EFAULT;
+                                               }
+                                               }
+                                       } else {
+                                               *p3 = r;
+                                               *(p3 + 1) = g;
+                                               *(p3 + 2) = b;
+                                       }
+                                       p2 += 2;
+                                       if (isuy)
+                                               isuy = false;
+                                       else
+                                               isuy = true;
+                                       p3 += bytesperpixel;
+                               }
+                               return 0;
+                       } else {
+                               /* BGR */
+                               while (pz > p2) {
+                                       if (pr <= (p3 + bytesperpixel))
+                                               last = true;
+                                       else
+                                               last = false;
+                                       y = *p2;
+                                       if (last && (0x0C & mask)) {
+                                               if (0x04 & mask) {
+                                                       if (isuy)
+                                                               v = margin;
+                                                       else
+                                                               u = margin;
+                                               }
+                                       else
+                                               if (0x08 & mask)
+                                                       ;
+                                       } else {
+                                               if (isuy)
+                                                       v = *(p2 + 1);
+                                               else
+                                                       u = *(p2 + 1);
+                                       }
+
+                                       tmp = ay[(int)y] + rv[(int)v];
+                                       r = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+                                       tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
+                                       g = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+                                       tmp = ay[(int)y] + bu[(int)u];
+                                       b = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+
+                                       if (last && rump) {
+                                               pcache = &peasycap->cache[0];
+                                               switch (bytesperpixel - rump) {
+                                               case 1: {
+                                                       *p3 = b;
+                                                       *pcache++ = g;
+                                                       *pcache++ = r;
+                                                       break;
+                                               }
+                                               case 2: {
+                                                       *p3 = b;
+                                                       *(p3 + 1) = g;
+                                                       *pcache++ = r;
+                                                       break;
+                                               }
+                                               default: {
+                                                       SAM("MISTAKE: %i=rump\n",
+                                                               bytesperpixel - rump);
+                                                       return -EFAULT;
+                                               }
+                                               }
+                                       } else {
+                                               *p3 = b;
+                                               *(p3 + 1) = g;
+                                               *(p3 + 2) = r;
+                                               }
+                                       p2 += 2;
+                                       if (isuy)
+                                               isuy = false;
+                                       else
+                                               isuy = true;
+                                       p3 += bytesperpixel;
+                                       }
+                               }
+                       return 0;
+               } else {
+                       if (!byteswaporder) {
+                               /*  RGB DECIMATED */
+                               while (pz > p2) {
+                                       if (pr <= (p3 + bytesperpixel))
+                                               last = true;
+                                       else
+                                               last = false;
+                                       y = *p2;
+                                       if (last && (0x0C & mask)) {
+                                               if (0x04 & mask) {
+                                                       if (isuy)
+                                                               v = margin;
+                                                       else
+                                                               u = margin;
+                                               } else
+                                                       if (0x08 & mask)
+                                                               ;
+                                       } else {
+                                               if (isuy)
+                                                       v = *(p2 + 1);
+                                               else
+                                                       u = *(p2 + 1);
+                                       }
+
+                                       if (isuy) {
+                                               tmp = ay[(int)y] + rv[(int)v];
+                                               r = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+                                               tmp = ay[(int)y] - gu[(int)u] -
+                                                                       gv[(int)v];
+                                               g = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+                                               tmp = ay[(int)y] + bu[(int)u];
+                                               b = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+
+                                               if (last && rump) {
+                                                       pcache = &peasycap->cache[0];
+                                                       switch (bytesperpixel - rump) {
+                                                       case 1: {
+                                                               *p3 = r;
+                                                               *pcache++ = g;
+                                                               *pcache++ = b;
+                                                               break;
+                                                       }
+                                                       case 2: {
+                                                               *p3 = r;
+                                                               *(p3 + 1) = g;
+                                                               *pcache++ = b;
+                                                               break;
+                                                       }
+                                                       default: {
+                                                               SAM("MISTAKE: "
+                                                               "%i=rump\n",
+                                                               bytesperpixel - rump);
+                                                               return -EFAULT;
+                                                       }
+                                                       }
+                                               } else {
+                                                       *p3 = r;
+                                                       *(p3 + 1) = g;
+                                                       *(p3 + 2) = b;
+                                               }
+                                               isuy = false;
+                                               p3 += bytesperpixel;
+                                       } else {
+                                               isuy = true;
+                                       }
+                                       p2 += 2;
+                               }
+                               return 0;
+                       } else {
+                               /* BGR DECIMATED */
+                               while (pz > p2) {
+                                       if (pr <= (p3 + bytesperpixel))
+                                               last = true;
+                                       else
+                                               last = false;
+                                       y = *p2;
+                                       if (last && (0x0C & mask)) {
+                                               if (0x04 & mask) {
+                                                       if (isuy)
+                                                               v = margin;
+                                                       else
+                                                               u = margin;
+                                               } else
+                                                       if (0x08 & mask)
+                                                               ;
+                                       } else {
+                                               if (isuy)
+                                                       v = *(p2 + 1);
+                                               else
+                                                       u = *(p2 + 1);
+                                       }
+
+                                       if (isuy) {
+
+                                               tmp = ay[(int)y] + rv[(int)v];
+                                               r = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+                                               tmp = ay[(int)y] - gu[(int)u] -
+                                                                       gv[(int)v];
+                                               g = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+                                               tmp = ay[(int)y] + bu[(int)u];
+                                               b = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+
+                                               if (last && rump) {
+                                                       pcache = &peasycap->cache[0];
+                                                       switch (bytesperpixel - rump) {
+                                                       case 1: {
+                                                               *p3 = b;
+                                                               *pcache++ = g;
+                                                               *pcache++ = r;
+                                                               break;
+                                                       }
+                                                       case 2: {
+                                                               *p3 = b;
+                                                               *(p3 + 1) = g;
+                                                               *pcache++ = r;
+                                                               break;
+                                                       }
+                                                       default: {
+                                                               SAM("MISTAKE: "
+                                                               "%i=rump\n",
+                                                               bytesperpixel - rump);
+                                                               return -EFAULT;
+                                                       }
+                                                       }
+                                               } else {
+                                                       *p3 = b;
+                                                       *(p3 + 1) = g;
+                                                       *(p3 + 2) = r;
+                                                       }
+                                               isuy = false;
+                                               p3 += bytesperpixel;
+                                               }
+                                       else
+                                               isuy = true;
+                                       p2 += 2;
+                                       }
+                               return 0;
+                               }
+                       }
+               break;
+               }
+       case 4:
+               {
+               if (!decimatepixel) {
+                       if (!byteswaporder) {
+                               /* RGBA */
+                               while (pz > p2) {
+                                       if (pr <= (p3 + bytesperpixel))
+                                               last = true;
+                                       else
+                                               last = false;
+                                       y = *p2;
+                                       if (last && (0x0C & mask)) {
+                                               if (0x04 & mask) {
+                                                       if (isuy)
+                                                               v = margin;
+                                                       else
+                                                               u = margin;
+                                               } else
+                                                        if (0x08 & mask)
+                                                               ;
+                                       } else {
+                                               if (isuy)
+                                                       v = *(p2 + 1);
+                                               else
+                                                       u = *(p2 + 1);
+                                       }
+
+                                       tmp = ay[(int)y] + rv[(int)v];
+                                       r = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+                                       tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
+                                       g = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+                                       tmp = ay[(int)y] + bu[(int)u];
+                                       b = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+
+                                       if (last && rump) {
+                                               pcache = &peasycap->cache[0];
+                                               switch (bytesperpixel - rump) {
+                                               case 1: {
+                                                       *p3 = r;
+                                                       *pcache++ = g;
+                                                       *pcache++ = b;
+                                                       *pcache++ = 0;
+                                                       break;
+                                               }
+                                               case 2: {
+                                                       *p3 = r;
+                                                       *(p3 + 1) = g;
+                                                       *pcache++ = b;
+                                                       *pcache++ = 0;
+                                                       break;
+                                               }
+                                               case 3: {
+                                                       *p3 = r;
+                                                       *(p3 + 1) = g;
+                                                       *(p3 + 2) = b;
+                                                       *pcache++ = 0;
+                                                       break;
+                                               }
+                                               default: {
+                                                       SAM("MISTAKE: %i=rump\n",
+                                                               bytesperpixel - rump);
+                                                       return -EFAULT;
+                                               }
+                                               }
+                                       } else {
+                                               *p3 = r;
+                                               *(p3 + 1) = g;
+                                               *(p3 + 2) = b;
+                                               *(p3 + 3) = 0;
+                                       }
+                                       p2 += 2;
+                                       if (isuy)
+                                               isuy = false;
+                                       else
+                                               isuy = true;
+                                       p3 += bytesperpixel;
+                               }
+                               return 0;
+                       } else {
+                               /*
+                                *  BGRA
+                                */
+                               while (pz > p2) {
+                                       if (pr <= (p3 + bytesperpixel))
+                                               last = true;
+                                       else
+                                               last = false;
+                                       y = *p2;
+                                       if (last && (0x0C & mask)) {
+                                               if (0x04 & mask) {
+                                                       if (isuy)
+                                                               v = margin;
+                                                       else
+                                                               u = margin;
+                                               } else
+                                                        if (0x08 & mask)
+                                                               ;
+                                       } else {
+                                               if (isuy)
+                                                       v = *(p2 + 1);
+                                               else
+                                                       u = *(p2 + 1);
+                                       }
+
+                                       tmp = ay[(int)y] + rv[(int)v];
+                                       r = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+                                       tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
+                                       g = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+                                       tmp = ay[(int)y] + bu[(int)u];
+                                       b = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+
+                                       if (last && rump) {
+                                               pcache = &peasycap->cache[0];
+                                               switch (bytesperpixel - rump) {
+                                               case 1: {
+                                                       *p3 = b;
+                                                       *pcache++ = g;
+                                                       *pcache++ = r;
+                                                       *pcache++ = 0;
+                                                       break;
+                                               }
+                                               case 2: {
+                                                       *p3 = b;
+                                                       *(p3 + 1) = g;
+                                                       *pcache++ = r;
+                                                       *pcache++ = 0;
+                                                       break;
+                                               }
+                                               case 3: {
+                                                       *p3 = b;
+                                                       *(p3 + 1) = g;
+                                                       *(p3 + 2) = r;
+                                                       *pcache++ = 0;
+                                                       break;
+                                               }
+                                               default:
+                                                       SAM("MISTAKE: %i=rump\n",
+                                                               bytesperpixel - rump);
+                                                       return -EFAULT;
+                                               }
+                                       } else {
+                                               *p3 = b;
+                                               *(p3 + 1) = g;
+                                               *(p3 + 2) = r;
+                                               *(p3 + 3) = 0;
+                                       }
+                                       p2 += 2;
+                                       if (isuy)
+                                               isuy = false;
+                                       else
+                                               isuy = true;
+                                       p3 += bytesperpixel;
+                               }
+                       }
+                       return 0;
+               } else {
+                       if (!byteswaporder) {
+                               /*
+                                *  RGBA DECIMATED
+                                */
+                               while (pz > p2) {
+                                       if (pr <= (p3 + bytesperpixel))
+                                               last = true;
+                                       else
+                                               last = false;
+                                       y = *p2;
+                                       if (last && (0x0C & mask)) {
+                                               if (0x04 & mask) {
+                                                       if (isuy)
+                                                               v = margin;
+                                                       else
+                                                               u = margin;
+                                               } else
+                                                       if (0x08 & mask)
+                                                               ;
+                                       } else {
+                                               if (isuy)
+                                                       v = *(p2 + 1);
+                                               else
+                                                       u = *(p2 + 1);
+                                       }
+
+                                       if (isuy) {
+
+                                               tmp = ay[(int)y] + rv[(int)v];
+                                               r = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+                                               tmp = ay[(int)y] - gu[(int)u] -
+                                                                       gv[(int)v];
+                                               g = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+                                               tmp = ay[(int)y] + bu[(int)u];
+                                               b = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+
+                                               if (last && rump) {
+                                                       pcache = &peasycap->cache[0];
+                                                       switch (bytesperpixel - rump) {
+                                                       case 1: {
+                                                               *p3 = r;
+                                                               *pcache++ = g;
+                                                               *pcache++ = b;
+                                                               *pcache++ = 0;
+                                                               break;
+                                                       }
+                                                       case 2: {
+                                                               *p3 = r;
+                                                               *(p3 + 1) = g;
+                                                               *pcache++ = b;
+                                                               *pcache++ = 0;
+                                                               break;
+                                                       }
+                                                       case 3: {
+                                                               *p3 = r;
+                                                               *(p3 + 1) = g;
+                                                               *(p3 + 2) = b;
+                                                               *pcache++ = 0;
+                                                               break;
+                                                       }
+                                                       default: {
+                                                               SAM("MISTAKE: "
+                                                               "%i=rump\n",
+                                                               bytesperpixel -
+                                                               rump);
+                                                               return -EFAULT;
+                                                               }
+                                                       }
+                                               } else {
+                                                       *p3 = r;
+                                                       *(p3 + 1) = g;
+                                                       *(p3 + 2) = b;
+                                                       *(p3 + 3) = 0;
+                                                       }
+                                               isuy = false;
+                                               p3 += bytesperpixel;
+                                       } else
+                                               isuy = true;
+                                       p2 += 2;
+                               }
+                               return 0;
+                       } else {
+                               /*
+                                *  BGRA DECIMATED
+                                */
+                               while (pz > p2) {
+                                       if (pr <= (p3 + bytesperpixel))
+                                               last = true;
+                                       else
+                                               last = false;
+                                       y = *p2;
+                                       if (last && (0x0C & mask)) {
+                                               if (0x04 & mask) {
+                                                       if (isuy)
+                                                               v = margin;
+                                                       else
+                                                               u = margin;
+                                               } else
+                                                       if (0x08 & mask)
+                                                               ;
+                                       } else {
+                                               if (isuy)
+                                                       v = *(p2 + 1);
+                                               else
+                                                       u = *(p2 + 1);
+                                       }
+
+                                       if (isuy) {
+                                               tmp = ay[(int)y] + rv[(int)v];
+                                               r = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+                                               tmp = ay[(int)y] - gu[(int)u] -
+                                                                       gv[(int)v];
+                                               g = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+                                               tmp = ay[(int)y] + bu[(int)u];
+                                               b = (255 < tmp) ? 255 : ((0 > tmp) ?
+                                                                       0 : (u8)tmp);
+
+                                               if (last && rump) {
+                                                       pcache = &peasycap->cache[0];
+                                                       switch (bytesperpixel - rump) {
+                                                       case 1: {
+                                                               *p3 = b;
+                                                               *pcache++ = g;
+                                                               *pcache++ = r;
+                                                               *pcache++ = 0;
+                                                               break;
+                                                       }
+                                                       case 2: {
+                                                               *p3 = b;
+                                                               *(p3 + 1) = g;
+                                                               *pcache++ = r;
+                                                               *pcache++ = 0;
+                                                               break;
+                                                       }
+                                                       case 3: {
+                                                               *p3 = b;
+                                                               *(p3 + 1) = g;
+                                                               *(p3 + 2) = r;
+                                                               *pcache++ = 0;
+                                                               break;
+                                                       }
+                                                       default: {
+                                                               SAM("MISTAKE: "
+                                                               "%i=rump\n",
+                                                               bytesperpixel - rump);
+                                                               return -EFAULT;
+                                                       }
+                                                       }
+                                               } else {
+                                                       *p3 = b;
+                                                       *(p3 + 1) = g;
+                                                       *(p3 + 2) = r;
+                                                       *(p3 + 3) = 0;
+                                               }
+                                               isuy = false;
+                                               p3 += bytesperpixel;
+                                       } else
+                                               isuy = true;
+                                               p2 += 2;
+                                       }
+                                       return 0;
+                               }
+                       }
+               break;
+               }
+       default: {
+               SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
+               return -EFAULT;
+               }
+       }
+       return 0;
+}
+/*****************************************************************************/
+/*
+ *  SEE CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGES 430-434
+ */
+/*****************************************************************************/
+static void easycap_vma_open(struct vm_area_struct *pvma)
+{
+       struct easycap *peasycap;
+
+       peasycap = pvma->vm_private_data;
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return;
+       }
+       peasycap->vma_many++;
+       JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
+       return;
+}
+/*****************************************************************************/
+static void easycap_vma_close(struct vm_area_struct *pvma)
+{
+       struct easycap *peasycap;
+
+       peasycap = pvma->vm_private_data;
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return;
+       }
+       peasycap->vma_many--;
+       JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
+       return;
+}
+/*****************************************************************************/
+static int easycap_vma_fault(struct vm_area_struct *pvma, struct vm_fault *pvmf)
+{
+       int k, m, retcode;
+       void *pbuf;
+       struct page *page;
+       struct easycap *peasycap;
+
+       retcode = VM_FAULT_NOPAGE;
+
+       if (!pvma) {
+               SAY("pvma is NULL\n");
+               return retcode;
+       }
+       if (!pvmf) {
+               SAY("pvmf is NULL\n");
+               return retcode;
+       }
+
+       k = (pvmf->pgoff) / (FRAME_BUFFER_SIZE/PAGE_SIZE);
+       m = (pvmf->pgoff) % (FRAME_BUFFER_SIZE/PAGE_SIZE);
+
+       if (!m)
+               JOT(4, "%4i=k, %4i=m\n", k, m);
+       else
+               JOT(16, "%4i=k, %4i=m\n", k, m);
+
+       if ((0 > k) || (FRAME_BUFFER_MANY <= k)) {
+               SAY("ERROR: buffer index %i out of range\n", k);
+               return retcode;
+       }
+       if ((0 > m) || (FRAME_BUFFER_SIZE/PAGE_SIZE <= m)) {
+               SAY("ERROR: page number  %i out of range\n", m);
+               return retcode;
+       }
+       peasycap = pvma->vm_private_data;
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return retcode;
+       }
+/*---------------------------------------------------------------------------*/
+       pbuf = peasycap->frame_buffer[k][m].pgo;
+       if (!pbuf) {
+               SAM("ERROR:  pbuf is NULL\n");
+               return retcode;
+       }
+       page = virt_to_page(pbuf);
+       if (!page) {
+               SAM("ERROR:  page is NULL\n");
+               return retcode;
+       }
+       get_page(page);
+/*---------------------------------------------------------------------------*/
+       if (!page) {
+               SAM("ERROR:  page is NULL after get_page(page)\n");
+       } else {
+               pvmf->page = page;
+               retcode = VM_FAULT_MINOR;
+       }
+       return retcode;
+}
+
+static const struct vm_operations_struct easycap_vm_ops = {
+       .open  = easycap_vma_open,
+       .close = easycap_vma_close,
+       .fault = easycap_vma_fault,
+};
+
+static int easycap_mmap(struct file *file, struct vm_area_struct *pvma)
+{
+       JOT(8, "\n");
+
+       pvma->vm_ops = &easycap_vm_ops;
+       pvma->vm_flags |= VM_RESERVED;
+       if (file)
+               pvma->vm_private_data = file->private_data;
+       easycap_vma_open(pvma);
+       return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  ON COMPLETION OF A VIDEO URB ITS DATA IS COPIED TO THE FIELD BUFFERS
+ *  PROVIDED peasycap->video_idle IS ZERO.  REGARDLESS OF THIS BEING TRUE,
+ *  IT IS RESUBMITTED PROVIDED peasycap->video_isoc_streaming IS NOT ZERO.
+ *
+ *  THIS FUNCTION IS AN INTERRUPT SERVICE ROUTINE AND MUST NOT SLEEP.
+ *
+ *  INFORMATION ABOUT THE VALIDITY OF THE CONTENTS OF THE FIELD BUFFER ARE
+ *  STORED IN THE TWO-BYTE STATUS PARAMETER
+ *        peasycap->field_buffer[peasycap->field_fill][0].kount
+ *  NOTICE THAT THE INFORMATION IS STORED ONLY WITH PAGE 0 OF THE FIELD BUFFER.
+ *
+ *  THE LOWER BYTE CONTAINS THE FIELD PARITY BYTE FURNISHED BY THE SAA7113H
+ *  CHIP.
+ *
+ *  THE UPPER BYTE IS ZERO IF NO PROBLEMS, OTHERWISE:
+ *      0 != (kount & 0x8000)   => AT LEAST ONE URB COMPLETED WITH ERRORS
+ *      0 != (kount & 0x4000)   => BUFFER HAS TOO MUCH DATA
+ *      0 != (kount & 0x2000)   => BUFFER HAS NOT ENOUGH DATA
+ *      0 != (kount & 0x1000)   => BUFFER HAS DATA FROM DISPARATE INPUTS
+ *      0 != (kount & 0x0400)   => RESERVED
+ *      0 != (kount & 0x0200)   => FIELD BUFFER NOT YET CHECKED
+ *      0 != (kount & 0x0100)   => BUFFER HAS TWO EXTRA BYTES - WHY?
+ */
+/*---------------------------------------------------------------------------*/
+static void easycap_complete(struct urb *purb)
+{
+       struct easycap *peasycap;
+       struct data_buffer *pfield_buffer;
+       char errbuf[16];
+       int i, more, much, leap, rc, last;
+       int videofieldamount;
+       unsigned int override, bad;
+       int framestatus, framelength, frameactual, frameoffset;
+       u8 *pu;
+
+       if (!purb) {
+               SAY("ERROR: easycap_complete(): purb is NULL\n");
+               return;
+       }
+       peasycap = purb->context;
+       if (!peasycap) {
+               SAY("ERROR: easycap_complete(): peasycap is NULL\n");
+               return;
+       }
+       if (peasycap->video_eof)
+               return;
+       for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++)
+               if (purb->transfer_buffer == peasycap->video_isoc_buffer[i].pgo)
+                       break;
+       JOM(16, "%2i=urb\n", i);
+       last = peasycap->video_isoc_sequence;
+       if ((((VIDEO_ISOC_BUFFER_MANY - 1) == last) && (0 != i)) ||
+            (((VIDEO_ISOC_BUFFER_MANY - 1) != last) && ((last + 1) != i))) {
+               JOM(16, "ERROR: out-of-order urbs %i,%i ... continuing\n",
+                                               last, i);
+       }
+       peasycap->video_isoc_sequence = i;
+
+       if (peasycap->video_idle) {
+               JOM(16, "%i=video_idle  %i=video_isoc_streaming\n",
+                               peasycap->video_idle, peasycap->video_isoc_streaming);
+               if (peasycap->video_isoc_streaming) {
+                       rc = usb_submit_urb(purb, GFP_ATOMIC);
+                       if (rc) {
+                               SAM("%s:%d ENOMEM\n", strerror(rc), rc);
+                               if (-ENODEV != rc)
+                                       SAM("ERROR: while %i=video_idle, "
+                                                               "usb_submit_urb() "
+                                                               "failed with rc:\n",
+                                                               peasycap->video_idle);
+                       }
+               }
+       return;
+       }
+       override = 0;
+/*---------------------------------------------------------------------------*/
+       if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
+               SAM("ERROR: bad peasycap->field_fill\n");
+               return;
+       }
+       if (purb->status) {
+               if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
+                       JOM(8, "urb status -ESHUTDOWN or -ENOENT\n");
+                       return;
+               }
+
+               (peasycap->field_buffer[peasycap->field_fill][0].kount) |= 0x8000 ;
+               SAM("ERROR: bad urb status -%s: %d\n",
+                               strerror(purb->status), purb->status);
+/*---------------------------------------------------------------------------*/
+       } else {
+               for (i = 0;  i < purb->number_of_packets; i++) {
+                       if (0 != purb->iso_frame_desc[i].status) {
+                               (peasycap->field_buffer
+                                       [peasycap->field_fill][0].kount) |= 0x8000 ;
+                               /* FIXME: 1. missing '-' check boundaries */
+                               strcpy(&errbuf[0],
+                                       strerror(purb->iso_frame_desc[i].status));
+                       }
+                       framestatus = purb->iso_frame_desc[i].status;
+                       framelength = purb->iso_frame_desc[i].length;
+                       frameactual = purb->iso_frame_desc[i].actual_length;
+                       frameoffset = purb->iso_frame_desc[i].offset;
+
+                       JOM(16, "frame[%2i]:"
+                                       "%4i=status "
+                                       "%4i=actual "
+                                       "%4i=length "
+                                       "%5i=offset\n",
+                               i, framestatus, frameactual, framelength, frameoffset);
+                       if (!purb->iso_frame_desc[i].status) {
+                               more = purb->iso_frame_desc[i].actual_length;
+                               pfield_buffer = &peasycap->field_buffer
+                                         [peasycap->field_fill][peasycap->field_page];
+                               videofieldamount = (peasycap->field_page *
+                                       PAGE_SIZE) +
+                                       (int)(pfield_buffer->pto - pfield_buffer->pgo);
+                       if (4 == more)
+                               peasycap->video_mt++;
+                       if (4 < more) {
+                               if (peasycap->video_mt) {
+                                       JOM(8, "%4i empty video urb frames\n",
+                                                               peasycap->video_mt);
+                                       peasycap->video_mt = 0;
+                               }
+                               if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
+                                       SAM("ERROR: bad peasycap->field_fill\n");
+                                       return;
+                               }
+                               if (FIELD_BUFFER_SIZE/PAGE_SIZE <=
+                                                               peasycap->field_page) {
+                                       SAM("ERROR: bad peasycap->field_page\n");
+                                       return;
+                               }
+                               pfield_buffer = &peasycap->field_buffer
+                                       [peasycap->field_fill][peasycap->field_page];
+                               pu = (u8 *)(purb->transfer_buffer +
+                                               purb->iso_frame_desc[i].offset);
+                               if (0x80 & *pu)
+                                       leap = 8;
+                               else
+                                       leap = 4;
+/*--------------------------------------------------------------------------*/
+/*
+ *  EIGHT-BYTE END-OF-VIDEOFIELD MARKER.
+ *  NOTE:  A SUCCESSION OF URB FRAMES FOLLOWING THIS ARE EMPTY,
+ *         CORRESPONDING TO THE FIELD FLYBACK (VERTICAL BLANKING) PERIOD.
+ *
+ *  PROVIDED THE FIELD BUFFER CONTAINS GOOD DATA AS INDICATED BY A ZERO UPPER
+ *  BYTE OF
+ *        peasycap->field_buffer[peasycap->field_fill][0].kount
+ *  THE CONTENTS OF THE FIELD BUFFER ARE OFFERED TO dqbuf(), field_read IS
+ *  UPDATED AND field_fill IS BUMPED.  IF THE FIELD BUFFER CONTAINS BAD DATA
+ *  NOTHING IS OFFERED TO dqbuf().
+ *
+ *  THE DECISION ON WHETHER THE PARITY OF THE OFFERED FIELD BUFFER IS RIGHT
+ *  RESTS WITH dqbuf().
+ */
+/*---------------------------------------------------------------------------*/
+                               if ((8 == more) || override) {
+                                       if (videofieldamount >
+                                                       peasycap->videofieldamount) {
+                                               if (2 == videofieldamount -
+                                                               peasycap->
+                                                               videofieldamount) {
+                                                       (peasycap->field_buffer
+                                                       [peasycap->field_fill]
+                                                               [0].kount) |= 0x0100;
+                                                       peasycap->video_junk += (1 +
+                                                               VIDEO_JUNK_TOLERATE);
+                                               } else
+                                                       (peasycap->field_buffer
+                                                       [peasycap->field_fill]
+                                                               [0].kount) |= 0x4000;
+                                               } else if (videofieldamount <
+                                                               peasycap->
+                                                               videofieldamount) {
+                                                       (peasycap->field_buffer
+                                                       [peasycap->field_fill]
+                                                               [0].kount) |= 0x2000;
+                                               }
+                                               bad = 0xFF00 & peasycap->field_buffer
+                                                       [peasycap->field_fill]
+                                                       [0].kount;
+                                               if (!bad) {
+                                                       (peasycap->video_junk)--;
+                                                       if (-VIDEO_JUNK_TOLERATE >
+                                                               peasycap->video_junk)
+                                                               peasycap->video_junk =
+                                                               -VIDEO_JUNK_TOLERATE;
+                                                       peasycap->field_read =
+                                                               (peasycap->
+                                                                       field_fill)++;
+                                                       if (FIELD_BUFFER_MANY <=
+                                                                       peasycap->
+                                                                       field_fill)
+                                                               peasycap->
+                                                                       field_fill = 0;
+                                                       peasycap->field_page = 0;
+                                                       pfield_buffer = &peasycap->
+                                                               field_buffer
+                                                               [peasycap->
+                                                               field_fill]
+                                                               [peasycap->
+                                                               field_page];
+                                                       pfield_buffer->pto =
+                                                               pfield_buffer->pgo;
+                                                       JOM(8, "bumped to: %i="
+                                                               "peasycap->"
+                                                               "field_fill  %i="
+                                                               "parity\n",
+                                                               peasycap->field_fill,
+                                                               0x00FF &
+                                                               pfield_buffer->kount);
+                                                       JOM(8, "field buffer %i has "
+                                                               "%i bytes fit to be "
+                                                               "read\n",
+                                                               peasycap->field_read,
+                                                               videofieldamount);
+                                                       JOM(8, "wakeup call to "
+                                                               "wq_video, "
+                                                               "%i=field_read "
+                                                               "%i=field_fill "
+                                                               "%i=parity\n",
+                                                               peasycap->field_read,
+                                                               peasycap->field_fill,
+                                                               0x00FF & peasycap->
+                                                               field_buffer
+                                                               [peasycap->
+                                                               field_read][0].kount);
+                                                       wake_up_interruptible
+                                                               (&(peasycap->
+                                                                        wq_video));
+                                               } else {
+                                               peasycap->video_junk++;
+                                               if (bad & 0x0010)
+                                                       peasycap->video_junk +=
+                                                       (1 + VIDEO_JUNK_TOLERATE/2);
+                                               JOM(8, "field buffer %i had %i "
+                                                       "bytes, now discarded: "
+                                                       "0x%04X\n",
+                                                       peasycap->field_fill,
+                                                       videofieldamount,
+                                                       (0xFF00 &
+                                                       peasycap->field_buffer
+                                                       [peasycap->field_fill][0].
+                                                       kount));
+                                               (peasycap->field_fill)++;
+
+                                               if (FIELD_BUFFER_MANY <=
+                                                               peasycap->field_fill)
+                                                       peasycap->field_fill = 0;
+                                               peasycap->field_page = 0;
+                                               pfield_buffer =
+                                                       &peasycap->field_buffer
+                                                       [peasycap->field_fill]
+                                                       [peasycap->field_page];
+                                               pfield_buffer->pto =
+                                                               pfield_buffer->pgo;
+
+                                               JOM(8, "bumped to: %i=peasycap->"
+                                                       "field_fill  %i=parity\n",
+                                                       peasycap->field_fill,
+                                                       0x00FF & pfield_buffer->kount);
+                                       }
+                                       if (8 == more) {
+                                               JOM(8, "end-of-field: received "
+                                                       "parity byte 0x%02X\n",
+                                                       (0xFF & *pu));
+                                               if (0x40 & *pu)
+                                                       pfield_buffer->kount = 0x0000;
+                                               else
+                                                       pfield_buffer->kount = 0x0001;
+                                               pfield_buffer->input = 0x08 |
+                                                       (0x07 & peasycap->input);
+                                               JOM(8, "end-of-field: 0x%02X=kount\n",
+                                                       0xFF & pfield_buffer->kount);
+                                       }
+                               }
+/*---------------------------------------------------------------------------*/
+/*
+ *  COPY more BYTES FROM ISOC BUFFER TO FIELD BUFFER
+ */
+/*---------------------------------------------------------------------------*/
+                               pu += leap;
+                               more -= leap;
+
+                               if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
+                                       SAM("ERROR: bad peasycap->field_fill\n");
+                                       return;
+                               }
+                               if (FIELD_BUFFER_SIZE/PAGE_SIZE <= peasycap->field_page) {
+                                       SAM("ERROR: bad peasycap->field_page\n");
+                                       return;
+                               }
+                               pfield_buffer = &peasycap->field_buffer
+                                       [peasycap->field_fill][peasycap->field_page];
+                               while (more) {
+                                       pfield_buffer = &peasycap->field_buffer
+                                                       [peasycap->field_fill]
+                                                       [peasycap->field_page];
+                                       if (PAGE_SIZE < (pfield_buffer->pto -
+                                                               pfield_buffer->pgo)) {
+                                               SAM("ERROR: bad pfield_buffer->pto\n");
+                                               return;
+                                       }
+                                       if (PAGE_SIZE == (pfield_buffer->pto -
+                                                               pfield_buffer->pgo)) {
+                                               (peasycap->field_page)++;
+                                               if (FIELD_BUFFER_SIZE/PAGE_SIZE <=
+                                                               peasycap->field_page) {
+                                                       JOM(16, "wrapping peasycap->"
+                                                               "field_page\n");
+                                                       peasycap->field_page = 0;
+                                               }
+                                               pfield_buffer = &peasycap->
+                                                               field_buffer
+                                                               [peasycap->field_fill]
+                                                               [peasycap->field_page];
+                                               pfield_buffer->pto = pfield_buffer->pgo;
+                                               pfield_buffer->input = 0x08 |
+                                                       (0x07 & peasycap->input);
+                                               if ((peasycap->field_buffer[peasycap->
+                                                               field_fill][0]).
+                                                                       input !=
+                                                               pfield_buffer->input)
+                                                       (peasycap->field_buffer
+                                                               [peasycap->field_fill]
+                                                               [0]).kount |= 0x1000;
+                                       }
+
+                                       much = PAGE_SIZE -
+                                               (int)(pfield_buffer->pto -
+                                                       pfield_buffer->pgo);
+
+                                       if (much > more)
+                                               much = more;
+                                       memcpy(pfield_buffer->pto, pu, much);
+                                       pu += much;
+                                       (pfield_buffer->pto) += much;
+                                       more -= much;
+                                       }
+                               }
+                       }
+               }
+       }
+/*---------------------------------------------------------------------------*/
+/*
+ *  RESUBMIT THIS URB, UNLESS A SEVERE PERSISTENT ERROR CONDITION EXISTS.
+ *
+ *  IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO AN ERROR CONDITION
+ *  THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT.   BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+       if (VIDEO_ISOC_BUFFER_MANY <= peasycap->video_junk) {
+               SAM("easycap driver shutting down on condition green\n");
+               peasycap->status = 1;
+               peasycap->video_eof = 1;
+               peasycap->video_junk = 0;
+               wake_up_interruptible(&peasycap->wq_video);
+#if !defined(PERSEVERE)
+               peasycap->audio_eof = 1;
+               wake_up_interruptible(&peasycap->wq_audio);
+#endif /*PERSEVERE*/
+               return;
+       }
+       if (peasycap->video_isoc_streaming) {
+               rc = usb_submit_urb(purb, GFP_ATOMIC);
+               if (rc) {
+                       SAM("%s: %d\n", strerror(rc), rc);
+                       if (-ENODEV != rc)
+                               SAM("ERROR: while %i=video_idle, "
+                                       "usb_submit_urb() "
+                                       "failed with rc:\n",
+                                       peasycap->video_idle);
+               }
+       }
+       return;
+}
+static const struct file_operations easycap_fops = {
+       .owner          = THIS_MODULE,
+       .open           = easycap_open,
+       .unlocked_ioctl = easycap_unlocked_ioctl,
+       .poll           = easycap_poll,
+       .mmap           = easycap_mmap,
+       .llseek         = no_llseek,
+};
+static const struct usb_class_driver easycap_class = {
+       .name = "usb/easycap%d",
+       .fops = &easycap_fops,
+       .minor_base = USB_SKEL_MINOR_BASE,
+};
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+static const struct v4l2_file_operations v4l2_fops = {
+       .owner          = THIS_MODULE,
+       .open           = easycap_open_noinode,
+       .unlocked_ioctl = easycap_unlocked_ioctl,
+       .poll           = easycap_poll,
+       .mmap           = easycap_mmap,
+};
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  WHEN THE EasyCAP IS PHYSICALLY PLUGGED IN, THIS FUNCTION IS CALLED THREE
+ *  TIMES, ONCE FOR EACH OF THE THREE INTERFACES.  BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+static int easycap_usb_probe(struct usb_interface *intf,
+                           const struct usb_device_id *id)
+{
+       struct usb_device *usbdev;
+       struct usb_host_interface *alt;
+       struct usb_endpoint_descriptor *ep;
+       struct usb_interface_descriptor *interface;
+       struct urb *purb;
+       struct easycap *peasycap;
+       int ndong;
+       struct data_urb *pdata_urb;
+       int i, j, k, m, rc;
+       u8 bInterfaceNumber;
+       u8 bInterfaceClass;
+       u8 bInterfaceSubClass;
+       void *pbuf;
+       int okalt[8], isokalt;
+       int okepn[8];
+       int okmps[8];
+       int maxpacketsize;
+       u16 mask;
+       s32 value;
+       struct easycap_format *peasycap_format;
+       int fmtidx;
+       struct inputset *inputset;
+
+       usbdev = interface_to_usbdev(intf);
+
+/*---------------------------------------------------------------------------*/
+       alt = usb_altnum_to_altsetting(intf, 0);
+       if (!alt) {
+               SAY("ERROR: usb_host_interface not found\n");
+               return -EFAULT;
+       }
+       interface = &alt->desc;
+       if (!interface) {
+               SAY("ERROR: intf_descriptor is NULL\n");
+               return -EFAULT;
+       }
+/*---------------------------------------------------------------------------*/
+/*
+ *  GET PROPERTIES OF PROBED INTERFACE
+ */
+/*---------------------------------------------------------------------------*/
+       bInterfaceNumber = interface->bInterfaceNumber;
+       bInterfaceClass = interface->bInterfaceClass;
+       bInterfaceSubClass = interface->bInterfaceSubClass;
+
+       JOT(4, "intf[%i]: num_altsetting=%i\n",
+                       bInterfaceNumber, intf->num_altsetting);
+       JOT(4, "intf[%i]: cur_altsetting - altsetting=%li\n",
+               bInterfaceNumber,
+               (long int)(intf->cur_altsetting - intf->altsetting));
+       JOT(4, "intf[%i]: bInterfaceClass=0x%02X bInterfaceSubClass=0x%02X\n",
+                       bInterfaceNumber, bInterfaceClass, bInterfaceSubClass);
+/*---------------------------------------------------------------------------*/
+/*
+ *  A NEW struct easycap IS ALWAYS ALLOCATED WHEN INTERFACE 0 IS PROBED.
+ *  IT IS NOT POSSIBLE HERE TO FREE ANY EXISTING struct easycap.  THIS
+ *  SHOULD HAVE BEEN DONE BY easycap_delete() WHEN THE EasyCAP WAS
+ *  PHYSICALLY UNPLUGGED.
+ *
+ *  THE POINTER peasycap TO THE struct easycap IS REMEMBERED WHEN
+ *  INTERFACES 1 AND 2 ARE PROBED.
+*/
+/*---------------------------------------------------------------------------*/
+       if (0 == bInterfaceNumber) {
+               peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
+               if (!peasycap) {
+                       SAY("ERROR: Could not allocate peasycap\n");
+                       return -ENOMEM;
+               }
+/*---------------------------------------------------------------------------*/
+/*
+ *  PERFORM URGENT INTIALIZATIONS ...
+*/
+/*---------------------------------------------------------------------------*/
+               peasycap->minor = -1;
+               kref_init(&peasycap->kref);
+               JOM(8, "intf[%i]: after kref_init(..._video) "
+                               "%i=peasycap->kref.refcount.counter\n",
+                               bInterfaceNumber, peasycap->kref.refcount.counter);
+
+               /* module params */
+               peasycap->gain = (s8)clamp(easycap_gain, 0, 31);
+
+               init_waitqueue_head(&peasycap->wq_video);
+               init_waitqueue_head(&peasycap->wq_audio);
+               init_waitqueue_head(&peasycap->wq_trigger);
+
+               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 ((!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, ndong);
+                                       break;
+                               }
+                       }
+                       if (DONGLE_MANY <= ndong) {
+                               SAM("ERROR: too many dongles\n");
+                               mutex_unlock(&mutex_dongle);
+                               return -ENOMEM;
+                       }
+                       mutex_unlock(&mutex_dongle);
+               }
+               peasycap->allocation_video_struct = sizeof(struct easycap);
+               peasycap->allocation_video_page = 0;
+               peasycap->allocation_video_urb = 0;
+               peasycap->allocation_audio_struct = 0;
+               peasycap->allocation_audio_page = 0;
+               peasycap->allocation_audio_urb = 0;
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  ... AND FURTHER INITIALIZE THE STRUCTURE
+*/
+/*---------------------------------------------------------------------------*/
+               peasycap->pusb_device = usbdev;
+               peasycap->pusb_interface = intf;
+
+               peasycap->ilk = 0;
+               peasycap->microphone = false;
+
+               peasycap->video_interface = -1;
+               peasycap->video_altsetting_on = -1;
+               peasycap->video_altsetting_off = -1;
+               peasycap->video_endpointnumber = -1;
+               peasycap->video_isoc_maxframesize = -1;
+               peasycap->video_isoc_buffer_size = -1;
+
+               peasycap->audio_interface = -1;
+               peasycap->audio_altsetting_on = -1;
+               peasycap->audio_altsetting_off = -1;
+               peasycap->audio_endpointnumber = -1;
+               peasycap->audio_isoc_maxframesize = -1;
+               peasycap->audio_isoc_buffer_size = -1;
+
+               peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
+
+               for (k = 0; k < INPUT_MANY; k++)
+                       peasycap->lost[k] = 0;
+               peasycap->skip = 0;
+               peasycap->skipped = 0;
+               peasycap->offerfields = 0;
+/*---------------------------------------------------------------------------*/
+/*
+ *  DYNAMICALLY FILL IN THE AVAILABLE FORMATS ...
+ */
+/*---------------------------------------------------------------------------*/
+               rc = fillin_formats();
+               if (0 > rc) {
+                       SAM("ERROR: fillin_formats() rc = %i\n", rc);
+                       return -EFAULT;
+               }
+               JOM(4, "%i formats available\n", rc);
+/*---------------------------------------------------------------------------*/
+/*
+ *  ... AND POPULATE easycap.inputset[]
+*/
+/*---------------------------------------------------------------------------*/
+               /* FIXME: maybe we just use memset 0 */
+               inputset = peasycap->inputset;
+               for (k = 0; k < INPUT_MANY; k++) {
+                       inputset[k].input_ok = 0;
+                       inputset[k].standard_offset_ok = 0;
+                       inputset[k].format_offset_ok = 0;
+                       inputset[k].brightness_ok = 0;
+                       inputset[k].contrast_ok = 0;
+                       inputset[k].saturation_ok = 0;
+                       inputset[k].hue_ok = 0;
+               }
+
+               fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN;
+               m = 0;
+               mask = 0;
+               for (i = 0; 0xFFFF != easycap_standard[i].mask; i++) {
+                       if (fmtidx == easycap_standard[i].v4l2_standard.index) {
+                               m++;
+                               for (k = 0; k < INPUT_MANY; k++)
+                                       inputset[k].standard_offset = i;
+
+                               mask = easycap_standard[i].mask;
+                       }
+               }
+
+               if (1 != m) {
+                       SAM("ERROR: "
+                           "inputset->standard_offset unpopulated, %i=m\n", m);
+                       return -ENOENT;
+               }
+
+               peasycap_format = &easycap_format[0];
+               m = 0;
+               for (i = 0; peasycap_format->v4l2_format.fmt.pix.width; i++) {
+                       struct v4l2_pix_format *pix =
+                               &peasycap_format->v4l2_format.fmt.pix;
+                       if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) &&
+                           pix->field == V4L2_FIELD_NONE &&
+                           pix->pixelformat == V4L2_PIX_FMT_UYVY &&
+                           pix->width  == 640 && pix->height == 480) {
+                               m++;
+                               for (k = 0; k < INPUT_MANY; k++)
+                                       inputset[k].format_offset = i;
+                               break;
+                       }
+                       peasycap_format++;
+               }
+               if (1 != m) {
+                       SAM("ERROR: inputset[]->format_offset unpopulated\n");
+                       return -ENOENT;
+               }
+
+               m = 0;
+               for (i = 0; 0xFFFFFFFF != easycap_control[i].id; i++) {
+                       value = easycap_control[i].default_value;
+                       if (V4L2_CID_BRIGHTNESS == easycap_control[i].id) {
+                               m++;
+                               for (k = 0; k < INPUT_MANY; k++)
+                                       inputset[k].brightness = value;
+                       } else if (V4L2_CID_CONTRAST == easycap_control[i].id) {
+                               m++;
+                               for (k = 0; k < INPUT_MANY; k++)
+                                       inputset[k].contrast = value;
+                       } else if (V4L2_CID_SATURATION == easycap_control[i].id) {
+                               m++;
+                               for (k = 0; k < INPUT_MANY; k++)
+                                       inputset[k].saturation = value;
+                       } else if (V4L2_CID_HUE == easycap_control[i].id) {
+                               m++;
+                               for (k = 0; k < INPUT_MANY; k++)
+                                       inputset[k].hue = value;
+                       }
+               }
+
+               if (4 != m) {
+                       SAM("ERROR: inputset[]->brightness underpopulated\n");
+                       return -ENOENT;
+               }
+               for (k = 0; k < INPUT_MANY; k++)
+                       inputset[k].input = k;
+               JOM(4, "populated inputset[]\n");
+               JOM(4, "finished initialization\n");
+       } else {
+/*---------------------------------------------------------------------------*/
+/*
+ *                                 FIXME
+ *
+ *  IDENTIFY THE APPROPRIATE POINTER peasycap FOR INTERFACES 1 AND 2.
+ *  THE ADDRESS OF peasycap->pusb_device IS RELUCTANTLY USED FOR THIS PURPOSE.
+ */
+/*---------------------------------------------------------------------------*/
+               for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
+                       if (usbdev == easycapdc60_dongle[ndong].peasycap->
+                                                                       pusb_device) {
+                               peasycap = easycapdc60_dongle[ndong].peasycap;
+                               JOT(8, "intf[%i]: dongle[%i].peasycap\n",
+                                               bInterfaceNumber, ndong);
+                               break;
+                       }
+               }
+               if (DONGLE_MANY <= ndong) {
+                       SAY("ERROR: peasycap is unknown when probing interface %i\n",
+                                                               bInterfaceNumber);
+                       return -ENODEV;
+               }
+               if (!peasycap) {
+                       SAY("ERROR: peasycap is NULL when probing interface %i\n",
+                                                               bInterfaceNumber);
+                       return -ENODEV;
+               }
+       }
+/*---------------------------------------------------------------------------*/
+       if ((USB_CLASS_VIDEO == bInterfaceClass) ||
+           (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
+               if (-1 == peasycap->video_interface) {
+                       peasycap->video_interface = bInterfaceNumber;
+                       JOM(4, "setting peasycap->video_interface=%i\n",
+                                                       peasycap->video_interface);
+               } else {
+                       if (peasycap->video_interface != bInterfaceNumber) {
+                               SAM("ERROR: attempting to reset "
+                                               "peasycap->video_interface\n");
+                               SAM("...... continuing with "
+                                               "%i=peasycap->video_interface\n",
+                                               peasycap->video_interface);
+                       }
+               }
+       } else if ((USB_CLASS_AUDIO == bInterfaceClass) &&
+                  (USB_SUBCLASS_AUDIOSTREAMING == bInterfaceSubClass)) {
+               if (-1 == peasycap->audio_interface) {
+                       peasycap->audio_interface = bInterfaceNumber;
+                       JOM(4, "setting peasycap->audio_interface=%i\n",
+                                                        peasycap->audio_interface);
+               } else {
+                       if (peasycap->audio_interface != bInterfaceNumber) {
+                               SAM("ERROR: attempting to reset "
+                                               "peasycap->audio_interface\n");
+                               SAM("...... continuing with "
+                                               "%i=peasycap->audio_interface\n",
+                                               peasycap->audio_interface);
+                       }
+               }
+       }
+/*---------------------------------------------------------------------------*/
+/*
+ *  INVESTIGATE ALL ALTSETTINGS.
+ *  DONE IN DETAIL BECAUSE USB DEVICE 05e1:0408 HAS DISPARATE INCARNATIONS.
+ */
+/*---------------------------------------------------------------------------*/
+       isokalt = 0;
+
+       for (i = 0; i < intf->num_altsetting; i++) {
+               alt = usb_altnum_to_altsetting(intf, i);
+               if (!alt) {
+                       SAM("ERROR: alt is NULL\n");
+                       return -EFAULT;
+               }
+               interface = &alt->desc;
+               if (!interface) {
+                       SAM("ERROR: intf_descriptor is NULL\n");
+                       return -EFAULT;
+               }
+
+               if (0 == interface->bNumEndpoints)
+                       JOM(4, "intf[%i]alt[%i] has no endpoints\n",
+                                               bInterfaceNumber, i);
+/*---------------------------------------------------------------------------*/
+               for (j = 0; j < interface->bNumEndpoints; j++) {
+                       ep = &alt->endpoint[j].desc;
+                       if (!ep) {
+                               SAM("ERROR:  ep is NULL.\n");
+                               SAM("...... skipping\n");
+                               continue;
+                       }
+
+                       if (!usb_endpoint_is_isoc_in(ep)) {
+                               JOM(4, "intf[%i]alt[%i]end[%i] is a %d endpoint\n",
+                                               bInterfaceNumber,
+                                               i, j, ep->bmAttributes);
+                               if (usb_endpoint_dir_out(ep)) {
+                                       SAM("ERROR: OUT endpoint unexpected\n");
+                                       SAM("...... continuing\n");
+                               }
+                               continue;
+                       }
+                       switch (bInterfaceClass) {
+                       case USB_CLASS_VIDEO:
+                       case USB_CLASS_VENDOR_SPEC: {
+                               if (ep->wMaxPacketSize) {
+                                       if (8 > isokalt) {
+                                               okalt[isokalt] = i;
+                                               JOM(4,
+                                               "%i=okalt[%i]\n",
+                                               okalt[isokalt],
+                                               isokalt);
+                                               okepn[isokalt] =
+                                               ep->
+                                               bEndpointAddress &
+                                               0x0F;
+                                               JOM(4,
+                                               "%i=okepn[%i]\n",
+                                               okepn[isokalt],
+                                               isokalt);
+                                               okmps[isokalt] =
+                                               le16_to_cpu(ep->
+                                               wMaxPacketSize);
+                                               JOM(4,
+                                               "%i=okmps[%i]\n",
+                                               okmps[isokalt],
+                                               isokalt);
+                                               isokalt++;
+                                       }
+                               } else {
+                                       if (-1 == peasycap->
+                                               video_altsetting_off) {
+                                               peasycap->
+                                               video_altsetting_off =
+                                                                i;
+                                               JOM(4, "%i=video_"
+                                               "altsetting_off "
+                                                       "<====\n",
+                                               peasycap->
+                                               video_altsetting_off);
+                                       } else {
+                                               SAM("ERROR: peasycap"
+                                               "->video_altsetting_"
+                                               "off already set\n");
+                                               SAM("...... "
+                                               "continuing with "
+                                               "%i=peasycap->video_"
+                                               "altsetting_off\n",
+                                               peasycap->
+                                               video_altsetting_off);
+                                       }
+                               }
+                               break;
+                       }
+                       case USB_CLASS_AUDIO: {
+                               if (bInterfaceSubClass !=
+                                   USB_SUBCLASS_AUDIOSTREAMING)
+                                       break;
+                               if (!peasycap) {
+                                       SAM("MISTAKE: "
+                                       "peasycap is NULL\n");
+                                       return -EFAULT;
+                               }
+                               if (ep->wMaxPacketSize) {
+                                       if (8 > isokalt) {
+                                               okalt[isokalt] = i ;
+                                               JOM(4,
+                                               "%i=okalt[%i]\n",
+                                               okalt[isokalt],
+                                               isokalt);
+                                               okepn[isokalt] =
+                                               ep->
+                                               bEndpointAddress &
+                                               0x0F;
+                                               JOM(4,
+                                               "%i=okepn[%i]\n",
+                                               okepn[isokalt],
+                                               isokalt);
+                                               okmps[isokalt] =
+                                               le16_to_cpu(ep->
+                                               wMaxPacketSize);
+                                               JOM(4,
+                                               "%i=okmps[%i]\n",
+                                               okmps[isokalt],
+                                               isokalt);
+                                               isokalt++;
+                                       }
+                               } else {
+                                       if (-1 == peasycap->
+                                               audio_altsetting_off) {
+                                               peasycap->
+                                               audio_altsetting_off =
+                                                                i;
+                                               JOM(4, "%i=audio_"
+                                               "altsetting_off "
+                                               "<====\n",
+                                               peasycap->
+                                               audio_altsetting_off);
+                                       } else {
+                                               SAM("ERROR: peasycap"
+                                               "->audio_altsetting_"
+                                               "off already set\n");
+                                               SAM("...... "
+                                               "continuing with "
+                                               "%i=peasycap->"
+                                               "audio_altsetting_"
+                                               "off\n",
+                                               peasycap->
+                                               audio_altsetting_off);
+                                       }
+                               }
+                       break;
+                       }
+                       default:
+                               break;
+                       }
+                       if (0 == ep->wMaxPacketSize) {
+                               JOM(4, "intf[%i]alt[%i]end[%i] "
+                                                       "has zero packet size\n",
+                                                       bInterfaceNumber, i, j);
+                       }
+               }
+       }
+/*---------------------------------------------------------------------------*/
+/*
+ *  PERFORM INITIALIZATION OF THE PROBED INTERFACE
+ */
+/*---------------------------------------------------------------------------*/
+       JOM(4, "initialization begins for interface %i\n",
+               interface->bInterfaceNumber);
+       switch (bInterfaceNumber) {
+/*---------------------------------------------------------------------------*/
+/*
+ *  INTERFACE 0 IS THE VIDEO INTERFACE
+ */
+/*---------------------------------------------------------------------------*/
+       case 0: {
+               if (!peasycap) {
+                       SAM("MISTAKE: peasycap is NULL\n");
+                       return -EFAULT;
+               }
+               if (!isokalt) {
+                       SAM("ERROR:  no viable video_altsetting_on\n");
+                       return -ENOENT;
+               } else {
+                       peasycap->video_altsetting_on = okalt[isokalt - 1];
+                       JOM(4, "%i=video_altsetting_on <====\n",
+                                               peasycap->video_altsetting_on);
+               }
+/*---------------------------------------------------------------------------*/
+/*
+ *  DECIDE THE VIDEO STREAMING PARAMETERS
+ */
+/*---------------------------------------------------------------------------*/
+               peasycap->video_endpointnumber = okepn[isokalt - 1];
+               JOM(4, "%i=video_endpointnumber\n", peasycap->video_endpointnumber);
+               maxpacketsize = okmps[isokalt - 1];
+
+               peasycap->video_isoc_maxframesize =
+                               min(maxpacketsize, USB_2_0_MAXPACKETSIZE);
+               if (0 >= peasycap->video_isoc_maxframesize) {
+                       SAM("ERROR:  bad video_isoc_maxframesize\n");
+                       SAM("        possibly because port is USB 1.1\n");
+                       return -ENOENT;
+               }
+               JOM(4, "%i=video_isoc_maxframesize\n",
+                                       peasycap->video_isoc_maxframesize);
+
+               peasycap->video_isoc_framesperdesc = VIDEO_ISOC_FRAMESPERDESC;
+               JOM(4, "%i=video_isoc_framesperdesc\n",
+                                       peasycap->video_isoc_framesperdesc);
+               if (0 >= peasycap->video_isoc_framesperdesc) {
+                       SAM("ERROR:  bad video_isoc_framesperdesc\n");
+                       return -ENOENT;
+               }
+               peasycap->video_isoc_buffer_size =
+                                       peasycap->video_isoc_maxframesize *
+                                       peasycap->video_isoc_framesperdesc;
+               JOM(4, "%i=video_isoc_buffer_size\n",
+                                       peasycap->video_isoc_buffer_size);
+               if ((PAGE_SIZE << VIDEO_ISOC_ORDER) <
+                                       peasycap->video_isoc_buffer_size) {
+                       SAM("MISTAKE: peasycap->video_isoc_buffer_size too big\n");
+                       return -EFAULT;
+               }
+/*---------------------------------------------------------------------------*/
+               if (-1 == peasycap->video_interface) {
+                       SAM("MISTAKE:  video_interface is unset\n");
+                       return -EFAULT;
+               }
+               if (-1 == peasycap->video_altsetting_on) {
+                       SAM("MISTAKE:  video_altsetting_on is unset\n");
+                       return -EFAULT;
+               }
+               if (-1 == peasycap->video_altsetting_off) {
+                       SAM("MISTAKE:  video_interface_off is unset\n");
+                       return -EFAULT;
+               }
+               if (-1 == peasycap->video_endpointnumber) {
+                       SAM("MISTAKE:  video_endpointnumber is unset\n");
+                       return -EFAULT;
+               }
+               if (-1 == peasycap->video_isoc_maxframesize) {
+                       SAM("MISTAKE:  video_isoc_maxframesize is unset\n");
+                       return -EFAULT;
+               }
+               if (-1 == peasycap->video_isoc_buffer_size) {
+                       SAM("MISTAKE:  video_isoc_buffer_size is unset\n");
+                       return -EFAULT;
+               }
+/*---------------------------------------------------------------------------*/
+/*
+ *  ALLOCATE MEMORY FOR VIDEO BUFFERS.  LISTS MUST BE INITIALIZED FIRST.
+ */
+/*---------------------------------------------------------------------------*/
+               INIT_LIST_HEAD(&(peasycap->urb_video_head));
+               peasycap->purb_video_head = &(peasycap->urb_video_head);
+/*---------------------------------------------------------------------------*/
+               JOM(4, "allocating %i frame buffers of size %li\n",
+                               FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
+               JOM(4, ".... each scattered over %li pages\n",
+                                                       FRAME_BUFFER_SIZE/PAGE_SIZE);
+
+               for (k = 0;  k < FRAME_BUFFER_MANY;  k++) {
+                       for (m = 0;  m < FRAME_BUFFER_SIZE/PAGE_SIZE;  m++) {
+                               if (peasycap->frame_buffer[k][m].pgo)
+                                       SAM("attempting to reallocate frame "
+                                                                       " buffers\n");
+                               else {
+                                       pbuf = (void *)__get_free_page(GFP_KERNEL);
+                                       if (!pbuf) {
+                                               SAM("ERROR: Could not allocate frame "
+                                                       "buffer %i page %i\n", k, m);
+                                               return -ENOMEM;
+                                       } else
+                                               peasycap->allocation_video_page += 1;
+                                       peasycap->frame_buffer[k][m].pgo = pbuf;
+                               }
+                               peasycap->frame_buffer[k][m].pto =
+                                               peasycap->frame_buffer[k][m].pgo;
+                       }
+               }
+
+               peasycap->frame_fill = 0;
+               peasycap->frame_read = 0;
+               JOM(4, "allocation of frame buffers done:  %i pages\n", k *
+                                                                       m);
+/*---------------------------------------------------------------------------*/
+               JOM(4, "allocating %i field buffers of size %li\n",
+                               FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
+               JOM(4, ".... each scattered over %li pages\n",
+                                               FIELD_BUFFER_SIZE/PAGE_SIZE);
+
+               for (k = 0;  k < FIELD_BUFFER_MANY;  k++) {
+                       for (m = 0;  m < FIELD_BUFFER_SIZE/PAGE_SIZE;  m++) {
+                               if (peasycap->field_buffer[k][m].pgo) {
+                                       SAM("ERROR: attempting to reallocate "
+                                                               "field buffers\n");
+                               } else {
+                                       pbuf = (void *) __get_free_page(GFP_KERNEL);
+                                       if (!pbuf) {
+                                               SAM("ERROR: Could not allocate field"
+                                                       " buffer %i page %i\n", k, m);
+                                               return -ENOMEM;
+                                               }
+                                       else
+                                               peasycap->allocation_video_page += 1;
+                                       peasycap->field_buffer[k][m].pgo = pbuf;
+                                       }
+                               peasycap->field_buffer[k][m].pto =
+                                               peasycap->field_buffer[k][m].pgo;
+                       }
+                       peasycap->field_buffer[k][0].kount = 0x0200;
+               }
+               peasycap->field_fill = 0;
+               peasycap->field_page = 0;
+               peasycap->field_read = 0;
+               JOM(4, "allocation of field buffers done:  %i pages\n", k *
+                                                                       m);
+/*---------------------------------------------------------------------------*/
+               JOM(4, "allocating %i isoc video buffers of size %i\n",
+                                               VIDEO_ISOC_BUFFER_MANY,
+                                               peasycap->video_isoc_buffer_size);
+               JOM(4, ".... each occupying contiguous memory pages\n");
+
+               for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY; k++) {
+                       pbuf = (void *)__get_free_pages(GFP_KERNEL,
+                                                       VIDEO_ISOC_ORDER);
+                       if (!pbuf) {
+                               SAM("ERROR: Could not allocate isoc video buffer "
+                                                                       "%i\n", k);
+                               return -ENOMEM;
+                       } else
+                               peasycap->allocation_video_page +=
+                                       BIT(VIDEO_ISOC_ORDER);
+
+                       peasycap->video_isoc_buffer[k].pgo = pbuf;
+                       peasycap->video_isoc_buffer[k].pto =
+                               pbuf + peasycap->video_isoc_buffer_size;
+                       peasycap->video_isoc_buffer[k].kount = k;
+               }
+               JOM(4, "allocation of isoc video buffers done: %i pages\n",
+                                               k * (0x01 << VIDEO_ISOC_ORDER));
+/*---------------------------------------------------------------------------*/
+/*
+ *  ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
+ */
+/*---------------------------------------------------------------------------*/
+               JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
+               JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n",
+                                               peasycap->video_isoc_framesperdesc);
+               JOM(4, "using %i=peasycap->video_isoc_maxframesize\n",
+                                               peasycap->video_isoc_maxframesize);
+               JOM(4, "using %i=peasycap->video_isoc_buffer_sizen",
+                                               peasycap->video_isoc_buffer_size);
+
+               for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY; k++) {
+                       purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc,
+                                                                       GFP_KERNEL);
+                       if (!purb) {
+                               SAM("ERROR: usb_alloc_urb returned NULL for buffer "
+                                                                       "%i\n", k);
+                               return -ENOMEM;
+                       } else
+                               peasycap->allocation_video_urb += 1;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+                       pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
+                       if (!pdata_urb) {
+                               SAM("ERROR: Could not allocate struct data_urb.\n");
+                               return -ENOMEM;
+                       } else
+                               peasycap->allocation_video_struct +=
+                                                       sizeof(struct data_urb);
+
+                       pdata_urb->purb = purb;
+                       pdata_urb->isbuf = k;
+                       pdata_urb->length = 0;
+                       list_add_tail(&(pdata_urb->list_head),
+                                                       peasycap->purb_video_head);
+/*---------------------------------------------------------------------------*/
+/*
+ *  ... AND INITIALIZE THEM
+ */
+/*---------------------------------------------------------------------------*/
+                       if (!k) {
+                               JOM(4, "initializing video urbs thus:\n");
+                               JOM(4, "  purb->interval = 1;\n");
+                               JOM(4, "  purb->dev = peasycap->pusb_device;\n");
+                               JOM(4, "  purb->pipe = usb_rcvisocpipe"
+                                               "(peasycap->pusb_device,%i);\n",
+                                               peasycap->video_endpointnumber);
+                               JOM(4, "  purb->transfer_flags = URB_ISO_ASAP;\n");
+                               JOM(4, "  purb->transfer_buffer = peasycap->"
+                                               "video_isoc_buffer[.].pgo;\n");
+                               JOM(4, "  purb->transfer_buffer_length = %i;\n",
+                                               peasycap->video_isoc_buffer_size);
+                               JOM(4, "  purb->complete = easycap_complete;\n");
+                               JOM(4, "  purb->context = peasycap;\n");
+                               JOM(4, "  purb->start_frame = 0;\n");
+                               JOM(4, "  purb->number_of_packets = %i;\n",
+                                               peasycap->video_isoc_framesperdesc);
+                               JOM(4, "  for (j = 0; j < %i; j++)\n",
+                                               peasycap->video_isoc_framesperdesc);
+                               JOM(4, "    {\n");
+                               JOM(4, "    purb->iso_frame_desc[j].offset = j*%i;\n",
+                                               peasycap->video_isoc_maxframesize);
+                               JOM(4, "    purb->iso_frame_desc[j].length = %i;\n",
+                                               peasycap->video_isoc_maxframesize);
+                               JOM(4, "    }\n");
+                       }
+
+                       purb->interval = 1;
+                       purb->dev = peasycap->pusb_device;
+                       purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
+                                               peasycap->video_endpointnumber);
+                       purb->transfer_flags = URB_ISO_ASAP;
+                       purb->transfer_buffer = peasycap->video_isoc_buffer[k].pgo;
+                       purb->transfer_buffer_length =
+                                               peasycap->video_isoc_buffer_size;
+                       purb->complete = easycap_complete;
+                       purb->context = peasycap;
+                       purb->start_frame = 0;
+                       purb->number_of_packets = peasycap->video_isoc_framesperdesc;
+                       for (j = 0;  j < peasycap->video_isoc_framesperdesc; j++) {
+                               purb->iso_frame_desc[j].offset = j *
+                                               peasycap->video_isoc_maxframesize;
+                               purb->iso_frame_desc[j].length =
+                                               peasycap->video_isoc_maxframesize;
+                       }
+               }
+               JOM(4, "allocation of %i struct urb done.\n", k);
+/*--------------------------------------------------------------------------*/
+/*
+ *  SAVE POINTER peasycap IN THIS INTERFACE.
+ */
+/*--------------------------------------------------------------------------*/
+               usb_set_intfdata(intf, peasycap);
+/*---------------------------------------------------------------------------*/
+/*
+ *  IT IS ESSENTIAL TO INITIALIZE THE HARDWARE BEFORE, RATHER THAN AFTER,
+ *  THE DEVICE IS REGISTERED, BECAUSE SOME VERSIONS OF THE videodev MODULE
+ *  CALL easycap_open() IMMEDIATELY AFTER REGISTRATION, CAUSING A CLASH.
+ *  BEWARE.
+*/
+/*---------------------------------------------------------------------------*/
+               peasycap->ntsc = easycap_ntsc;
+               JOM(8, "defaulting initially to %s\n",
+                       easycap_ntsc ? "NTSC" : "PAL");
+               rc = reset(peasycap);
+               if (rc) {
+                       SAM("ERROR: reset() rc = %i\n", rc);
+                       return -EFAULT;
+               }
+/*--------------------------------------------------------------------------*/
+/*
+ *  THE VIDEO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
+ */
+/*--------------------------------------------------------------------------*/
+               if (v4l2_device_register(&intf->dev, &peasycap->v4l2_device)) {
+                       SAM("v4l2_device_register() failed\n");
+                       return -ENODEV;
+               }
+               JOM(4, "registered device instance: %s\n",
+                       peasycap->v4l2_device.name);
+/*---------------------------------------------------------------------------*/
+/*
+ *                                 FIXME
+ *
+ *
+ *  THIS IS BELIEVED TO BE HARMLESS, BUT MAY WELL BE UNNECESSARY OR WRONG:
+*/
+/*---------------------------------------------------------------------------*/
+               peasycap->video_device.v4l2_dev = NULL;
+/*---------------------------------------------------------------------------*/
+
+
+               strcpy(&peasycap->video_device.name[0], "easycapdc60");
+               peasycap->video_device.fops = &v4l2_fops;
+               peasycap->video_device.minor = -1;
+               peasycap->video_device.release = (void *)(&videodev_release);
+
+               video_set_drvdata(&(peasycap->video_device), (void *)peasycap);
+
+               if (0 != (video_register_device(&(peasycap->video_device),
+                                                       VFL_TYPE_GRABBER, -1))) {
+                       err("Not able to register with videodev");
+                       videodev_release(&(peasycap->video_device));
+                       return -ENODEV;
+               } else {
+                       (peasycap->registered_video)++;
+                       SAM("registered with videodev: %i=minor\n",
+                                                       peasycap->video_device.minor);
+                       peasycap->minor = peasycap->video_device.minor;
+               }
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+
+               break;
+       }
+/*--------------------------------------------------------------------------*/
+/*
+ *  INTERFACE 1 IS THE AUDIO CONTROL INTERFACE
+ *  INTERFACE 2 IS THE AUDIO STREAMING INTERFACE
+ */
+/*--------------------------------------------------------------------------*/
+       case 1: {
+               if (!peasycap) {
+                       SAM("MISTAKE: peasycap is NULL\n");
+                       return -EFAULT;
+               }
+/*--------------------------------------------------------------------------*/
+/*
+ *  SAVE POINTER peasycap IN INTERFACE 1
+ */
+/*--------------------------------------------------------------------------*/
+               usb_set_intfdata(intf, peasycap);
+               JOM(4, "no initialization required for interface %i\n",
+                                       interface->bInterfaceNumber);
+               break;
+       }
+/*--------------------------------------------------------------------------*/
+       case 2: {
+               if (!peasycap) {
+                       SAM("MISTAKE: peasycap is NULL\n");
+                       return -EFAULT;
+               }
+               if (!isokalt) {
+                       SAM("ERROR:  no viable audio_altsetting_on\n");
+                       return -ENOENT;
+               } else {
+                       peasycap->audio_altsetting_on = okalt[isokalt - 1];
+                       JOM(4, "%i=audio_altsetting_on <====\n",
+                                                       peasycap->audio_altsetting_on);
+               }
+
+               peasycap->audio_endpointnumber = okepn[isokalt - 1];
+               JOM(4, "%i=audio_endpointnumber\n", peasycap->audio_endpointnumber);
+
+               peasycap->audio_isoc_maxframesize = okmps[isokalt - 1];
+               JOM(4, "%i=audio_isoc_maxframesize\n",
+                                               peasycap->audio_isoc_maxframesize);
+               if (0 >= peasycap->audio_isoc_maxframesize) {
+                       SAM("ERROR:  bad audio_isoc_maxframesize\n");
+                       return -ENOENT;
+               }
+               if (9 == peasycap->audio_isoc_maxframesize) {
+                       peasycap->ilk |= 0x02;
+                       SAM("audio hardware is microphone\n");
+                       peasycap->microphone = true;
+                       peasycap->audio_pages_per_fragment =
+                                       PAGES_PER_AUDIO_FRAGMENT;
+               } else if (256 == peasycap->audio_isoc_maxframesize) {
+                       peasycap->ilk &= ~0x02;
+                       SAM("audio hardware is AC'97\n");
+                       peasycap->microphone = false;
+                       peasycap->audio_pages_per_fragment =
+                                       PAGES_PER_AUDIO_FRAGMENT;
+               } else {
+                       SAM("hardware is unidentified:\n");
+                       SAM("%i=audio_isoc_maxframesize\n",
+                               peasycap->audio_isoc_maxframesize);
+                       return -ENOENT;
+               }
+
+               peasycap->audio_bytes_per_fragment =
+                               peasycap->audio_pages_per_fragment * PAGE_SIZE;
+               peasycap->audio_buffer_page_many = (AUDIO_FRAGMENT_MANY *
+                               peasycap->audio_pages_per_fragment);
+
+               JOM(4, "%6i=AUDIO_FRAGMENT_MANY\n", AUDIO_FRAGMENT_MANY);
+               JOM(4, "%6i=audio_pages_per_fragment\n",
+                                               peasycap->audio_pages_per_fragment);
+               JOM(4, "%6i=audio_bytes_per_fragment\n",
+                                               peasycap->audio_bytes_per_fragment);
+               JOM(4, "%6i=audio_buffer_page_many\n",
+                                               peasycap->audio_buffer_page_many);
+
+               peasycap->audio_isoc_framesperdesc = AUDIO_ISOC_FRAMESPERDESC;
+
+               JOM(4, "%i=audio_isoc_framesperdesc\n",
+                                               peasycap->audio_isoc_framesperdesc);
+               if (0 >= peasycap->audio_isoc_framesperdesc) {
+                       SAM("ERROR:  bad audio_isoc_framesperdesc\n");
+                       return -ENOENT;
+               }
+
+               peasycap->audio_isoc_buffer_size =
+                                       peasycap->audio_isoc_maxframesize *
+                                       peasycap->audio_isoc_framesperdesc;
+               JOM(4, "%i=audio_isoc_buffer_size\n",
+                                               peasycap->audio_isoc_buffer_size);
+               if (AUDIO_ISOC_BUFFER_SIZE < peasycap->audio_isoc_buffer_size) {
+                               SAM("MISTAKE:  audio_isoc_buffer_size bigger "
+                               "than %li=AUDIO_ISOC_BUFFER_SIZE\n",
+                                                       AUDIO_ISOC_BUFFER_SIZE);
+                       return -EFAULT;
+               }
+               if (-1 == peasycap->audio_interface) {
+                       SAM("MISTAKE:  audio_interface is unset\n");
+                       return -EFAULT;
+               }
+               if (-1 == peasycap->audio_altsetting_on) {
+                       SAM("MISTAKE:  audio_altsetting_on is unset\n");
+                       return -EFAULT;
+               }
+               if (-1 == peasycap->audio_altsetting_off) {
+                       SAM("MISTAKE:  audio_interface_off is unset\n");
+                       return -EFAULT;
+               }
+               if (-1 == peasycap->audio_endpointnumber) {
+                       SAM("MISTAKE:  audio_endpointnumber is unset\n");
+                       return -EFAULT;
+               }
+               if (-1 == peasycap->audio_isoc_maxframesize) {
+                       SAM("MISTAKE:  audio_isoc_maxframesize is unset\n");
+                       return -EFAULT;
+               }
+               if (-1 == peasycap->audio_isoc_buffer_size) {
+                       SAM("MISTAKE:  audio_isoc_buffer_size is unset\n");
+                       return -EFAULT;
+               }
+/*---------------------------------------------------------------------------*/
+/*
+ *  ALLOCATE MEMORY FOR AUDIO BUFFERS.  LISTS MUST BE INITIALIZED FIRST.
+ */
+/*---------------------------------------------------------------------------*/
+               INIT_LIST_HEAD(&(peasycap->urb_audio_head));
+               peasycap->purb_audio_head = &(peasycap->urb_audio_head);
+
+/*---------------------------------------------------------------------------*/
+               JOM(4, "allocating %i isoc audio buffers of size %i\n",
+                       AUDIO_ISOC_BUFFER_MANY,
+                       peasycap->audio_isoc_buffer_size);
+               JOM(4, ".... each occupying contiguous memory pages\n");
+
+               for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY;  k++) {
+                       pbuf = (void *)__get_free_pages(GFP_KERNEL,
+                                                       AUDIO_ISOC_ORDER);
+                       if (!pbuf) {
+                               SAM("ERROR: Could not allocate isoc audio buffer "
+                                                               "%i\n", k);
+                               return -ENOMEM;
+                       } else
+                               peasycap->allocation_audio_page +=
+                                               BIT(AUDIO_ISOC_ORDER);
+
+                       peasycap->audio_isoc_buffer[k].pgo = pbuf;
+                       peasycap->audio_isoc_buffer[k].pto = pbuf +
+                       peasycap->audio_isoc_buffer_size;
+                       peasycap->audio_isoc_buffer[k].kount = k;
+               }
+               JOM(4, "allocation of isoc audio buffers done.\n");
+/*---------------------------------------------------------------------------*/
+/*
+ *  ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
+ */
+/*---------------------------------------------------------------------------*/
+               JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
+               JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n",
+                                       peasycap->audio_isoc_framesperdesc);
+               JOM(4, "using %i=peasycap->audio_isoc_maxframesize\n",
+                                       peasycap->audio_isoc_maxframesize);
+               JOM(4, "using %i=peasycap->audio_isoc_buffer_size\n",
+                                       peasycap->audio_isoc_buffer_size);
+
+               for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY; k++) {
+                       purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc,
+                                                               GFP_KERNEL);
+                       if (!purb) {
+                               SAM("ERROR: usb_alloc_urb returned NULL for buffer "
+                                                               "%i\n", k);
+                               return -ENOMEM;
+                       }
+                       peasycap->allocation_audio_urb += 1 ;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+                       pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
+                       if (!pdata_urb) {
+                               SAM("ERROR: Could not allocate struct data_urb.\n");
+                               return -ENOMEM;
+                       }
+                       peasycap->allocation_audio_struct +=
+                                               sizeof(struct data_urb);
+
+                       pdata_urb->purb = purb;
+                       pdata_urb->isbuf = k;
+                       pdata_urb->length = 0;
+                       list_add_tail(&(pdata_urb->list_head),
+                                                       peasycap->purb_audio_head);
+/*---------------------------------------------------------------------------*/
+/*
+ *  ... AND INITIALIZE THEM
+ */
+/*---------------------------------------------------------------------------*/
+                       if (!k) {
+                               JOM(4, "initializing audio urbs thus:\n");
+                               JOM(4, "  purb->interval = 1;\n");
+                               JOM(4, "  purb->dev = peasycap->pusb_device;\n");
+                               JOM(4, "  purb->pipe = usb_rcvisocpipe(peasycap->"
+                                               "pusb_device,%i);\n",
+                                               peasycap->audio_endpointnumber);
+                               JOM(4, "  purb->transfer_flags = URB_ISO_ASAP;\n");
+                               JOM(4, "  purb->transfer_buffer = "
+                                       "peasycap->audio_isoc_buffer[.].pgo;\n");
+                               JOM(4, "  purb->transfer_buffer_length = %i;\n",
+                                       peasycap->audio_isoc_buffer_size);
+                               JOM(4, "  purb->complete = easycap_alsa_complete;\n");
+                               JOM(4, "  purb->context = peasycap;\n");
+                               JOM(4, "  purb->start_frame = 0;\n");
+                               JOM(4, "  purb->number_of_packets = %i;\n",
+                                               peasycap->audio_isoc_framesperdesc);
+                               JOM(4, "  for (j = 0; j < %i; j++)\n",
+                                               peasycap->audio_isoc_framesperdesc);
+                               JOM(4, "    {\n");
+                               JOM(4, "    purb->iso_frame_desc[j].offset = j*%i;\n",
+                                       peasycap->audio_isoc_maxframesize);
+                               JOM(4, "    purb->iso_frame_desc[j].length = %i;\n",
+                                       peasycap->audio_isoc_maxframesize);
+                               JOM(4, "    }\n");
+                       }
+
+                       purb->interval = 1;
+                       purb->dev = peasycap->pusb_device;
+                       purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
+                                               peasycap->audio_endpointnumber);
+                       purb->transfer_flags = URB_ISO_ASAP;
+                       purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
+                       purb->transfer_buffer_length =
+                                               peasycap->audio_isoc_buffer_size;
+                       purb->complete = easycap_alsa_complete;
+                       purb->context = peasycap;
+                       purb->start_frame = 0;
+                       purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
+                       for (j = 0;  j < peasycap->audio_isoc_framesperdesc; j++) {
+                               purb->iso_frame_desc[j].offset = j *
+                                               peasycap->audio_isoc_maxframesize;
+                               purb->iso_frame_desc[j].length =
+                                               peasycap->audio_isoc_maxframesize;
+                       }
+               }
+               JOM(4, "allocation of %i struct urb done.\n", k);
+/*---------------------------------------------------------------------------*/
+/*
+ *  SAVE POINTER peasycap IN THIS INTERFACE.
+ */
+/*---------------------------------------------------------------------------*/
+               usb_set_intfdata(intf, peasycap);
+/*---------------------------------------------------------------------------*/
+/*
+ *  THE AUDIO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
+ */
+/*---------------------------------------------------------------------------*/
+               JOM(4, "initializing ALSA card\n");
+
+               rc = easycap_alsa_probe(peasycap);
+               if (rc) {
+                       err("easycap_alsa_probe() rc = %i\n", rc);
+                       return -ENODEV;
+               }
+
+
+               JOM(8, "kref_get() with %i=kref.refcount.counter\n",
+                               peasycap->kref.refcount.counter);
+               kref_get(&peasycap->kref);
+               peasycap->registered_audio++;
+               break;
+       }
+/*---------------------------------------------------------------------------*/
+/*
+ *  INTERFACES OTHER THAN 0, 1 AND 2 ARE UNEXPECTED
+ */
+/*---------------------------------------------------------------------------*/
+       default:
+               JOM(4, "ERROR: unexpected interface %i\n", bInterfaceNumber);
+               return -EINVAL;
+       }
+       SAM("ends successfully for interface %i\n", bInterfaceNumber);
+       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 ALSA.  BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
+{
+       struct usb_host_interface *pusb_host_interface;
+       struct usb_interface_descriptor *pusb_interface_descriptor;
+       u8 bInterfaceNumber;
+       struct easycap *peasycap;
+
+       struct list_head *plist_head;
+       struct data_urb *pdata_urb;
+       int minor, m, kd;
+
+       JOT(4, "\n");
+
+       pusb_host_interface = pusb_interface->cur_altsetting;
+       if (!pusb_host_interface) {
+               JOT(4, "ERROR: pusb_host_interface is NULL\n");
+               return;
+       }
+       pusb_interface_descriptor = &(pusb_host_interface->desc);
+       if (!pusb_interface_descriptor) {
+               JOT(4, "ERROR: pusb_interface_descriptor is NULL\n");
+               return;
+       }
+       bInterfaceNumber = pusb_interface_descriptor->bInterfaceNumber;
+       minor = pusb_interface->minor;
+       JOT(4, "intf[%i]: minor=%i\n", bInterfaceNumber, minor);
+
+       if (1 == bInterfaceNumber)
+               return;
+
+       peasycap = usb_get_intfdata(pusb_interface);
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return;
+       }
+/*---------------------------------------------------------------------------*/
+/*
+ *  IF THE WAIT QUEUES ARE NOT CLEARED A DEADLOCK IS POSSIBLE.  BEWARE.
+*/
+/*---------------------------------------------------------------------------*/
+       peasycap->video_eof = 1;
+       peasycap->audio_eof = 1;
+       wake_up_interruptible(&(peasycap->wq_video));
+       wake_up_interruptible(&(peasycap->wq_audio));
+/*---------------------------------------------------------------------------*/
+       switch (bInterfaceNumber) {
+       case 0: {
+               if (peasycap->purb_video_head) {
+                       JOM(4, "killing video urbs\n");
+                       m = 0;
+                       list_for_each(plist_head, peasycap->purb_video_head) {
+                               pdata_urb = list_entry(plist_head,
+                                               struct data_urb, list_head);
+                               if (pdata_urb) {
+                                       if (pdata_urb->purb) {
+                                               usb_kill_urb(pdata_urb->purb);
+                                               m++;
+                                       }
+                               }
+                       }
+                       JOM(4, "%i video urbs killed\n", m);
+               }
+               break;
+       }
+/*---------------------------------------------------------------------------*/
+       case 2: {
+               if (peasycap->purb_audio_head) {
+                       JOM(4, "killing audio urbs\n");
+                       m = 0;
+                       list_for_each(plist_head, peasycap->purb_audio_head) {
+                               pdata_urb = list_entry(plist_head,
+                                               struct data_urb, list_head);
+                               if (pdata_urb) {
+                                       if (pdata_urb->purb) {
+                                               usb_kill_urb(pdata_urb->purb);
+                                               m++;
+                                       }
+                               }
+                       }
+                       JOM(4, "%i audio urbs killed\n", m);
+               }
+               break;
+       }
+       default:
+               break;
+       }
+/*--------------------------------------------------------------------------*/
+/*
+ *  DEREGISTER
+ *
+ *  THIS PROCEDURE WILL BLOCK UNTIL easycap_poll(), VIDEO IOCTL AND AUDIO
+ *  IOCTL ARE ALL UNLOCKED.  IF THIS IS NOT DONE AN Oops CAN OCCUR WHEN
+ *  AN EasyCAP IS UNPLUGGED WHILE THE URBS ARE RUNNING.  BEWARE.
+ */
+/*--------------------------------------------------------------------------*/
+       kd = isdongle(peasycap);
+       switch (bInterfaceNumber) {
+       case 0: {
+               if (0 <= kd && DONGLE_MANY > kd) {
+                       wake_up_interruptible(&peasycap->wq_video);
+                       JOM(4, "about to lock dongle[%i].mutex_video\n", kd);
+                       if (mutex_lock_interruptible(&easycapdc60_dongle[kd].
+                                                               mutex_video)) {
+                               SAY("ERROR: "
+                                   "cannot lock dongle[%i].mutex_video\n", kd);
+                               return;
+                       }
+                       JOM(4, "locked dongle[%i].mutex_video\n", kd);
+               } else {
+                       SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
+               }
+/*---------------------------------------------------------------------------*/
+               if (!peasycap->v4l2_device.name[0]) {
+                       SAM("ERROR: peasycap->v4l2_device.name is empty\n");
+                       if (0 <= kd && DONGLE_MANY > kd)
+                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       return;
+               }
+               v4l2_device_disconnect(&peasycap->v4l2_device);
+               JOM(4, "v4l2_device_disconnect() OK\n");
+               v4l2_device_unregister(&peasycap->v4l2_device);
+               JOM(4, "v4l2_device_unregister() OK\n");
+
+               video_unregister_device(&peasycap->video_device);
+               JOM(4, "intf[%i]: video_unregister_device() minor=%i\n",
+                               bInterfaceNumber, minor);
+               peasycap->registered_video--;
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+
+               if (0 <= kd && DONGLE_MANY > kd) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+                       JOM(4, "unlocked 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 dongle[%i].mutex_audio\n", kd);
+                       if (mutex_lock_interruptible(&easycapdc60_dongle[kd].
+                                                               mutex_audio)) {
+                               SAY("ERROR: "
+                                   "cannot lock dongle[%i].mutex_audio\n", kd);
+                               return;
+                       }
+                       JOM(4, "locked dongle[%i].mutex_audio\n", kd);
+               } else
+                       SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
+               if (0 != snd_card_free(peasycap->psnd_card)) {
+                       SAY("ERROR: snd_card_free() failed\n");
+               } else {
+                       peasycap->psnd_card = NULL;
+                       (peasycap->registered_audio)--;
+               }
+               if (0 <= kd && DONGLE_MANY > kd) {
+                       mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
+                       JOM(4, "unlocked dongle[%i].mutex_audio\n", kd);
+               }
+               break;
+       }
+       default:
+               break;
+       }
+/*---------------------------------------------------------------------------*/
+/*
+ *  CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap
+ *  (ALSO WHEN ALSA HAS BEEN IN USE)
+ */
+/*---------------------------------------------------------------------------*/
+       if (!peasycap->kref.refcount.counter) {
+               SAM("ERROR: peasycap->kref.refcount.counter is zero "
+                                                       "so cannot call kref_put()\n");
+               SAM("ending unsuccessfully: may cause memory leak\n");
+               return;
+       }
+       if (0 <= kd && DONGLE_MANY > kd) {
+               JOM(4, "about to lock dongle[%i].mutex_video\n", kd);
+               if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
+                       SAY("ERROR: cannot lock dongle[%i].mutex_video\n", kd);
+                       SAM("ending unsuccessfully: may cause memory leak\n");
+                       return;
+               }
+               JOM(4, "locked dongle[%i].mutex_video\n", kd);
+               JOM(4, "about to lock dongle[%i].mutex_audio\n", kd);
+               if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_audio)) {
+                       SAY("ERROR: cannot lock dongle[%i].mutex_audio\n", kd);
+                       mutex_unlock(&(easycapdc60_dongle[kd].mutex_video));
+                       JOM(4, "unlocked dongle[%i].mutex_video\n", kd);
+                       SAM("ending unsuccessfully: may cause memory leak\n");
+                       return;
+               }
+               JOM(4, "locked 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(&(easycapdc60_dongle[kd].mutex_audio));
+               JOT(4, "unlocked dongle[%i].mutex_audio\n", kd);
+               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
+               JOT(4, "unlocked dongle[%i].mutex_video\n", kd);
+       }
+/*---------------------------------------------------------------------------*/
+       JOM(4, "ends\n");
+       return;
+}
+/*****************************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  PARAMETERS APPLICABLE TO ENTIRE DRIVER, I.E. BOTH VIDEO AND AUDIO
+ */
+/*---------------------------------------------------------------------------*/
+static struct usb_device_id easycap_usb_device_id_table[] = {
+       {USB_DEVICE(USB_EASYCAP_VENDOR_ID, USB_EASYCAP_PRODUCT_ID)},
+       { }
+};
+
+MODULE_DEVICE_TABLE(usb, easycap_usb_device_id_table);
+struct usb_driver easycap_usb_driver = {
+       .name = "easycap",
+       .id_table = easycap_usb_device_id_table,
+       .probe = easycap_usb_probe,
+       .disconnect = easycap_usb_disconnect,
+};
+
+static int __init easycap_module_init(void)
+{
+       int k, rc;
+
+       printk(KERN_INFO "Easycap version: "EASYCAP_DRIVER_VERSION "\n");
+
+       JOT(4, "begins.  %i=debug %i=bars %i=gain\n",
+               easycap_debug, easycap_bars, easycap_gain);
+
+       mutex_init(&mutex_dongle);
+       for (k = 0; k < DONGLE_MANY; k++) {
+               easycapdc60_dongle[k].peasycap = NULL;
+               mutex_init(&easycapdc60_dongle[k].mutex_video);
+               mutex_init(&easycapdc60_dongle[k].mutex_audio);
+       }
+       rc = usb_register(&easycap_usb_driver);
+       if (rc)
+               printk(KERN_ERR "Easycap: usb_register failed rc=%d\n", rc);
+
+       return rc;
+}
+/*****************************************************************************/
+static void __exit easycap_module_exit(void)
+{
+       usb_deregister(&easycap_usb_driver);
+}
+/*****************************************************************************/
+
+module_init(easycap_module_init);
+module_exit(easycap_module_exit);
+
+/*****************************************************************************/
diff --git a/drivers/staging/media/easycap/easycap_settings.c b/drivers/staging/media/easycap/easycap_settings.c
new file mode 100644 (file)
index 0000000..70f59b1
--- /dev/null
@@ -0,0 +1,696 @@
+/******************************************************************************
+*                                                                             *
+*  easycap_settings.c                                                         *
+*                                                                             *
+******************************************************************************/
+/*
+ *
+ *  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
+ *
+*/
+/*****************************************************************************/
+
+#include "easycap.h"
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  THE LEAST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
+ *                         0 => 25 fps
+ *                         1 => 30 fps
+ *
+ *  THE MOST  SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
+ *                         0 => full framerate
+ *                         1 => 20%  framerate
+ */
+/*---------------------------------------------------------------------------*/
+const struct easycap_standard easycap_standard[] = {
+       {
+               .mask = 0x00FF & PAL_BGHIN ,
+               .v4l2_standard = {
+                       .index = PAL_BGHIN,
+                       .id = (V4L2_STD_PAL_B |
+                               V4L2_STD_PAL_G | V4L2_STD_PAL_H |
+                               V4L2_STD_PAL_I | V4L2_STD_PAL_N),
+                       .name = "PAL_BGHIN",
+                       .frameperiod = {1, 25},
+                       .framelines = 625,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x00FF & NTSC_N_443 ,
+               .v4l2_standard = {
+                       .index = NTSC_N_443,
+                       .id = V4L2_STD_UNKNOWN,
+                       .name = "NTSC_N_443",
+                       .frameperiod = {1, 25},
+                       .framelines = 480,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x00FF & PAL_Nc ,
+               .v4l2_standard = {
+                       .index = PAL_Nc,
+                       .id = V4L2_STD_PAL_Nc,
+                       .name = "PAL_Nc",
+                       .frameperiod = {1, 25},
+                       .framelines = 625,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x00FF & NTSC_N ,
+               .v4l2_standard = {
+                       .index = NTSC_N,
+                       .id = V4L2_STD_UNKNOWN,
+                       .name = "NTSC_N",
+                       .frameperiod = {1, 25},
+                       .framelines = 525,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x00FF & SECAM ,
+               .v4l2_standard = {
+                       .index = SECAM,
+                       .id = V4L2_STD_SECAM,
+                       .name = "SECAM",
+                       .frameperiod = {1, 25},
+                       .framelines = 625,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x00FF & NTSC_M ,
+               .v4l2_standard = {
+                       .index = NTSC_M,
+                       .id = V4L2_STD_NTSC_M,
+                       .name = "NTSC_M",
+                       .frameperiod = {1, 30},
+                       .framelines = 525,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x00FF & NTSC_M_JP ,
+               .v4l2_standard = {
+                       .index = NTSC_M_JP,
+                       .id = V4L2_STD_NTSC_M_JP,
+                       .name = "NTSC_M_JP",
+                       .frameperiod = {1, 30},
+                       .framelines = 525,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x00FF & PAL_60 ,
+               .v4l2_standard = {
+                       .index = PAL_60,
+                       .id = V4L2_STD_PAL_60,
+                       .name = "PAL_60",
+                       .frameperiod = {1, 30},
+                       .framelines = 525,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x00FF & NTSC_443 ,
+               .v4l2_standard = {
+                       .index = NTSC_443,
+                       .id = V4L2_STD_NTSC_443,
+                       .name = "NTSC_443",
+                       .frameperiod = {1, 30},
+                       .framelines = 525,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x00FF & PAL_M ,
+               .v4l2_standard = {
+                       .index = PAL_M,
+                       .id = V4L2_STD_PAL_M,
+                       .name = "PAL_M",
+                       .frameperiod = {1, 30},
+                       .framelines = 525,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x8000 | (0x00FF & PAL_BGHIN_SLOW),
+               .v4l2_standard = {
+                       .index = PAL_BGHIN_SLOW,
+                       .id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G |
+                               V4L2_STD_PAL_H |
+                               V4L2_STD_PAL_I | V4L2_STD_PAL_N |
+                               (((v4l2_std_id)0x01) << 32)),
+                       .name = "PAL_BGHIN_SLOW",
+                       .frameperiod = {1, 5},
+                       .framelines = 625,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x8000 | (0x00FF & NTSC_N_443_SLOW),
+               .v4l2_standard = {
+                       .index = NTSC_N_443_SLOW,
+                       .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x11) << 32)),
+                       .name = "NTSC_N_443_SLOW",
+                       .frameperiod = {1, 5},
+                       .framelines = 480,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x8000 | (0x00FF & PAL_Nc_SLOW),
+               .v4l2_standard = {
+                       .index = PAL_Nc_SLOW,
+                       .id = (V4L2_STD_PAL_Nc | (((v4l2_std_id)0x01) << 32)),
+                       .name = "PAL_Nc_SLOW",
+                       .frameperiod = {1, 5},
+                       .framelines = 625,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x8000 | (0x00FF & NTSC_N_SLOW),
+               .v4l2_standard = {
+                       .index = NTSC_N_SLOW,
+                       .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x21) << 32)),
+                       .name = "NTSC_N_SLOW",
+                       .frameperiod = {1, 5},
+                       .framelines = 525,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x8000 | (0x00FF & SECAM_SLOW),
+               .v4l2_standard = {
+                       .index = SECAM_SLOW,
+                       .id = (V4L2_STD_SECAM | (((v4l2_std_id)0x01) << 32)),
+                       .name = "SECAM_SLOW",
+                       .frameperiod = {1, 5},
+                       .framelines = 625,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x8000 | (0x00FF & NTSC_M_SLOW),
+               .v4l2_standard = {
+                       .index = NTSC_M_SLOW,
+                       .id = (V4L2_STD_NTSC_M | (((v4l2_std_id)0x01) << 32)),
+                       .name = "NTSC_M_SLOW",
+                       .frameperiod = {1, 6},
+                       .framelines = 525,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x8000 | (0x00FF & NTSC_M_JP_SLOW),
+               .v4l2_standard = {
+                       .index = NTSC_M_JP_SLOW,
+                       .id = (V4L2_STD_NTSC_M_JP |
+                               (((v4l2_std_id)0x01) << 32)),
+                       .name = "NTSC_M_JP_SLOW",
+                       .frameperiod = {1, 6},
+                       .framelines = 525,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x8000 | (0x00FF & PAL_60_SLOW),
+               .v4l2_standard = {
+                       .index = PAL_60_SLOW,
+                       .id = (V4L2_STD_PAL_60 | (((v4l2_std_id)0x01) << 32)),
+                       .name = "PAL_60_SLOW",
+                       .frameperiod = {1, 6},
+                       .framelines = 525,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x8000 | (0x00FF & NTSC_443_SLOW),
+               .v4l2_standard = {
+                       .index = NTSC_443_SLOW,
+                       .id = (V4L2_STD_NTSC_443 | (((v4l2_std_id)0x01) << 32)),
+                       .name = "NTSC_443_SLOW",
+                       .frameperiod = {1, 6},
+                       .framelines = 525,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0x8000 | (0x00FF & PAL_M_SLOW),
+               .v4l2_standard = {
+                       .index = PAL_M_SLOW,
+                       .id = (V4L2_STD_PAL_M | (((v4l2_std_id)0x01) << 32)),
+                       .name = "PAL_M_SLOW",
+                       .frameperiod = {1, 6},
+                       .framelines = 525,
+                       .reserved = {0, 0, 0, 0}
+               }
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .mask = 0xFFFF
+       }
+};
+/*---------------------------------------------------------------------------*/
+/*
+ *  THE 16-BIT easycap_format.mask HAS MEANING:
+ *    (least significant) BIT  0:     0 => PAL, 25 FPS;   1 => NTSC, 30 FPS
+ *                        BITS 2-4:   RESERVED FOR DIFFERENTIATING STANDARDS
+ *                        BITS 5-7:   NUMBER OF BYTES PER PIXEL
+ *                        BIT  8:     0 => NATIVE BYTE ORDER;  1 => SWAPPED
+ *                        BITS 9-10:  RESERVED FOR OTHER BYTE PERMUTATIONS
+ *                        BIT 11:     0 => UNDECIMATED;    1 => DECIMATED
+ *                        BIT 12:     0 => OFFER FRAMES;   1 => OFFER FIELDS
+ *                        BIT 13:     0 => FULL FRAMERATE; 1 => REDUCED
+ *     (most significant) BITS 14-15: RESERVED FOR OTHER FIELD/FRAME OPTIONS
+ *  IT FOLLOWS THAT:
+ *     bytesperpixel IS         ((0x00E0 & easycap_format.mask) >> 5)
+ *     byteswaporder IS true IF (0 != (0x0100 & easycap_format.mask))
+ *
+ *     decimatepixel IS true IF (0 != (0x0800 & easycap_format.mask))
+ *
+ *       offerfields IS true IF (0 != (0x1000 & easycap_format.mask))
+ */
+/*---------------------------------------------------------------------------*/
+
+struct easycap_format easycap_format[1 + SETTINGS_MANY];
+
+int fillin_formats(void)
+{
+       const char *name1, *name2, *name3, *name4;
+       struct v4l2_format *fmt;
+       int i, j, k, m, n;
+       u32 width, height, pixelformat, bytesperline, sizeimage;
+       u16 mask1, mask2, mask3, mask4;
+       enum v4l2_field field;
+       enum v4l2_colorspace colorspace;
+
+       for (i = 0, n = 0; i < STANDARD_MANY; i++) {
+               mask1 = 0x0000;
+               switch (i) {
+               case PAL_BGHIN: {
+                       mask1 = 0x1F & PAL_BGHIN;
+                       name1 = "PAL_BGHIN";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+                       break;
+               }
+               case SECAM: {
+                       mask1 = 0x1F & SECAM;
+                       name1 = "SECAM";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+                       break;
+               }
+               case PAL_Nc: {
+                       mask1 = 0x1F & PAL_Nc;
+                       name1 = "PAL_Nc";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+                       break;
+               }
+               case PAL_60: {
+                       mask1 = 0x1F & PAL_60;
+                       name1 = "PAL_60";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+                       break;
+               }
+               case PAL_M: {
+                       mask1 = 0x1F & PAL_M;
+                       name1 = "PAL_M";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+                       break;
+               }
+               case NTSC_M: {
+                       mask1 = 0x1F & NTSC_M;
+                       name1 = "NTSC_M";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+                       break;
+               }
+               case NTSC_443: {
+                       mask1 = 0x1F & NTSC_443;
+                       name1 = "NTSC_443";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+                       break;
+               }
+               case NTSC_M_JP: {
+                       mask1 = 0x1F & NTSC_M_JP;
+                       name1 = "NTSC_M_JP";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+                       break;
+               }
+               case NTSC_N: {
+                       mask1 = 0x1F & NTSC_M;
+                       name1 = "NTSC_N";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+                       break;
+               }
+               case NTSC_N_443: {
+                       mask1 = 0x1F & NTSC_N_443;
+                       name1 = "NTSC_N_443";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+                       break;
+               }
+               case PAL_BGHIN_SLOW: {
+                       mask1 = 0x001F & PAL_BGHIN_SLOW;
+                       mask1 |= 0x0200;
+                       name1 = "PAL_BGHIN_SLOW";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+                       break;
+               }
+               case SECAM_SLOW: {
+                       mask1 = 0x001F & SECAM_SLOW;
+                       mask1 |= 0x0200;
+                       name1 = "SECAM_SLOW";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+                       break;
+               }
+               case PAL_Nc_SLOW: {
+                       mask1 = 0x001F & PAL_Nc_SLOW;
+                       mask1 |= 0x0200;
+                       name1 = "PAL_Nc_SLOW";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+                       break;
+               }
+               case PAL_60_SLOW: {
+                       mask1 = 0x001F & PAL_60_SLOW;
+                       mask1 |= 0x0200;
+                       name1 = "PAL_60_SLOW";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+                       break;
+               }
+               case PAL_M_SLOW: {
+                       mask1 = 0x001F & PAL_M_SLOW;
+                       mask1 |= 0x0200;
+                       name1 = "PAL_M_SLOW";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+                       break;
+               }
+               case NTSC_M_SLOW: {
+                       mask1 = 0x001F & NTSC_M_SLOW;
+                       mask1 |= 0x0200;
+                       name1 = "NTSC_M_SLOW";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+                       break;
+               }
+               case NTSC_443_SLOW: {
+                       mask1 = 0x001F & NTSC_443_SLOW;
+                       mask1 |= 0x0200;
+                       name1 = "NTSC_443_SLOW";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+                       break;
+               }
+               case NTSC_M_JP_SLOW: {
+                       mask1 = 0x001F & NTSC_M_JP_SLOW;
+                       mask1 |= 0x0200;
+                       name1 = "NTSC_M_JP_SLOW";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+                       break;
+               }
+               case NTSC_N_SLOW: {
+                       mask1 = 0x001F & NTSC_N_SLOW;
+                       mask1 |= 0x0200;
+                       name1 = "NTSC_N_SLOW";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+                       break;
+               }
+               case NTSC_N_443_SLOW: {
+                       mask1 = 0x001F & NTSC_N_443_SLOW;
+                       mask1 |= 0x0200;
+                       name1 = "NTSC_N_443_SLOW";
+                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+                       break;
+               }
+               default:
+                       return -1;
+               }
+
+               for (j = 0; j < RESOLUTION_MANY; j++) {
+                       mask2 = 0x0000;
+                       switch (j) {
+                       case AT_720x576: {
+                               if (0x1 & mask1)
+                                       continue;
+                               name2 = "_AT_720x576";
+                               width = 720;
+                               height = 576;
+                               break;
+                       }
+                       case AT_704x576: {
+                               if (0x1 & mask1)
+                                       continue;
+                               name2 = "_AT_704x576";
+                               width = 704;
+                               height = 576;
+                               break;
+                       }
+                       case AT_640x480: {
+                               name2 = "_AT_640x480";
+                               width = 640;
+                               height = 480;
+                               break;
+                       }
+                       case AT_720x480: {
+                               if (!(0x1 & mask1))
+                                       continue;
+                               name2 = "_AT_720x480";
+                               width = 720;
+                               height = 480;
+                               break;
+                       }
+                       case AT_360x288: {
+                               if (0x1 & mask1)
+                                       continue;
+                               name2 = "_AT_360x288";
+                               width = 360;
+                               height = 288;
+                               mask2 = 0x0800;
+                               break;
+                       }
+                       case AT_320x240: {
+                               name2 = "_AT_320x240";
+                               width = 320;
+                               height = 240;
+                               mask2 = 0x0800;
+                               break;
+                       }
+                       case AT_360x240: {
+                               if (!(0x1 & mask1))
+                                       continue;
+                               name2 = "_AT_360x240";
+                               width = 360;
+                               height = 240;
+                               mask2 = 0x0800;
+                               break;
+                       }
+                       default:
+                               return -2;
+                       }
+
+                       for (k = 0; k < PIXELFORMAT_MANY; k++) {
+                               mask3 = 0x0000;
+                               switch (k) {
+                               case FMT_UYVY: {
+                                       name3 = __stringify(FMT_UYVY);
+                                       pixelformat = V4L2_PIX_FMT_UYVY;
+                                       mask3 |= (0x02 << 5);
+                                       break;
+                               }
+                               case FMT_YUY2: {
+                                       name3 = __stringify(FMT_YUY2);
+                                       pixelformat = V4L2_PIX_FMT_YUYV;
+                                       mask3 |= (0x02 << 5);
+                                       mask3 |= 0x0100;
+                                       break;
+                               }
+                               case FMT_RGB24: {
+                                       name3 = __stringify(FMT_RGB24);
+                                       pixelformat = V4L2_PIX_FMT_RGB24;
+                                       mask3 |= (0x03 << 5);
+                                       break;
+                               }
+                               case FMT_RGB32: {
+                                       name3 = __stringify(FMT_RGB32);
+                                       pixelformat = V4L2_PIX_FMT_RGB32;
+                                       mask3 |= (0x04 << 5);
+                                       break;
+                               }
+                               case FMT_BGR24: {
+                                       name3 = __stringify(FMT_BGR24);
+                                       pixelformat = V4L2_PIX_FMT_BGR24;
+                                       mask3 |= (0x03 << 5);
+                                       mask3 |= 0x0100;
+                                       break;
+                               }
+                               case FMT_BGR32: {
+                                       name3 = __stringify(FMT_BGR32);
+                                       pixelformat = V4L2_PIX_FMT_BGR32;
+                                       mask3 |= (0x04 << 5);
+                                       mask3 |= 0x0100;
+                                       break;
+                               }
+                               default:
+                                       return -3;
+                               }
+                               bytesperline = width * ((mask3 & 0x00E0) >> 5);
+                               sizeimage =  bytesperline * height;
+
+                               for (m = 0; m < INTERLACE_MANY; m++) {
+                                       mask4 = 0x0000;
+                                       switch (m) {
+                                       case FIELD_NONE: {
+                                               name4 = "-n";
+                                               field = V4L2_FIELD_NONE;
+                                               break;
+                                       }
+                                       case FIELD_INTERLACED: {
+                                               name4 = "-i";
+                                               mask4 |= 0x1000;
+                                               field = V4L2_FIELD_INTERLACED;
+                                               break;
+                                       }
+                                       default:
+                                               return -4;
+                                       }
+                                       if (SETTINGS_MANY <= n)
+                                               return -5;
+
+                                       strcpy(easycap_format[n].name, name1);
+                                       strcat(easycap_format[n].name, name2);
+                                       strcat(easycap_format[n].name, "_");
+                                       strcat(easycap_format[n].name, name3);
+                                       strcat(easycap_format[n].name, name4);
+                                       easycap_format[n].mask =
+                                               mask1 | mask2 | mask3 | mask4;
+                                       fmt = &easycap_format[n].v4l2_format;
+
+                                       fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                                       fmt->fmt.pix.width = width;
+                                       fmt->fmt.pix.height = height;
+                                       fmt->fmt.pix.pixelformat = pixelformat;
+                                       fmt->fmt.pix.field = field;
+                                       fmt->fmt.pix.bytesperline = bytesperline;
+                                       fmt->fmt.pix.sizeimage = sizeimage;
+                                       fmt->fmt.pix.colorspace = colorspace;
+                                       fmt->fmt.pix.priv = 0;
+                                       n++;
+                               }
+                       }
+               }
+       }
+       if ((1 + SETTINGS_MANY) <= n)
+               return -6;
+       easycap_format[n].mask = 0xFFFF;
+       return n;
+}
+/*---------------------------------------------------------------------------*/
+struct v4l2_queryctrl easycap_control[] = {
+       {
+               .id       = V4L2_CID_BRIGHTNESS,
+               .type     = V4L2_CTRL_TYPE_INTEGER,
+               .name     = "Brightness",
+               .minimum  = 0,
+               .maximum  = 255,
+               .step     =  1,
+               .default_value = SAA_0A_DEFAULT,
+               .flags    = 0,
+               .reserved = {0, 0}
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .id       = V4L2_CID_CONTRAST,
+               .type     = V4L2_CTRL_TYPE_INTEGER,
+               .name     = "Contrast",
+               .minimum  = 0,
+               .maximum  = 255,
+               .step     =   1,
+               .default_value = SAA_0B_DEFAULT + 128,
+               .flags    = 0,
+               .reserved = {0, 0}
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .id       = V4L2_CID_SATURATION,
+               .type     = V4L2_CTRL_TYPE_INTEGER,
+               .name     = "Saturation",
+               .minimum  = 0,
+               .maximum  = 255,
+               .step     =   1,
+               .default_value = SAA_0C_DEFAULT + 128,
+               .flags    = 0,
+               .reserved = {0, 0}
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .id       = V4L2_CID_HUE,
+               .type     = V4L2_CTRL_TYPE_INTEGER,
+               .name     = "Hue",
+               .minimum  = 0,
+               .maximum  = 255,
+               .step     =   1,
+               .default_value = SAA_0D_DEFAULT + 128,
+               .flags    = 0,
+               .reserved = {0, 0}
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .id       = V4L2_CID_AUDIO_VOLUME,
+               .type     = V4L2_CTRL_TYPE_INTEGER,
+               .name     = "Volume",
+               .minimum  = 0,
+               .maximum  = 31,
+               .step     =   1,
+               .default_value = 16,
+               .flags    = 0,
+               .reserved = {0, 0}
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .id       = V4L2_CID_AUDIO_MUTE,
+               .type     = V4L2_CTRL_TYPE_BOOLEAN,
+               .name     = "Mute",
+               .default_value = true,
+               .flags    = 0,
+               .reserved = {0, 0}
+       },
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+       {
+               .id = 0xFFFFFFFF
+       }
+};
+/*****************************************************************************/
diff --git a/drivers/staging/media/easycap/easycap_sound.c b/drivers/staging/media/easycap/easycap_sound.c
new file mode 100644 (file)
index 0000000..b22bb39
--- /dev/null
@@ -0,0 +1,816 @@
+/******************************************************************************
+*                                                                             *
+*  easycap_sound.c                                                            *
+*                                                                             *
+*  Audio driver for EasyCAP USB2.0 Video Capture Device DC60                  *
+*                                                                             *
+*                                                                             *
+******************************************************************************/
+/*
+ *
+ *  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
+ *
+*/
+/*****************************************************************************/
+
+#include "easycap.h"
+
+/*--------------------------------------------------------------------------*/
+/*
+ *  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,
+};
+
+
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  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 tmp;
+       int i, j, more, much, rc;
+#ifdef UPSAMPLE
+       int k;
+       s16 oldaudio, newaudio, delta;
+#endif /*UPSAMPLE*/
+
+       JOT(16, "\n");
+
+       if (!purb) {
+               SAY("ERROR: purb is NULL\n");
+               return;
+       }
+       peasycap = purb->context;
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\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 (!pss)
+               goto resubmit;
+       prt = pss->runtime;
+       if (!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: -%s: %d\n",
+                   strerror(purb->status), purb->status);
+               goto resubmit;
+       }
+/*---------------------------------------------------------------------------*/
+/*
+ *  PROCEED HERE WHEN NO ERROR
+ */
+/*---------------------------------------------------------------------------*/
+
+#ifdef UPSAMPLE
+       oldaudio = peasycap->oldaudio;
+#endif /*UPSAMPLE*/
+
+       for (i = 0;  i < purb->number_of_packets; i++) {
+               if (purb->iso_frame_desc[i].status < 0) {
+                       SAM("-%s: %d\n",
+                           strerror(purb->iso_frame_desc[i].status),
+                           purb->iso_frame_desc[i].status);
+               }
+               if (purb->iso_frame_desc[i].status) {
+                       JOM(12, "discarding audio samples because "
+                           "%i=purb->iso_frame_desc[i].status\n",
+                           purb->iso_frame_desc[i].status);
+                       continue;
+               }
+               more = purb->iso_frame_desc[i].actual_length;
+               if (more == 0) {
+                       peasycap->audio_mt++;
+                       continue;
+               }
+               if (0 > more) {
+                       SAM("MISTAKE: more is negative\n");
+                       return;
+               }
+
+               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) {
+                       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 (!peasycap->microphone) {
+                               if (much > more)
+                                       much = more;
+                               memcpy(prt->dma_area + peasycap->dma_fill,
+                                       p1, much);
+                               p1 += much;
+                               more -= much;
+                       } else {
+#ifdef 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;
+                                       tmp = oldaudio + delta;
+
+                                       for (k = 0;  k < 4;  k++) {
+                                               *p2 = (0x00FF & tmp);
+                                               *(p2 + 1) = (0xFF00 & tmp) >> 8;
+                                               p2 += 2;
+                                               *p2 = (0x00FF & tmp);
+                                               *(p2 + 1) = (0xFF00 & tmp) >> 8;
+                                               p2 += 2;
+                                               tmp += delta;
+                                       }
+                                       p1++;
+                                       more--;
+                                       oldaudio = tmp;
+                               }
+#else /*!UPSAMPLE*/
+                               if (much > (2 * more))
+                                       much = 2 * more;
+                               p2 = (u8 *)(prt->dma_area + peasycap->dma_fill);
+
+                               for (j = 0;  j < (much / 2);  j++) {
+                                       tmp = ((int) *p1) - 128;
+                                       tmp = 128 * tmp;
+                                       *p2 = (0x00FF & tmp);
+                                       *(p2 + 1) = (0xFF00 & tmp) >> 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_elapsed(), %i="
+                                           "isfragment\n", isfragment);
+                                       snd_pcm_period_elapsed(pss);
+                               }
+                       }
+               }
+
+#ifdef UPSAMPLE
+               peasycap->oldaudio = oldaudio;
+#endif /*UPSAMPLE*/
+
+       }
+/*---------------------------------------------------------------------------*/
+/*
+ *  RESUBMIT THIS URB
+ */
+/*---------------------------------------------------------------------------*/
+resubmit:
+       if (peasycap->audio_isoc_streaming == 0)
+               return;
+
+       rc = usb_submit_urb(purb, GFP_ATOMIC);
+       if (rc) {
+               if ((-ENODEV != rc) && (-ENOENT != rc)) {
+                       SAM("ERROR: while %i=audio_idle, usb_submit_urb failed "
+                           "with rc: -%s :%d\n",
+                               peasycap->audio_idle, strerror(rc), rc);
+               }
+               if (0 < peasycap->audio_isoc_streaming)
+                       peasycap->audio_isoc_streaming--;
+       }
+       return;
+}
+/*****************************************************************************/
+static 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 (!pss) {
+               SAY("ERROR:  pss is NULL\n");
+               return -EFAULT;
+       }
+       psnd_pcm = pss->pcm;
+       if (!psnd_pcm) {
+               SAY("ERROR:  psnd_pcm is NULL\n");
+               return -EFAULT;
+       }
+       psnd_card = psnd_pcm->card;
+       if (!psnd_card) {
+               SAY("ERROR:  psnd_card is NULL\n");
+               return -EFAULT;
+       }
+
+       peasycap = psnd_card->private_data;
+       if (!peasycap) {
+               SAY("ERROR:  peasycap is NULL\n");
+               return -EFAULT;
+       }
+       if (peasycap->psnd_card != psnd_card) {
+               SAM("ERROR: bad peasycap->psnd_card\n");
+               return -EFAULT;
+       }
+       if (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;
+}
+/*****************************************************************************/
+static int easycap_alsa_close(struct snd_pcm_substream *pss)
+{
+       struct easycap *peasycap;
+
+       JOT(4, "\n");
+       if (!pss) {
+               SAY("ERROR:  pss is NULL\n");
+               return -EFAULT;
+       }
+       peasycap = snd_pcm_substream_chip(pss);
+       if (!peasycap) {
+               SAY("ERROR:  peasycap is NULL\n");
+               return -EFAULT;
+       }
+       pss->private_data = NULL;
+       peasycap->psubstream = NULL;
+       JOT(4, "ending successfully\n");
+       return 0;
+}
+/*****************************************************************************/
+static int easycap_alsa_vmalloc(struct snd_pcm_substream *pss, size_t sz)
+{
+       struct snd_pcm_runtime *prt;
+       JOT(4, "\n");
+
+       if (!pss) {
+               SAY("ERROR:  pss is NULL\n");
+               return -EFAULT;
+       }
+       prt = pss->runtime;
+       if (!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 (!prt->dma_area)
+               return -ENOMEM;
+       prt->dma_bytes = sz;
+       return 0;
+}
+/*****************************************************************************/
+static 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 (!pss) {
+               SAY("ERROR:  pss is NULL\n");
+               return -EFAULT;
+       }
+       rc = easycap_alsa_vmalloc(pss, params_buffer_bytes(phw));
+       if (rc)
+               return rc;
+       return 0;
+}
+/*****************************************************************************/
+static int easycap_alsa_hw_free(struct snd_pcm_substream *pss)
+{
+       struct snd_pcm_runtime *prt;
+       JOT(4, "\n");
+
+       if (!pss) {
+               SAY("ERROR:  pss is NULL\n");
+               return -EFAULT;
+       }
+       prt = pss->runtime;
+       if (!prt) {
+               SAY("ERROR: substream.runtime is NULL\n");
+               return -EFAULT;
+       }
+       if (prt->dma_area) {
+               JOT(8, "prt->dma_area = %p\n", prt->dma_area);
+               vfree(prt->dma_area);
+               prt->dma_area = NULL;
+       } else
+               JOT(8, "dma_area already freed\n");
+       return 0;
+}
+/*****************************************************************************/
+static int easycap_alsa_prepare(struct snd_pcm_substream *pss)
+{
+       struct easycap *peasycap;
+       struct snd_pcm_runtime *prt;
+
+       JOT(4, "\n");
+       if (!pss) {
+               SAY("ERROR:  pss is NULL\n");
+               return -EFAULT;
+       }
+       prt = pss->runtime;
+       peasycap = snd_pcm_substream_chip(pss);
+       if (!peasycap) {
+               SAY("ERROR:  peasycap is NULL\n");
+               return -EFAULT;
+       }
+
+       JOM(16, "ALSA decides %8i Hz=rate\n", pss->runtime->rate);
+       JOM(16, "ALSA decides %8ld =period_size\n", pss->runtime->period_size);
+       JOM(16, "ALSA decides %8i =periods\n", pss->runtime->periods);
+       JOM(16, "ALSA decides %8ld =buffer_size\n", pss->runtime->buffer_size);
+       JOM(16, "ALSA decides %8zd =dma_bytes\n", pss->runtime->dma_bytes);
+       JOM(16, "ALSA decides %8ld =boundary\n", pss->runtime->boundary);
+       JOM(16, "ALSA decides %8i =period_step\n", pss->runtime->period_step);
+       JOM(16, "ALSA decides %8i =sample_bits\n", pss->runtime->sample_bits);
+       JOM(16, "ALSA decides %8i =frame_bits\n", pss->runtime->frame_bits);
+       JOM(16, "ALSA decides %8ld =min_align\n", pss->runtime->min_align);
+       JOM(12, "ALSA decides %8ld =hw_ptr_base\n", pss->runtime->hw_ptr_base);
+       JOM(12, "ALSA decides %8ld =hw_ptr_interrupt\n",
+               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;
+}
+/*****************************************************************************/
+static int easycap_alsa_ack(struct snd_pcm_substream *pss)
+{
+       return 0;
+}
+/*****************************************************************************/
+static 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 (!pss) {
+               SAY("ERROR:  pss is NULL\n");
+               return -EFAULT;
+       }
+       peasycap = snd_pcm_substream_chip(pss);
+       if (!peasycap) {
+               SAY("ERROR:  peasycap is NULL\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;
+}
+/*****************************************************************************/
+static snd_pcm_uframes_t easycap_alsa_pointer(struct snd_pcm_substream *pss)
+{
+       struct easycap *peasycap;
+       snd_pcm_uframes_t offset;
+
+       JOT(16, "\n");
+       if (!pss) {
+               SAY("ERROR:  pss is NULL\n");
+               return -EFAULT;
+       }
+       peasycap = snd_pcm_substream_chip(pss);
+       if (!peasycap) {
+               SAY("ERROR:  peasycap is NULL\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;
+}
+/*****************************************************************************/
+static struct page *
+easycap_alsa_page(struct snd_pcm_substream *pss, unsigned long offset)
+{
+       return vmalloc_to_page(pss->runtime->dma_area + offset);
+}
+/*****************************************************************************/
+
+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 (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -ENODEV;
+       }
+       if (0 > peasycap->minor) {
+               SAY("ERROR: no minor\n");
+               return -ENODEV;
+       }
+
+       peasycap->alsa_hardware = alsa_hardware;
+       if (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 (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;
+       }
+
+       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 (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 = NULL;
+
+       rc = snd_card_register(psnd_card);
+       if (rc) {
+               SAM("ERROR: Cannot do ALSA snd_card_register()\n");
+               snd_card_free(psnd_card);
+               return -EFAULT;
+       }
+
+       SAM("registered %s\n", &psnd_card->id[0]);
+       return 0;
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  COMMON AUDIO INITIALIZATION
+ */
+/*---------------------------------------------------------------------------*/
+int
+easycap_sound_setup(struct easycap *peasycap)
+{
+       int rc;
+
+       JOM(4, "starting initialization\n");
+
+       if (!peasycap) {
+               SAY("ERROR:  peasycap is NULL.\n");
+               return -EFAULT;
+       }
+       if (!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 (!peasycap->pusb_device) {
+               SAM("ERROR: peasycap->pusb_device has become NULL\n");
+               return -ENODEV;
+       }
+/*---------------------------------------------------------------------------*/
+       if (!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;
+
+       submit_audio_urbs(peasycap);
+
+       JOM(4, "finished initialization\n");
+       return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  SUBMIT ALL AUDIO URBS.
+ */
+/*---------------------------------------------------------------------------*/
+int
+submit_audio_urbs(struct easycap *peasycap)
+{
+       struct data_urb *pdata_urb;
+       struct urb *purb;
+       struct list_head *plist_head;
+       int j, isbad, nospc, m, rc;
+       int isbuf;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+       if (!peasycap->purb_audio_head) {
+               SAM("ERROR: peasycap->urb_audio_head uninitialized\n");
+               return -EFAULT;
+       }
+       if (!peasycap->pusb_device) {
+               SAM("ERROR: peasycap->pusb_device is NULL\n");
+               return -EFAULT;
+       }
+
+       if (peasycap->audio_isoc_streaming) {
+               JOM(4, "already streaming audio urbs\n");
+               return 0;
+       }
+
+       JOM(4, "initial submission of all audio urbs\n");
+       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);
+
+       isbad = 0;
+       nospc = 0;
+       m = 0;
+       list_for_each(plist_head, peasycap->purb_audio_head) {
+               pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+               if (pdata_urb && pdata_urb->purb) {
+                       purb = pdata_urb->purb;
+                       isbuf = pdata_urb->isbuf;
+
+                       purb->interval = 1;
+                       purb->dev = peasycap->pusb_device;
+                       purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
+                                       peasycap->audio_endpointnumber);
+                       purb->transfer_flags = URB_ISO_ASAP;
+                       purb->transfer_buffer = peasycap->audio_isoc_buffer[isbuf].pgo;
+                       purb->transfer_buffer_length = peasycap->audio_isoc_buffer_size;
+                       purb->complete = easycap_alsa_complete;
+                       purb->context = peasycap;
+                       purb->start_frame = 0;
+                       purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
+                       for (j = 0;  j < peasycap->audio_isoc_framesperdesc; j++) {
+                               purb->iso_frame_desc[j].offset = j * peasycap->audio_isoc_maxframesize;
+                               purb->iso_frame_desc[j].length = peasycap->audio_isoc_maxframesize;
+                       }
+
+                       rc = usb_submit_urb(purb, GFP_KERNEL);
+                       if (rc) {
+                               isbad++;
+                               SAM("ERROR: usb_submit_urb() failed"
+                                   " for urb with rc: -%s: %d\n",
+                                   strerror(rc), rc);
+                       } else {
+                               m++;
+                       }
+               } else {
+                       isbad++;
+               }
+       }
+       if (nospc) {
+               SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
+               SAM(".....  possibly inadequate USB bandwidth\n");
+               peasycap->audio_eof = 1;
+       }
+       if (isbad) {
+               JOM(4, "attempting cleanup instead of submitting\n");
+               list_for_each(plist_head, (peasycap->purb_audio_head)) {
+                       pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+                       if (pdata_urb && pdata_urb->purb)
+                               usb_kill_urb(pdata_urb->purb);
+               }
+               peasycap->audio_isoc_streaming = 0;
+       } else {
+               peasycap->audio_isoc_streaming = m;
+               JOM(4, "submitted %i audio urbs\n", m);
+       }
+
+       return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  KILL ALL AUDIO URBS.
+ */
+/*---------------------------------------------------------------------------*/
+int
+kill_audio_urbs(struct easycap *peasycap)
+{
+       int m;
+       struct list_head *plist_head;
+       struct data_urb *pdata_urb;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return -EFAULT;
+       }
+
+       if (!peasycap->audio_isoc_streaming) {
+               JOM(8, "%i=audio_isoc_streaming, no audio urbs killed\n",
+                   peasycap->audio_isoc_streaming);
+               return 0;
+       }
+
+       if (!peasycap->purb_audio_head) {
+               SAM("ERROR: peasycap->purb_audio_head is NULL\n");
+               return -EFAULT;
+       }
+
+       peasycap->audio_isoc_streaming = 0;
+       JOM(4, "killing audio urbs\n");
+       m = 0;
+       list_for_each(plist_head, (peasycap->purb_audio_head)) {
+               pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+               if (pdata_urb && pdata_urb->purb) {
+                       usb_kill_urb(pdata_urb->purb);
+                       m++;
+               }
+       }
+       JOM(4, "%i audio urbs killed\n", m);
+
+       return 0;
+}
+/*****************************************************************************/
diff --git a/drivers/staging/media/easycap/easycap_testcard.c b/drivers/staging/media/easycap/easycap_testcard.c
new file mode 100644 (file)
index 0000000..0f71470
--- /dev/null
@@ -0,0 +1,155 @@
+/******************************************************************************
+*                                                                             *
+*  easycap_testcard.c                                                         *
+*                                                                             *
+******************************************************************************/
+/*
+ *
+ *  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
+ *
+*/
+/*****************************************************************************/
+
+#include "easycap.h"
+
+/*****************************************************************************/
+#define TESTCARD_BYTESPERLINE (2 * 720)
+void
+easycap_testcard(struct easycap *peasycap, int field)
+{
+       int total;
+       int y, u, v, r, g, b;
+       unsigned char uyvy[4];
+       int i1, line, k, m, n, more, much, barwidth, barheight;
+       unsigned char bfbar[TESTCARD_BYTESPERLINE / 8], *p1, *p2;
+       struct data_buffer *pfield_buffer;
+
+       if (!peasycap) {
+               SAY("ERROR: peasycap is NULL\n");
+               return;
+       }
+       JOM(8, "%i=field\n", field);
+       switch (peasycap->width) {
+       case 720:
+       case 360: {
+               barwidth = (2 * 720) / 8;
+               break;
+       }
+       case 704:
+       case 352: {
+               barwidth = (2 * 704) / 8;
+               break;
+       }
+       case 640:
+       case 320: {
+               barwidth = (2 * 640) / 8;
+               break;
+       }
+       default: {
+               SAM("ERROR:  cannot set barwidth\n");
+               return;
+       }
+       }
+       if (TESTCARD_BYTESPERLINE < barwidth) {
+               SAM("ERROR: barwidth is too large\n");
+               return;
+       }
+       switch (peasycap->height) {
+       case 576:
+       case 288: {
+               barheight = 576;
+               break;
+       }
+       case 480:
+       case 240: {
+               barheight = 480;
+               break;
+       }
+       default: {
+               SAM("ERROR: cannot set barheight\n");
+               return;
+       }
+       }
+       total = 0;
+       k = field;
+       m = 0;
+       n = 0;
+
+       for (line = 0;  line < (barheight / 2);  line++) {
+               for (i1 = 0;  i1 < 8;  i1++) {
+                       r = (i1 * 256)/8;
+                       g = (i1 * 256)/8;
+                       b = (i1 * 256)/8;
+
+                       y =  299*r/1000 + 587*g/1000 + 114*b/1000 ;
+                       u = -147*r/1000 - 289*g/1000 + 436*b/1000 ;
+                       u = u + 128;
+                       v =  615*r/1000 - 515*g/1000 - 100*b/1000 ;
+                       v = v + 128;
+
+                       uyvy[0] =  0xFF & u ;
+                       uyvy[1] =  0xFF & y ;
+                       uyvy[2] =  0xFF & v ;
+                       uyvy[3] =  0xFF & y ;
+
+                       p1 = &bfbar[0];
+                       while (p1 < &bfbar[barwidth]) {
+                               *p1++ = uyvy[0] ;
+                               *p1++ = uyvy[1] ;
+                               *p1++ = uyvy[2] ;
+                               *p1++ = uyvy[3] ;
+                               total += 4;
+                       }
+
+                       p1 = &bfbar[0];
+                       more = barwidth;
+
+                       while (more) {
+                               if ((FIELD_BUFFER_SIZE/PAGE_SIZE) <= m) {
+                                       SAM("ERROR:  bad m reached\n");
+                                       return;
+                               }
+                               if (PAGE_SIZE < n) {
+                                       SAM("ERROR:  bad n reached\n");
+                                       return;
+                               }
+
+                               if (0 > more) {
+                                       SAM("ERROR:  internal fault\n");
+                                       return;
+                               }
+
+                               much = PAGE_SIZE - n;
+                               if (much > more)
+                                       much = more;
+                               pfield_buffer = &peasycap->field_buffer[k][m];
+                               p2 = pfield_buffer->pgo + n;
+                               memcpy(p2, p1, much);
+
+                               p1 += much;
+                               n += much;
+                               more -= much;
+                               if (PAGE_SIZE == n) {
+                                       m++;
+                                       n = 0;
+                               }
+                       }
+               }
+       }
+       return;
+}
diff --git a/drivers/staging/media/go7007/Kconfig b/drivers/staging/media/go7007/Kconfig
new file mode 100644 (file)
index 0000000..7dfb281
--- /dev/null
@@ -0,0 +1,109 @@
+config VIDEO_GO7007
+       tristate "WIS GO7007 MPEG encoder support"
+       depends on VIDEO_DEV && PCI && I2C
+       depends on SND
+       select VIDEOBUF_DMA_SG
+       depends on RC_CORE
+       select VIDEO_TUNER
+       select VIDEO_TVEEPROM
+       select SND_PCM
+       select CRC32
+       default N
+       ---help---
+         This is a video4linux driver for the WIS GO7007 MPEG
+         encoder chip.
+
+         To compile this driver as a module, choose M here: the
+         module will be called go7007
+
+config VIDEO_GO7007_USB
+       tristate "WIS GO7007 USB support"
+       depends on VIDEO_GO7007 && USB
+       default N
+       ---help---
+         This is a video4linux driver for the WIS GO7007 MPEG
+         encoder chip over USB.
+
+         To compile this driver as a module, choose M here: the
+         module will be called go7007-usb
+
+config VIDEO_GO7007_USB_S2250_BOARD
+       tristate "Sensoray 2250/2251 support"
+       depends on VIDEO_GO7007_USB && DVB_USB
+       default N
+       ---help---
+         This is a video4linux driver for the Sensoray 2250/2251 device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called s2250
+
+config VIDEO_GO7007_OV7640
+       tristate "OV7640 subdev support"
+       depends on VIDEO_GO7007
+       default N
+       ---help---
+         This is a video4linux driver for the OV7640 sub-device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called wis-ov7640
+
+config VIDEO_GO7007_SAA7113
+       tristate "SAA7113 subdev support"
+       depends on VIDEO_GO7007
+       default N
+       ---help---
+         This is a video4linux driver for the SAA7113 sub-device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called wis-saa7113
+
+config VIDEO_GO7007_SAA7115
+       tristate "SAA7115 subdev support"
+       depends on VIDEO_GO7007
+       default N
+       ---help---
+         This is a video4linux driver for the SAA7115 sub-device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called wis-saa7115
+
+config VIDEO_GO7007_TW9903
+       tristate "TW9903 subdev support"
+       depends on VIDEO_GO7007
+       default N
+       ---help---
+         This is a video4linux driver for the TW9903 sub-device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called wis-tw9903
+
+config VIDEO_GO7007_UDA1342
+       tristate "UDA1342 subdev support"
+       depends on VIDEO_GO7007
+       default N
+       ---help---
+         This is a video4linux driver for the UDA1342 sub-device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called wis-uda1342
+
+config VIDEO_GO7007_SONY_TUNER
+       tristate "Sony tuner subdev support"
+       depends on VIDEO_GO7007
+       default N
+       ---help---
+         This is a video4linux driver for the Sony Tuner sub-device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called wis-sony-tuner
+
+config VIDEO_GO7007_TW2804
+       tristate "TW2804 subdev support"
+       depends on VIDEO_GO7007
+       default N
+       ---help---
+         This is a video4linux driver for the TW2804 sub-device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called wis-tw2804
+
diff --git a/drivers/staging/media/go7007/Makefile b/drivers/staging/media/go7007/Makefile
new file mode 100644 (file)
index 0000000..6ee837c
--- /dev/null
@@ -0,0 +1,30 @@
+#obj-m += go7007.o go7007-usb.o snd-go7007.o wis-saa7115.o wis-tw9903.o \
+               wis-uda1342.o wis-sony-tuner.o wis-saa7113.o wis-ov7640.o \
+               wis-tw2804.o
+
+
+obj-$(CONFIG_VIDEO_GO7007) += go7007.o
+obj-$(CONFIG_VIDEO_GO7007_USB) += go7007-usb.o
+obj-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD) += s2250.o s2250-loader.o
+obj-$(CONFIG_VIDEO_GO7007_SAA7113) += wis-saa7113.o
+obj-$(CONFIG_VIDEO_GO7007_OV7640) += wis-ov7640.o
+obj-$(CONFIG_VIDEO_GO7007_SAA7115) += wis-saa7115.o
+obj-$(CONFIG_VIDEO_GO7007_TW9903) += wis-tw9903.o
+obj-$(CONFIG_VIDEO_GO7007_UDA1342) += wis-uda1342.o
+obj-$(CONFIG_VIDEO_GO7007_SONY_TUNER) += wis-sony-tuner.o
+obj-$(CONFIG_VIDEO_GO7007_TW2804) += wis-tw2804.o
+
+go7007-y := go7007-v4l2.o go7007-driver.o go7007-i2c.o go7007-fw.o \
+               snd-go7007.o
+
+s2250-y := s2250-board.o
+
+# Uncomment when the saa7134 patches get into upstream
+#obj-$(CONFIG_VIDEO_SAA7134) += saa7134-go7007.o
+#ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/video/saa7134 -DSAA7134_MPEG_GO7007=3
+
+# S2250 needs cypress ezusb loader from dvb-usb
+ccflags-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD:m=y) += -Idrivers/media/dvb/dvb-usb
+
+ccflags-y += -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/staging/media/go7007/README b/drivers/staging/media/go7007/README
new file mode 100644 (file)
index 0000000..48f4476
--- /dev/null
@@ -0,0 +1,11 @@
+Todo:
+       - checkpatch.pl cleanups
+       - sparse cleanups
+       - lots of little modules, should be merged together
+         and added to the build.
+       - testing?
+       - handle churn in v4l layer.
+
+Please send patchs to Greg Kroah-Hartman <greg@kroah.com> and Cc: Ross
+Cohen <rcohen@snurgle.org> as well.
+
diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c
new file mode 100644 (file)
index 0000000..6c9279a
--- /dev/null
@@ -0,0 +1,659 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/unistd.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <asm/system.h>
+#include <linux/videodev2.h>
+#include <media/tuner.h>
+#include <media/v4l2-common.h>
+
+#include "go7007-priv.h"
+#include "wis-i2c.h"
+
+/*
+ * Wait for an interrupt to be delivered from the GO7007SB and return
+ * the associated value and data.
+ *
+ * Must be called with the hw_lock held.
+ */
+int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data)
+{
+       go->interrupt_available = 0;
+       go->hpi_ops->read_interrupt(go);
+       if (wait_event_timeout(go->interrupt_waitq,
+                               go->interrupt_available, 5*HZ) < 0) {
+               v4l2_err(&go->v4l2_dev, "timeout waiting for read interrupt\n");
+               return -1;
+       }
+       if (!go->interrupt_available)
+               return -1;
+       go->interrupt_available = 0;
+       *value = go->interrupt_value & 0xfffe;
+       *data = go->interrupt_data;
+       return 0;
+}
+EXPORT_SYMBOL(go7007_read_interrupt);
+
+/*
+ * Read a register/address on the GO7007SB.
+ *
+ * Must be called with the hw_lock held.
+ */
+int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data)
+{
+       int count = 100;
+       u16 value;
+
+       if (go7007_write_interrupt(go, 0x0010, addr) < 0)
+               return -EIO;
+       while (count-- > 0) {
+               if (go7007_read_interrupt(go, &value, data) == 0 &&
+                               value == 0xa000)
+                       return 0;
+       }
+       return -EIO;
+}
+EXPORT_SYMBOL(go7007_read_addr);
+
+/*
+ * Send the boot firmware to the encoder, which just wakes it up and lets
+ * us talk to the GPIO pins and on-board I2C adapter.
+ *
+ * Must be called with the hw_lock held.
+ */
+static int go7007_load_encoder(struct go7007 *go)
+{
+       const struct firmware *fw_entry;
+       char fw_name[] = "go7007fw.bin";
+       void *bounce;
+       int fw_len, rv = 0;
+       u16 intr_val, intr_data;
+
+       if (request_firmware(&fw_entry, fw_name, go->dev)) {
+               v4l2_err(go, "unable to load firmware from file "
+                       "\"%s\"\n", fw_name);
+               return -1;
+       }
+       if (fw_entry->size < 16 || memcmp(fw_entry->data, "WISGO7007FW", 11)) {
+               v4l2_err(go, "file \"%s\" does not appear to be "
+                               "go7007 firmware\n", fw_name);
+               release_firmware(fw_entry);
+               return -1;
+       }
+       fw_len = fw_entry->size - 16;
+       bounce = kmalloc(fw_len, GFP_KERNEL);
+       if (bounce == NULL) {
+               v4l2_err(go, "unable to allocate %d bytes for "
+                               "firmware transfer\n", fw_len);
+               release_firmware(fw_entry);
+               return -1;
+       }
+       memcpy(bounce, fw_entry->data + 16, fw_len);
+       release_firmware(fw_entry);
+       if (go7007_interface_reset(go) < 0 ||
+                       go7007_send_firmware(go, bounce, fw_len) < 0 ||
+                       go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
+                       (intr_val & ~0x1) != 0x5a5a) {
+               v4l2_err(go, "error transferring firmware\n");
+               rv = -1;
+       }
+       kfree(bounce);
+       return rv;
+}
+
+MODULE_FIRMWARE("go7007fw.bin");
+
+/*
+ * Boot the encoder and register the I2C adapter if requested.  Do the
+ * minimum initialization necessary, since the board-specific code may
+ * still need to probe the board ID.
+ *
+ * Must NOT be called with the hw_lock held.
+ */
+int go7007_boot_encoder(struct go7007 *go, int init_i2c)
+{
+       int ret;
+
+       mutex_lock(&go->hw_lock);
+       ret = go7007_load_encoder(go);
+       mutex_unlock(&go->hw_lock);
+       if (ret < 0)
+               return -1;
+       if (!init_i2c)
+               return 0;
+       if (go7007_i2c_init(go) < 0)
+               return -1;
+       go->i2c_adapter_online = 1;
+       return 0;
+}
+EXPORT_SYMBOL(go7007_boot_encoder);
+
+/*
+ * Configure any hardware-related registers in the GO7007, such as GPIO
+ * pins and bus parameters, which are board-specific.  This assumes
+ * the boot firmware has already been downloaded.
+ *
+ * Must be called with the hw_lock held.
+ */
+static int go7007_init_encoder(struct go7007 *go)
+{
+       if (go->board_info->audio_flags & GO7007_AUDIO_I2S_MASTER) {
+               go7007_write_addr(go, 0x1000, 0x0811);
+               go7007_write_addr(go, 0x1000, 0x0c11);
+       }
+       if (go->board_id == GO7007_BOARDID_MATRIX_REV) {
+               /* Set GPIO pin 0 to be an output (audio clock control) */
+               go7007_write_addr(go, 0x3c82, 0x0001);
+               go7007_write_addr(go, 0x3c80, 0x00fe);
+       }
+       return 0;
+}
+
+/*
+ * Send the boot firmware to the GO7007 and configure the registers.  This
+ * is the only way to stop the encoder once it has started streaming video.
+ *
+ * Must be called with the hw_lock held.
+ */
+int go7007_reset_encoder(struct go7007 *go)
+{
+       if (go7007_load_encoder(go) < 0)
+               return -1;
+       return go7007_init_encoder(go);
+}
+
+/*
+ * Attempt to instantiate an I2C client by ID, probably loading a module.
+ */
+static int init_i2c_module(struct i2c_adapter *adapter, const char *type,
+                          int addr)
+{
+       struct go7007 *go = i2c_get_adapdata(adapter);
+       struct v4l2_device *v4l2_dev = &go->v4l2_dev;
+
+       if (v4l2_i2c_new_subdev(v4l2_dev, adapter, type, addr, NULL))
+               return 0;
+
+       printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", type);
+       return -1;
+}
+
+/*
+ * Finalize the GO7007 hardware setup, register the on-board I2C adapter
+ * (if used on this board), load the I2C client driver for the sensor
+ * (SAA7115 or whatever) and other devices, and register the ALSA and V4L2
+ * interfaces.
+ *
+ * Must NOT be called with the hw_lock held.
+ */
+int go7007_register_encoder(struct go7007 *go)
+{
+       int i, ret;
+
+       printk(KERN_INFO "go7007: registering new %s\n", go->name);
+
+       mutex_lock(&go->hw_lock);
+       ret = go7007_init_encoder(go);
+       mutex_unlock(&go->hw_lock);
+       if (ret < 0)
+               return -1;
+
+       /* v4l2 init must happen before i2c subdevs */
+       ret = go7007_v4l2_init(go);
+       if (ret < 0)
+               return ret;
+
+       if (!go->i2c_adapter_online &&
+                       go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) {
+               if (go7007_i2c_init(go) < 0)
+                       return -1;
+               go->i2c_adapter_online = 1;
+       }
+       if (go->i2c_adapter_online) {
+               for (i = 0; i < go->board_info->num_i2c_devs; ++i)
+                       init_i2c_module(&go->i2c_adapter,
+                                       go->board_info->i2c_devs[i].type,
+                                       go->board_info->i2c_devs[i].addr);
+               if (go->board_id == GO7007_BOARDID_ADLINK_MPG24)
+                       i2c_clients_command(&go->i2c_adapter,
+                               DECODER_SET_CHANNEL, &go->channel_number);
+       }
+       if (go->board_info->flags & GO7007_BOARD_HAS_AUDIO) {
+               go->audio_enabled = 1;
+               go7007_snd_init(go);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(go7007_register_encoder);
+
+/*
+ * Send the encode firmware to the encoder, which will cause it
+ * to immediately start delivering the video and audio streams.
+ *
+ * Must be called with the hw_lock held.
+ */
+int go7007_start_encoder(struct go7007 *go)
+{
+       u8 *fw;
+       int fw_len, rv = 0, i;
+       u16 intr_val, intr_data;
+
+       go->modet_enable = 0;
+       if (!go->dvd_mode)
+               for (i = 0; i < 4; ++i) {
+                       if (go->modet[i].enable) {
+                               go->modet_enable = 1;
+                               continue;
+                       }
+                       go->modet[i].pixel_threshold = 32767;
+                       go->modet[i].motion_threshold = 32767;
+                       go->modet[i].mb_threshold = 32767;
+               }
+
+       if (go7007_construct_fw_image(go, &fw, &fw_len) < 0)
+               return -1;
+
+       if (go7007_send_firmware(go, fw, fw_len) < 0 ||
+                       go7007_read_interrupt(go, &intr_val, &intr_data) < 0) {
+               v4l2_err(&go->v4l2_dev, "error transferring firmware\n");
+               rv = -1;
+               goto start_error;
+       }
+
+       go->state = STATE_DATA;
+       go->parse_length = 0;
+       go->seen_frame = 0;
+       if (go7007_stream_start(go) < 0) {
+               v4l2_err(&go->v4l2_dev, "error starting stream transfer\n");
+               rv = -1;
+               goto start_error;
+       }
+
+start_error:
+       kfree(fw);
+       return rv;
+}
+
+/*
+ * Store a byte in the current video buffer, if there is one.
+ */
+static inline void store_byte(struct go7007_buffer *gobuf, u8 byte)
+{
+       if (gobuf != NULL && gobuf->bytesused < GO7007_BUF_SIZE) {
+               unsigned int pgidx = gobuf->offset >> PAGE_SHIFT;
+               unsigned int pgoff = gobuf->offset & ~PAGE_MASK;
+
+               *((u8 *)page_address(gobuf->pages[pgidx]) + pgoff) = byte;
+               ++gobuf->offset;
+               ++gobuf->bytesused;
+       }
+}
+
+/*
+ * Deliver the last video buffer and get a new one to start writing to.
+ */
+static void frame_boundary(struct go7007 *go)
+{
+       struct go7007_buffer *gobuf;
+       int i;
+
+       if (go->active_buf) {
+               if (go->active_buf->modet_active) {
+                       if (go->active_buf->bytesused + 216 < GO7007_BUF_SIZE) {
+                               for (i = 0; i < 216; ++i)
+                                       store_byte(go->active_buf,
+                                                       go->active_map[i]);
+                               go->active_buf->bytesused -= 216;
+                       } else
+                               go->active_buf->modet_active = 0;
+               }
+               go->active_buf->state = BUF_STATE_DONE;
+               wake_up_interruptible(&go->frame_waitq);
+               go->active_buf = NULL;
+       }
+       list_for_each_entry(gobuf, &go->stream, stream)
+               if (gobuf->state == BUF_STATE_QUEUED) {
+                       gobuf->seq = go->next_seq;
+                       do_gettimeofday(&gobuf->timestamp);
+                       go->active_buf = gobuf;
+                       break;
+               }
+       ++go->next_seq;
+}
+
+static void write_bitmap_word(struct go7007 *go)
+{
+       int x, y, i, stride = ((go->width >> 4) + 7) >> 3;
+
+       for (i = 0; i < 16; ++i) {
+               y = (((go->parse_length - 1) << 3) + i) / (go->width >> 4);
+               x = (((go->parse_length - 1) << 3) + i) % (go->width >> 4);
+               if (stride * y + (x >> 3) < sizeof(go->active_map))
+                       go->active_map[stride * y + (x >> 3)] |=
+                                       (go->modet_word & 1) << (x & 0x7);
+               go->modet_word >>= 1;
+       }
+}
+
+/*
+ * Parse a chunk of the video stream into frames.  The frames are not
+ * delimited by the hardware, so we have to parse the frame boundaries
+ * based on the type of video stream we're receiving.
+ */
+void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
+{
+       int i, seq_start_code = -1, frame_start_code = -1;
+
+       spin_lock(&go->spinlock);
+
+       switch (go->format) {
+       case GO7007_FORMAT_MPEG4:
+               seq_start_code = 0xB0;
+               frame_start_code = 0xB6;
+               break;
+       case GO7007_FORMAT_MPEG1:
+       case GO7007_FORMAT_MPEG2:
+               seq_start_code = 0xB3;
+               frame_start_code = 0x00;
+               break;
+       }
+
+       for (i = 0; i < length; ++i) {
+               if (go->active_buf != NULL &&
+                           go->active_buf->bytesused >= GO7007_BUF_SIZE - 3) {
+                       v4l2_info(&go->v4l2_dev, "dropping oversized frame\n");
+                       go->active_buf->offset -= go->active_buf->bytesused;
+                       go->active_buf->bytesused = 0;
+                       go->active_buf->modet_active = 0;
+                       go->active_buf = NULL;
+               }
+
+               switch (go->state) {
+               case STATE_DATA:
+                       switch (buf[i]) {
+                       case 0x00:
+                               go->state = STATE_00;
+                               break;
+                       case 0xFF:
+                               go->state = STATE_FF;
+                               break;
+                       default:
+                               store_byte(go->active_buf, buf[i]);
+                               break;
+                       }
+                       break;
+               case STATE_00:
+                       switch (buf[i]) {
+                       case 0x00:
+                               go->state = STATE_00_00;
+                               break;
+                       case 0xFF:
+                               store_byte(go->active_buf, 0x00);
+                               go->state = STATE_FF;
+                               break;
+                       default:
+                               store_byte(go->active_buf, 0x00);
+                               store_byte(go->active_buf, buf[i]);
+                               go->state = STATE_DATA;
+                               break;
+                       }
+                       break;
+               case STATE_00_00:
+                       switch (buf[i]) {
+                       case 0x00:
+                               store_byte(go->active_buf, 0x00);
+                               /* go->state remains STATE_00_00 */
+                               break;
+                       case 0x01:
+                               go->state = STATE_00_00_01;
+                               break;
+                       case 0xFF:
+                               store_byte(go->active_buf, 0x00);
+                               store_byte(go->active_buf, 0x00);
+                               go->state = STATE_FF;
+                               break;
+                       default:
+                               store_byte(go->active_buf, 0x00);
+                               store_byte(go->active_buf, 0x00);
+                               store_byte(go->active_buf, buf[i]);
+                               go->state = STATE_DATA;
+                               break;
+                       }
+                       break;
+               case STATE_00_00_01:
+                       if (buf[i] == 0xF8 && go->modet_enable == 0) {
+                               /* MODET start code, but MODET not enabled */
+                               store_byte(go->active_buf, 0x00);
+                               store_byte(go->active_buf, 0x00);
+                               store_byte(go->active_buf, 0x01);
+                               store_byte(go->active_buf, 0xF8);
+                               go->state = STATE_DATA;
+                               break;
+                       }
+                       /* If this is the start of a new MPEG frame,
+                        * get a new buffer */
+                       if ((go->format == GO7007_FORMAT_MPEG1 ||
+                                       go->format == GO7007_FORMAT_MPEG2 ||
+                                       go->format == GO7007_FORMAT_MPEG4) &&
+                                       (buf[i] == seq_start_code ||
+                                               buf[i] == 0xB8 || /* GOP code */
+                                               buf[i] == frame_start_code)) {
+                               if (go->active_buf == NULL || go->seen_frame)
+                                       frame_boundary(go);
+                               if (buf[i] == frame_start_code) {
+                                       if (go->active_buf != NULL)
+                                               go->active_buf->frame_offset =
+                                                       go->active_buf->offset;
+                                       go->seen_frame = 1;
+                               } else {
+                                       go->seen_frame = 0;
+                               }
+                       }
+                       /* Handle any special chunk types, or just write the
+                        * start code to the (potentially new) buffer */
+                       switch (buf[i]) {
+                       case 0xF5: /* timestamp */
+                               go->parse_length = 12;
+                               go->state = STATE_UNPARSED;
+                               break;
+                       case 0xF6: /* vbi */
+                               go->state = STATE_VBI_LEN_A;
+                               break;
+                       case 0xF8: /* MD map */
+                               go->parse_length = 0;
+                               memset(go->active_map, 0,
+                                               sizeof(go->active_map));
+                               go->state = STATE_MODET_MAP;
+                               break;
+                       case 0xFF: /* Potential JPEG start code */
+                               store_byte(go->active_buf, 0x00);
+                               store_byte(go->active_buf, 0x00);
+                               store_byte(go->active_buf, 0x01);
+                               go->state = STATE_FF;
+                               break;
+                       default:
+                               store_byte(go->active_buf, 0x00);
+                               store_byte(go->active_buf, 0x00);
+                               store_byte(go->active_buf, 0x01);
+                               store_byte(go->active_buf, buf[i]);
+                               go->state = STATE_DATA;
+                               break;
+                       }
+                       break;
+               case STATE_FF:
+                       switch (buf[i]) {
+                       case 0x00:
+                               store_byte(go->active_buf, 0xFF);
+                               go->state = STATE_00;
+                               break;
+                       case 0xFF:
+                               store_byte(go->active_buf, 0xFF);
+                               /* go->state remains STATE_FF */
+                               break;
+                       case 0xD8:
+                               if (go->format == GO7007_FORMAT_MJPEG)
+                                       frame_boundary(go);
+                               /* fall through */
+                       default:
+                               store_byte(go->active_buf, 0xFF);
+                               store_byte(go->active_buf, buf[i]);
+                               go->state = STATE_DATA;
+                               break;
+                       }
+                       break;
+               case STATE_VBI_LEN_A:
+                       go->parse_length = buf[i] << 8;
+                       go->state = STATE_VBI_LEN_B;
+                       break;
+               case STATE_VBI_LEN_B:
+                       go->parse_length |= buf[i];
+                       if (go->parse_length > 0)
+                               go->state = STATE_UNPARSED;
+                       else
+                               go->state = STATE_DATA;
+                       break;
+               case STATE_MODET_MAP:
+                       if (go->parse_length < 204) {
+                               if (go->parse_length & 1) {
+                                       go->modet_word |= buf[i];
+                                       write_bitmap_word(go);
+                               } else
+                                       go->modet_word = buf[i] << 8;
+                       } else if (go->parse_length == 207 && go->active_buf) {
+                               go->active_buf->modet_active = buf[i];
+                       }
+                       if (++go->parse_length == 208)
+                               go->state = STATE_DATA;
+                       break;
+               case STATE_UNPARSED:
+                       if (--go->parse_length == 0)
+                               go->state = STATE_DATA;
+                       break;
+               }
+       }
+
+       spin_unlock(&go->spinlock);
+}
+EXPORT_SYMBOL(go7007_parse_video_stream);
+
+/*
+ * Allocate a new go7007 struct.  Used by the hardware-specific probe.
+ */
+struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev)
+{
+       struct go7007 *go;
+       int i;
+
+       go = kmalloc(sizeof(struct go7007), GFP_KERNEL);
+       if (go == NULL)
+               return NULL;
+       go->dev = dev;
+       go->board_info = board;
+       go->board_id = 0;
+       go->tuner_type = -1;
+       go->channel_number = 0;
+       go->name[0] = 0;
+       mutex_init(&go->hw_lock);
+       init_waitqueue_head(&go->frame_waitq);
+       spin_lock_init(&go->spinlock);
+       go->video_dev = NULL;
+       go->ref_count = 0;
+       go->status = STATUS_INIT;
+       memset(&go->i2c_adapter, 0, sizeof(go->i2c_adapter));
+       go->i2c_adapter_online = 0;
+       go->interrupt_available = 0;
+       init_waitqueue_head(&go->interrupt_waitq);
+       go->in_use = 0;
+       go->input = 0;
+       if (board->sensor_flags & GO7007_SENSOR_TV) {
+               go->standard = GO7007_STD_NTSC;
+               go->width = 720;
+               go->height = 480;
+               go->sensor_framerate = 30000;
+       } else {
+               go->standard = GO7007_STD_OTHER;
+               go->width = board->sensor_width;
+               go->height = board->sensor_height;
+               go->sensor_framerate = board->sensor_framerate;
+       }
+       go->encoder_v_offset = board->sensor_v_offset;
+       go->encoder_h_offset = board->sensor_h_offset;
+       go->encoder_h_halve = 0;
+       go->encoder_v_halve = 0;
+       go->encoder_subsample = 0;
+       go->streaming = 0;
+       go->format = GO7007_FORMAT_MJPEG;
+       go->bitrate = 1500000;
+       go->fps_scale = 1;
+       go->pali = 0;
+       go->aspect_ratio = GO7007_RATIO_1_1;
+       go->gop_size = 0;
+       go->ipb = 0;
+       go->closed_gop = 0;
+       go->repeat_seqhead = 0;
+       go->seq_header_enable = 0;
+       go->gop_header_enable = 0;
+       go->dvd_mode = 0;
+       go->interlace_coding = 0;
+       for (i = 0; i < 4; ++i)
+               go->modet[i].enable = 0;
+       for (i = 0; i < 1624; ++i)
+               go->modet_map[i] = 0;
+       go->audio_deliver = NULL;
+       go->audio_enabled = 0;
+       INIT_LIST_HEAD(&go->stream);
+
+       return go;
+}
+EXPORT_SYMBOL(go7007_alloc);
+
+/*
+ * Detach and unregister the encoder.  The go7007 struct won't be freed
+ * until v4l2 finishes releasing its resources and all associated fds are
+ * closed by applications.
+ */
+void go7007_remove(struct go7007 *go)
+{
+       if (go->i2c_adapter_online) {
+               if (i2c_del_adapter(&go->i2c_adapter) == 0)
+                       go->i2c_adapter_online = 0;
+               else
+                       v4l2_err(&go->v4l2_dev,
+                               "error removing I2C adapter!\n");
+       }
+
+       if (go->audio_enabled)
+               go7007_snd_remove(go);
+       go7007_v4l2_remove(go);
+}
+EXPORT_SYMBOL(go7007_remove);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/go7007-fw.c b/drivers/staging/media/go7007/go7007-fw.c
new file mode 100644 (file)
index 0000000..c9a6409
--- /dev/null
@@ -0,0 +1,1636 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+/*
+ * This file contains code to generate a firmware image for the GO7007SB
+ * encoder.  Much of the firmware is read verbatim from a file, but some of
+ * it concerning bitrate control and other things that can be configured at
+ * run-time are generated dynamically.  Note that the format headers
+ * generated here do not affect the functioning of the encoder; they are
+ * merely parroted back to the host at the start of each frame.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <asm/byteorder.h>
+
+#include "go7007-priv.h"
+
+/* Constants used in the source firmware image to describe code segments */
+
+#define        FLAG_MODE_MJPEG         (1)
+#define        FLAG_MODE_MPEG1         (1<<1)
+#define        FLAG_MODE_MPEG2         (1<<2)
+#define        FLAG_MODE_MPEG4         (1<<3)
+#define        FLAG_MODE_H263          (1<<4)
+#define FLAG_MODE_ALL          (FLAG_MODE_MJPEG | FLAG_MODE_MPEG1 | \
+                                       FLAG_MODE_MPEG2 | FLAG_MODE_MPEG4 | \
+                                       FLAG_MODE_H263)
+#define FLAG_SPECIAL           (1<<8)
+
+#define SPECIAL_FRM_HEAD       0
+#define SPECIAL_BRC_CTRL       1
+#define SPECIAL_CONFIG         2
+#define SPECIAL_SEQHEAD                3
+#define SPECIAL_AV_SYNC                4
+#define SPECIAL_FINAL          5
+#define SPECIAL_AUDIO          6
+#define SPECIAL_MODET          7
+
+/* Little data class for creating MPEG headers bit-by-bit */
+
+struct code_gen {
+       unsigned char *p; /* destination */
+       u32 a; /* collects bits at the top of the variable */
+       int b; /* bit position of most recently-written bit */
+       int len; /* written out so far */
+};
+
+#define CODE_GEN(name, dest) struct code_gen name = { dest, 0, 32, 0 }
+
+#define CODE_ADD(name, val, length) do { \
+       name.b -= (length); \
+       name.a |= (val) << name.b; \
+       while (name.b <= 24) { \
+               *name.p = name.a >> 24; \
+               ++name.p; \
+               name.a <<= 8; \
+               name.b += 8; \
+               name.len += 8; \
+       } \
+} while (0)
+
+#define CODE_LENGTH(name) (name.len + (32 - name.b))
+
+/* Tables for creating the bitrate control data */
+
+static const s16 converge_speed_ip[101] = {
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+       2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
+       3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
+       5, 5, 5, 6, 6, 6, 7, 7, 8, 8,
+       9, 10, 10, 11, 12, 13, 14, 15, 16, 17,
+       19, 20, 22, 23, 25, 27, 30, 32, 35, 38,
+       41, 45, 49, 53, 58, 63, 69, 76, 83, 91,
+       100
+};
+
+static const s16 converge_speed_ipb[101] = {
+       3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+       3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+       3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
+       4, 4, 4, 4, 5, 5, 5, 5, 5, 6,
+       6, 6, 6, 7, 7, 7, 7, 8, 8, 9,
+       9, 9, 10, 10, 11, 12, 12, 13, 14, 14,
+       15, 16, 17, 18, 19, 20, 22, 23, 25, 26,
+       28, 30, 32, 34, 37, 40, 42, 46, 49, 53,
+       57, 61, 66, 71, 77, 83, 90, 97, 106, 115,
+       125, 135, 147, 161, 175, 191, 209, 228, 249, 273,
+       300
+};
+
+static const s16 LAMBDA_table[4][101] = {
+       {       16, 16, 16, 16, 17, 17, 17, 18, 18, 18,
+               19, 19, 19, 20, 20, 20, 21, 21, 22, 22,
+               22, 23, 23, 24, 24, 25, 25, 25, 26, 26,
+               27, 27, 28, 28, 29, 29, 30, 31, 31, 32,
+               32, 33, 33, 34, 35, 35, 36, 37, 37, 38,
+               39, 39, 40, 41, 42, 42, 43, 44, 45, 46,
+               46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+               56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+               67, 68, 69, 70, 72, 73, 74, 76, 77, 78,
+               80, 81, 83, 84, 86, 87, 89, 90, 92, 94,
+               96
+       },
+       {
+               20, 20, 20, 21, 21, 21, 22, 22, 23, 23,
+               23, 24, 24, 25, 25, 26, 26, 27, 27, 28,
+               28, 29, 29, 30, 30, 31, 31, 32, 33, 33,
+               34, 34, 35, 36, 36, 37, 38, 38, 39, 40,
+               40, 41, 42, 43, 43, 44, 45, 46, 47, 48,
+               48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+               58, 59, 60, 61, 62, 64, 65, 66, 67, 68,
+               70, 71, 72, 73, 75, 76, 78, 79, 80, 82,
+               83, 85, 86, 88, 90, 91, 93, 95, 96, 98,
+               100, 102, 103, 105, 107, 109, 111, 113, 115, 117,
+               120
+       },
+       {
+               24, 24, 24, 25, 25, 26, 26, 27, 27, 28,
+               28, 29, 29, 30, 30, 31, 31, 32, 33, 33,
+               34, 34, 35, 36, 36, 37, 38, 38, 39, 40,
+               41, 41, 42, 43, 44, 44, 45, 46, 47, 48,
+               49, 50, 50, 51, 52, 53, 54, 55, 56, 57,
+               58, 59, 60, 62, 63, 64, 65, 66, 67, 69,
+               70, 71, 72, 74, 75, 76, 78, 79, 81, 82,
+               84, 85, 87, 88, 90, 92, 93, 95, 97, 98,
+               100, 102, 104, 106, 108, 110, 112, 114, 116, 118,
+               120, 122, 124, 127, 129, 131, 134, 136, 138, 141,
+               144
+       },
+       {
+               32, 32, 33, 33, 34, 34, 35, 36, 36, 37,
+               38, 38, 39, 40, 41, 41, 42, 43, 44, 44,
+               45, 46, 47, 48, 49, 50, 50, 51, 52, 53,
+               54, 55, 56, 57, 58, 59, 60, 62, 63, 64,
+               65, 66, 67, 69, 70, 71, 72, 74, 75, 76,
+               78, 79, 81, 82, 84, 85, 87, 88, 90, 92,
+               93, 95, 97, 98, 100, 102, 104, 106, 108, 110,
+               112, 114, 116, 118, 120, 122, 124, 127, 129, 131,
+               134, 136, 139, 141, 144, 146, 149, 152, 154, 157,
+               160, 163, 166, 169, 172, 175, 178, 181, 185, 188,
+               192
+       }
+};
+
+/* MPEG blank frame generation tables */
+
+enum mpeg_frame_type {
+       PFRAME,
+       BFRAME_PRE,
+       BFRAME_POST,
+       BFRAME_BIDIR,
+       BFRAME_EMPTY
+};
+
+static const u32 addrinctab[33][2] = {
+       { 0x01, 1 },    { 0x03, 3 },    { 0x02, 3 },    { 0x03, 4 },
+       { 0x02, 4 },    { 0x03, 5 },    { 0x02, 5 },    { 0x07, 7 },
+       { 0x06, 7 },    { 0x0b, 8 },    { 0x0a, 8 },    { 0x09, 8 },
+       { 0x08, 8 },    { 0x07, 8 },    { 0x06, 8 },    { 0x17, 10 },
+       { 0x16, 10 },   { 0x15, 10 },   { 0x14, 10 },   { 0x13, 10 },
+       { 0x12, 10 },   { 0x23, 11 },   { 0x22, 11 },   { 0x21, 11 },
+       { 0x20, 11 },   { 0x1f, 11 },   { 0x1e, 11 },   { 0x1d, 11 },
+       { 0x1c, 11 },   { 0x1b, 11 },   { 0x1a, 11 },   { 0x19, 11 },
+       { 0x18, 11 }
+};
+
+/* Standard JPEG tables */
+
+static const u8 default_intra_quant_table[] = {
+        8, 16, 19, 22, 26, 27, 29, 34,
+       16, 16, 22, 24, 27, 29, 34, 37,
+       19, 22, 26, 27, 29, 34, 34, 38,
+       22, 22, 26, 27, 29, 34, 37, 40,
+       22, 26, 27, 29, 32, 35, 40, 48,
+       26, 27, 29, 32, 35, 40, 48, 58,
+       26, 27, 29, 34, 38, 46, 56, 69,
+       27, 29, 35, 38, 46, 56, 69, 83
+};
+
+static const u8 bits_dc_luminance[] = {
+       0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const u8 val_dc_luminance[] = {
+       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const u8 bits_dc_chrominance[] = {
+       0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
+};
+
+static const u8 val_dc_chrominance[] = {
+       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const u8 bits_ac_luminance[] = {
+       0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
+};
+
+static const u8 val_ac_luminance[] = {
+       0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+       0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+       0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+       0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+       0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+       0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+       0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+       0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+       0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+       0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+       0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+       0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+       0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+       0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+       0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+       0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+       0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+       0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+       0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+       0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+       0xf9, 0xfa
+};
+
+static const u8 bits_ac_chrominance[] = {
+       0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
+};
+
+static const u8 val_ac_chrominance[] = {
+       0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+       0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+       0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+       0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+       0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+       0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+       0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+       0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+       0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+       0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+       0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+       0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+       0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+       0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+       0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+       0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+       0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+       0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+       0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+       0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+       0xf9, 0xfa
+};
+
+/* Zig-zag mapping for quant table
+ *
+ * OK, let's do this mapping on the actual table above so it doesn't have
+ * to be done on the fly.
+ */
+static const int zz[64] = {
+       0,   1,  8, 16,  9,  2,  3, 10, 17, 24, 32, 25, 18, 11,  4,  5,
+       12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13,  6,  7, 14, 21, 28,
+       35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
+       58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
+};
+
+static int copy_packages(__le16 *dest, u16 *src, int pkg_cnt, int space)
+{
+       int i, cnt = pkg_cnt * 32;
+
+       if (space < cnt)
+               return -1;
+
+       for (i = 0; i < cnt; ++i)
+               dest[i] = cpu_to_le16p(src + i);
+
+       return cnt;
+}
+
+static int mjpeg_frame_header(struct go7007 *go, unsigned char *buf, int q)
+{
+       int i, p = 0;
+
+       buf[p++] = 0xff;
+       buf[p++] = 0xd8;
+       buf[p++] = 0xff;
+       buf[p++] = 0xdb;
+       buf[p++] = 0;
+       buf[p++] = 2 + 65;
+       buf[p++] = 0;
+       buf[p++] = default_intra_quant_table[0];
+       for (i = 1; i < 64; ++i)
+               /* buf[p++] = (default_intra_quant_table[i] * q) >> 3; */
+               buf[p++] = (default_intra_quant_table[zz[i]] * q) >> 3;
+       buf[p++] = 0xff;
+       buf[p++] = 0xc0;
+       buf[p++] = 0;
+       buf[p++] = 17;
+       buf[p++] = 8;
+       buf[p++] = go->height >> 8;
+       buf[p++] = go->height & 0xff;
+       buf[p++] = go->width >> 8;
+       buf[p++] = go->width & 0xff;
+       buf[p++] = 3;
+       buf[p++] = 1;
+       buf[p++] = 0x22;
+       buf[p++] = 0;
+       buf[p++] = 2;
+       buf[p++] = 0x11;
+       buf[p++] = 0;
+       buf[p++] = 3;
+       buf[p++] = 0x11;
+       buf[p++] = 0;
+       buf[p++] = 0xff;
+       buf[p++] = 0xc4;
+       buf[p++] = 418 >> 8;
+       buf[p++] = 418 & 0xff;
+       buf[p++] = 0x00;
+       memcpy(buf + p, bits_dc_luminance + 1, 16);
+       p += 16;
+       memcpy(buf + p, val_dc_luminance, sizeof(val_dc_luminance));
+       p += sizeof(val_dc_luminance);
+       buf[p++] = 0x01;
+       memcpy(buf + p, bits_dc_chrominance + 1, 16);
+       p += 16;
+       memcpy(buf + p, val_dc_chrominance, sizeof(val_dc_chrominance));
+       p += sizeof(val_dc_chrominance);
+       buf[p++] = 0x10;
+       memcpy(buf + p, bits_ac_luminance + 1, 16);
+       p += 16;
+       memcpy(buf + p, val_ac_luminance, sizeof(val_ac_luminance));
+       p += sizeof(val_ac_luminance);
+       buf[p++] = 0x11;
+       memcpy(buf + p, bits_ac_chrominance + 1, 16);
+       p += 16;
+       memcpy(buf + p, val_ac_chrominance, sizeof(val_ac_chrominance));
+       p += sizeof(val_ac_chrominance);
+       buf[p++] = 0xff;
+       buf[p++] = 0xda;
+       buf[p++] = 0;
+       buf[p++] = 12;
+       buf[p++] = 3;
+       buf[p++] = 1;
+       buf[p++] = 0x00;
+       buf[p++] = 2;
+       buf[p++] = 0x11;
+       buf[p++] = 3;
+       buf[p++] = 0x11;
+       buf[p++] = 0;
+       buf[p++] = 63;
+       buf[p++] = 0;
+       return p;
+}
+
+static int gen_mjpeghdr_to_package(struct go7007 *go, __le16 *code, int space)
+{
+       u8 *buf;
+       u16 mem = 0x3e00;
+       unsigned int addr = 0x19;
+       int size = 0, i, off = 0, chunk;
+
+       buf = kzalloc(4096, GFP_KERNEL);
+       if (buf == NULL) {
+               printk(KERN_ERR "go7007: unable to allocate 4096 bytes for "
+                               "firmware construction\n");
+               return -1;
+       }
+
+       for (i = 1; i < 32; ++i) {
+               mjpeg_frame_header(go, buf + size, i);
+               size += 80;
+       }
+       chunk = mjpeg_frame_header(go, buf + size, 1);
+       memmove(buf + size, buf + size + 80, chunk - 80);
+       size += chunk - 80;
+
+       for (i = 0; i < size; i += chunk * 2) {
+               if (space - off < 32) {
+                       off = -1;
+                       goto done;
+               }
+
+               code[off + 1] = __cpu_to_le16(0x8000 | mem);
+
+               chunk = 28;
+               if (mem + chunk > 0x4000)
+                       chunk = 0x4000 - mem;
+               if (i + 2 * chunk > size)
+                       chunk = (size - i) / 2;
+
+               if (chunk < 28) {
+                       code[off] = __cpu_to_le16(0x4000 | chunk);
+                       code[off + 31] = __cpu_to_le16(addr++);
+                       mem = 0x3e00;
+               } else {
+                       code[off] = __cpu_to_le16(0x1000 | 28);
+                       code[off + 31] = 0;
+                       mem += 28;
+               }
+
+               memcpy(&code[off + 2], buf + i, chunk * 2);
+               off += 32;
+       }
+done:
+       kfree(buf);
+       return off;
+}
+
+static int mpeg1_frame_header(struct go7007 *go, unsigned char *buf,
+               int modulo, int pict_struct, enum mpeg_frame_type frame)
+{
+       int i, j, mb_code, mb_len;
+       int rows = go->interlace_coding ? go->height / 32 : go->height / 16;
+       CODE_GEN(c, buf + 6);
+
+       switch (frame) {
+       case PFRAME:
+               mb_code = 0x1;
+               mb_len = 3;
+               break;
+       case BFRAME_PRE:
+               mb_code = 0x2;
+               mb_len = 4;
+               break;
+       case BFRAME_POST:
+               mb_code = 0x2;
+               mb_len = 3;
+               break;
+       case BFRAME_BIDIR:
+               mb_code = 0x2;
+               mb_len = 2;
+               break;
+       default: /* keep the compiler happy */
+               mb_code = mb_len = 0;
+               break;
+       }
+
+       CODE_ADD(c, frame == PFRAME ? 0x2 : 0x3, 13);
+       CODE_ADD(c, 0xffff, 16);
+       CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4);
+       if (frame != PFRAME)
+               CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4);
+       else
+               CODE_ADD(c, 0, 4); /* Is this supposed to be here?? */
+       CODE_ADD(c, 0, 3); /* What is this?? */
+       /* Byte-align with zeros */
+       j = 8 - (CODE_LENGTH(c) % 8);
+       if (j != 8)
+               CODE_ADD(c, 0, j);
+
+       if (go->format == GO7007_FORMAT_MPEG2) {
+               CODE_ADD(c, 0x1, 24);
+               CODE_ADD(c, 0xb5, 8);
+               CODE_ADD(c, 0x844, 12);
+               CODE_ADD(c, frame == PFRAME ? 0xff : 0x44, 8);
+               if (go->interlace_coding) {
+                       CODE_ADD(c, pict_struct, 4);
+                       if (go->dvd_mode)
+                               CODE_ADD(c, 0x000, 11);
+                       else
+                               CODE_ADD(c, 0x200, 11);
+               } else {
+                       CODE_ADD(c, 0x3, 4);
+                       CODE_ADD(c, 0x20c, 11);
+               }
+               /* Byte-align with zeros */
+               j = 8 - (CODE_LENGTH(c) % 8);
+               if (j != 8)
+                       CODE_ADD(c, 0, j);
+       }
+
+       for (i = 0; i < rows; ++i) {
+               CODE_ADD(c, 1, 24);
+               CODE_ADD(c, i + 1, 8);
+               CODE_ADD(c, 0x2, 6);
+               CODE_ADD(c, 0x1, 1);
+               CODE_ADD(c, mb_code, mb_len);
+               if (go->interlace_coding) {
+                       CODE_ADD(c, 0x1, 2);
+                       CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1);
+               }
+               if (frame == BFRAME_BIDIR) {
+                       CODE_ADD(c, 0x3, 2);
+                       if (go->interlace_coding)
+                               CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1);
+               }
+               CODE_ADD(c, 0x3, 2);
+               for (j = (go->width >> 4) - 2; j >= 33; j -= 33)
+                       CODE_ADD(c, 0x8, 11);
+               CODE_ADD(c, addrinctab[j][0], addrinctab[j][1]);
+               CODE_ADD(c, mb_code, mb_len);
+               if (go->interlace_coding) {
+                       CODE_ADD(c, 0x1, 2);
+                       CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1);
+               }
+               if (frame == BFRAME_BIDIR) {
+                       CODE_ADD(c, 0x3, 2);
+                       if (go->interlace_coding)
+                               CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1);
+               }
+               CODE_ADD(c, 0x3, 2);
+
+               /* Byte-align with zeros */
+               j = 8 - (CODE_LENGTH(c) % 8);
+               if (j != 8)
+                       CODE_ADD(c, 0, j);
+       }
+
+       i = CODE_LENGTH(c) + 4 * 8;
+       buf[2] = 0x00;
+       buf[3] = 0x00;
+       buf[4] = 0x01;
+       buf[5] = 0x00;
+       return i;
+}
+
+static int mpeg1_sequence_header(struct go7007 *go, unsigned char *buf, int ext)
+{
+       int i, aspect_ratio, picture_rate;
+       CODE_GEN(c, buf + 6);
+
+       if (go->format == GO7007_FORMAT_MPEG1) {
+               switch (go->aspect_ratio) {
+               case GO7007_RATIO_4_3:
+                       aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2;
+                       break;
+               case GO7007_RATIO_16_9:
+                       aspect_ratio = go->standard == GO7007_STD_NTSC ? 5 : 4;
+                       break;
+               default:
+                       aspect_ratio = 1;
+                       break;
+               }
+       } else {
+               switch (go->aspect_ratio) {
+               case GO7007_RATIO_4_3:
+                       aspect_ratio = 2;
+                       break;
+               case GO7007_RATIO_16_9:
+                       aspect_ratio = 3;
+                       break;
+               default:
+                       aspect_ratio = 1;
+                       break;
+               }
+       }
+       switch (go->sensor_framerate) {
+       case 24000:
+               picture_rate = 1;
+               break;
+       case 24024:
+               picture_rate = 2;
+               break;
+       case 25025:
+               picture_rate = go->interlace_coding ? 6 : 3;
+               break;
+       case 30000:
+               picture_rate = go->interlace_coding ? 7 : 4;
+               break;
+       case 30030:
+               picture_rate = go->interlace_coding ? 8 : 5;
+               break;
+       default:
+               picture_rate = 5; /* 30 fps seems like a reasonable default */
+               break;
+       }
+
+       CODE_ADD(c, go->width, 12);
+       CODE_ADD(c, go->height, 12);
+       CODE_ADD(c, aspect_ratio, 4);
+       CODE_ADD(c, picture_rate, 4);
+       CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 20000 : 0x3ffff, 18);
+       CODE_ADD(c, 1, 1);
+       CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 112 : 20, 10);
+       CODE_ADD(c, 0, 3);
+
+       /* Byte-align with zeros */
+       i = 8 - (CODE_LENGTH(c) % 8);
+       if (i != 8)
+               CODE_ADD(c, 0, i);
+
+       if (go->format == GO7007_FORMAT_MPEG2) {
+               CODE_ADD(c, 0x1, 24);
+               CODE_ADD(c, 0xb5, 8);
+               CODE_ADD(c, 0x148, 12);
+               if (go->interlace_coding)
+                       CODE_ADD(c, 0x20001, 20);
+               else
+                       CODE_ADD(c, 0xa0001, 20);
+               CODE_ADD(c, 0, 16);
+
+               /* Byte-align with zeros */
+               i = 8 - (CODE_LENGTH(c) % 8);
+               if (i != 8)
+                       CODE_ADD(c, 0, i);
+
+               if (ext) {
+                       CODE_ADD(c, 0x1, 24);
+                       CODE_ADD(c, 0xb52, 12);
+                       CODE_ADD(c, go->standard == GO7007_STD_NTSC ? 2 : 1, 3);
+                       CODE_ADD(c, 0x105, 9);
+                       CODE_ADD(c, 0x505, 16);
+                       CODE_ADD(c, go->width, 14);
+                       CODE_ADD(c, 1, 1);
+                       CODE_ADD(c, go->height, 14);
+
+                       /* Byte-align with zeros */
+                       i = 8 - (CODE_LENGTH(c) % 8);
+                       if (i != 8)
+                               CODE_ADD(c, 0, i);
+               }
+       }
+
+       i = CODE_LENGTH(c) + 4 * 8;
+       buf[0] = i & 0xff;
+       buf[1] = i >> 8;
+       buf[2] = 0x00;
+       buf[3] = 0x00;
+       buf[4] = 0x01;
+       buf[5] = 0xb3;
+       return i;
+}
+
+static int gen_mpeg1hdr_to_package(struct go7007 *go,
+                                       __le16 *code, int space, int *framelen)
+{
+       u8 *buf;
+       u16 mem = 0x3e00;
+       unsigned int addr = 0x19;
+       int i, off = 0, chunk;
+
+       buf = kzalloc(5120, GFP_KERNEL);
+       if (buf == NULL) {
+               printk(KERN_ERR "go7007: unable to allocate 5120 bytes for "
+                               "firmware construction\n");
+               return -1;
+       }
+       framelen[0] = mpeg1_frame_header(go, buf, 0, 1, PFRAME);
+       if (go->interlace_coding)
+               framelen[0] += mpeg1_frame_header(go, buf + framelen[0] / 8,
+                                                       0, 2, PFRAME);
+       buf[0] = framelen[0] & 0xff;
+       buf[1] = framelen[0] >> 8;
+       i = 368;
+       framelen[1] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_PRE);
+       if (go->interlace_coding)
+               framelen[1] += mpeg1_frame_header(go, buf + i + framelen[1] / 8,
+                                                       0, 2, BFRAME_PRE);
+       buf[i] = framelen[1] & 0xff;
+       buf[i + 1] = framelen[1] >> 8;
+       i += 1632;
+       framelen[2] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_POST);
+       if (go->interlace_coding)
+               framelen[2] += mpeg1_frame_header(go, buf + i + framelen[2] / 8,
+                                                       0, 2, BFRAME_POST);
+       buf[i] = framelen[2] & 0xff;
+       buf[i + 1] = framelen[2] >> 8;
+       i += 1432;
+       framelen[3] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_BIDIR);
+       if (go->interlace_coding)
+               framelen[3] += mpeg1_frame_header(go, buf + i + framelen[3] / 8,
+                                                       0, 2, BFRAME_BIDIR);
+       buf[i] = framelen[3] & 0xff;
+       buf[i + 1] = framelen[3] >> 8;
+       i += 1632 + 16;
+       mpeg1_sequence_header(go, buf + i, 0);
+       i += 40;
+       for (i = 0; i < 5120; i += chunk * 2) {
+               if (space - off < 32) {
+                       off = -1;
+                       goto done;
+               }
+
+               code[off + 1] = __cpu_to_le16(0x8000 | mem);
+
+               chunk = 28;
+               if (mem + chunk > 0x4000)
+                       chunk = 0x4000 - mem;
+               if (i + 2 * chunk > 5120)
+                       chunk = (5120 - i) / 2;
+
+               if (chunk < 28) {
+                       code[off] = __cpu_to_le16(0x4000 | chunk);
+                       code[off + 31] = __cpu_to_le16(addr);
+                       if (mem + chunk == 0x4000) {
+                               mem = 0x3e00;
+                               ++addr;
+                       }
+               } else {
+                       code[off] = __cpu_to_le16(0x1000 | 28);
+                       code[off + 31] = 0;
+                       mem += 28;
+               }
+
+               memcpy(&code[off + 2], buf + i, chunk * 2);
+               off += 32;
+       }
+done:
+       kfree(buf);
+       return off;
+}
+
+static int vti_bitlen(struct go7007 *go)
+{
+       unsigned int i, max_time_incr = go->sensor_framerate / go->fps_scale;
+
+       for (i = 31; (max_time_incr & ((1 << i) - 1)) == max_time_incr; --i);
+       return i + 1;
+}
+
+static int mpeg4_frame_header(struct go7007 *go, unsigned char *buf,
+               int modulo, enum mpeg_frame_type frame)
+{
+       int i;
+       CODE_GEN(c, buf + 6);
+       int mb_count = (go->width >> 4) * (go->height >> 4);
+
+       CODE_ADD(c, frame == PFRAME ? 0x1 : 0x2, 2);
+       if (modulo)
+               CODE_ADD(c, 0x1, 1);
+       CODE_ADD(c, 0x1, 2);
+       CODE_ADD(c, 0, vti_bitlen(go));
+       CODE_ADD(c, 0x3, 2);
+       if (frame == PFRAME)
+               CODE_ADD(c, 0, 1);
+       CODE_ADD(c, 0xc, 11);
+       if (frame != PFRAME)
+               CODE_ADD(c, 0x4, 3);
+       if (frame != BFRAME_EMPTY) {
+               for (i = 0; i < mb_count; ++i) {
+                       switch (frame) {
+                       case PFRAME:
+                               CODE_ADD(c, 0x1, 1);
+                               break;
+                       case BFRAME_PRE:
+                               CODE_ADD(c, 0x47, 8);
+                               break;
+                       case BFRAME_POST:
+                               CODE_ADD(c, 0x27, 7);
+                               break;
+                       case BFRAME_BIDIR:
+                               CODE_ADD(c, 0x5f, 8);
+                               break;
+                       case BFRAME_EMPTY: /* keep compiler quiet */
+                               break;
+                       }
+               }
+       }
+
+       /* Byte-align with a zero followed by ones */
+       i = 8 - (CODE_LENGTH(c) % 8);
+       CODE_ADD(c, 0, 1);
+       CODE_ADD(c, (1 << (i - 1)) - 1, i - 1);
+
+       i = CODE_LENGTH(c) + 4 * 8;
+       buf[0] = i & 0xff;
+       buf[1] = i >> 8;
+       buf[2] = 0x00;
+       buf[3] = 0x00;
+       buf[4] = 0x01;
+       buf[5] = 0xb6;
+       return i;
+}
+
+static int mpeg4_sequence_header(struct go7007 *go, unsigned char *buf, int ext)
+{
+       const unsigned char head[] = { 0x00, 0x00, 0x01, 0xb0, go->pali,
+               0x00, 0x00, 0x01, 0xb5, 0x09,
+               0x00, 0x00, 0x01, 0x00,
+               0x00, 0x00, 0x01, 0x20, };
+       int i, aspect_ratio;
+       int fps = go->sensor_framerate / go->fps_scale;
+       CODE_GEN(c, buf + 2 + sizeof(head));
+
+       switch (go->aspect_ratio) {
+       case GO7007_RATIO_4_3:
+               aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2;
+               break;
+       case GO7007_RATIO_16_9:
+               aspect_ratio = go->standard == GO7007_STD_NTSC ? 5 : 4;
+               break;
+       default:
+               aspect_ratio = 1;
+               break;
+       }
+
+       memcpy(buf + 2, head, sizeof(head));
+       CODE_ADD(c, 0x191, 17);
+       CODE_ADD(c, aspect_ratio, 4);
+       CODE_ADD(c, 0x1, 4);
+       CODE_ADD(c, fps, 16);
+       CODE_ADD(c, 0x3, 2);
+       CODE_ADD(c, 1001, vti_bitlen(go));
+       CODE_ADD(c, 1, 1);
+       CODE_ADD(c, go->width, 13);
+       CODE_ADD(c, 1, 1);
+       CODE_ADD(c, go->height, 13);
+       CODE_ADD(c, 0x2830, 14);
+
+       /* Byte-align */
+       i = 8 - (CODE_LENGTH(c) % 8);
+       CODE_ADD(c, 0, 1);
+       CODE_ADD(c, (1 << (i - 1)) - 1, i - 1);
+
+       i = CODE_LENGTH(c) + sizeof(head) * 8;
+       buf[0] = i & 0xff;
+       buf[1] = i >> 8;
+       return i;
+}
+
+static int gen_mpeg4hdr_to_package(struct go7007 *go,
+                                       __le16 *code, int space, int *framelen)
+{
+       u8 *buf;
+       u16 mem = 0x3e00;
+       unsigned int addr = 0x19;
+       int i, off = 0, chunk;
+
+       buf = kzalloc(5120, GFP_KERNEL);
+       if (buf == NULL) {
+               printk(KERN_ERR "go7007: unable to allocate 5120 bytes for "
+                               "firmware construction\n");
+               return -1;
+       }
+       framelen[0] = mpeg4_frame_header(go, buf, 0, PFRAME);
+       i = 368;
+       framelen[1] = mpeg4_frame_header(go, buf + i, 0, BFRAME_PRE);
+       i += 1632;
+       framelen[2] = mpeg4_frame_header(go, buf + i, 0, BFRAME_POST);
+       i += 1432;
+       framelen[3] = mpeg4_frame_header(go, buf + i, 0, BFRAME_BIDIR);
+       i += 1632;
+       mpeg4_frame_header(go, buf + i, 0, BFRAME_EMPTY);
+       i += 16;
+       mpeg4_sequence_header(go, buf + i, 0);
+       i += 40;
+       for (i = 0; i < 5120; i += chunk * 2) {
+               if (space - off < 32) {
+                       off = -1;
+                       goto done;
+               }
+
+               code[off + 1] = __cpu_to_le16(0x8000 | mem);
+
+               chunk = 28;
+               if (mem + chunk > 0x4000)
+                       chunk = 0x4000 - mem;
+               if (i + 2 * chunk > 5120)
+                       chunk = (5120 - i) / 2;
+
+               if (chunk < 28) {
+                       code[off] = __cpu_to_le16(0x4000 | chunk);
+                       code[off + 31] = __cpu_to_le16(addr);
+                       if (mem + chunk == 0x4000) {
+                               mem = 0x3e00;
+                               ++addr;
+                       }
+               } else {
+                       code[off] = __cpu_to_le16(0x1000 | 28);
+                       code[off + 31] = 0;
+                       mem += 28;
+               }
+
+               memcpy(&code[off + 2], buf + i, chunk * 2);
+               off += 32;
+       }
+       mem = 0x3e00;
+       addr = go->ipb ? 0x14f9 : 0x0af9;
+       memset(buf, 0, 5120);
+       framelen[4] = mpeg4_frame_header(go, buf, 1, PFRAME);
+       i = 368;
+       framelen[5] = mpeg4_frame_header(go, buf + i, 1, BFRAME_PRE);
+       i += 1632;
+       framelen[6] = mpeg4_frame_header(go, buf + i, 1, BFRAME_POST);
+       i += 1432;
+       framelen[7] = mpeg4_frame_header(go, buf + i, 1, BFRAME_BIDIR);
+       i += 1632;
+       mpeg4_frame_header(go, buf + i, 1, BFRAME_EMPTY);
+       i += 16;
+       for (i = 0; i < 5120; i += chunk * 2) {
+               if (space - off < 32) {
+                       off = -1;
+                       goto done;
+               }
+
+               code[off + 1] = __cpu_to_le16(0x8000 | mem);
+
+               chunk = 28;
+               if (mem + chunk > 0x4000)
+                       chunk = 0x4000 - mem;
+               if (i + 2 * chunk > 5120)
+                       chunk = (5120 - i) / 2;
+
+               if (chunk < 28) {
+                       code[off] = __cpu_to_le16(0x4000 | chunk);
+                       code[off + 31] = __cpu_to_le16(addr);
+                       if (mem + chunk == 0x4000) {
+                               mem = 0x3e00;
+                               ++addr;
+                       }
+               } else {
+                       code[off] = __cpu_to_le16(0x1000 | 28);
+                       code[off + 31] = 0;
+                       mem += 28;
+               }
+
+               memcpy(&code[off + 2], buf + i, chunk * 2);
+               off += 32;
+       }
+done:
+       kfree(buf);
+       return off;
+}
+
+static int brctrl_to_package(struct go7007 *go,
+                                       __le16 *code, int space, int *framelen)
+{
+       int converge_speed = 0;
+       int lambda = (go->format == GO7007_FORMAT_MJPEG || go->dvd_mode) ?
+                               100 : 0;
+       int peak_rate = 6 * go->bitrate / 5;
+       int vbv_buffer = go->format == GO7007_FORMAT_MJPEG ?
+                               go->bitrate :
+                               (go->dvd_mode ? 900000 : peak_rate);
+       int fps = go->sensor_framerate / go->fps_scale;
+       int q = 0;
+       /* Bizarre math below depends on rounding errors in division */
+       u32 sgop_expt_addr = go->bitrate / 32 * (go->ipb ? 3 : 1) * 1001 / fps;
+       u32 sgop_peak_addr = peak_rate / 32 * 1001 / fps;
+       u32 total_expt_addr = go->bitrate / 32 * 1000 / fps * (fps / 1000);
+       u32 vbv_alert_addr = vbv_buffer * 3 / (4 * 32);
+       u32 cplx[] = {
+               q > 0 ? sgop_expt_addr * q :
+                       2 * go->width * go->height * (go->ipb ? 6 : 4) / 32,
+               q > 0 ? sgop_expt_addr * q :
+                       2 * go->width * go->height * (go->ipb ? 6 : 4) / 32,
+               q > 0 ? sgop_expt_addr * q :
+                       2 * go->width * go->height * (go->ipb ? 6 : 4) / 32,
+               q > 0 ? sgop_expt_addr * q :
+                       2 * go->width * go->height * (go->ipb ? 6 : 4) / 32,
+       };
+       u32 calc_q = q > 0 ? q : cplx[0] / sgop_expt_addr;
+       u16 pack[] = {
+               0x200e,         0x0000,
+               0xBF20,         go->ipb ? converge_speed_ipb[converge_speed]
+                                       : converge_speed_ip[converge_speed],
+               0xBF21,         go->ipb ? 2 : 0,
+               0xBF22,         go->ipb ? LAMBDA_table[0][lambda / 2 + 50]
+                                       : 32767,
+               0xBF23,         go->ipb ? LAMBDA_table[1][lambda] : 32767,
+               0xBF24,         32767,
+               0xBF25,         lambda > 99 ? 32767 : LAMBDA_table[3][lambda],
+               0xBF26,         sgop_expt_addr & 0x0000FFFF,
+               0xBF27,         sgop_expt_addr >> 16,
+               0xBF28,         sgop_peak_addr & 0x0000FFFF,
+               0xBF29,         sgop_peak_addr >> 16,
+               0xBF2A,         vbv_alert_addr & 0x0000FFFF,
+               0xBF2B,         vbv_alert_addr >> 16,
+               0xBF2C,         0,
+               0xBF2D,         0,
+               0,              0,
+
+               0x200e,         0x0000,
+               0xBF2E,         vbv_alert_addr & 0x0000FFFF,
+               0xBF2F,         vbv_alert_addr >> 16,
+               0xBF30,         cplx[0] & 0x0000FFFF,
+               0xBF31,         cplx[0] >> 16,
+               0xBF32,         cplx[1] & 0x0000FFFF,
+               0xBF33,         cplx[1] >> 16,
+               0xBF34,         cplx[2] & 0x0000FFFF,
+               0xBF35,         cplx[2] >> 16,
+               0xBF36,         cplx[3] & 0x0000FFFF,
+               0xBF37,         cplx[3] >> 16,
+               0xBF38,         0,
+               0xBF39,         0,
+               0xBF3A,         total_expt_addr & 0x0000FFFF,
+               0xBF3B,         total_expt_addr >> 16,
+               0,              0,
+
+               0x200e,         0x0000,
+               0xBF3C,         total_expt_addr & 0x0000FFFF,
+               0xBF3D,         total_expt_addr >> 16,
+               0xBF3E,         0,
+               0xBF3F,         0,
+               0xBF48,         0,
+               0xBF49,         0,
+               0xBF4A,         calc_q < 4 ? 4 : (calc_q > 124 ? 124 : calc_q),
+               0xBF4B,         4,
+               0xBF4C,         0,
+               0xBF4D,         0,
+               0xBF4E,         0,
+               0xBF4F,         0,
+               0xBF50,         0,
+               0xBF51,         0,
+               0,              0,
+
+               0x200e,         0x0000,
+               0xBF40,         sgop_expt_addr & 0x0000FFFF,
+               0xBF41,         sgop_expt_addr >> 16,
+               0xBF42,         0,
+               0xBF43,         0,
+               0xBF44,         0,
+               0xBF45,         0,
+               0xBF46,         (go->width >> 4) * (go->height >> 4),
+               0xBF47,         0,
+               0xBF64,         0,
+               0xBF65,         0,
+               0xBF18,         framelen[4],
+               0xBF19,         framelen[5],
+               0xBF1A,         framelen[6],
+               0xBF1B,         framelen[7],
+               0,              0,
+
+#if 0
+               /* Remove once we don't care about matching */
+               0x200e,         0x0000,
+               0xBF56,         4,
+               0xBF57,         0,
+               0xBF58,         5,
+               0xBF59,         0,
+               0xBF5A,         6,
+               0xBF5B,         0,
+               0xBF5C,         8,
+               0xBF5D,         0,
+               0xBF5E,         1,
+               0xBF5F,         0,
+               0xBF60,         1,
+               0xBF61,         0,
+               0xBF62,         0,
+               0xBF63,         0,
+               0,              0,
+#else
+               0x2008,         0x0000,
+               0xBF56,         4,
+               0xBF57,         0,
+               0xBF58,         5,
+               0xBF59,         0,
+               0xBF5A,         6,
+               0xBF5B,         0,
+               0xBF5C,         8,
+               0xBF5D,         0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+#endif
+
+               0x200e,         0x0000,
+               0xBF10,         0,
+               0xBF11,         0,
+               0xBF12,         0,
+               0xBF13,         0,
+               0xBF14,         0,
+               0xBF15,         0,
+               0xBF16,         0,
+               0xBF17,         0,
+               0xBF7E,         0,
+               0xBF7F,         1,
+               0xBF52,         framelen[0],
+               0xBF53,         framelen[1],
+               0xBF54,         framelen[2],
+               0xBF55,         framelen[3],
+               0,              0,
+       };
+
+       return copy_packages(code, pack, 6, space);
+}
+
+static int config_package(struct go7007 *go, __le16 *code, int space)
+{
+       int fps = go->sensor_framerate / go->fps_scale / 1000;
+       int rows = go->interlace_coding ? go->height / 32 : go->height / 16;
+       int brc_window_size = fps;
+       int q_min = 2, q_max = 31;
+       int THACCoeffSet0 = 0;
+       u16 pack[] = {
+               0x200e,         0x0000,
+               0xc002,         0x14b4,
+               0xc003,         0x28b4,
+               0xc004,         0x3c5a,
+               0xdc05,         0x2a77,
+               0xc6c3,         go->format == GO7007_FORMAT_MPEG4 ? 0 :
+                               (go->format == GO7007_FORMAT_H263 ? 0 : 1),
+               0xc680,         go->format == GO7007_FORMAT_MPEG4 ? 0xf1 :
+                               (go->format == GO7007_FORMAT_H263 ? 0x61 :
+                                                                       0xd3),
+               0xc780,         0x0140,
+               0xe009,         0x0001,
+               0xc60f,         0x0008,
+               0xd4ff,         0x0002,
+               0xe403,         2340,
+               0xe406,         75,
+               0xd411,         0x0001,
+               0xd410,         0xa1d6,
+               0x0001,         0x2801,
+
+               0x200d,         0x0000,
+               0xe402,         0x018b,
+               0xe401,         0x8b01,
+               0xd472,         (go->board_info->sensor_flags &
+                                                       GO7007_SENSOR_TV) &&
+                                               (!go->interlace_coding) ?
+                                       0x01b0 : 0x0170,
+               0xd475,         (go->board_info->sensor_flags &
+                                                       GO7007_SENSOR_TV) &&
+                                               (!go->interlace_coding) ?
+                                       0x0008 : 0x0009,
+               0xc404,         go->interlace_coding ? 0x44 :
+                               (go->format == GO7007_FORMAT_MPEG4 ? 0x11 :
+                               (go->format == GO7007_FORMAT_MPEG1 ? 0x02 :
+                               (go->format == GO7007_FORMAT_MPEG2 ? 0x04 :
+                               (go->format == GO7007_FORMAT_H263  ? 0x08 :
+                                                                    0x20)))),
+               0xbf0a,         (go->format == GO7007_FORMAT_MPEG4 ? 8 :
+                               (go->format == GO7007_FORMAT_MPEG1 ? 1 :
+                               (go->format == GO7007_FORMAT_MPEG2 ? 2 :
+                               (go->format == GO7007_FORMAT_H263 ? 4 : 16)))) |
+                               ((go->repeat_seqhead ? 1 : 0) << 6) |
+                               ((go->dvd_mode ? 1 : 0) << 9) |
+                               ((go->gop_header_enable ? 1 : 0) << 10),
+               0xbf0b,         0,
+               0xdd5a,         go->ipb ? 0x14 : 0x0a,
+               0xbf0c,         0,
+               0xbf0d,         0,
+               0xc683,         THACCoeffSet0,
+               0xc40a,         (go->width << 4) | rows,
+               0xe01a,         go->board_info->hpi_buffer_cap,
+               0,              0,
+               0,              0,
+
+               0x2008,         0,
+               0xe402,         0x88,
+               0xe401,         0x8f01,
+               0xbf6a,         0,
+               0xbf6b,         0,
+               0xbf6c,         0,
+               0xbf6d,         0,
+               0xbf6e,         0,
+               0xbf6f,         0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+
+               0x200e,         0,
+               0xbf66,         brc_window_size,
+               0xbf67,         0,
+               0xbf68,         q_min,
+               0xbf69,         q_max,
+               0xbfe0,         0,
+               0xbfe1,         0,
+               0xbfe2,         0,
+               0xbfe3,         go->ipb ? 3 : 1,
+               0xc031,         go->board_info->sensor_flags &
+                                       GO7007_SENSOR_VBI ? 1 : 0,
+               0xc01c,         0x1f,
+               0xdd8c,         0x15,
+               0xdd94,         0x15,
+               0xdd88,         go->ipb ? 0x1401 : 0x0a01,
+               0xdd90,         go->ipb ? 0x1401 : 0x0a01,
+               0,              0,
+
+               0x200e,         0,
+               0xbfe4,         0,
+               0xbfe5,         0,
+               0xbfe6,         0,
+               0xbfe7,         fps << 8,
+               0xbfe8,         0x3a00,
+               0xbfe9,         0,
+               0xbfea,         0,
+               0xbfeb,         0,
+               0xbfec,         (go->interlace_coding ? 1 << 15 : 0) |
+                                       (go->modet_enable ? 0xa : 0) |
+                                       (go->board_info->sensor_flags &
+                                               GO7007_SENSOR_VBI ? 1 : 0),
+               0xbfed,         0,
+               0xbfee,         0,
+               0xbfef,         0,
+               0xbff0,         go->board_info->sensor_flags &
+                                       GO7007_SENSOR_TV ? 0xf060 : 0xb060,
+               0xbff1,         0,
+               0,              0,
+       };
+
+       return copy_packages(code, pack, 5, space);
+}
+
+static int seqhead_to_package(struct go7007 *go, __le16 *code, int space,
+       int (*sequence_header_func)(struct go7007 *go,
+               unsigned char *buf, int ext))
+{
+       int vop_time_increment_bitlength = vti_bitlen(go);
+       int fps = go->sensor_framerate / go->fps_scale *
+                                       (go->interlace_coding ? 2 : 1);
+       unsigned char buf[40] = { };
+       int len = sequence_header_func(go, buf, 1);
+       u16 pack[] = {
+               0x2006,         0,
+               0xbf08,         fps,
+               0xbf09,         0,
+               0xbff2,         vop_time_increment_bitlength,
+               0xbff3,         (1 << vop_time_increment_bitlength) - 1,
+               0xbfe6,         0,
+               0xbfe7,         (fps / 1000) << 8,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+
+               0x2007,         0,
+               0xc800,         buf[2] << 8 | buf[3],
+               0xc801,         buf[4] << 8 | buf[5],
+               0xc802,         buf[6] << 8 | buf[7],
+               0xc803,         buf[8] << 8 | buf[9],
+               0xc406,         64,
+               0xc407,         len - 64,
+               0xc61b,         1,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+
+               0x200e,         0,
+               0xc808,         buf[10] << 8 | buf[11],
+               0xc809,         buf[12] << 8 | buf[13],
+               0xc80a,         buf[14] << 8 | buf[15],
+               0xc80b,         buf[16] << 8 | buf[17],
+               0xc80c,         buf[18] << 8 | buf[19],
+               0xc80d,         buf[20] << 8 | buf[21],
+               0xc80e,         buf[22] << 8 | buf[23],
+               0xc80f,         buf[24] << 8 | buf[25],
+               0xc810,         buf[26] << 8 | buf[27],
+               0xc811,         buf[28] << 8 | buf[29],
+               0xc812,         buf[30] << 8 | buf[31],
+               0xc813,         buf[32] << 8 | buf[33],
+               0xc814,         buf[34] << 8 | buf[35],
+               0xc815,         buf[36] << 8 | buf[37],
+               0,              0,
+               0,              0,
+               0,              0,
+       };
+
+       return copy_packages(code, pack, 3, space);
+}
+
+static int relative_prime(int big, int little)
+{
+       int remainder;
+
+       while (little != 0) {
+               remainder = big % little;
+               big = little;
+               little = remainder;
+       }
+       return big;
+}
+
+static int avsync_to_package(struct go7007 *go, __le16 *code, int space)
+{
+       int arate = go->board_info->audio_rate * 1001 * go->fps_scale;
+       int ratio = arate / go->sensor_framerate;
+       int adjratio = ratio * 215 / 100;
+       int rprime = relative_prime(go->sensor_framerate,
+                                       arate % go->sensor_framerate);
+       int f1 = (arate % go->sensor_framerate) / rprime;
+       int f2 = (go->sensor_framerate - arate % go->sensor_framerate) / rprime;
+       u16 pack[] = {
+               0x200e,         0,
+               0xbf98,         (u16)((-adjratio) & 0xffff),
+               0xbf99,         (u16)((-adjratio) >> 16),
+               0xbf92,         0,
+               0xbf93,         0,
+               0xbff4,         f1 > f2 ? f1 : f2,
+               0xbff5,         f1 < f2 ? f1 : f2,
+               0xbff6,         f1 < f2 ? ratio : ratio + 1,
+               0xbff7,         f1 > f2 ? ratio : ratio + 1,
+               0xbff8,         0,
+               0xbff9,         0,
+               0xbffa,         adjratio & 0xffff,
+               0xbffb,         adjratio >> 16,
+               0xbf94,         0,
+               0xbf95,         0,
+               0,              0,
+       };
+
+       return copy_packages(code, pack, 1, space);
+}
+
+static int final_package(struct go7007 *go, __le16 *code, int space)
+{
+       int rows = go->interlace_coding ? go->height / 32 : go->height / 16;
+       u16 pack[] = {
+               0x8000,
+               0,
+               0,
+               0,
+               0,
+               0,
+               0,
+               2,
+               ((go->board_info->sensor_flags & GO7007_SENSOR_TV) &&
+                                               (!go->interlace_coding) ?
+                                       (1 << 14) | (1 << 9) : 0) |
+                       ((go->encoder_subsample ? 1 : 0) << 8) |
+                       (go->board_info->sensor_flags &
+                               GO7007_SENSOR_CONFIG_MASK),
+               ((go->encoder_v_halve ? 1 : 0) << 14) |
+                       (go->encoder_v_halve ? rows << 9 : rows << 8) |
+                       (go->encoder_h_halve ? 1 << 6 : 0) |
+                       (go->encoder_h_halve ? go->width >> 3 : go->width >> 4),
+               (1 << 15) | (go->encoder_v_offset << 6) |
+                       (1 << 7) | (go->encoder_h_offset >> 2),
+               (1 << 6),
+               0,
+               0,
+               ((go->fps_scale - 1) << 8) |
+                       (go->board_info->sensor_flags & GO7007_SENSOR_TV ?
+                                               (1 << 7) : 0) |
+                       0x41,
+               go->ipb ? 0xd4c : 0x36b,
+               (rows << 8) | (go->width >> 4),
+               go->format == GO7007_FORMAT_MPEG4 ? 0x0404 : 0,
+               (1 << 15) | ((go->interlace_coding ? 1 : 0) << 13) |
+                       ((go->closed_gop ? 1 : 0) << 12) |
+                       ((go->format == GO7007_FORMAT_MPEG4 ? 1 : 0) << 11) |
+               /*      (1 << 9) |   */
+                       ((go->ipb ? 3 : 0) << 7) |
+                       ((go->modet_enable ? 1 : 0) << 2) |
+                       ((go->dvd_mode ? 1 : 0) << 1) | 1,
+               (go->format == GO7007_FORMAT_MPEG1 ? 0x89a0 :
+                       (go->format == GO7007_FORMAT_MPEG2 ? 0x89a0 :
+                       (go->format == GO7007_FORMAT_MJPEG ? 0x89a0 :
+                       (go->format == GO7007_FORMAT_MPEG4 ? 0x8920 :
+                       (go->format == GO7007_FORMAT_H263 ? 0x8920 : 0))))),
+               go->ipb ? 0x1f15 : 0x1f0b,
+               go->ipb ? 0x0015 : 0x000b,
+               go->ipb ? 0xa800 : 0x5800,
+               0xffff,
+               0x0020 + 0x034b * 0,
+               0x0020 + 0x034b * 1,
+               0x0020 + 0x034b * 2,
+               0x0020 + 0x034b * 3,
+               0x0020 + 0x034b * 4,
+               0x0020 + 0x034b * 5,
+               go->ipb ? (go->gop_size / 3) : go->gop_size,
+               (go->height >> 4) * (go->width >> 4) * 110 / 100,
+       };
+
+       return copy_packages(code, pack, 1, space);
+}
+
+static int audio_to_package(struct go7007 *go, __le16 *code, int space)
+{
+       int clock_config = ((go->board_info->audio_flags &
+                               GO7007_AUDIO_I2S_MASTER ? 1 : 0) << 11) |
+                       ((go->board_info->audio_flags &
+                               GO7007_AUDIO_OKI_MODE ? 1 : 0) << 8) |
+                       (((go->board_info->audio_bclk_div / 4) - 1) << 4) |
+                       (go->board_info->audio_main_div - 1);
+       u16 pack[] = {
+               0x200d,         0,
+               0x9002,         0,
+               0x9002,         0,
+               0x9031,         0,
+               0x9032,         0,
+               0x9033,         0,
+               0x9034,         0,
+               0x9035,         0,
+               0x9036,         0,
+               0x9037,         0,
+               0x9040,         0,
+               0x9000,         clock_config,
+               0x9001,         (go->board_info->audio_flags & 0xffff) |
+                                       (1 << 9),
+               0x9000,         ((go->board_info->audio_flags &
+                                               GO7007_AUDIO_I2S_MASTER ?
+                                               1 : 0) << 10) |
+                                       clock_config,
+               0,              0,
+               0,              0,
+               0x2005,         0,
+               0x9041,         0,
+               0x9042,         256,
+               0x9043,         0,
+               0x9044,         16,
+               0x9045,         16,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+               0,              0,
+       };
+
+       return copy_packages(code, pack, 2, space);
+}
+
+static int modet_to_package(struct go7007 *go, __le16 *code, int space)
+{
+       int ret, mb, i, addr, cnt = 0;
+       u16 pack[32];
+       u16 thresholds[] = {
+               0x200e,         0,
+               0xbf82,         go->modet[0].pixel_threshold,
+               0xbf83,         go->modet[1].pixel_threshold,
+               0xbf84,         go->modet[2].pixel_threshold,
+               0xbf85,         go->modet[3].pixel_threshold,
+               0xbf86,         go->modet[0].motion_threshold,
+               0xbf87,         go->modet[1].motion_threshold,
+               0xbf88,         go->modet[2].motion_threshold,
+               0xbf89,         go->modet[3].motion_threshold,
+               0xbf8a,         go->modet[0].mb_threshold,
+               0xbf8b,         go->modet[1].mb_threshold,
+               0xbf8c,         go->modet[2].mb_threshold,
+               0xbf8d,         go->modet[3].mb_threshold,
+               0xbf8e,         0,
+               0xbf8f,         0,
+               0,              0,
+       };
+
+       ret = copy_packages(code, thresholds, 1, space);
+       if (ret < 0)
+               return -1;
+       cnt += ret;
+
+       addr = 0xbac0;
+       memset(pack, 0, 64);
+       i = 0;
+       for (mb = 0; mb < 1624; ++mb) {
+               pack[i * 2 + 3] <<= 2;
+               pack[i * 2 + 3] |= go->modet_map[mb];
+               if (mb % 8 != 7)
+                       continue;
+               pack[i * 2 + 2] = addr++;
+               ++i;
+               if (i == 10 || mb == 1623) {
+                       pack[0] = 0x2000 | i;
+                       ret = copy_packages(code + cnt, pack, 1, space - cnt);
+                       if (ret < 0)
+                               return -1;
+                       cnt += ret;
+                       i = 0;
+                       memset(pack, 0, 64);
+               }
+               pack[i * 2 + 3] = 0;
+       }
+
+       memset(pack, 0, 64);
+       i = 0;
+       for (addr = 0xbb90; addr < 0xbbfa; ++addr) {
+               pack[i * 2 + 2] = addr;
+               pack[i * 2 + 3] = 0;
+               ++i;
+               if (i == 10 || addr == 0xbbf9) {
+                       pack[0] = 0x2000 | i;
+                       ret = copy_packages(code + cnt, pack, 1, space - cnt);
+                       if (ret < 0)
+                               return -1;
+                       cnt += ret;
+                       i = 0;
+                       memset(pack, 0, 64);
+               }
+       }
+       return cnt;
+}
+
+static int do_special(struct go7007 *go, u16 type, __le16 *code, int space,
+                       int *framelen)
+{
+       switch (type) {
+       case SPECIAL_FRM_HEAD:
+               switch (go->format) {
+               case GO7007_FORMAT_MJPEG:
+                       return gen_mjpeghdr_to_package(go, code, space);
+               case GO7007_FORMAT_MPEG1:
+               case GO7007_FORMAT_MPEG2:
+                       return gen_mpeg1hdr_to_package(go, code, space,
+                                                               framelen);
+               case GO7007_FORMAT_MPEG4:
+                       return gen_mpeg4hdr_to_package(go, code, space,
+                                                               framelen);
+               }
+       case SPECIAL_BRC_CTRL:
+               return brctrl_to_package(go, code, space, framelen);
+       case SPECIAL_CONFIG:
+               return config_package(go, code, space);
+       case SPECIAL_SEQHEAD:
+               switch (go->format) {
+               case GO7007_FORMAT_MPEG1:
+               case GO7007_FORMAT_MPEG2:
+                       return seqhead_to_package(go, code, space,
+                                       mpeg1_sequence_header);
+               case GO7007_FORMAT_MPEG4:
+                       return seqhead_to_package(go, code, space,
+                                       mpeg4_sequence_header);
+               default:
+                       return 0;
+               }
+       case SPECIAL_AV_SYNC:
+               return avsync_to_package(go, code, space);
+       case SPECIAL_FINAL:
+               return final_package(go, code, space);
+       case SPECIAL_AUDIO:
+               return audio_to_package(go, code, space);
+       case SPECIAL_MODET:
+               return modet_to_package(go, code, space);
+       }
+       printk(KERN_ERR
+               "go7007: firmware file contains unsupported feature %04x\n",
+               type);
+       return -1;
+}
+
+int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen)
+{
+       const struct firmware *fw_entry;
+       __le16 *code, *src;
+       int framelen[8] = { }; /* holds the lengths of empty frame templates */
+       int codespace = 64 * 1024, i = 0, srclen, chunk_len, chunk_flags;
+       int mode_flag;
+       int ret;
+
+       switch (go->format) {
+       case GO7007_FORMAT_MJPEG:
+               mode_flag = FLAG_MODE_MJPEG;
+               break;
+       case GO7007_FORMAT_MPEG1:
+               mode_flag = FLAG_MODE_MPEG1;
+               break;
+       case GO7007_FORMAT_MPEG2:
+               mode_flag = FLAG_MODE_MPEG2;
+               break;
+       case GO7007_FORMAT_MPEG4:
+               mode_flag = FLAG_MODE_MPEG4;
+               break;
+       default:
+               return -1;
+       }
+       if (request_firmware(&fw_entry, go->board_info->firmware, go->dev)) {
+               printk(KERN_ERR
+                       "go7007: unable to load firmware from file \"%s\"\n",
+                       go->board_info->firmware);
+               return -1;
+       }
+       code = kzalloc(codespace * 2, GFP_KERNEL);
+       if (code == NULL) {
+               printk(KERN_ERR "go7007: unable to allocate %d bytes for "
+                               "firmware construction\n", codespace * 2);
+               goto fw_failed;
+       }
+       src = (__le16 *)fw_entry->data;
+       srclen = fw_entry->size / 2;
+       while (srclen >= 2) {
+               chunk_flags = __le16_to_cpu(src[0]);
+               chunk_len = __le16_to_cpu(src[1]);
+               if (chunk_len + 2 > srclen) {
+                       printk(KERN_ERR "go7007: firmware file \"%s\" "
+                                       "appears to be corrupted\n",
+                                       go->board_info->firmware);
+                       goto fw_failed;
+               }
+               if (chunk_flags & mode_flag) {
+                       if (chunk_flags & FLAG_SPECIAL) {
+                               ret = do_special(go, __le16_to_cpu(src[2]),
+                                       &code[i], codespace - i, framelen);
+                               if (ret < 0) {
+                                       printk(KERN_ERR "go7007: insufficient "
+                                                       "memory for firmware "
+                                                       "construction\n");
+                                       goto fw_failed;
+                               }
+                               i += ret;
+                       } else {
+                               if (codespace - i < chunk_len) {
+                                       printk(KERN_ERR "go7007: insufficient "
+                                                       "memory for firmware "
+                                                       "construction\n");
+                                       goto fw_failed;
+                               }
+                               memcpy(&code[i], &src[2], chunk_len * 2);
+                               i += chunk_len;
+                       }
+               }
+               srclen -= chunk_len + 2;
+               src += chunk_len + 2;
+       }
+       release_firmware(fw_entry);
+       *fw = (u8 *)code;
+       *fwlen = i * 2;
+       return 0;
+
+fw_failed:
+       kfree(code);
+       release_firmware(fw_entry);
+       return -1;
+}
diff --git a/drivers/staging/media/go7007/go7007-i2c.c b/drivers/staging/media/go7007/go7007-i2c.c
new file mode 100644 (file)
index 0000000..b8cfa1a
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/unistd.h>
+#include <linux/time.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#include "go7007-priv.h"
+#include "wis-i2c.h"
+
+/********************* Driver for on-board I2C adapter *********************/
+
+/* #define GO7007_I2C_DEBUG */
+
+#define SPI_I2C_ADDR_BASE              0x1400
+#define STATUS_REG_ADDR                        (SPI_I2C_ADDR_BASE + 0x2)
+#define I2C_CTRL_REG_ADDR              (SPI_I2C_ADDR_BASE + 0x6)
+#define I2C_DEV_UP_ADDR_REG_ADDR       (SPI_I2C_ADDR_BASE + 0x7)
+#define I2C_LO_ADDR_REG_ADDR           (SPI_I2C_ADDR_BASE + 0x8)
+#define I2C_DATA_REG_ADDR              (SPI_I2C_ADDR_BASE + 0x9)
+#define I2C_CLKFREQ_REG_ADDR           (SPI_I2C_ADDR_BASE + 0xa)
+
+#define I2C_STATE_MASK                 0x0007
+#define I2C_READ_READY_MASK            0x0008
+
+/* There is only one I2C port on the TW2804 that feeds all four GO7007 VIPs
+ * on the Adlink PCI-MPG24, so access is shared between all of them. */
+static DEFINE_MUTEX(adlink_mpg24_i2c_lock);
+
+static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read,
+               u16 command, int flags, u8 *data)
+{
+       int i, ret = -1;
+       u16 val;
+
+       if (go->status == STATUS_SHUTDOWN)
+               return -1;
+
+#ifdef GO7007_I2C_DEBUG
+       if (read)
+               printk(KERN_DEBUG "go7007-i2c: reading 0x%02x on 0x%02x\n",
+                       command, addr);
+       else
+               printk(KERN_DEBUG
+                       "go7007-i2c: writing 0x%02x to 0x%02x on 0x%02x\n",
+                       *data, command, addr);
+#endif
+
+       mutex_lock(&go->hw_lock);
+
+       if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) {
+               /* Bridge the I2C port on this GO7007 to the shared bus */
+               mutex_lock(&adlink_mpg24_i2c_lock);
+               go7007_write_addr(go, 0x3c82, 0x0020);
+       }
+
+       /* Wait for I2C adapter to be ready */
+       for (i = 0; i < 10; ++i) {
+               if (go7007_read_addr(go, STATUS_REG_ADDR, &val) < 0)
+                       goto i2c_done;
+               if (!(val & I2C_STATE_MASK))
+                       break;
+               msleep(100);
+       }
+       if (i == 10) {
+               printk(KERN_ERR "go7007-i2c: I2C adapter is hung\n");
+               goto i2c_done;
+       }
+
+       /* Set target register (command) */
+       go7007_write_addr(go, I2C_CTRL_REG_ADDR, flags);
+       go7007_write_addr(go, I2C_LO_ADDR_REG_ADDR, command);
+
+       /* If we're writing, send the data and target address and we're done */
+       if (!read) {
+               go7007_write_addr(go, I2C_DATA_REG_ADDR, *data);
+               go7007_write_addr(go, I2C_DEV_UP_ADDR_REG_ADDR,
+                                       (addr << 9) | (command >> 8));
+               ret = 0;
+               goto i2c_done;
+       }
+
+       /* Otherwise, we're reading.  First clear i2c_rx_data_rdy. */
+       if (go7007_read_addr(go, I2C_DATA_REG_ADDR, &val) < 0)
+               goto i2c_done;
+
+       /* Send the target address plus read flag */
+       go7007_write_addr(go, I2C_DEV_UP_ADDR_REG_ADDR,
+                       (addr << 9) | 0x0100 | (command >> 8));
+
+       /* Wait for i2c_rx_data_rdy */
+       for (i = 0; i < 10; ++i) {
+               if (go7007_read_addr(go, STATUS_REG_ADDR, &val) < 0)
+                       goto i2c_done;
+               if (val & I2C_READ_READY_MASK)
+                       break;
+               msleep(100);
+       }
+       if (i == 10) {
+               printk(KERN_ERR "go7007-i2c: I2C adapter is hung\n");
+               goto i2c_done;
+       }
+
+       /* Retrieve the read byte */
+       if (go7007_read_addr(go, I2C_DATA_REG_ADDR, &val) < 0)
+               goto i2c_done;
+       *data = val;
+       ret = 0;
+
+i2c_done:
+       if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) {
+               /* Isolate the I2C port on this GO7007 from the shared bus */
+               go7007_write_addr(go, 0x3c82, 0x0000);
+               mutex_unlock(&adlink_mpg24_i2c_lock);
+       }
+       mutex_unlock(&go->hw_lock);
+       return ret;
+}
+
+static int go7007_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+               unsigned short flags, char read_write,
+               u8 command, int size, union i2c_smbus_data *data)
+{
+       struct go7007 *go = i2c_get_adapdata(adapter);
+
+       if (size != I2C_SMBUS_BYTE_DATA)
+               return -1;
+       return go7007_i2c_xfer(go, addr, read_write == I2C_SMBUS_READ, command,
+                       flags & I2C_CLIENT_SCCB ? 0x10 : 0x00, &data->byte);
+}
+
+/* VERY LIMITED I2C master xfer function -- only needed because the
+ * SMBus functions only support 8-bit commands and the SAA7135 uses
+ * 16-bit commands.  The I2C interface on the GO7007, as limited as
+ * it is, does support this mode. */
+
+static int go7007_i2c_master_xfer(struct i2c_adapter *adapter,
+                                       struct i2c_msg msgs[], int num)
+{
+       struct go7007 *go = i2c_get_adapdata(adapter);
+       int i;
+
+       for (i = 0; i < num; ++i) {
+               /* We can only do two things here -- write three bytes, or
+                * write two bytes and read one byte. */
+               if (msgs[i].len == 2) {
+                       if (i + 1 == num || msgs[i].addr != msgs[i + 1].addr ||
+                                       (msgs[i].flags & I2C_M_RD) ||
+                                       !(msgs[i + 1].flags & I2C_M_RD) ||
+                                       msgs[i + 1].len != 1)
+                               return -1;
+                       if (go7007_i2c_xfer(go, msgs[i].addr, 1,
+                                       (msgs[i].buf[0] << 8) | msgs[i].buf[1],
+                                       0x01, &msgs[i + 1].buf[0]) < 0)
+                               return -1;
+                       ++i;
+               } else if (msgs[i].len == 3) {
+                       if (msgs[i].flags & I2C_M_RD)
+                               return -1;
+                       if (msgs[i].len != 3)
+                               return -1;
+                       if (go7007_i2c_xfer(go, msgs[i].addr, 0,
+                                       (msgs[i].buf[0] << 8) | msgs[i].buf[1],
+                                       0x01, &msgs[i].buf[2]) < 0)
+                               return -1;
+               } else
+                       return -1;
+       }
+
+       return 0;
+}
+
+static u32 go7007_functionality(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static struct i2c_algorithm go7007_algo = {
+       .smbus_xfer     = go7007_smbus_xfer,
+       .master_xfer    = go7007_i2c_master_xfer,
+       .functionality  = go7007_functionality,
+};
+
+static struct i2c_adapter go7007_adap_templ = {
+       .owner                  = THIS_MODULE,
+       .name                   = "WIS GO7007SB",
+       .algo                   = &go7007_algo,
+};
+
+int go7007_i2c_init(struct go7007 *go)
+{
+       memcpy(&go->i2c_adapter, &go7007_adap_templ,
+                       sizeof(go7007_adap_templ));
+       go->i2c_adapter.dev.parent = go->dev;
+       i2c_set_adapdata(&go->i2c_adapter, go);
+       if (i2c_add_adapter(&go->i2c_adapter) < 0) {
+               printk(KERN_ERR
+                       "go7007-i2c: error: i2c_add_adapter failed\n");
+               return -1;
+       }
+       return 0;
+}
diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h
new file mode 100644 (file)
index 0000000..b58c394
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+/*
+ * This is the private include file for the go7007 driver.  It should not
+ * be included by anybody but the driver itself, and especially not by
+ * user-space applications.
+ */
+
+#include <media/v4l2-device.h>
+
+struct go7007;
+
+/* IDs to activate board-specific support code */
+#define GO7007_BOARDID_MATRIX_II       0
+#define GO7007_BOARDID_MATRIX_RELOAD   1
+#define GO7007_BOARDID_STAR_TREK       2
+#define GO7007_BOARDID_PCI_VOYAGER     3
+#define GO7007_BOARDID_XMEN            4
+#define GO7007_BOARDID_XMEN_II         5
+#define GO7007_BOARDID_XMEN_III                6
+#define GO7007_BOARDID_MATRIX_REV      7
+#define GO7007_BOARDID_PX_M402U                16
+#define GO7007_BOARDID_PX_TV402U_ANY   17 /* need to check tuner model */
+#define GO7007_BOARDID_PX_TV402U_NA    18 /* detected NTSC tuner */
+#define GO7007_BOARDID_PX_TV402U_EU    19 /* detected PAL tuner */
+#define GO7007_BOARDID_PX_TV402U_JP    20 /* detected NTSC-J tuner */
+#define GO7007_BOARDID_LIFEVIEW_LR192  21 /* TV Walker Ultra */
+#define GO7007_BOARDID_ENDURA          22
+#define GO7007_BOARDID_ADLINK_MPG24    23
+#define GO7007_BOARDID_SENSORAY_2250   24 /* Sensoray 2250/2251 */
+
+/* Various characteristics of each board */
+#define GO7007_BOARD_HAS_AUDIO         (1<<0)
+#define GO7007_BOARD_USE_ONBOARD_I2C   (1<<1)
+#define GO7007_BOARD_HAS_TUNER         (1<<2)
+
+/* Characteristics of sensor devices */
+#define GO7007_SENSOR_VALID_POLAR      (1<<0)
+#define GO7007_SENSOR_HREF_POLAR       (1<<1)
+#define GO7007_SENSOR_VREF_POLAR       (1<<2)
+#define GO7007_SENSOR_FIELD_ID_POLAR   (1<<3)
+#define GO7007_SENSOR_BIT_WIDTH                (1<<4)
+#define GO7007_SENSOR_VALID_ENABLE     (1<<5)
+#define GO7007_SENSOR_656              (1<<6)
+#define GO7007_SENSOR_CONFIG_MASK      0x7f
+#define GO7007_SENSOR_TV               (1<<7)
+#define GO7007_SENSOR_VBI              (1<<8)
+#define GO7007_SENSOR_SCALING          (1<<9)
+
+/* Characteristics of audio sensor devices */
+#define GO7007_AUDIO_I2S_MODE_1                (1)
+#define GO7007_AUDIO_I2S_MODE_2                (2)
+#define GO7007_AUDIO_I2S_MODE_3                (3)
+#define GO7007_AUDIO_BCLK_POLAR                (1<<2)
+#define GO7007_AUDIO_WORD_14           (14<<4)
+#define GO7007_AUDIO_WORD_16           (16<<4)
+#define GO7007_AUDIO_ONE_CHANNEL       (1<<11)
+#define GO7007_AUDIO_I2S_MASTER                (1<<16)
+#define GO7007_AUDIO_OKI_MODE          (1<<17)
+
+struct go7007_board_info {
+       char *firmware;
+       unsigned int flags;
+       int hpi_buffer_cap;
+       unsigned int sensor_flags;
+       int sensor_width;
+       int sensor_height;
+       int sensor_framerate;
+       int sensor_h_offset;
+       int sensor_v_offset;
+       unsigned int audio_flags;
+       int audio_rate;
+       int audio_bclk_div;
+       int audio_main_div;
+       int num_i2c_devs;
+       struct {
+               const char *type;
+               int id;
+               int addr;
+       } i2c_devs[4];
+       int num_inputs;
+       struct {
+               int video_input;
+               int audio_input;
+               char *name;
+       } inputs[4];
+};
+
+struct go7007_hpi_ops {
+       int (*interface_reset)(struct go7007 *go);
+       int (*write_interrupt)(struct go7007 *go, int addr, int data);
+       int (*read_interrupt)(struct go7007 *go);
+       int (*stream_start)(struct go7007 *go);
+       int (*stream_stop)(struct go7007 *go);
+       int (*send_firmware)(struct go7007 *go, u8 *data, int len);
+       int (*send_command)(struct go7007 *go, unsigned int cmd, void *arg);
+};
+
+/* The video buffer size must be a multiple of PAGE_SIZE */
+#define        GO7007_BUF_PAGES        (128 * 1024 / PAGE_SIZE)
+#define        GO7007_BUF_SIZE         (GO7007_BUF_PAGES << PAGE_SHIFT)
+
+struct go7007_buffer {
+       struct go7007 *go; /* Reverse reference for VMA ops */
+       int index; /* Reverse reference for DQBUF */
+       enum { BUF_STATE_IDLE, BUF_STATE_QUEUED, BUF_STATE_DONE } state;
+       u32 seq;
+       struct timeval timestamp;
+       struct list_head stream;
+       struct page *pages[GO7007_BUF_PAGES + 1]; /* extra for straddling */
+       unsigned long user_addr;
+       unsigned int page_count;
+       unsigned int offset;
+       unsigned int bytesused;
+       unsigned int frame_offset;
+       u32 modet_active;
+       int mapped;
+};
+
+struct go7007_file {
+       struct go7007 *go;
+       struct mutex lock;
+       int buf_count;
+       struct go7007_buffer *bufs;
+};
+
+#define        GO7007_FORMAT_MJPEG     0
+#define GO7007_FORMAT_MPEG4    1
+#define GO7007_FORMAT_MPEG1    2
+#define GO7007_FORMAT_MPEG2    3
+#define GO7007_FORMAT_H263     4
+
+#define GO7007_RATIO_1_1       0
+#define GO7007_RATIO_4_3       1
+#define GO7007_RATIO_16_9      2
+
+enum go7007_parser_state {
+       STATE_DATA,
+       STATE_00,
+       STATE_00_00,
+       STATE_00_00_01,
+       STATE_FF,
+       STATE_VBI_LEN_A,
+       STATE_VBI_LEN_B,
+       STATE_MODET_MAP,
+       STATE_UNPARSED,
+};
+
+struct go7007 {
+       struct device *dev;
+       struct go7007_board_info *board_info;
+       unsigned int board_id;
+       int tuner_type;
+       int channel_number; /* for multi-channel boards like Adlink PCI-MPG24 */
+       char name[64];
+       struct video_device *video_dev;
+       struct v4l2_device v4l2_dev;
+       int ref_count;
+       enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status;
+       spinlock_t spinlock;
+       struct mutex hw_lock;
+       int streaming;
+       int in_use;
+       int audio_enabled;
+
+       /* Video input */
+       int input;
+       enum { GO7007_STD_NTSC, GO7007_STD_PAL, GO7007_STD_OTHER } standard;
+       int sensor_framerate;
+       int width;
+       int height;
+       int encoder_h_offset;
+       int encoder_v_offset;
+       unsigned int encoder_h_halve:1;
+       unsigned int encoder_v_halve:1;
+       unsigned int encoder_subsample:1;
+
+       /* Encoder config */
+       int format;
+       int bitrate;
+       int fps_scale;
+       int pali;
+       int aspect_ratio;
+       int gop_size;
+       unsigned int ipb:1;
+       unsigned int closed_gop:1;
+       unsigned int repeat_seqhead:1;
+       unsigned int seq_header_enable:1;
+       unsigned int gop_header_enable:1;
+       unsigned int dvd_mode:1;
+       unsigned int interlace_coding:1;
+
+       /* Motion detection */
+       unsigned int modet_enable:1;
+       struct {
+               unsigned int enable:1;
+               int pixel_threshold;
+               int motion_threshold;
+               int mb_threshold;
+       } modet[4];
+       unsigned char modet_map[1624];
+       unsigned char active_map[216];
+
+       /* Video streaming */
+       struct go7007_buffer *active_buf;
+       enum go7007_parser_state state;
+       int parse_length;
+       u16 modet_word;
+       int seen_frame;
+       u32 next_seq;
+       struct list_head stream;
+       wait_queue_head_t frame_waitq;
+
+       /* Audio streaming */
+       void (*audio_deliver)(struct go7007 *go, u8 *buf, int length);
+       void *snd_context;
+
+       /* I2C */
+       int i2c_adapter_online;
+       struct i2c_adapter i2c_adapter;
+
+       /* HPI driver */
+       struct go7007_hpi_ops *hpi_ops;
+       void *hpi_context;
+       int interrupt_available;
+       wait_queue_head_t interrupt_waitq;
+       unsigned short interrupt_value;
+       unsigned short interrupt_data;
+};
+
+static inline struct go7007 *to_go7007(struct v4l2_device *v4l2_dev)
+{
+       return container_of(v4l2_dev, struct go7007, v4l2_dev);
+}
+
+/* All of these must be called with the hpi_lock mutex held! */
+#define go7007_interface_reset(go) \
+                       ((go)->hpi_ops->interface_reset(go))
+#define        go7007_write_interrupt(go, x, y) \
+                       ((go)->hpi_ops->write_interrupt)((go), (x), (y))
+#define go7007_stream_start(go) \
+                       ((go)->hpi_ops->stream_start(go))
+#define go7007_stream_stop(go) \
+                       ((go)->hpi_ops->stream_stop(go))
+#define        go7007_send_firmware(go, x, y) \
+                       ((go)->hpi_ops->send_firmware)((go), (x), (y))
+#define go7007_write_addr(go, x, y) \
+                       ((go)->hpi_ops->write_interrupt)((go), (x)|0x8000, (y))
+
+/* go7007-driver.c */
+int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data);
+int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data);
+int go7007_boot_encoder(struct go7007 *go, int init_i2c);
+int go7007_reset_encoder(struct go7007 *go);
+int go7007_register_encoder(struct go7007 *go);
+int go7007_start_encoder(struct go7007 *go);
+void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length);
+struct go7007 *go7007_alloc(struct go7007_board_info *board,
+                                       struct device *dev);
+void go7007_remove(struct go7007 *go);
+
+/* go7007-fw.c */
+int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen);
+
+/* go7007-i2c.c */
+int go7007_i2c_init(struct go7007 *go);
+int go7007_i2c_remove(struct go7007 *go);
+
+/* go7007-v4l2.c */
+int go7007_v4l2_init(struct go7007 *go);
+void go7007_v4l2_remove(struct go7007 *go);
+
+/* snd-go7007.c */
+int go7007_snd_init(struct go7007 *go);
+int go7007_snd_remove(struct go7007 *go);
diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c
new file mode 100644 (file)
index 0000000..3db3b0a
--- /dev/null
@@ -0,0 +1,1288 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <asm/byteorder.h>
+#include <media/tvaudio.h>
+
+#include "go7007-priv.h"
+#include "wis-i2c.h"
+
+static unsigned int assume_endura;
+module_param(assume_endura, int, 0644);
+MODULE_PARM_DESC(assume_endura, "when probing fails, "
+                               "hardware is a Pelco Endura");
+
+/* #define GO7007_USB_DEBUG */
+/* #define GO7007_I2C_DEBUG */ /* for debugging the EZ-USB I2C adapter */
+
+#define        HPI_STATUS_ADDR 0xFFF4
+#define        INT_PARAM_ADDR  0xFFF6
+#define        INT_INDEX_ADDR  0xFFF8
+
+/*
+ * Pipes on EZ-USB interface:
+ *     0 snd - Control
+ *     0 rcv - Control
+ *     2 snd - Download firmware (control)
+ *     4 rcv - Read Interrupt (interrupt)
+ *     6 rcv - Read Video (bulk)
+ *     8 rcv - Read Audio (bulk)
+ */
+
+#define GO7007_USB_EZUSB               (1<<0)
+#define GO7007_USB_EZUSB_I2C           (1<<1)
+
+struct go7007_usb_board {
+       unsigned int flags;
+       struct go7007_board_info main_info;
+};
+
+struct go7007_usb {
+       struct go7007_usb_board *board;
+       struct mutex i2c_lock;
+       struct usb_device *usbdev;
+       struct urb *video_urbs[8];
+       struct urb *audio_urbs[8];
+       struct urb *intr_urb;
+};
+
+/*********************** Product specification data ***********************/
+
+static struct go7007_usb_board board_matrix_ii = {
+       .flags          = GO7007_USB_EZUSB,
+       .main_info      = {
+               .firmware        = "go7007tv.bin",
+               .flags           = GO7007_BOARD_HAS_AUDIO |
+                                       GO7007_BOARD_USE_ONBOARD_I2C,
+               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
+                                       GO7007_AUDIO_WORD_16,
+               .audio_rate      = 48000,
+               .audio_bclk_div  = 8,
+               .audio_main_div  = 2,
+               .hpi_buffer_cap  = 7,
+               .sensor_flags    = GO7007_SENSOR_656 |
+                                       GO7007_SENSOR_VALID_ENABLE |
+                                       GO7007_SENSOR_TV |
+                                       GO7007_SENSOR_VBI |
+                                       GO7007_SENSOR_SCALING,
+               .num_i2c_devs    = 1,
+               .i2c_devs        = {
+                       {
+                               .type   = "wis_saa7115",
+                               .id     = I2C_DRIVERID_WIS_SAA7115,
+                               .addr   = 0x20,
+                       },
+               },
+               .num_inputs      = 2,
+               .inputs          = {
+                       {
+                               .video_input    = 0,
+                               .name           = "Composite",
+                       },
+                       {
+                               .video_input    = 9,
+                               .name           = "S-Video",
+                       },
+               },
+       },
+};
+
+static struct go7007_usb_board board_matrix_reload = {
+       .flags          = GO7007_USB_EZUSB,
+       .main_info      = {
+               .firmware        = "go7007tv.bin",
+               .flags           = GO7007_BOARD_HAS_AUDIO |
+                                       GO7007_BOARD_USE_ONBOARD_I2C,
+               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
+                                       GO7007_AUDIO_I2S_MASTER |
+                                       GO7007_AUDIO_WORD_16,
+               .audio_rate      = 48000,
+               .audio_bclk_div  = 8,
+               .audio_main_div  = 2,
+               .hpi_buffer_cap  = 7,
+               .sensor_flags    = GO7007_SENSOR_656 |
+                                       GO7007_SENSOR_TV,
+               .num_i2c_devs    = 1,
+               .i2c_devs        = {
+                       {
+                               .type   = "wis_saa7113",
+                               .id     = I2C_DRIVERID_WIS_SAA7113,
+                               .addr   = 0x25,
+                       },
+               },
+               .num_inputs      = 2,
+               .inputs          = {
+                       {
+                               .video_input    = 0,
+                               .name           = "Composite",
+                       },
+                       {
+                               .video_input    = 9,
+                               .name           = "S-Video",
+                       },
+               },
+       },
+};
+
+static struct go7007_usb_board board_star_trek = {
+       .flags          = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
+       .main_info      = {
+               .firmware        = "go7007tv.bin",
+               .flags           = GO7007_BOARD_HAS_AUDIO, /* |
+                                       GO7007_BOARD_HAS_TUNER, */
+               .sensor_flags    = GO7007_SENSOR_656 |
+                                       GO7007_SENSOR_VALID_ENABLE |
+                                       GO7007_SENSOR_TV |
+                                       GO7007_SENSOR_VBI |
+                                       GO7007_SENSOR_SCALING,
+               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
+                                       GO7007_AUDIO_WORD_16,
+               .audio_bclk_div  = 8,
+               .audio_main_div  = 2,
+               .hpi_buffer_cap  = 7,
+               .num_i2c_devs    = 1,
+               .i2c_devs        = {
+                       {
+                               .type   = "wis_saa7115",
+                               .id     = I2C_DRIVERID_WIS_SAA7115,
+                               .addr   = 0x20,
+                       },
+               },
+               .num_inputs      = 2,
+               .inputs          = {
+                       {
+                               .video_input    = 1,
+                       /*      .audio_input    = AUDIO_EXTERN, */
+                               .name           = "Composite",
+                       },
+                       {
+                               .video_input    = 8,
+                       /*      .audio_input    = AUDIO_EXTERN, */
+                               .name           = "S-Video",
+                       },
+               /*      {
+                *              .video_input    = 3,
+                *              .audio_input    = AUDIO_TUNER,
+                *              .name           = "Tuner",
+                *      },
+                */
+               },
+       },
+};
+
+static struct go7007_usb_board board_px_tv402u = {
+       .flags          = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
+       .main_info      = {
+               .firmware        = "go7007tv.bin",
+               .flags           = GO7007_BOARD_HAS_AUDIO |
+                                       GO7007_BOARD_HAS_TUNER,
+               .sensor_flags    = GO7007_SENSOR_656 |
+                                       GO7007_SENSOR_VALID_ENABLE |
+                                       GO7007_SENSOR_TV |
+                                       GO7007_SENSOR_VBI |
+                                       GO7007_SENSOR_SCALING,
+               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
+                                       GO7007_AUDIO_WORD_16,
+               .audio_bclk_div  = 8,
+               .audio_main_div  = 2,
+               .hpi_buffer_cap  = 7,
+               .num_i2c_devs    = 3,
+               .i2c_devs        = {
+                       {
+                               .type   = "wis_saa7115",
+                               .id     = I2C_DRIVERID_WIS_SAA7115,
+                               .addr   = 0x20,
+                       },
+                       {
+                               .type   = "wis_uda1342",
+                               .id     = I2C_DRIVERID_WIS_UDA1342,
+                               .addr   = 0x1a,
+                       },
+                       {
+                               .type   = "wis_sony_tuner",
+                               .id     = I2C_DRIVERID_WIS_SONY_TUNER,
+                               .addr   = 0x60,
+                       },
+               },
+               .num_inputs      = 3,
+               .inputs          = {
+                       {
+                               .video_input    = 1,
+                               .audio_input    = TVAUDIO_INPUT_EXTERN,
+                               .name           = "Composite",
+                       },
+                       {
+                               .video_input    = 8,
+                               .audio_input    = TVAUDIO_INPUT_EXTERN,
+                               .name           = "S-Video",
+                       },
+                       {
+                               .video_input    = 3,
+                               .audio_input    = TVAUDIO_INPUT_TUNER,
+                               .name           = "Tuner",
+                       },
+               },
+       },
+};
+
+static struct go7007_usb_board board_xmen = {
+       .flags          = 0,
+       .main_info      = {
+               .firmware         = "go7007tv.bin",
+               .flags            = GO7007_BOARD_USE_ONBOARD_I2C,
+               .hpi_buffer_cap   = 0,
+               .sensor_flags     = GO7007_SENSOR_VREF_POLAR,
+               .sensor_width     = 320,
+               .sensor_height    = 240,
+               .sensor_framerate = 30030,
+               .audio_flags      = GO7007_AUDIO_ONE_CHANNEL |
+                                       GO7007_AUDIO_I2S_MODE_3 |
+                                       GO7007_AUDIO_WORD_14 |
+                                       GO7007_AUDIO_I2S_MASTER |
+                                       GO7007_AUDIO_BCLK_POLAR |
+                                       GO7007_AUDIO_OKI_MODE,
+               .audio_rate       = 8000,
+               .audio_bclk_div   = 48,
+               .audio_main_div   = 1,
+               .num_i2c_devs     = 1,
+               .i2c_devs         = {
+                       {
+                               .type   = "wis_ov7640",
+                               .id     = I2C_DRIVERID_WIS_OV7640,
+                               .addr   = 0x21,
+                       },
+               },
+               .num_inputs       = 1,
+               .inputs           = {
+                       {
+                               .name           = "Camera",
+                       },
+               },
+       },
+};
+
+static struct go7007_usb_board board_matrix_revolution = {
+       .flags          = GO7007_USB_EZUSB,
+       .main_info      = {
+               .firmware        = "go7007tv.bin",
+               .flags           = GO7007_BOARD_HAS_AUDIO |
+                                       GO7007_BOARD_USE_ONBOARD_I2C,
+               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
+                                       GO7007_AUDIO_I2S_MASTER |
+                                       GO7007_AUDIO_WORD_16,
+               .audio_rate      = 48000,
+               .audio_bclk_div  = 8,
+               .audio_main_div  = 2,
+               .hpi_buffer_cap  = 7,
+               .sensor_flags    = GO7007_SENSOR_656 |
+                                       GO7007_SENSOR_TV |
+                                       GO7007_SENSOR_VBI,
+               .num_i2c_devs    = 1,
+               .i2c_devs        = {
+                       {
+                               .type   = "wis_tw9903",
+                               .id     = I2C_DRIVERID_WIS_TW9903,
+                               .addr   = 0x44,
+                       },
+               },
+               .num_inputs      = 2,
+               .inputs          = {
+                       {
+                               .video_input    = 2,
+                               .name           = "Composite",
+                       },
+                       {
+                               .video_input    = 8,
+                               .name           = "S-Video",
+                       },
+               },
+       },
+};
+
+static struct go7007_usb_board board_lifeview_lr192 = {
+       .flags          = GO7007_USB_EZUSB,
+       .main_info      = {
+               .firmware        = "go7007tv.bin",
+               .flags           = GO7007_BOARD_HAS_AUDIO |
+                                       GO7007_BOARD_USE_ONBOARD_I2C,
+               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
+                                       GO7007_AUDIO_WORD_16,
+               .audio_rate      = 48000,
+               .audio_bclk_div  = 8,
+               .audio_main_div  = 2,
+               .hpi_buffer_cap  = 7,
+               .sensor_flags    = GO7007_SENSOR_656 |
+                                       GO7007_SENSOR_VALID_ENABLE |
+                                       GO7007_SENSOR_TV |
+                                       GO7007_SENSOR_VBI |
+                                       GO7007_SENSOR_SCALING,
+               .num_i2c_devs    = 0,
+               .num_inputs      = 1,
+               .inputs          = {
+                       {
+                               .video_input    = 0,
+                               .name           = "Composite",
+                       },
+               },
+       },
+};
+
+static struct go7007_usb_board board_endura = {
+       .flags          = 0,
+       .main_info      = {
+               .firmware        = "go7007tv.bin",
+               .flags           = 0,
+               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
+                                       GO7007_AUDIO_I2S_MASTER |
+                                       GO7007_AUDIO_WORD_16,
+               .audio_rate      = 8000,
+               .audio_bclk_div  = 48,
+               .audio_main_div  = 8,
+               .hpi_buffer_cap  = 0,
+               .sensor_flags    = GO7007_SENSOR_656 |
+                                       GO7007_SENSOR_TV,
+               .sensor_h_offset = 8,
+               .num_i2c_devs    = 0,
+               .num_inputs      = 1,
+               .inputs          = {
+                       {
+                               .name           = "Camera",
+                       },
+               },
+       },
+};
+
+static struct go7007_usb_board board_adlink_mpg24 = {
+       .flags          = 0,
+       .main_info      = {
+               .firmware        = "go7007tv.bin",
+               .flags           = GO7007_BOARD_USE_ONBOARD_I2C,
+               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
+                                       GO7007_AUDIO_I2S_MASTER |
+                                       GO7007_AUDIO_WORD_16,
+               .audio_rate      = 48000,
+               .audio_bclk_div  = 8,
+               .audio_main_div  = 2,
+               .hpi_buffer_cap  = 0,
+               .sensor_flags    = GO7007_SENSOR_656 |
+                                       GO7007_SENSOR_TV |
+                                       GO7007_SENSOR_VBI,
+               .num_i2c_devs    = 1,
+               .i2c_devs        = {
+                       {
+                               .type   = "wis_tw2804",
+                               .id     = I2C_DRIVERID_WIS_TW2804,
+                               .addr   = 0x00, /* yes, really */
+                       },
+               },
+               .num_inputs      = 1,
+               .inputs          = {
+                       {
+                               .name           = "Composite",
+                       },
+               },
+       },
+};
+
+static struct go7007_usb_board board_sensoray_2250 = {
+       .flags          = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
+       .main_info      = {
+               .firmware        = "go7007tv.bin",
+               .audio_flags     = GO7007_AUDIO_I2S_MODE_1 |
+                                       GO7007_AUDIO_I2S_MASTER |
+                                       GO7007_AUDIO_WORD_16,
+               .flags           = GO7007_BOARD_HAS_AUDIO,
+               .audio_rate      = 48000,
+               .audio_bclk_div  = 8,
+               .audio_main_div  = 2,
+               .hpi_buffer_cap  = 7,
+               .sensor_flags    = GO7007_SENSOR_656 |
+                                       GO7007_SENSOR_TV,
+               .num_i2c_devs    = 1,
+               .i2c_devs        = {
+                       {
+                               .type   = "s2250",
+                               .id     = I2C_DRIVERID_S2250,
+                               .addr   = 0x43,
+                       },
+               },
+               .num_inputs      = 2,
+               .inputs          = {
+                       {
+                               .video_input    = 0,
+                               .name           = "Composite",
+                       },
+                       {
+                               .video_input    = 1,
+                               .name           = "S-Video",
+                       },
+               },
+       },
+};
+
+MODULE_FIRMWARE("go7007tv.bin");
+
+static const struct usb_device_id go7007_usb_id_table[] = {
+       {
+               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
+                                       USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
+               .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
+               .bcdDevice_lo   = 0x200,   /* Revision number of XMen */
+               .bcdDevice_hi   = 0x200,
+               .bInterfaceClass        = 255,
+               .bInterfaceSubClass     = 0,
+               .bInterfaceProtocol     = 255,
+               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_XMEN,
+       },
+       {
+               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+               .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
+               .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
+               .bcdDevice_lo   = 0x202,   /* Revision number of Matrix II */
+               .bcdDevice_hi   = 0x202,
+               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_MATRIX_II,
+       },
+       {
+               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+               .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
+               .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
+               .bcdDevice_lo   = 0x204,   /* Revision number of Matrix */
+               .bcdDevice_hi   = 0x204,   /*     Reloaded */
+               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_MATRIX_RELOAD,
+       },
+       {
+               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
+                                       USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
+               .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
+               .bcdDevice_lo   = 0x205,   /* Revision number of XMen-II */
+               .bcdDevice_hi   = 0x205,
+               .bInterfaceClass        = 255,
+               .bInterfaceSubClass     = 0,
+               .bInterfaceProtocol     = 255,
+               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_XMEN_II,
+       },
+       {
+               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+               .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
+               .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
+               .bcdDevice_lo   = 0x208,   /* Revision number of Star Trek */
+               .bcdDevice_hi   = 0x208,
+               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_STAR_TREK,
+       },
+       {
+               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
+                                       USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
+               .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
+               .bcdDevice_lo   = 0x209,   /* Revision number of XMen-III */
+               .bcdDevice_hi   = 0x209,
+               .bInterfaceClass        = 255,
+               .bInterfaceSubClass     = 0,
+               .bInterfaceProtocol     = 255,
+               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_XMEN_III,
+       },
+       {
+               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+               .idVendor       = 0x0eb1,  /* Vendor ID of WIS Technologies */
+               .idProduct      = 0x7007,  /* Product ID of GO7007SB chip */
+               .bcdDevice_lo   = 0x210,   /* Revision number of Matrix */
+               .bcdDevice_hi   = 0x210,   /*     Revolution */
+               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_MATRIX_REV,
+       },
+       {
+               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+               .idVendor       = 0x093b,  /* Vendor ID of Plextor */
+               .idProduct      = 0xa102,  /* Product ID of M402U */
+               .bcdDevice_lo   = 0x1,     /* revision number of Blueberry */
+               .bcdDevice_hi   = 0x1,
+               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_PX_M402U,
+       },
+       {
+               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+               .idVendor       = 0x093b,  /* Vendor ID of Plextor */
+               .idProduct      = 0xa104,  /* Product ID of TV402U */
+               .bcdDevice_lo   = 0x1,
+               .bcdDevice_hi   = 0x1,
+               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U_ANY,
+       },
+       {
+               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+               .idVendor       = 0x10fd,  /* Vendor ID of Anubis Electronics */
+               .idProduct      = 0xde00,  /* Product ID of Lifeview LR192 */
+               .bcdDevice_lo   = 0x1,
+               .bcdDevice_hi   = 0x1,
+               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_LIFEVIEW_LR192,
+       },
+       {
+               .match_flags    = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+               .idVendor       = 0x1943,  /* Vendor ID Sensoray */
+               .idProduct      = 0x2250,  /* Product ID of 2250/2251 */
+               .bcdDevice_lo   = 0x1,
+               .bcdDevice_hi   = 0x1,
+               .driver_info    = (kernel_ulong_t)GO7007_BOARDID_SENSORAY_2250,
+       },
+       { }                                     /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, go7007_usb_id_table);
+
+/********************* Driver for EZ-USB HPI interface *********************/
+
+static int go7007_usb_vendor_request(struct go7007 *go, int request,
+               int value, int index, void *transfer_buffer, int length, int in)
+{
+       struct go7007_usb *usb = go->hpi_context;
+       int timeout = 5000;
+
+       if (in) {
+               return usb_control_msg(usb->usbdev,
+                               usb_rcvctrlpipe(usb->usbdev, 0), request,
+                               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                               value, index, transfer_buffer, length, timeout);
+       } else {
+               return usb_control_msg(usb->usbdev,
+                               usb_sndctrlpipe(usb->usbdev, 0), request,
+                               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               value, index, transfer_buffer, length, timeout);
+       }
+}
+
+static int go7007_usb_interface_reset(struct go7007 *go)
+{
+       struct go7007_usb *usb = go->hpi_context;
+       u16 intr_val, intr_data;
+
+       /* Reset encoder */
+       if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)
+               return -1;
+       msleep(100);
+
+       if (usb->board->flags & GO7007_USB_EZUSB) {
+               /* Reset buffer in EZ-USB */
+#ifdef GO7007_USB_DEBUG
+               printk(KERN_DEBUG "go7007-usb: resetting EZ-USB buffers\n");
+#endif
+               if (go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0 ||
+                   go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0)
+                       return -1;
+
+               /* Reset encoder again */
+               if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)
+                       return -1;
+               msleep(100);
+       }
+
+       /* Wait for an interrupt to indicate successful hardware reset */
+       if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
+                       (intr_val & ~0x1) != 0x55aa) {
+               printk(KERN_ERR
+                       "go7007-usb: unable to reset the USB interface\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int go7007_usb_ezusb_write_interrupt(struct go7007 *go,
+                                               int addr, int data)
+{
+       struct go7007_usb *usb = go->hpi_context;
+       int i, r;
+       u16 status_reg;
+       int timeout = 500;
+
+#ifdef GO7007_USB_DEBUG
+       printk(KERN_DEBUG
+               "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data);
+#endif
+
+       for (i = 0; i < 100; ++i) {
+               r = usb_control_msg(usb->usbdev,
+                               usb_rcvctrlpipe(usb->usbdev, 0), 0x14,
+                               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                               0, HPI_STATUS_ADDR, &status_reg,
+                               sizeof(status_reg), timeout);
+               if (r < 0)
+                       goto write_int_error;
+               __le16_to_cpus(&status_reg);
+               if (!(status_reg & 0x0010))
+                       break;
+               msleep(10);
+       }
+       if (i == 100) {
+               printk(KERN_ERR
+                       "go7007-usb: device is hung, status reg = 0x%04x\n",
+                       status_reg);
+               return -1;
+       }
+       r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), 0x12,
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE, data,
+                       INT_PARAM_ADDR, NULL, 0, timeout);
+       if (r < 0)
+               goto write_int_error;
+       r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0),
+                       0x12, USB_TYPE_VENDOR | USB_RECIP_DEVICE, addr,
+                       INT_INDEX_ADDR, NULL, 0, timeout);
+       if (r < 0)
+               goto write_int_error;
+       return 0;
+
+write_int_error:
+       printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r);
+       return r;
+}
+
+static int go7007_usb_onboard_write_interrupt(struct go7007 *go,
+                                               int addr, int data)
+{
+       struct go7007_usb *usb = go->hpi_context;
+       u8 *tbuf;
+       int r;
+       int timeout = 500;
+
+#ifdef GO7007_USB_DEBUG
+       printk(KERN_DEBUG
+               "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data);
+#endif
+
+       tbuf = kzalloc(8, GFP_KERNEL);
+       if (tbuf == NULL)
+               return -ENOMEM;
+       tbuf[0] = data & 0xff;
+       tbuf[1] = data >> 8;
+       tbuf[2] = addr & 0xff;
+       tbuf[3] = addr >> 8;
+       r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 2), 0x00,
+                       USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x55aa,
+                       0xf0f0, tbuf, 8, timeout);
+       kfree(tbuf);
+       if (r < 0) {
+               printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r);
+               return r;
+       }
+       return 0;
+}
+
+static void go7007_usb_readinterrupt_complete(struct urb *urb)
+{
+       struct go7007 *go = (struct go7007 *)urb->context;
+       u16 *regs = (u16 *)urb->transfer_buffer;
+       int status = urb->status;
+
+       if (status) {
+               if (status != -ESHUTDOWN &&
+                               go->status != STATUS_SHUTDOWN) {
+                       printk(KERN_ERR
+                               "go7007-usb: error in read interrupt: %d\n",
+                               urb->status);
+               } else {
+                       wake_up(&go->interrupt_waitq);
+                       return;
+               }
+       } else if (urb->actual_length != urb->transfer_buffer_length) {
+               printk(KERN_ERR "go7007-usb: short read in interrupt pipe!\n");
+       } else {
+               go->interrupt_available = 1;
+               go->interrupt_data = __le16_to_cpu(regs[0]);
+               go->interrupt_value = __le16_to_cpu(regs[1]);
+#ifdef GO7007_USB_DEBUG
+               printk(KERN_DEBUG "go7007-usb: ReadInterrupt: %04x %04x\n",
+                               go->interrupt_value, go->interrupt_data);
+#endif
+       }
+
+       wake_up(&go->interrupt_waitq);
+}
+
+static int go7007_usb_read_interrupt(struct go7007 *go)
+{
+       struct go7007_usb *usb = go->hpi_context;
+       int r;
+
+       r = usb_submit_urb(usb->intr_urb, GFP_KERNEL);
+       if (r < 0) {
+               printk(KERN_ERR
+                       "go7007-usb: unable to submit interrupt urb: %d\n", r);
+               return r;
+       }
+       return 0;
+}
+
+static void go7007_usb_read_video_pipe_complete(struct urb *urb)
+{
+       struct go7007 *go = (struct go7007 *)urb->context;
+       int r, status = urb->status;
+
+       if (!go->streaming) {
+               wake_up_interruptible(&go->frame_waitq);
+               return;
+       }
+       if (status) {
+               printk(KERN_ERR "go7007-usb: error in video pipe: %d\n",
+                       status);
+               return;
+       }
+       if (urb->actual_length != urb->transfer_buffer_length) {
+               printk(KERN_ERR "go7007-usb: short read in video pipe!\n");
+               return;
+       }
+       go7007_parse_video_stream(go, urb->transfer_buffer, urb->actual_length);
+       r = usb_submit_urb(urb, GFP_ATOMIC);
+       if (r < 0)
+               printk(KERN_ERR "go7007-usb: error in video pipe: %d\n", r);
+}
+
+static void go7007_usb_read_audio_pipe_complete(struct urb *urb)
+{
+       struct go7007 *go = (struct go7007 *)urb->context;
+       int r, status = urb->status;
+
+       if (!go->streaming)
+               return;
+       if (status) {
+               printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n",
+                       status);
+               return;
+       }
+       if (urb->actual_length != urb->transfer_buffer_length) {
+               printk(KERN_ERR "go7007-usb: short read in audio pipe!\n");
+               return;
+       }
+       if (go->audio_deliver != NULL)
+               go->audio_deliver(go, urb->transfer_buffer, urb->actual_length);
+       r = usb_submit_urb(urb, GFP_ATOMIC);
+       if (r < 0)
+               printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", r);
+}
+
+static int go7007_usb_stream_start(struct go7007 *go)
+{
+       struct go7007_usb *usb = go->hpi_context;
+       int i, r;
+
+       for (i = 0; i < 8; ++i) {
+               r = usb_submit_urb(usb->video_urbs[i], GFP_KERNEL);
+               if (r < 0) {
+                       printk(KERN_ERR "go7007-usb: error submitting video "
+                                       "urb %d: %d\n", i, r);
+                       goto video_submit_failed;
+               }
+       }
+       if (!go->audio_enabled)
+               return 0;
+
+       for (i = 0; i < 8; ++i) {
+               r = usb_submit_urb(usb->audio_urbs[i], GFP_KERNEL);
+               if (r < 0) {
+                       printk(KERN_ERR "go7007-usb: error submitting audio "
+                                       "urb %d: %d\n", i, r);
+                       goto audio_submit_failed;
+               }
+       }
+       return 0;
+
+audio_submit_failed:
+       for (i = 0; i < 7; ++i)
+               usb_kill_urb(usb->audio_urbs[i]);
+video_submit_failed:
+       for (i = 0; i < 8; ++i)
+               usb_kill_urb(usb->video_urbs[i]);
+       return -1;
+}
+
+static int go7007_usb_stream_stop(struct go7007 *go)
+{
+       struct go7007_usb *usb = go->hpi_context;
+       int i;
+
+       if (go->status == STATUS_SHUTDOWN)
+               return 0;
+       for (i = 0; i < 8; ++i)
+               usb_kill_urb(usb->video_urbs[i]);
+       if (go->audio_enabled)
+               for (i = 0; i < 8; ++i)
+                       usb_kill_urb(usb->audio_urbs[i]);
+       return 0;
+}
+
+static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len)
+{
+       struct go7007_usb *usb = go->hpi_context;
+       int transferred, pipe;
+       int timeout = 500;
+
+#ifdef GO7007_USB_DEBUG
+       printk(KERN_DEBUG "go7007-usb: DownloadBuffer sending %d bytes\n", len);
+#endif
+
+       if (usb->board->flags & GO7007_USB_EZUSB)
+               pipe = usb_sndbulkpipe(usb->usbdev, 2);
+       else
+               pipe = usb_sndbulkpipe(usb->usbdev, 3);
+
+       return usb_bulk_msg(usb->usbdev, pipe, data, len,
+                                       &transferred, timeout);
+}
+
+static struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = {
+       .interface_reset        = go7007_usb_interface_reset,
+       .write_interrupt        = go7007_usb_ezusb_write_interrupt,
+       .read_interrupt         = go7007_usb_read_interrupt,
+       .stream_start           = go7007_usb_stream_start,
+       .stream_stop            = go7007_usb_stream_stop,
+       .send_firmware          = go7007_usb_send_firmware,
+};
+
+static struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = {
+       .interface_reset        = go7007_usb_interface_reset,
+       .write_interrupt        = go7007_usb_onboard_write_interrupt,
+       .read_interrupt         = go7007_usb_read_interrupt,
+       .stream_start           = go7007_usb_stream_start,
+       .stream_stop            = go7007_usb_stream_stop,
+       .send_firmware          = go7007_usb_send_firmware,
+};
+
+/********************* Driver for EZ-USB I2C adapter *********************/
+
+static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter,
+                                       struct i2c_msg msgs[], int num)
+{
+       struct go7007 *go = i2c_get_adapdata(adapter);
+       struct go7007_usb *usb = go->hpi_context;
+       u8 buf[16];
+       int buf_len, i;
+       int ret = -1;
+
+       if (go->status == STATUS_SHUTDOWN)
+               return -1;
+
+       mutex_lock(&usb->i2c_lock);
+
+       for (i = 0; i < num; ++i) {
+               /* The hardware command is "write some bytes then read some
+                * bytes", so we try to coalesce a write followed by a read
+                * into a single USB transaction */
+               if (i + 1 < num && msgs[i].addr == msgs[i + 1].addr &&
+                               !(msgs[i].flags & I2C_M_RD) &&
+                               (msgs[i + 1].flags & I2C_M_RD)) {
+#ifdef GO7007_I2C_DEBUG
+                       printk(KERN_DEBUG "go7007-usb: i2c write/read %d/%d "
+                                       "bytes on %02x\n", msgs[i].len,
+                                       msgs[i + 1].len, msgs[i].addr);
+#endif
+                       buf[0] = 0x01;
+                       buf[1] = msgs[i].len + 1;
+                       buf[2] = msgs[i].addr << 1;
+                       memcpy(&buf[3], msgs[i].buf, msgs[i].len);
+                       buf_len = msgs[i].len + 3;
+                       buf[buf_len++] = msgs[++i].len;
+               } else if (msgs[i].flags & I2C_M_RD) {
+#ifdef GO7007_I2C_DEBUG
+                       printk(KERN_DEBUG "go7007-usb: i2c read %d "
+                                       "bytes on %02x\n", msgs[i].len,
+                                       msgs[i].addr);
+#endif
+                       buf[0] = 0x01;
+                       buf[1] = 1;
+                       buf[2] = msgs[i].addr << 1;
+                       buf[3] = msgs[i].len;
+                       buf_len = 4;
+               } else {
+#ifdef GO7007_I2C_DEBUG
+                       printk(KERN_DEBUG "go7007-usb: i2c write %d "
+                                       "bytes on %02x\n", msgs[i].len,
+                                       msgs[i].addr);
+#endif
+                       buf[0] = 0x00;
+                       buf[1] = msgs[i].len + 1;
+                       buf[2] = msgs[i].addr << 1;
+                       memcpy(&buf[3], msgs[i].buf, msgs[i].len);
+                       buf_len = msgs[i].len + 3;
+                       buf[buf_len++] = 0;
+               }
+               if (go7007_usb_vendor_request(go, 0x24, 0, 0,
+                                               buf, buf_len, 0) < 0)
+                       goto i2c_done;
+               if (msgs[i].flags & I2C_M_RD) {
+                       memset(buf, 0, sizeof(buf));
+                       if (go7007_usb_vendor_request(go, 0x25, 0, 0, buf,
+                                               msgs[i].len + 1, 1) < 0)
+                               goto i2c_done;
+                       memcpy(msgs[i].buf, buf + 1, msgs[i].len);
+               }
+       }
+       ret = 0;
+
+i2c_done:
+       mutex_unlock(&usb->i2c_lock);
+       return ret;
+}
+
+static u32 go7007_usb_functionality(struct i2c_adapter *adapter)
+{
+       /* No errors are reported by the hardware, so we don't bother
+        * supporting quick writes to avoid confusing probing */
+       return (I2C_FUNC_SMBUS_EMUL) & ~I2C_FUNC_SMBUS_QUICK;
+}
+
+static struct i2c_algorithm go7007_usb_algo = {
+       .master_xfer    = go7007_usb_i2c_master_xfer,
+       .functionality  = go7007_usb_functionality,
+};
+
+static struct i2c_adapter go7007_usb_adap_templ = {
+       .owner                  = THIS_MODULE,
+       .name                   = "WIS GO7007SB EZ-USB",
+       .algo                   = &go7007_usb_algo,
+};
+
+/********************* USB add/remove functions *********************/
+
+static int go7007_usb_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       struct go7007 *go;
+       struct go7007_usb *usb;
+       struct go7007_usb_board *board;
+       struct usb_device *usbdev = interface_to_usbdev(intf);
+       char *name;
+       int video_pipe, i, v_urb_len;
+
+       printk(KERN_DEBUG "go7007-usb: probing new GO7007 USB board\n");
+
+       switch (id->driver_info) {
+       case GO7007_BOARDID_MATRIX_II:
+               name = "WIS Matrix II or compatible";
+               board = &board_matrix_ii;
+               break;
+       case GO7007_BOARDID_MATRIX_RELOAD:
+               name = "WIS Matrix Reloaded or compatible";
+               board = &board_matrix_reload;
+               break;
+       case GO7007_BOARDID_MATRIX_REV:
+               name = "WIS Matrix Revolution or compatible";
+               board = &board_matrix_revolution;
+               break;
+       case GO7007_BOARDID_STAR_TREK:
+               name = "WIS Star Trek or compatible";
+               board = &board_star_trek;
+               break;
+       case GO7007_BOARDID_XMEN:
+               name = "WIS XMen or compatible";
+               board = &board_xmen;
+               break;
+       case GO7007_BOARDID_XMEN_II:
+               name = "WIS XMen II or compatible";
+               board = &board_xmen;
+               break;
+       case GO7007_BOARDID_XMEN_III:
+               name = "WIS XMen III or compatible";
+               board = &board_xmen;
+               break;
+       case GO7007_BOARDID_PX_M402U:
+               name = "Plextor PX-M402U";
+               board = &board_matrix_ii;
+               break;
+       case GO7007_BOARDID_PX_TV402U_ANY:
+               name = "Plextor PX-TV402U (unknown tuner)";
+               board = &board_px_tv402u;
+               break;
+       case GO7007_BOARDID_LIFEVIEW_LR192:
+               printk(KERN_ERR "go7007-usb: The Lifeview TV Walker Ultra "
+                               "is not supported.  Sorry!\n");
+               return 0;
+               name = "Lifeview TV Walker Ultra";
+               board = &board_lifeview_lr192;
+               break;
+       case GO7007_BOARDID_SENSORAY_2250:
+               printk(KERN_INFO "Sensoray 2250 found\n");
+               name = "Sensoray 2250/2251";
+               board = &board_sensoray_2250;
+               break;
+       default:
+               printk(KERN_ERR "go7007-usb: unknown board ID %d!\n",
+                               (unsigned int)id->driver_info);
+               return 0;
+       }
+
+       usb = kzalloc(sizeof(struct go7007_usb), GFP_KERNEL);
+       if (usb == NULL)
+               return -ENOMEM;
+
+       /* Allocate the URB and buffer for receiving incoming interrupts */
+       usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (usb->intr_urb == NULL)
+               goto allocfail;
+       usb->intr_urb->transfer_buffer = kmalloc(2*sizeof(u16), GFP_KERNEL);
+       if (usb->intr_urb->transfer_buffer == NULL)
+               goto allocfail;
+
+       go = go7007_alloc(&board->main_info, &intf->dev);
+       if (go == NULL)
+               goto allocfail;
+       usb->board = board;
+       usb->usbdev = usbdev;
+       go->board_id = id->driver_info;
+       strncpy(go->name, name, sizeof(go->name));
+       if (board->flags & GO7007_USB_EZUSB)
+               go->hpi_ops = &go7007_usb_ezusb_hpi_ops;
+       else
+               go->hpi_ops = &go7007_usb_onboard_hpi_ops;
+       go->hpi_context = usb;
+       usb_fill_int_urb(usb->intr_urb, usb->usbdev,
+                       usb_rcvintpipe(usb->usbdev, 4),
+                       usb->intr_urb->transfer_buffer, 2*sizeof(u16),
+                       go7007_usb_readinterrupt_complete, go, 8);
+       usb_set_intfdata(intf, &go->v4l2_dev);
+
+       /* Boot the GO7007 */
+       if (go7007_boot_encoder(go, go->board_info->flags &
+                                       GO7007_BOARD_USE_ONBOARD_I2C) < 0)
+               goto initfail;
+
+       /* Register the EZ-USB I2C adapter, if we're using it */
+       if (board->flags & GO7007_USB_EZUSB_I2C) {
+               memcpy(&go->i2c_adapter, &go7007_usb_adap_templ,
+                               sizeof(go7007_usb_adap_templ));
+               mutex_init(&usb->i2c_lock);
+               go->i2c_adapter.dev.parent = go->dev;
+               i2c_set_adapdata(&go->i2c_adapter, go);
+               if (i2c_add_adapter(&go->i2c_adapter) < 0) {
+                       printk(KERN_ERR
+                               "go7007-usb: error: i2c_add_adapter failed\n");
+                       goto initfail;
+               }
+               go->i2c_adapter_online = 1;
+       }
+
+       /* Pelco and Adlink reused the XMen and XMen-III vendor and product
+        * IDs for their own incompatible designs.  We can detect XMen boards
+        * by probing the sensor, but there is no way to probe the sensors on
+        * the Pelco and Adlink designs so we default to the Adlink.  If it
+        * is actually a Pelco, the user must set the assume_endura module
+        * parameter. */
+       if ((go->board_id == GO7007_BOARDID_XMEN ||
+                               go->board_id == GO7007_BOARDID_XMEN_III) &&
+                       go->i2c_adapter_online) {
+               union i2c_smbus_data data;
+
+               /* Check to see if register 0x0A is 0x76 */
+               i2c_smbus_xfer(&go->i2c_adapter, 0x21, I2C_CLIENT_SCCB,
+                       I2C_SMBUS_READ, 0x0A, I2C_SMBUS_BYTE_DATA, &data);
+               if (data.byte != 0x76) {
+                       if (assume_endura) {
+                               go->board_id = GO7007_BOARDID_ENDURA;
+                               usb->board = board = &board_endura;
+                               go->board_info = &board->main_info;
+                               strncpy(go->name, "Pelco Endura",
+                                       sizeof(go->name));
+                       } else {
+                               u16 channel;
+
+                               /* set GPIO5 to be an output, currently low */
+                               go7007_write_addr(go, 0x3c82, 0x0000);
+                               go7007_write_addr(go, 0x3c80, 0x00df);
+                               /* read channel number from GPIO[1:0] */
+                               go7007_read_addr(go, 0x3c81, &channel);
+                               channel &= 0x3;
+                               go->board_id = GO7007_BOARDID_ADLINK_MPG24;
+                               usb->board = board = &board_adlink_mpg24;
+                               go->board_info = &board->main_info;
+                               go->channel_number = channel;
+                               snprintf(go->name, sizeof(go->name),
+                                       "Adlink PCI-MPG24, channel #%d",
+                                       channel);
+                       }
+               }
+       }
+
+       /* Probe the tuner model on the TV402U */
+       if (go->board_id == GO7007_BOARDID_PX_TV402U_ANY) {
+               u8 data[3];
+
+               /* Board strapping indicates tuner model */
+               if (go7007_usb_vendor_request(go, 0x41, 0, 0, data, 3, 1) < 0) {
+                       printk(KERN_ERR "go7007-usb: GPIO read failed!\n");
+                       goto initfail;
+               }
+               switch (data[0] >> 6) {
+               case 1:
+                       go->board_id = GO7007_BOARDID_PX_TV402U_EU;
+                       go->tuner_type = TUNER_SONY_BTF_PG472Z;
+                       strncpy(go->name, "Plextor PX-TV402U-EU",
+                                       sizeof(go->name));
+                       break;
+               case 2:
+                       go->board_id = GO7007_BOARDID_PX_TV402U_JP;
+                       go->tuner_type = TUNER_SONY_BTF_PK467Z;
+                       strncpy(go->name, "Plextor PX-TV402U-JP",
+                                       sizeof(go->name));
+                       break;
+               case 3:
+                       go->board_id = GO7007_BOARDID_PX_TV402U_NA;
+                       go->tuner_type = TUNER_SONY_BTF_PB463Z;
+                       strncpy(go->name, "Plextor PX-TV402U-NA",
+                                       sizeof(go->name));
+                       break;
+               default:
+                       printk(KERN_DEBUG "go7007-usb: unable to detect "
+                                               "tuner type!\n");
+                       break;
+               }
+               /* Configure tuner mode selection inputs connected
+                * to the EZ-USB GPIO output pins */
+               if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0,
+                                       NULL, 0, 0) < 0) {
+                       printk(KERN_ERR "go7007-usb: GPIO write failed!\n");
+                       goto initfail;
+               }
+       }
+
+       /* Print a nasty message if the user attempts to use a USB2.0 device in
+        * a USB1.1 port.  There will be silent corruption of the stream. */
+       if ((board->flags & GO7007_USB_EZUSB) &&
+                       usbdev->speed != USB_SPEED_HIGH)
+               printk(KERN_ERR "go7007-usb: *** WARNING ***  This device "
+                               "must be connected to a USB 2.0 port!  "
+                               "Attempting to capture video through a USB 1.1 "
+                               "port will result in stream corruption, even "
+                               "at low bitrates!\n");
+
+       /* Do any final GO7007 initialization, then register the
+        * V4L2 and ALSA interfaces */
+       if (go7007_register_encoder(go) < 0)
+               goto initfail;
+
+       /* Allocate the URBs and buffers for receiving the video stream */
+       if (board->flags & GO7007_USB_EZUSB) {
+               v_urb_len = 1024;
+               video_pipe = usb_rcvbulkpipe(usb->usbdev, 6);
+       } else {
+               v_urb_len = 512;
+               video_pipe = usb_rcvbulkpipe(usb->usbdev, 1);
+       }
+       for (i = 0; i < 8; ++i) {
+               usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
+               if (usb->video_urbs[i] == NULL)
+                       goto initfail;
+               usb->video_urbs[i]->transfer_buffer =
+                                               kmalloc(v_urb_len, GFP_KERNEL);
+               if (usb->video_urbs[i]->transfer_buffer == NULL)
+                       goto initfail;
+               usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe,
+                               usb->video_urbs[i]->transfer_buffer, v_urb_len,
+                               go7007_usb_read_video_pipe_complete, go);
+       }
+
+       /* Allocate the URBs and buffers for receiving the audio stream */
+       if ((board->flags & GO7007_USB_EZUSB) && go->audio_enabled)
+               for (i = 0; i < 8; ++i) {
+                       usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
+                       if (usb->audio_urbs[i] == NULL)
+                               goto initfail;
+                       usb->audio_urbs[i]->transfer_buffer = kmalloc(4096,
+                                                               GFP_KERNEL);
+                       if (usb->audio_urbs[i]->transfer_buffer == NULL)
+                               goto initfail;
+                       usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev,
+                               usb_rcvbulkpipe(usb->usbdev, 8),
+                               usb->audio_urbs[i]->transfer_buffer, 4096,
+                               go7007_usb_read_audio_pipe_complete, go);
+               }
+
+
+       go->status = STATUS_ONLINE;
+       return 0;
+
+initfail:
+       go->status = STATUS_SHUTDOWN;
+       return 0;
+
+allocfail:
+       if (usb->intr_urb) {
+               kfree(usb->intr_urb->transfer_buffer);
+               usb_free_urb(usb->intr_urb);
+       }
+       kfree(usb);
+       return -ENOMEM;
+}
+
+static void go7007_usb_disconnect(struct usb_interface *intf)
+{
+       struct go7007 *go = to_go7007(usb_get_intfdata(intf));
+       struct go7007_usb *usb = go->hpi_context;
+       struct urb *vurb, *aurb;
+       int i;
+
+       go->status = STATUS_SHUTDOWN;
+       usb_kill_urb(usb->intr_urb);
+
+       /* Free USB-related structs */
+       for (i = 0; i < 8; ++i) {
+               vurb = usb->video_urbs[i];
+               if (vurb) {
+                       usb_kill_urb(vurb);
+                       kfree(vurb->transfer_buffer);
+                       usb_free_urb(vurb);
+               }
+               aurb = usb->audio_urbs[i];
+               if (aurb) {
+                       usb_kill_urb(aurb);
+                       kfree(aurb->transfer_buffer);
+                       usb_free_urb(aurb);
+               }
+       }
+       kfree(usb->intr_urb->transfer_buffer);
+       usb_free_urb(usb->intr_urb);
+
+       kfree(go->hpi_context);
+
+       go7007_remove(go);
+}
+
+static struct usb_driver go7007_usb_driver = {
+       .name           = "go7007",
+       .probe          = go7007_usb_probe,
+       .disconnect     = go7007_usb_disconnect,
+       .id_table       = go7007_usb_id_table,
+};
+
+static int __init go7007_usb_init(void)
+{
+       return usb_register(&go7007_usb_driver);
+}
+
+static void __exit go7007_usb_cleanup(void)
+{
+       usb_deregister(&go7007_usb_driver);
+}
+
+module_init(go7007_usb_init);
+module_exit(go7007_usb_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c
new file mode 100644 (file)
index 0000000..2b27d8d
--- /dev/null
@@ -0,0 +1,1839 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/unistd.h>
+#include <linux/time.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#include "go7007.h"
+#include "go7007-priv.h"
+#include "wis-i2c.h"
+
+/* Temporary defines until accepted in v4l-dvb */
+#ifndef V4L2_MPEG_STREAM_TYPE_MPEG_ELEM
+#define        V4L2_MPEG_STREAM_TYPE_MPEG_ELEM   6 /* MPEG elementary stream */
+#endif
+#ifndef V4L2_MPEG_VIDEO_ENCODING_MPEG_4
+#define        V4L2_MPEG_VIDEO_ENCODING_MPEG_4   3
+#endif
+
+#define call_all(dev, o, f, args...) \
+       v4l2_device_call_until_err(dev, 0, o, f, ##args)
+
+static void deactivate_buffer(struct go7007_buffer *gobuf)
+{
+       int i;
+
+       if (gobuf->state != BUF_STATE_IDLE) {
+               list_del(&gobuf->stream);
+               gobuf->state = BUF_STATE_IDLE;
+       }
+       if (gobuf->page_count > 0) {
+               for (i = 0; i < gobuf->page_count; ++i)
+                       page_cache_release(gobuf->pages[i]);
+               gobuf->page_count = 0;
+       }
+}
+
+static void abort_queued(struct go7007 *go)
+{
+       struct go7007_buffer *gobuf, *next;
+
+       list_for_each_entry_safe(gobuf, next, &go->stream, stream) {
+               deactivate_buffer(gobuf);
+       }
+}
+
+static int go7007_streamoff(struct go7007 *go)
+{
+       int retval = -EINVAL;
+       unsigned long flags;
+
+       mutex_lock(&go->hw_lock);
+       if (go->streaming) {
+               go->streaming = 0;
+               go7007_stream_stop(go);
+               spin_lock_irqsave(&go->spinlock, flags);
+               abort_queued(go);
+               spin_unlock_irqrestore(&go->spinlock, flags);
+               go7007_reset_encoder(go);
+               retval = 0;
+       }
+       mutex_unlock(&go->hw_lock);
+       return 0;
+}
+
+static int go7007_open(struct file *file)
+{
+       struct go7007 *go = video_get_drvdata(video_devdata(file));
+       struct go7007_file *gofh;
+
+       if (go->status != STATUS_ONLINE)
+               return -EBUSY;
+       gofh = kmalloc(sizeof(struct go7007_file), GFP_KERNEL);
+       if (gofh == NULL)
+               return -ENOMEM;
+       ++go->ref_count;
+       gofh->go = go;
+       mutex_init(&gofh->lock);
+       gofh->buf_count = 0;
+       file->private_data = gofh;
+       return 0;
+}
+
+static int go7007_release(struct file *file)
+{
+       struct go7007_file *gofh = file->private_data;
+       struct go7007 *go = gofh->go;
+
+       if (gofh->buf_count > 0) {
+               go7007_streamoff(go);
+               go->in_use = 0;
+               kfree(gofh->bufs);
+               gofh->buf_count = 0;
+       }
+       kfree(gofh);
+       if (--go->ref_count == 0)
+               kfree(go);
+       file->private_data = NULL;
+       return 0;
+}
+
+static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format)
+{
+       u8 *f = page_address(gobuf->pages[0]);
+
+       switch (format) {
+       case GO7007_FORMAT_MJPEG:
+               return V4L2_BUF_FLAG_KEYFRAME;
+       case GO7007_FORMAT_MPEG4:
+               switch ((f[gobuf->frame_offset + 4] >> 6) & 0x3) {
+               case 0:
+                       return V4L2_BUF_FLAG_KEYFRAME;
+               case 1:
+                       return V4L2_BUF_FLAG_PFRAME;
+               case 2:
+                       return V4L2_BUF_FLAG_BFRAME;
+               default:
+                       return 0;
+               }
+       case GO7007_FORMAT_MPEG1:
+       case GO7007_FORMAT_MPEG2:
+               switch ((f[gobuf->frame_offset + 5] >> 3) & 0x7) {
+               case 1:
+                       return V4L2_BUF_FLAG_KEYFRAME;
+               case 2:
+                       return V4L2_BUF_FLAG_PFRAME;
+               case 3:
+                       return V4L2_BUF_FLAG_BFRAME;
+               default:
+                       return 0;
+               }
+       }
+
+       return 0;
+}
+
+static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
+{
+       int sensor_height = 0, sensor_width = 0;
+       int width, height, i;
+
+       if (fmt != NULL && fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG &&
+                       fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG &&
+                       fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG4)
+               return -EINVAL;
+
+       switch (go->standard) {
+       case GO7007_STD_NTSC:
+               sensor_width = 720;
+               sensor_height = 480;
+               break;
+       case GO7007_STD_PAL:
+               sensor_width = 720;
+               sensor_height = 576;
+               break;
+       case GO7007_STD_OTHER:
+               sensor_width = go->board_info->sensor_width;
+               sensor_height = go->board_info->sensor_height;
+               break;
+       }
+
+       if (fmt == NULL) {
+               width = sensor_width;
+               height = sensor_height;
+       } else if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
+               if (fmt->fmt.pix.width > sensor_width)
+                       width = sensor_width;
+               else if (fmt->fmt.pix.width < 144)
+                       width = 144;
+               else
+                       width = fmt->fmt.pix.width & ~0x0f;
+
+               if (fmt->fmt.pix.height > sensor_height)
+                       height = sensor_height;
+               else if (fmt->fmt.pix.height < 96)
+                       height = 96;
+               else
+                       height = fmt->fmt.pix.height & ~0x0f;
+       } else {
+               int requested_size = fmt->fmt.pix.width * fmt->fmt.pix.height;
+               int sensor_size = sensor_width * sensor_height;
+
+               if (64 * requested_size < 9 * sensor_size) {
+                       width = sensor_width / 4;
+                       height = sensor_height / 4;
+               } else if (64 * requested_size < 36 * sensor_size) {
+                       width = sensor_width / 2;
+                       height = sensor_height / 2;
+               } else {
+                       width = sensor_width;
+                       height = sensor_height;
+               }
+               width &= ~0xf;
+               height &= ~0xf;
+       }
+
+       if (fmt != NULL) {
+               u32 pixelformat = fmt->fmt.pix.pixelformat;
+
+               memset(fmt, 0, sizeof(*fmt));
+               fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               fmt->fmt.pix.width = width;
+               fmt->fmt.pix.height = height;
+               fmt->fmt.pix.pixelformat = pixelformat;
+               fmt->fmt.pix.field = V4L2_FIELD_NONE;
+               fmt->fmt.pix.bytesperline = 0;
+               fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
+               fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* ?? */
+       }
+
+       if (try)
+               return 0;
+
+       go->width = width;
+       go->height = height;
+       go->encoder_h_offset = go->board_info->sensor_h_offset;
+       go->encoder_v_offset = go->board_info->sensor_v_offset;
+       for (i = 0; i < 4; ++i)
+               go->modet[i].enable = 0;
+       for (i = 0; i < 1624; ++i)
+               go->modet_map[i] = 0;
+
+       if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
+               struct v4l2_mbus_framefmt mbus_fmt;
+
+               mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+               if (fmt != NULL)
+                       mbus_fmt.width = fmt->fmt.pix.width;
+               else
+                       mbus_fmt.width = width;
+
+               if (height > sensor_height / 2) {
+                       mbus_fmt.height = height / 2;
+                       go->encoder_v_halve = 0;
+               } else {
+                       mbus_fmt.height = height;
+                       go->encoder_v_halve = 1;
+               }
+               call_all(&go->v4l2_dev, video, s_mbus_fmt, &mbus_fmt);
+       } else {
+               if (width <= sensor_width / 4) {
+                       go->encoder_h_halve = 1;
+                       go->encoder_v_halve = 1;
+                       go->encoder_subsample = 1;
+               } else if (width <= sensor_width / 2) {
+                       go->encoder_h_halve = 1;
+                       go->encoder_v_halve = 1;
+                       go->encoder_subsample = 0;
+               } else {
+                       go->encoder_h_halve = 0;
+                       go->encoder_v_halve = 0;
+                       go->encoder_subsample = 0;
+               }
+       }
+
+       if (fmt == NULL)
+               return 0;
+
+       switch (fmt->fmt.pix.pixelformat) {
+       case V4L2_PIX_FMT_MPEG:
+               if (go->format == GO7007_FORMAT_MPEG1 ||
+                               go->format == GO7007_FORMAT_MPEG2 ||
+                               go->format == GO7007_FORMAT_MPEG4)
+                       break;
+               go->format = GO7007_FORMAT_MPEG1;
+               go->pali = 0;
+               go->aspect_ratio = GO7007_RATIO_1_1;
+               go->gop_size = go->sensor_framerate / 1000;
+               go->ipb = 0;
+               go->closed_gop = 1;
+               go->repeat_seqhead = 1;
+               go->seq_header_enable = 1;
+               go->gop_header_enable = 1;
+               go->dvd_mode = 0;
+               break;
+       /* Backwards compatibility only! */
+       case V4L2_PIX_FMT_MPEG4:
+               if (go->format == GO7007_FORMAT_MPEG4)
+                       break;
+               go->format = GO7007_FORMAT_MPEG4;
+               go->pali = 0xf5;
+               go->aspect_ratio = GO7007_RATIO_1_1;
+               go->gop_size = go->sensor_framerate / 1000;
+               go->ipb = 0;
+               go->closed_gop = 1;
+               go->repeat_seqhead = 1;
+               go->seq_header_enable = 1;
+               go->gop_header_enable = 1;
+               go->dvd_mode = 0;
+               break;
+       case V4L2_PIX_FMT_MJPEG:
+               go->format = GO7007_FORMAT_MJPEG;
+               go->pali = 0;
+               go->aspect_ratio = GO7007_RATIO_1_1;
+               go->gop_size = 0;
+               go->ipb = 0;
+               go->closed_gop = 0;
+               go->repeat_seqhead = 0;
+               go->seq_header_enable = 0;
+               go->gop_header_enable = 0;
+               go->dvd_mode = 0;
+               break;
+       }
+       return 0;
+}
+
+#if 0
+static int clip_to_modet_map(struct go7007 *go, int region,
+               struct v4l2_clip *clip_list)
+{
+       struct v4l2_clip clip, *clip_ptr;
+       int x, y, mbnum;
+
+       /* Check if coordinates are OK and if any macroblocks are already
+        * used by other regions (besides 0) */
+       clip_ptr = clip_list;
+       while (clip_ptr) {
+               if (copy_from_user(&clip, clip_ptr, sizeof(clip)))
+                       return -EFAULT;
+               if (clip.c.left < 0 || (clip.c.left & 0xF) ||
+                               clip.c.width <= 0 || (clip.c.width & 0xF))
+                       return -EINVAL;
+               if (clip.c.left + clip.c.width > go->width)
+                       return -EINVAL;
+               if (clip.c.top < 0 || (clip.c.top & 0xF) ||
+                               clip.c.height <= 0 || (clip.c.height & 0xF))
+                       return -EINVAL;
+               if (clip.c.top + clip.c.height > go->height)
+                       return -EINVAL;
+               for (y = 0; y < clip.c.height; y += 16)
+                       for (x = 0; x < clip.c.width; x += 16) {
+                               mbnum = (go->width >> 4) *
+                                               ((clip.c.top + y) >> 4) +
+                                       ((clip.c.left + x) >> 4);
+                               if (go->modet_map[mbnum] != 0 &&
+                                               go->modet_map[mbnum] != region)
+                                       return -EBUSY;
+                       }
+               clip_ptr = clip.next;
+       }
+
+       /* Clear old region macroblocks */
+       for (mbnum = 0; mbnum < 1624; ++mbnum)
+               if (go->modet_map[mbnum] == region)
+                       go->modet_map[mbnum] = 0;
+
+       /* Claim macroblocks in this list */
+       clip_ptr = clip_list;
+       while (clip_ptr) {
+               if (copy_from_user(&clip, clip_ptr, sizeof(clip)))
+                       return -EFAULT;
+               for (y = 0; y < clip.c.height; y += 16)
+                       for (x = 0; x < clip.c.width; x += 16) {
+                               mbnum = (go->width >> 4) *
+                                               ((clip.c.top + y) >> 4) +
+                                       ((clip.c.left + x) >> 4);
+                               go->modet_map[mbnum] = region;
+                       }
+               clip_ptr = clip.next;
+       }
+       return 0;
+}
+#endif
+
+static int mpeg_query_ctrl(struct v4l2_queryctrl *ctrl)
+{
+       static const u32 mpeg_ctrls[] = {
+               V4L2_CID_MPEG_CLASS,
+               V4L2_CID_MPEG_STREAM_TYPE,
+               V4L2_CID_MPEG_VIDEO_ENCODING,
+               V4L2_CID_MPEG_VIDEO_ASPECT,
+               V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+               V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+               V4L2_CID_MPEG_VIDEO_BITRATE,
+               0
+       };
+       static const u32 *ctrl_classes[] = {
+               mpeg_ctrls,
+               NULL
+       };
+
+       ctrl->id = v4l2_ctrl_next(ctrl_classes, ctrl->id);
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_CLASS:
+               return v4l2_ctrl_query_fill(ctrl, 0, 0, 0, 0);
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               return v4l2_ctrl_query_fill(ctrl,
+                               V4L2_MPEG_STREAM_TYPE_MPEG2_DVD,
+                               V4L2_MPEG_STREAM_TYPE_MPEG_ELEM, 1,
+                               V4L2_MPEG_STREAM_TYPE_MPEG_ELEM);
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               return v4l2_ctrl_query_fill(ctrl,
+                               V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+                               V4L2_MPEG_VIDEO_ENCODING_MPEG_4, 1,
+                               V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               return v4l2_ctrl_query_fill(ctrl,
+                               V4L2_MPEG_VIDEO_ASPECT_1x1,
+                               V4L2_MPEG_VIDEO_ASPECT_16x9, 1,
+                               V4L2_MPEG_VIDEO_ASPECT_1x1);
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               return v4l2_ctrl_query_fill(ctrl, 0, 34, 1, 15);
+       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+               return v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               return v4l2_ctrl_query_fill(ctrl,
+                               64000,
+                               10000000, 1,
+                               1500000);
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int mpeg_s_ctrl(struct v4l2_control *ctrl, struct go7007 *go)
+{
+       /* pretty sure we can't change any of these while streaming */
+       if (go->streaming)
+               return -EBUSY;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               switch (ctrl->value) {
+               case V4L2_MPEG_STREAM_TYPE_MPEG2_DVD:
+                       go->format = GO7007_FORMAT_MPEG2;
+                       go->bitrate = 9800000;
+                       go->gop_size = 15;
+                       go->pali = 0x48;
+                       go->closed_gop = 1;
+                       go->repeat_seqhead = 0;
+                       go->seq_header_enable = 1;
+                       go->gop_header_enable = 1;
+                       go->dvd_mode = 1;
+                       break;
+               case V4L2_MPEG_STREAM_TYPE_MPEG_ELEM:
+                       /* todo: */
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               switch (ctrl->value) {
+               case V4L2_MPEG_VIDEO_ENCODING_MPEG_1:
+                       go->format = GO7007_FORMAT_MPEG1;
+                       go->pali = 0;
+                       break;
+               case V4L2_MPEG_VIDEO_ENCODING_MPEG_2:
+                       go->format = GO7007_FORMAT_MPEG2;
+                       /*if (mpeg->pali >> 24 == 2)
+                               go->pali = mpeg->pali & 0xff;
+                       else*/
+                               go->pali = 0x48;
+                       break;
+               case V4L2_MPEG_VIDEO_ENCODING_MPEG_4:
+                       go->format = GO7007_FORMAT_MPEG4;
+                       /*if (mpeg->pali >> 24 == 4)
+                               go->pali = mpeg->pali & 0xff;
+                       else*/
+                               go->pali = 0xf5;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               go->gop_header_enable =
+                       /*mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER
+                       ? 0 :*/ 1;
+               /*if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER)
+                       go->repeat_seqhead = 1;
+               else*/
+                       go->repeat_seqhead = 0;
+               go->dvd_mode = 0;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               if (go->format == GO7007_FORMAT_MJPEG)
+                       return -EINVAL;
+               switch (ctrl->value) {
+               case V4L2_MPEG_VIDEO_ASPECT_1x1:
+                       go->aspect_ratio = GO7007_RATIO_1_1;
+                       break;
+               case V4L2_MPEG_VIDEO_ASPECT_4x3:
+                       go->aspect_ratio = GO7007_RATIO_4_3;
+                       break;
+               case V4L2_MPEG_VIDEO_ASPECT_16x9:
+                       go->aspect_ratio = GO7007_RATIO_16_9;
+                       break;
+               case V4L2_MPEG_VIDEO_ASPECT_221x100:
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               if (ctrl->value < 0 || ctrl->value > 34)
+                       return -EINVAL;
+               go->gop_size = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+               if (ctrl->value != 0 && ctrl->value != 1)
+                       return -EINVAL;
+               go->closed_gop = ctrl->value;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               /* Upper bound is kind of arbitrary here */
+               if (ctrl->value < 64000 || ctrl->value > 10000000)
+                       return -EINVAL;
+               go->bitrate = ctrl->value;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int mpeg_g_ctrl(struct v4l2_control *ctrl, struct go7007 *go)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               if (go->dvd_mode)
+                       ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_DVD;
+               else
+                       ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG_ELEM;
+               break;
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               switch (go->format) {
+               case GO7007_FORMAT_MPEG1:
+                       ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+                       break;
+               case GO7007_FORMAT_MPEG2:
+                       ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+                       break;
+               case GO7007_FORMAT_MPEG4:
+                       ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               switch (go->aspect_ratio) {
+               case GO7007_RATIO_1_1:
+                       ctrl->value = V4L2_MPEG_VIDEO_ASPECT_1x1;
+                       break;
+               case GO7007_RATIO_4_3:
+                       ctrl->value = V4L2_MPEG_VIDEO_ASPECT_4x3;
+                       break;
+               case GO7007_RATIO_16_9:
+                       ctrl->value = V4L2_MPEG_VIDEO_ASPECT_16x9;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               ctrl->value = go->gop_size;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+               ctrl->value = go->closed_gop;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               ctrl->value = go->bitrate;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *cap)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       strlcpy(cap->driver, "go7007", sizeof(cap->driver));
+       strlcpy(cap->card, go->name, sizeof(cap->card));
+#if 0
+       strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info));
+#endif
+
+       cap->version = KERNEL_VERSION(0, 9, 8);
+
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+                           V4L2_CAP_STREAMING; /* | V4L2_CAP_AUDIO; */
+
+       if (go->board_info->flags & GO7007_BOARD_HAS_TUNER)
+               cap->capabilities |= V4L2_CAP_TUNER;
+
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *fmt)
+{
+       char *desc = NULL;
+
+       switch (fmt->index) {
+       case 0:
+               fmt->pixelformat = V4L2_PIX_FMT_MJPEG;
+               desc = "Motion-JPEG";
+               break;
+       case 1:
+               fmt->pixelformat = V4L2_PIX_FMT_MPEG;
+               desc = "MPEG1/MPEG2/MPEG4";
+               break;
+       default:
+               return -EINVAL;
+       }
+       fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fmt->flags = V4L2_FMT_FLAG_COMPRESSED;
+
+       strncpy(fmt->description, desc, sizeof(fmt->description));
+
+       return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *fmt)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fmt->fmt.pix.width = go->width;
+       fmt->fmt.pix.height = go->height;
+       fmt->fmt.pix.pixelformat = (go->format == GO7007_FORMAT_MJPEG) ?
+                                  V4L2_PIX_FMT_MJPEG : V4L2_PIX_FMT_MPEG;
+       fmt->fmt.pix.field = V4L2_FIELD_NONE;
+       fmt->fmt.pix.bytesperline = 0;
+       fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
+       fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                       struct v4l2_format *fmt)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       return set_capture_size(go, fmt, 1);
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                       struct v4l2_format *fmt)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       if (go->streaming)
+               return -EBUSY;
+
+       return set_capture_size(go, fmt, 0);
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *req)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+       int retval = -EBUSY;
+       unsigned int count, i;
+
+       if (go->streaming)
+               return retval;
+
+       if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+                       req->memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+
+       mutex_lock(&gofh->lock);
+       for (i = 0; i < gofh->buf_count; ++i)
+               if (gofh->bufs[i].mapped > 0)
+                       goto unlock_and_return;
+
+       mutex_lock(&go->hw_lock);
+       if (go->in_use > 0 && gofh->buf_count == 0) {
+               mutex_unlock(&go->hw_lock);
+               goto unlock_and_return;
+       }
+
+       if (gofh->buf_count > 0)
+               kfree(gofh->bufs);
+
+       retval = -ENOMEM;
+       count = req->count;
+       if (count > 0) {
+               if (count < 2)
+                       count = 2;
+               if (count > 32)
+                       count = 32;
+
+               gofh->bufs = kcalloc(count, sizeof(struct go7007_buffer),
+                                    GFP_KERNEL);
+
+               if (!gofh->bufs) {
+                       mutex_unlock(&go->hw_lock);
+                       goto unlock_and_return;
+               }
+
+               for (i = 0; i < count; ++i) {
+                       gofh->bufs[i].go = go;
+                       gofh->bufs[i].index = i;
+                       gofh->bufs[i].state = BUF_STATE_IDLE;
+                       gofh->bufs[i].mapped = 0;
+               }
+
+               go->in_use = 1;
+       } else {
+               go->in_use = 0;
+       }
+
+       gofh->buf_count = count;
+       mutex_unlock(&go->hw_lock);
+       mutex_unlock(&gofh->lock);
+
+       memset(req, 0, sizeof(*req));
+
+       req->count = count;
+       req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       req->memory = V4L2_MEMORY_MMAP;
+
+       return 0;
+
+unlock_and_return:
+       mutex_unlock(&gofh->lock);
+       return retval;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+                          struct v4l2_buffer *buf)
+{
+       struct go7007_file *gofh = priv;
+       int retval = -EINVAL;
+       unsigned int index;
+
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return retval;
+
+       index = buf->index;
+
+       mutex_lock(&gofh->lock);
+       if (index >= gofh->buf_count)
+               goto unlock_and_return;
+
+       memset(buf, 0, sizeof(*buf));
+       buf->index = index;
+       buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       switch (gofh->bufs[index].state) {
+       case BUF_STATE_QUEUED:
+               buf->flags = V4L2_BUF_FLAG_QUEUED;
+               break;
+       case BUF_STATE_DONE:
+               buf->flags = V4L2_BUF_FLAG_DONE;
+               break;
+       default:
+               buf->flags = 0;
+       }
+
+       if (gofh->bufs[index].mapped)
+               buf->flags |= V4L2_BUF_FLAG_MAPPED;
+       buf->memory = V4L2_MEMORY_MMAP;
+       buf->m.offset = index * GO7007_BUF_SIZE;
+       buf->length = GO7007_BUF_SIZE;
+       mutex_unlock(&gofh->lock);
+
+       return 0;
+
+unlock_and_return:
+       mutex_unlock(&gofh->lock);
+       return retval;
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+       struct go7007_buffer *gobuf;
+       unsigned long flags;
+       int retval = -EINVAL;
+       int ret;
+
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+                       buf->memory != V4L2_MEMORY_MMAP)
+               return retval;
+
+       mutex_lock(&gofh->lock);
+       if (buf->index < 0 || buf->index >= gofh->buf_count)
+               goto unlock_and_return;
+
+       gobuf = &gofh->bufs[buf->index];
+       if (!gobuf->mapped)
+               goto unlock_and_return;
+
+       retval = -EBUSY;
+       if (gobuf->state != BUF_STATE_IDLE)
+               goto unlock_and_return;
+
+       /* offset will be 0 until we really support USERPTR streaming */
+       gobuf->offset = gobuf->user_addr & ~PAGE_MASK;
+       gobuf->bytesused = 0;
+       gobuf->frame_offset = 0;
+       gobuf->modet_active = 0;
+       if (gobuf->offset > 0)
+               gobuf->page_count = GO7007_BUF_PAGES + 1;
+       else
+               gobuf->page_count = GO7007_BUF_PAGES;
+
+       retval = -ENOMEM;
+       down_read(&current->mm->mmap_sem);
+       ret = get_user_pages(current, current->mm,
+                       gobuf->user_addr & PAGE_MASK, gobuf->page_count,
+                       1, 1, gobuf->pages, NULL);
+       up_read(&current->mm->mmap_sem);
+
+       if (ret != gobuf->page_count) {
+               int i;
+               for (i = 0; i < ret; ++i)
+                       page_cache_release(gobuf->pages[i]);
+               gobuf->page_count = 0;
+               goto unlock_and_return;
+       }
+
+       gobuf->state = BUF_STATE_QUEUED;
+       spin_lock_irqsave(&go->spinlock, flags);
+       list_add_tail(&gobuf->stream, &go->stream);
+       spin_unlock_irqrestore(&go->spinlock, flags);
+       mutex_unlock(&gofh->lock);
+
+       return 0;
+
+unlock_and_return:
+       mutex_unlock(&gofh->lock);
+       return retval;
+}
+
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+       struct go7007_buffer *gobuf;
+       int retval = -EINVAL;
+       unsigned long flags;
+       u32 frame_type_flag;
+       DEFINE_WAIT(wait);
+
+       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return retval;
+       if (buf->memory != V4L2_MEMORY_MMAP)
+               return retval;
+
+       mutex_lock(&gofh->lock);
+       if (list_empty(&go->stream))
+               goto unlock_and_return;
+       gobuf = list_entry(go->stream.next,
+                       struct go7007_buffer, stream);
+
+       retval = -EAGAIN;
+       if (gobuf->state != BUF_STATE_DONE &&
+                       !(file->f_flags & O_NONBLOCK)) {
+               for (;;) {
+                       prepare_to_wait(&go->frame_waitq, &wait,
+                                       TASK_INTERRUPTIBLE);
+                       if (gobuf->state == BUF_STATE_DONE)
+                               break;
+                       if (signal_pending(current)) {
+                               retval = -ERESTARTSYS;
+                               break;
+                       }
+                       schedule();
+               }
+               finish_wait(&go->frame_waitq, &wait);
+       }
+       if (gobuf->state != BUF_STATE_DONE)
+               goto unlock_and_return;
+
+       spin_lock_irqsave(&go->spinlock, flags);
+       deactivate_buffer(gobuf);
+       spin_unlock_irqrestore(&go->spinlock, flags);
+       frame_type_flag = get_frame_type_flag(gobuf, go->format);
+       gobuf->state = BUF_STATE_IDLE;
+
+       memset(buf, 0, sizeof(*buf));
+       buf->index = gobuf->index;
+       buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       buf->bytesused = gobuf->bytesused;
+       buf->flags = V4L2_BUF_FLAG_MAPPED | frame_type_flag;
+       buf->field = V4L2_FIELD_NONE;
+       buf->timestamp = gobuf->timestamp;
+       buf->sequence = gobuf->seq;
+       buf->memory = V4L2_MEMORY_MMAP;
+       buf->m.offset = gobuf->index * GO7007_BUF_SIZE;
+       buf->length = GO7007_BUF_SIZE;
+       buf->reserved = gobuf->modet_active;
+
+       mutex_unlock(&gofh->lock);
+       return 0;
+
+unlock_and_return:
+       mutex_unlock(&gofh->lock);
+       return retval;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+                                       enum v4l2_buf_type type)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+       int retval = 0;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       mutex_lock(&gofh->lock);
+       mutex_lock(&go->hw_lock);
+
+       if (!go->streaming) {
+               go->streaming = 1;
+               go->next_seq = 0;
+               go->active_buf = NULL;
+               if (go7007_start_encoder(go) < 0)
+                       retval = -EIO;
+               else
+                       retval = 0;
+       }
+       mutex_unlock(&go->hw_lock);
+       mutex_unlock(&gofh->lock);
+
+       return retval;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+                                       enum v4l2_buf_type type)
+{
+       struct go7007_file *gofh = priv;
+       struct go7007 *go = gofh->go;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       mutex_lock(&gofh->lock);
+       go7007_streamoff(go);
+       mutex_unlock(&gofh->lock);
+
+       return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+                          struct v4l2_queryctrl *query)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+       int id = query->id;
+
+       if (0 == call_all(&go->v4l2_dev, core, queryctrl, query))
+               return 0;
+
+       query->id = id;
+       return mpeg_query_ctrl(query);
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       if (0 == call_all(&go->v4l2_dev, core, g_ctrl, ctrl))
+               return 0;
+
+       return mpeg_g_ctrl(ctrl, go);
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+                               struct v4l2_control *ctrl)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       if (0 == call_all(&go->v4l2_dev, core, s_ctrl, ctrl))
+               return 0;
+
+       return mpeg_s_ctrl(ctrl, go);
+}
+
+static int vidioc_g_parm(struct file *filp, void *priv,
+               struct v4l2_streamparm *parm)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+       struct v4l2_fract timeperframe = {
+               .numerator = 1001 *  go->fps_scale,
+               .denominator = go->sensor_framerate,
+       };
+
+       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME;
+       parm->parm.capture.timeperframe = timeperframe;
+
+       return 0;
+}
+
+static int vidioc_s_parm(struct file *filp, void *priv,
+               struct v4l2_streamparm *parm)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+       unsigned int n, d;
+
+       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (parm->parm.capture.capturemode != 0)
+               return -EINVAL;
+
+       n = go->sensor_framerate *
+               parm->parm.capture.timeperframe.numerator;
+       d = 1001 * parm->parm.capture.timeperframe.denominator;
+       if (n != 0 && d != 0 && n > d)
+               go->fps_scale = (n + d/2) / d;
+       else
+               go->fps_scale = 1;
+
+       return 0;
+}
+
+/* VIDIOC_ENUMSTD on go7007 were used for enumberating the supported fps and
+   its resolution, when the device is not connected to TV.
+   This were an API abuse, probably used by the lack of specific IOCTL's to
+   enumberate it, by the time the driver were written.
+
+   However, since kernel 2.6.19, two new ioctls (VIDIOC_ENUM_FRAMEINTERVALS
+   and VIDIOC_ENUM_FRAMESIZES) were added for this purpose.
+
+   The two functions bellow implements the newer ioctls
+*/
+static int vidioc_enum_framesizes(struct file *filp, void *priv,
+                                 struct v4l2_frmsizeenum *fsize)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       /* Return -EINVAL, if it is a TV board */
+       if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) ||
+           (go->board_info->sensor_flags & GO7007_SENSOR_TV))
+               return -EINVAL;
+
+       if (fsize->index > 0)
+               return -EINVAL;
+
+       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+       fsize->discrete.width = go->board_info->sensor_width;
+       fsize->discrete.height = go->board_info->sensor_height;
+
+       return 0;
+}
+
+static int vidioc_enum_frameintervals(struct file *filp, void *priv,
+                                     struct v4l2_frmivalenum *fival)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       /* Return -EINVAL, if it is a TV board */
+       if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) ||
+           (go->board_info->sensor_flags & GO7007_SENSOR_TV))
+               return -EINVAL;
+
+       if (fival->index > 0)
+               return -EINVAL;
+
+       fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+       fival->discrete.numerator = 1001;
+       fival->discrete.denominator = go->board_info->sensor_framerate;
+
+       return 0;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       switch (go->standard) {
+       case GO7007_STD_NTSC:
+               *std = V4L2_STD_NTSC;
+               break;
+       case GO7007_STD_PAL:
+               *std = V4L2_STD_PAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       if (go->streaming)
+               return -EBUSY;
+
+       if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) && *std != 0)
+               return -EINVAL;
+
+       if (*std == 0)
+               return -EINVAL;
+
+       if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
+                       go->input == go->board_info->num_inputs - 1) {
+               if (!go->i2c_adapter_online)
+                       return -EIO;
+               if (call_all(&go->v4l2_dev, core, s_std, *std) < 0)
+                       return -EINVAL;
+       }
+
+       if (*std & V4L2_STD_NTSC) {
+               go->standard = GO7007_STD_NTSC;
+               go->sensor_framerate = 30000;
+       } else if (*std & V4L2_STD_PAL) {
+               go->standard = GO7007_STD_PAL;
+               go->sensor_framerate = 25025;
+       } else if (*std & V4L2_STD_SECAM) {
+               go->standard = GO7007_STD_PAL;
+               go->sensor_framerate = 25025;
+       } else
+               return -EINVAL;
+
+       call_all(&go->v4l2_dev, core, s_std, *std);
+       set_capture_size(go, NULL, 0);
+
+       return 0;
+}
+
+static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
+                       go->input == go->board_info->num_inputs - 1) {
+               if (!go->i2c_adapter_online)
+                       return -EIO;
+               return call_all(&go->v4l2_dev, video, querystd, std);
+       } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
+               *std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
+       else
+               *std = 0;
+
+       return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *inp)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       if (inp->index >= go->board_info->num_inputs)
+               return -EINVAL;
+
+       strncpy(inp->name, go->board_info->inputs[inp->index].name,
+                       sizeof(inp->name));
+
+       /* If this board has a tuner, it will be the last input */
+       if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
+                       inp->index == go->board_info->num_inputs - 1)
+               inp->type = V4L2_INPUT_TYPE_TUNER;
+       else
+               inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+       inp->audioset = 0;
+       inp->tuner = 0;
+       if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
+               inp->std = V4L2_STD_NTSC | V4L2_STD_PAL |
+                                               V4L2_STD_SECAM;
+       else
+               inp->std = 0;
+
+       return 0;
+}
+
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *input)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       *input = go->input;
+
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int input)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       if (input >= go->board_info->num_inputs)
+               return -EINVAL;
+       if (go->streaming)
+               return -EBUSY;
+
+       go->input = input;
+
+       return call_all(&go->v4l2_dev, video, s_routing, input, 0, 0);
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+               return -EINVAL;
+       if (t->index != 0)
+               return -EINVAL;
+       if (!go->i2c_adapter_online)
+               return -EIO;
+
+       return call_all(&go->v4l2_dev, tuner, g_tuner, t);
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+                               struct v4l2_tuner *t)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+               return -EINVAL;
+       if (t->index != 0)
+               return -EINVAL;
+       if (!go->i2c_adapter_online)
+               return -EIO;
+
+       switch (go->board_id) {
+       case GO7007_BOARDID_PX_TV402U_NA:
+       case GO7007_BOARDID_PX_TV402U_JP:
+               /* No selectable options currently */
+               if (t->audmode != V4L2_TUNER_MODE_STEREO)
+                       return -EINVAL;
+               break;
+       }
+
+       return call_all(&go->v4l2_dev, tuner, s_tuner, t);
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+               return -EINVAL;
+       if (!go->i2c_adapter_online)
+               return -EIO;
+
+       f->type = V4L2_TUNER_ANALOG_TV;
+
+       return call_all(&go->v4l2_dev, tuner, g_frequency, f);
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+               return -EINVAL;
+       if (!go->i2c_adapter_online)
+               return -EIO;
+
+       return call_all(&go->v4l2_dev, tuner, s_frequency, f);
+}
+
+static int vidioc_cropcap(struct file *file, void *priv,
+                                       struct v4l2_cropcap *cropcap)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       /* These specify the raw input of the sensor */
+       switch (go->standard) {
+       case GO7007_STD_NTSC:
+               cropcap->bounds.top = 0;
+               cropcap->bounds.left = 0;
+               cropcap->bounds.width = 720;
+               cropcap->bounds.height = 480;
+               cropcap->defrect.top = 0;
+               cropcap->defrect.left = 0;
+               cropcap->defrect.width = 720;
+               cropcap->defrect.height = 480;
+               break;
+       case GO7007_STD_PAL:
+               cropcap->bounds.top = 0;
+               cropcap->bounds.left = 0;
+               cropcap->bounds.width = 720;
+               cropcap->bounds.height = 576;
+               cropcap->defrect.top = 0;
+               cropcap->defrect.left = 0;
+               cropcap->defrect.width = 720;
+               cropcap->defrect.height = 576;
+               break;
+       case GO7007_STD_OTHER:
+               cropcap->bounds.top = 0;
+               cropcap->bounds.left = 0;
+               cropcap->bounds.width = go->board_info->sensor_width;
+               cropcap->bounds.height = go->board_info->sensor_height;
+               cropcap->defrect.top = 0;
+               cropcap->defrect.left = 0;
+               cropcap->defrect.width = go->board_info->sensor_width;
+               cropcap->defrect.height = go->board_info->sensor_height;
+               break;
+       }
+
+       return 0;
+}
+
+static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+{
+       struct go7007 *go = ((struct go7007_file *) priv)->go;
+
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       /* These specify the raw input of the sensor */
+       switch (go->standard) {
+       case GO7007_STD_NTSC:
+               crop->c.top = 0;
+               crop->c.left = 0;
+               crop->c.width = 720;
+               crop->c.height = 480;
+               break;
+       case GO7007_STD_PAL:
+               crop->c.top = 0;
+               crop->c.left = 0;
+               crop->c.width = 720;
+               crop->c.height = 576;
+               break;
+       case GO7007_STD_OTHER:
+               crop->c.top = 0;
+               crop->c.left = 0;
+               crop->c.width = go->board_info->sensor_width;
+               crop->c.height = go->board_info->sensor_height;
+               break;
+       }
+
+       return 0;
+}
+
+/* FIXME: vidioc_s_crop is not really implemented!!!
+ */
+static int vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+{
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int vidioc_g_jpegcomp(struct file *file, void *priv,
+                        struct v4l2_jpegcompression *params)
+{
+       memset(params, 0, sizeof(*params));
+       params->quality = 50; /* ?? */
+       params->jpeg_markers = V4L2_JPEG_MARKER_DHT |
+                               V4L2_JPEG_MARKER_DQT;
+
+       return 0;
+}
+
+static int vidioc_s_jpegcomp(struct file *file, void *priv,
+                        struct v4l2_jpegcompression *params)
+{
+       if (params->quality != 50 ||
+                       params->jpeg_markers != (V4L2_JPEG_MARKER_DHT |
+                                               V4L2_JPEG_MARKER_DQT))
+               return -EINVAL;
+
+       return 0;
+}
+
+/* FIXME:
+       Those ioctls are private, and not needed, since several standard
+       extended controls already provide streaming control.
+       So, those ioctls should be converted into vidioc_g_ext_ctrls()
+       and vidioc_s_ext_ctrls()
+ */
+
+#if 0
+       /* Temporary ioctls for controlling compression characteristics */
+       case GO7007IOC_S_BITRATE:
+       {
+               int *bitrate = arg;
+
+               if (go->streaming)
+                       return -EINVAL;
+               /* Upper bound is kind of arbitrary here */
+               if (*bitrate < 64000 || *bitrate > 10000000)
+                       return -EINVAL;
+               go->bitrate = *bitrate;
+               return 0;
+       }
+       case GO7007IOC_G_BITRATE:
+       {
+               int *bitrate = arg;
+
+               *bitrate = go->bitrate;
+               return 0;
+       }
+       case GO7007IOC_S_COMP_PARAMS:
+       {
+               struct go7007_comp_params *comp = arg;
+
+               if (go->format == GO7007_FORMAT_MJPEG)
+                       return -EINVAL;
+               if (comp->gop_size > 0)
+                       go->gop_size = comp->gop_size;
+               else
+                       go->gop_size = go->sensor_framerate / 1000;
+               if (go->gop_size != 15)
+                       go->dvd_mode = 0;
+               /*go->ipb = comp->max_b_frames > 0;*/ /* completely untested */
+               if (go->board_info->sensor_flags & GO7007_SENSOR_TV) {
+                       switch (comp->aspect_ratio) {
+                       case GO7007_ASPECT_RATIO_4_3_NTSC:
+                       case GO7007_ASPECT_RATIO_4_3_PAL:
+                               go->aspect_ratio = GO7007_RATIO_4_3;
+                               break;
+                       case GO7007_ASPECT_RATIO_16_9_NTSC:
+                       case GO7007_ASPECT_RATIO_16_9_PAL:
+                               go->aspect_ratio = GO7007_RATIO_16_9;
+                               break;
+                       default:
+                               go->aspect_ratio = GO7007_RATIO_1_1;
+                               break;
+                       }
+               }
+               if (comp->flags & GO7007_COMP_OMIT_SEQ_HEADER) {
+                       go->dvd_mode = 0;
+                       go->seq_header_enable = 0;
+               } else {
+                       go->seq_header_enable = 1;
+               }
+               /* fall-through */
+       }
+       case GO7007IOC_G_COMP_PARAMS:
+       {
+               struct go7007_comp_params *comp = arg;
+
+               if (go->format == GO7007_FORMAT_MJPEG)
+                       return -EINVAL;
+               memset(comp, 0, sizeof(*comp));
+               comp->gop_size = go->gop_size;
+               comp->max_b_frames = go->ipb ? 2 : 0;
+               switch (go->aspect_ratio) {
+               case GO7007_RATIO_4_3:
+                       if (go->standard == GO7007_STD_NTSC)
+                               comp->aspect_ratio =
+                                       GO7007_ASPECT_RATIO_4_3_NTSC;
+                       else
+                               comp->aspect_ratio =
+                                       GO7007_ASPECT_RATIO_4_3_PAL;
+                       break;
+               case GO7007_RATIO_16_9:
+                       if (go->standard == GO7007_STD_NTSC)
+                               comp->aspect_ratio =
+                                       GO7007_ASPECT_RATIO_16_9_NTSC;
+                       else
+                               comp->aspect_ratio =
+                                       GO7007_ASPECT_RATIO_16_9_PAL;
+                       break;
+               default:
+                       comp->aspect_ratio = GO7007_ASPECT_RATIO_1_1;
+                       break;
+               }
+               if (go->closed_gop)
+                       comp->flags |= GO7007_COMP_CLOSED_GOP;
+               if (!go->seq_header_enable)
+                       comp->flags |= GO7007_COMP_OMIT_SEQ_HEADER;
+               return 0;
+       }
+       case GO7007IOC_S_MPEG_PARAMS:
+       {
+               struct go7007_mpeg_params *mpeg = arg;
+
+               if (go->format != GO7007_FORMAT_MPEG1 &&
+                               go->format != GO7007_FORMAT_MPEG2 &&
+                               go->format != GO7007_FORMAT_MPEG4)
+                       return -EINVAL;
+
+               if (mpeg->flags & GO7007_MPEG_FORCE_DVD_MODE) {
+                       go->format = GO7007_FORMAT_MPEG2;
+                       go->bitrate = 9800000;
+                       go->gop_size = 15;
+                       go->pali = 0x48;
+                       go->closed_gop = 1;
+                       go->repeat_seqhead = 0;
+                       go->seq_header_enable = 1;
+                       go->gop_header_enable = 1;
+                       go->dvd_mode = 1;
+               } else {
+                       switch (mpeg->mpeg_video_standard) {
+                       case GO7007_MPEG_VIDEO_MPEG1:
+                               go->format = GO7007_FORMAT_MPEG1;
+                               go->pali = 0;
+                               break;
+                       case GO7007_MPEG_VIDEO_MPEG2:
+                               go->format = GO7007_FORMAT_MPEG2;
+                               if (mpeg->pali >> 24 == 2)
+                                       go->pali = mpeg->pali & 0xff;
+                               else
+                                       go->pali = 0x48;
+                               break;
+                       case GO7007_MPEG_VIDEO_MPEG4:
+                               go->format = GO7007_FORMAT_MPEG4;
+                               if (mpeg->pali >> 24 == 4)
+                                       go->pali = mpeg->pali & 0xff;
+                               else
+                                       go->pali = 0xf5;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       go->gop_header_enable =
+                               mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER
+                               ? 0 : 1;
+                       if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER)
+                               go->repeat_seqhead = 1;
+                       else
+                               go->repeat_seqhead = 0;
+                       go->dvd_mode = 0;
+               }
+               /* fall-through */
+       }
+       case GO7007IOC_G_MPEG_PARAMS:
+       {
+               struct go7007_mpeg_params *mpeg = arg;
+
+               memset(mpeg, 0, sizeof(*mpeg));
+               switch (go->format) {
+               case GO7007_FORMAT_MPEG1:
+                       mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG1;
+                       mpeg->pali = 0;
+                       break;
+               case GO7007_FORMAT_MPEG2:
+                       mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2;
+                       mpeg->pali = GO7007_MPEG_PROFILE(2, go->pali);
+                       break;
+               case GO7007_FORMAT_MPEG4:
+                       mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4;
+                       mpeg->pali = GO7007_MPEG_PROFILE(4, go->pali);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               if (!go->gop_header_enable)
+                       mpeg->flags |= GO7007_MPEG_OMIT_GOP_HEADER;
+               if (go->repeat_seqhead)
+                       mpeg->flags |= GO7007_MPEG_REPEAT_SEQHEADER;
+               if (go->dvd_mode)
+                       mpeg->flags |= GO7007_MPEG_FORCE_DVD_MODE;
+               return 0;
+       }
+       case GO7007IOC_S_MD_PARAMS:
+       {
+               struct go7007_md_params *mdp = arg;
+
+               if (mdp->region > 3)
+                       return -EINVAL;
+               if (mdp->trigger > 0) {
+                       go->modet[mdp->region].pixel_threshold =
+                                       mdp->pixel_threshold >> 1;
+                       go->modet[mdp->region].motion_threshold =
+                                       mdp->motion_threshold >> 1;
+                       go->modet[mdp->region].mb_threshold =
+                                       mdp->trigger >> 1;
+                       go->modet[mdp->region].enable = 1;
+               } else
+                       go->modet[mdp->region].enable = 0;
+               /* fall-through */
+       }
+       case GO7007IOC_G_MD_PARAMS:
+       {
+               struct go7007_md_params *mdp = arg;
+               int region = mdp->region;
+
+               if (mdp->region > 3)
+                       return -EINVAL;
+               memset(mdp, 0, sizeof(struct go7007_md_params));
+               mdp->region = region;
+               if (!go->modet[region].enable)
+                       return 0;
+               mdp->pixel_threshold =
+                       (go->modet[region].pixel_threshold << 1) + 1;
+               mdp->motion_threshold =
+                       (go->modet[region].motion_threshold << 1) + 1;
+               mdp->trigger =
+                       (go->modet[region].mb_threshold << 1) + 1;
+               return 0;
+       }
+       case GO7007IOC_S_MD_REGION:
+       {
+               struct go7007_md_region *region = arg;
+
+               if (region->region < 1 || region->region > 3)
+                       return -EINVAL;
+               return clip_to_modet_map(go, region->region, region->clips);
+       }
+#endif
+
+static ssize_t go7007_read(struct file *file, char __user *data,
+               size_t count, loff_t *ppos)
+{
+       return -EINVAL;
+}
+
+static void go7007_vm_open(struct vm_area_struct *vma)
+{
+       struct go7007_buffer *gobuf = vma->vm_private_data;
+
+       ++gobuf->mapped;
+}
+
+static void go7007_vm_close(struct vm_area_struct *vma)
+{
+       struct go7007_buffer *gobuf = vma->vm_private_data;
+       unsigned long flags;
+
+       if (--gobuf->mapped == 0) {
+               spin_lock_irqsave(&gobuf->go->spinlock, flags);
+               deactivate_buffer(gobuf);
+               spin_unlock_irqrestore(&gobuf->go->spinlock, flags);
+       }
+}
+
+/* Copied from videobuf-dma-sg.c */
+static int go7007_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct page *page;
+
+       page = alloc_page(GFP_USER | __GFP_DMA32);
+       if (!page)
+               return VM_FAULT_OOM;
+       clear_user_highpage(page, (unsigned long)vmf->virtual_address);
+       vmf->page = page;
+       return 0;
+}
+
+static struct vm_operations_struct go7007_vm_ops = {
+       .open   = go7007_vm_open,
+       .close  = go7007_vm_close,
+       .fault  = go7007_vm_fault,
+};
+
+static int go7007_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct go7007_file *gofh = file->private_data;
+       unsigned int index;
+
+       if (gofh->go->status != STATUS_ONLINE)
+               return -EIO;
+       if (!(vma->vm_flags & VM_SHARED))
+               return -EINVAL; /* only support VM_SHARED mapping */
+       if (vma->vm_end - vma->vm_start != GO7007_BUF_SIZE)
+               return -EINVAL; /* must map exactly one full buffer */
+       mutex_lock(&gofh->lock);
+       index = vma->vm_pgoff / GO7007_BUF_PAGES;
+       if (index >= gofh->buf_count) {
+               mutex_unlock(&gofh->lock);
+               return -EINVAL; /* trying to map beyond requested buffers */
+       }
+       if (index * GO7007_BUF_PAGES != vma->vm_pgoff) {
+               mutex_unlock(&gofh->lock);
+               return -EINVAL; /* offset is not aligned on buffer boundary */
+       }
+       if (gofh->bufs[index].mapped > 0) {
+               mutex_unlock(&gofh->lock);
+               return -EBUSY;
+       }
+       gofh->bufs[index].mapped = 1;
+       gofh->bufs[index].user_addr = vma->vm_start;
+       vma->vm_ops = &go7007_vm_ops;
+       vma->vm_flags |= VM_DONTEXPAND;
+       vma->vm_flags &= ~VM_IO;
+       vma->vm_private_data = &gofh->bufs[index];
+       mutex_unlock(&gofh->lock);
+       return 0;
+}
+
+static unsigned int go7007_poll(struct file *file, poll_table *wait)
+{
+       struct go7007_file *gofh = file->private_data;
+       struct go7007_buffer *gobuf;
+
+       if (list_empty(&gofh->go->stream))
+               return POLLERR;
+       gobuf = list_entry(gofh->go->stream.next, struct go7007_buffer, stream);
+       poll_wait(file, &gofh->go->frame_waitq, wait);
+       if (gobuf->state == BUF_STATE_DONE)
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+static void go7007_vfl_release(struct video_device *vfd)
+{
+       struct go7007 *go = video_get_drvdata(vfd);
+
+       video_device_release(vfd);
+       if (--go->ref_count == 0)
+               kfree(go);
+}
+
+static struct v4l2_file_operations go7007_fops = {
+       .owner          = THIS_MODULE,
+       .open           = go7007_open,
+       .release        = go7007_release,
+       .ioctl          = video_ioctl2,
+       .read           = go7007_read,
+       .mmap           = go7007_mmap,
+       .poll           = go7007_poll,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+       .vidioc_querycap          = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+       .vidioc_reqbufs           = vidioc_reqbufs,
+       .vidioc_querybuf          = vidioc_querybuf,
+       .vidioc_qbuf              = vidioc_qbuf,
+       .vidioc_dqbuf             = vidioc_dqbuf,
+       .vidioc_g_std             = vidioc_g_std,
+       .vidioc_s_std             = vidioc_s_std,
+       .vidioc_querystd          = vidioc_querystd,
+       .vidioc_enum_input        = vidioc_enum_input,
+       .vidioc_g_input           = vidioc_g_input,
+       .vidioc_s_input           = vidioc_s_input,
+       .vidioc_queryctrl         = vidioc_queryctrl,
+       .vidioc_g_ctrl            = vidioc_g_ctrl,
+       .vidioc_s_ctrl            = vidioc_s_ctrl,
+       .vidioc_streamon          = vidioc_streamon,
+       .vidioc_streamoff         = vidioc_streamoff,
+       .vidioc_g_tuner           = vidioc_g_tuner,
+       .vidioc_s_tuner           = vidioc_s_tuner,
+       .vidioc_g_frequency       = vidioc_g_frequency,
+       .vidioc_s_frequency       = vidioc_s_frequency,
+       .vidioc_g_parm            = vidioc_g_parm,
+       .vidioc_s_parm            = vidioc_s_parm,
+       .vidioc_enum_framesizes   = vidioc_enum_framesizes,
+       .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
+       .vidioc_cropcap           = vidioc_cropcap,
+       .vidioc_g_crop            = vidioc_g_crop,
+       .vidioc_s_crop            = vidioc_s_crop,
+       .vidioc_g_jpegcomp        = vidioc_g_jpegcomp,
+       .vidioc_s_jpegcomp        = vidioc_s_jpegcomp,
+};
+
+static struct video_device go7007_template = {
+       .name           = "go7007",
+       .fops           = &go7007_fops,
+       .release        = go7007_vfl_release,
+       .ioctl_ops      = &video_ioctl_ops,
+       .tvnorms        = V4L2_STD_ALL,
+       .current_norm   = V4L2_STD_NTSC,
+};
+
+int go7007_v4l2_init(struct go7007 *go)
+{
+       int rv;
+
+       go->video_dev = video_device_alloc();
+       if (go->video_dev == NULL)
+               return -ENOMEM;
+       *go->video_dev = go7007_template;
+       go->video_dev->parent = go->dev;
+       rv = video_register_device(go->video_dev, VFL_TYPE_GRABBER, -1);
+       if (rv < 0) {
+               video_device_release(go->video_dev);
+               go->video_dev = NULL;
+               return rv;
+       }
+       rv = v4l2_device_register(go->dev, &go->v4l2_dev);
+       if (rv < 0) {
+               video_device_release(go->video_dev);
+               go->video_dev = NULL;
+               return rv;
+       }
+       video_set_drvdata(go->video_dev, go);
+       ++go->ref_count;
+       printk(KERN_INFO "%s: registered device %s [v4l2]\n",
+              go->video_dev->name, video_device_node_name(go->video_dev));
+
+       return 0;
+}
+
+void go7007_v4l2_remove(struct go7007 *go)
+{
+       unsigned long flags;
+
+       mutex_lock(&go->hw_lock);
+       if (go->streaming) {
+               go->streaming = 0;
+               go7007_stream_stop(go);
+               spin_lock_irqsave(&go->spinlock, flags);
+               abort_queued(go);
+               spin_unlock_irqrestore(&go->spinlock, flags);
+       }
+       mutex_unlock(&go->hw_lock);
+       if (go->video_dev)
+               video_unregister_device(go->video_dev);
+       v4l2_device_unregister(&go->v4l2_dev);
+}
diff --git a/drivers/staging/media/go7007/go7007.h b/drivers/staging/media/go7007/go7007.h
new file mode 100644 (file)
index 0000000..7399c91
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and the associated README documentation file (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* DEPRECATED -- use V4L2_PIX_FMT_MPEG and then call GO7007IOC_S_MPEG_PARAMS
+ * to select between MPEG1, MPEG2, and MPEG4 */
+#define V4L2_PIX_FMT_MPEG4     v4l2_fourcc('M', 'P', 'G', '4') /* MPEG4 */
+
+/* These will be replaced with a better interface
+ * soon, so don't get too attached to them */
+#define        GO7007IOC_S_BITRATE     _IOW('V', BASE_VIDIOC_PRIVATE + 0, int)
+#define        GO7007IOC_G_BITRATE     _IOR('V', BASE_VIDIOC_PRIVATE + 1, int)
+
+enum go7007_aspect_ratio {
+       GO7007_ASPECT_RATIO_1_1 = 0,
+       GO7007_ASPECT_RATIO_4_3_NTSC = 1,
+       GO7007_ASPECT_RATIO_4_3_PAL = 2,
+       GO7007_ASPECT_RATIO_16_9_NTSC = 3,
+       GO7007_ASPECT_RATIO_16_9_PAL = 4,
+};
+
+/* Used to set generic compression parameters */
+struct go7007_comp_params {
+       __u32 gop_size;
+       __u32 max_b_frames;
+       enum go7007_aspect_ratio aspect_ratio;
+       __u32 flags;
+       __u32 reserved[8];
+};
+
+#define GO7007_COMP_CLOSED_GOP         0x00000001
+#define GO7007_COMP_OMIT_SEQ_HEADER    0x00000002
+
+enum go7007_mpeg_video_standard {
+       GO7007_MPEG_VIDEO_MPEG1 = 0,
+       GO7007_MPEG_VIDEO_MPEG2 = 1,
+       GO7007_MPEG_VIDEO_MPEG4 = 2,
+};
+
+/* Used to set parameters for V4L2_PIX_FMT_MPEG format */
+struct go7007_mpeg_params {
+       enum go7007_mpeg_video_standard mpeg_video_standard;
+       __u32 flags;
+       __u32 pali;
+       __u32 reserved[8];
+};
+
+#define GO7007_MPEG_FORCE_DVD_MODE     0x00000001
+#define GO7007_MPEG_OMIT_GOP_HEADER    0x00000002
+#define GO7007_MPEG_REPEAT_SEQHEADER   0x00000004
+
+#define GO7007_MPEG_PROFILE(format, pali)      (((format)<<24)|(pali))
+
+#define GO7007_MPEG2_PROFILE_MAIN_MAIN         GO7007_MPEG_PROFILE(2, 0x48)
+
+#define GO7007_MPEG4_PROFILE_S_L0              GO7007_MPEG_PROFILE(4, 0x08)
+#define GO7007_MPEG4_PROFILE_S_L1              GO7007_MPEG_PROFILE(4, 0x01)
+#define GO7007_MPEG4_PROFILE_S_L2              GO7007_MPEG_PROFILE(4, 0x02)
+#define GO7007_MPEG4_PROFILE_S_L3              GO7007_MPEG_PROFILE(4, 0x03)
+#define GO7007_MPEG4_PROFILE_ARTS_L1           GO7007_MPEG_PROFILE(4, 0x91)
+#define GO7007_MPEG4_PROFILE_ARTS_L2           GO7007_MPEG_PROFILE(4, 0x92)
+#define GO7007_MPEG4_PROFILE_ARTS_L3           GO7007_MPEG_PROFILE(4, 0x93)
+#define GO7007_MPEG4_PROFILE_ARTS_L4           GO7007_MPEG_PROFILE(4, 0x94)
+#define GO7007_MPEG4_PROFILE_AS_L0             GO7007_MPEG_PROFILE(4, 0xf0)
+#define GO7007_MPEG4_PROFILE_AS_L1             GO7007_MPEG_PROFILE(4, 0xf1)
+#define GO7007_MPEG4_PROFILE_AS_L2             GO7007_MPEG_PROFILE(4, 0xf2)
+#define GO7007_MPEG4_PROFILE_AS_L3             GO7007_MPEG_PROFILE(4, 0xf3)
+#define GO7007_MPEG4_PROFILE_AS_L4             GO7007_MPEG_PROFILE(4, 0xf4)
+#define GO7007_MPEG4_PROFILE_AS_L5             GO7007_MPEG_PROFILE(4, 0xf5)
+
+struct go7007_md_params {
+       __u16 region;
+       __u16 trigger;
+       __u16 pixel_threshold;
+       __u16 motion_threshold;
+       __u32 reserved[8];
+};
+
+struct go7007_md_region {
+       __u16 region;
+       __u16 flags;
+       struct v4l2_clip *clips;
+       __u32 reserved[8];
+};
+
+#define        GO7007IOC_S_MPEG_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 2, \
+                                       struct go7007_mpeg_params)
+#define        GO7007IOC_G_MPEG_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 3, \
+                                       struct go7007_mpeg_params)
+#define        GO7007IOC_S_COMP_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 4, \
+                                       struct go7007_comp_params)
+#define        GO7007IOC_G_COMP_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 5, \
+                                       struct go7007_comp_params)
+#define        GO7007IOC_S_MD_PARAMS   _IOWR('V', BASE_VIDIOC_PRIVATE + 6, \
+                                       struct go7007_md_params)
+#define        GO7007IOC_G_MD_PARAMS   _IOR('V', BASE_VIDIOC_PRIVATE + 7, \
+                                       struct go7007_md_params)
+#define        GO7007IOC_S_MD_REGION   _IOW('V', BASE_VIDIOC_PRIVATE + 8, \
+                                       struct go7007_md_region)
diff --git a/drivers/staging/media/go7007/go7007.txt b/drivers/staging/media/go7007/go7007.txt
new file mode 100644 (file)
index 0000000..9db1f39
--- /dev/null
@@ -0,0 +1,481 @@
+This is a driver for the WIS GO7007SB multi-format video encoder.
+
+Pete Eberlein <pete@sensoray.com>
+
+The driver was originally released under the GPL and is currently hosted at:
+http://nikosapi.org/wiki/index.php/WIS_Go7007_Linux_driver
+The go7007 firmware can be acquired from the package on the site above.
+
+I've modified the driver to support the following Video4Linux2 MPEG
+controls, with acceptable values:
+
+V4L2_CID_MPEG_STREAM_TYPE      V4L2_MPEG_STREAM_TYPE_MPEG2_DVD
+                               V4L2_MPEG_STREAM_TYPE_MPEG_ELEM
+V4L2_CID_MPEG_VIDEO_ENCODING   V4L2_MPEG_VIDEO_ENCODING_MPEG_1
+                               V4L2_MPEG_VIDEO_ENCODING_MPEG_2
+                               V4L2_MPEG_VIDEO_ENCODING_MPEG_4
+V4L2_CID_MPEG_VIDEO_ASPECT     V4L2_MPEG_VIDEO_ASPECT_1x1
+                               V4L2_MPEG_VIDEO_ASPECT_4x3
+                               V4L2_MPEG_VIDEO_ASPECT_16x9
+V4L2_CID_MPEG_VIDEO_GOP_SIZE   integer
+V4L2_CID_MPEG_VIDEO_BITRATE    64000 .. 10000000
+
+These should be used instead of the non-standard GO7007 ioctls described
+below.
+
+
+The README files from the orignal package appear below:
+
+---------------------------------------------------------------------------
+                    WIS GO7007SB Public Linux Driver
+---------------------------------------------------------------------------
+
+
+*** Please see the file RELEASE-NOTES for important last-minute updates ***
+
+
+  0. OVERVIEW AND LICENSING/DISCLAIMER
+
+
+This driver kit contains Linux drivers for the WIS GO7007SB multi-format
+video encoder.  Only kernel version 2.6.x is supported.  The video stream
+is available through the Video4Linux2 API and the audio stream is available
+through the ALSA API (or the OSS emulation layer of the ALSA system).
+
+The files in kernel/ and hotplug/ are licensed under the GNU General Public
+License Version 2 from the Free Software Foundation.  A copy of the license
+is included in the file COPYING.
+
+The example applications in apps/ and C header files in include/ are
+licensed under a permissive license included in the source files which
+allows copying, modification and redistribution for any purpose without
+attribution.
+
+The firmware files included in the firmware/ directory may be freely
+redistributed only in conjunction with this document; but modification,
+tampering and reverse engineering are prohibited.
+
+MICRONAS USA, INC., MAKES NO WARRANTIES TO ANY PERSON OR ENTITY WITH
+RESPECT TO THE SOFTWARE OR ANY DERIVATIVES THEREOF OR ANY SERVICES OR
+LICENSES AND DISCLAIMS ALL IMPLIED WARRANTIES, INCLUDING WITHOUT LIMITATION
+WARRANTIES OF MERCHANTABILITY, SUPPORT, AND FITNESS FOR A PARTICULAR
+PURPOSE AND NON-INFRINGEMENT.
+
+
+  1. SYSTEM REQUIREMENTS
+
+
+This driver requires Linux kernel 2.6.  Kernel 2.4 is not supported.  Using
+kernel 2.6.10 or later is recommended, as earlier kernels are known to have
+unstable USB 2.0 support.
+
+A fully built kernel source tree must be available.  Typically this will be
+linked from "/lib/modules/<KERNEL VERSION>/build" for convenience.  If this
+link does not exist, an extra parameter will need to be passed to the
+`make` command.
+
+All vendor-built kernels should already be configured properly.  However,
+for custom-built kernels, the following options need to be enabled in the
+kernel as built-in or modules:
+
+       CONFIG_HOTPLUG           - Support for hot-pluggable devices
+       CONFIG_MODULES           - Enable loadable module support
+       CONFIG_KMOD              - Automatic kernel module loading
+       CONFIG_FW_LOADER         - Hotplug firmware loading support
+       CONFIG_I2C               - I2C support
+       CONFIG_VIDEO_DEV         - Video For Linux
+       CONFIG_SOUND             - Sound card support
+       CONFIG_SND               - Advanced Linux Sound Architecture
+       CONFIG_USB               - Support for Host-side USB
+       CONFIG_USB_DEVICEFS      - USB device filesystem
+       CONFIG_USB_EHCI_HCD      - EHCI HCD (USB 2.0) support
+
+Additionally, to use the example application, the following options need to
+be enabled in the ALSA section:
+
+       CONFIG_SND_MIXER_OSS     - OSS Mixer API
+       CONFIG_SND_PCM_OSS       - OSS PCM (digital audio) API
+
+The hotplug scripts, along with the fxload utility, must also be installed.
+These scripts can be obtained from <http://linux-hotplug.sourceforge.net/>.
+Hotplugging is used for loading firmware into the Cypruss EZ-USB chip using
+fxload and for loading firmware into the driver using the firmware agent.
+
+
+  2. COMPILING AND INSTALLING THE DRIVER
+
+
+Most users should be able to compile the driver by simply running:
+
+       $ make
+
+in the top-level directory of the driver kit.  First the kernel modules
+will be built, followed by the example applications.
+
+If the build system is unable to locate the kernel source tree for the
+currently-running kernel, or if the module should be built for a kernel
+other than the currently-running kernel, an additional parameter will need
+to be passed to make to specify the appropriate kernel source directory:
+
+       $ make KERNELSRC=/usr/src/linux-2.6.10-custom3
+
+Once the compile completes, the driver and firmware files should be
+installed by running:
+
+       $ make install
+
+The kernel modules will be placed in "/lib/modules/<KERNEL VERSION>/extra"
+and the firmware files will be placed in the appropriate hotplug firmware
+directory, usually /lib/firmware.  In addition, USB maps and scripts will
+be placed in /etc/hotplug/usb to enable fxload to initialize the EZ-USB
+control chip when the device is connected.
+
+
+  3. PAL/SECAM TUNER CONFIGURATION (TV402U-EU only)
+
+
+The PAL model of the Plextor ConvertX TV402U may require additional
+configuration to correctly select the appropriate TV frequency band and
+audio subchannel.
+
+Users with a device other than the Plextor ConvertX TV402U-EU should skip
+this section.
+
+The wide variety of PAL TV systems used in Europe requires that additional
+information about the local TV standards be passed to the driver in order
+to properly tune TV channels.  The two necessary parameters are (a) the PAL
+TV band, and (b) the audio subchannel format in use.
+
+In many cases, the appropriate TV band selection is passed to the driver
+from applications.  However, in some cases, the application only specifies
+that the driver should use PAL but not the specific information about the
+appropriate TV band.  To work around this issue, the correct TV band may be
+specified in the "force_band" parameter to the wis-sony-tuner module:
+
+     TV band           force_band
+     -------           ----------
+     PAL B/G                B
+     PAL I                  I
+     PAL D/K                D
+     SECAM L                L
+
+If the "force_band" parameter is specified, the driver will ignore any TV
+band specified by applications and will always use the band provided in the
+module parameter.
+
+The other parameter that can be specified is the audio subchannel format.
+There are several stereo audio carrier systems in use, including NICAM and
+three varieties of A2.  To receive audio broadcast on one of these stereo
+carriers, the "force_mpx_mode" parameter must be specified to the
+wis-sony-tuner module.
+
+     TV band           Audio subcarrier       force_mpx_mode
+     -------           ----------------       --------------
+     PAL B/G            Mono (default)               1
+     PAL B/G                  A2                     2
+     PAL B/G                 NICAM                   3
+     PAL I              Mono (default)               4
+     PAL I                   NICAM                   5
+     PAL D/K            Mono (default)               6
+     PAL D/K                 A2 (1)                  7
+     PAL D/K                 A2 (2)                  8
+     PAL D/K                 A2 (3)                  9
+     PAL D/K                 NICAM                  10
+     SECAM L            Mono (default)              11
+     SECAM L                 NICAM                  12
+
+If the "force_mpx_mode" parameter is not specified, the correct mono-only
+mode will be chosen based on the TV band.  However, the tuner will not
+receive stereo audio or bilingual broadcasts correctly.
+
+To pass the "force_band" or "force_mpx_mode" parameters to the
+wis-sony-tuner module, the following line must be added to the modprobe
+configuration file, which varies from one Linux distribution to another.
+
+     options wis-sony-tuner force_band=B force_mpx_mode=2
+
+The above example would force the tuner to the PAL B/G TV band and receive
+stereo audio broadcasts on the A2 carrier.
+
+To verify that the configuration has been placed in the correct location,
+execute:
+
+       $ modprobe -c | grep wis-sony-tuner
+
+If the configuration line appears, then modprobe will pass the parameters
+correctly the next time the wis-sony-tuner module is loaded into the
+kernel.
+
+
+  4. TESTING THE DRIVER
+
+
+Because few Linux applications are able to correctly capture from
+Video4Linux2 devices with only compressed formats supported, the new driver
+should be tested with the "gorecord" application in the apps/ directory.
+
+First connect a video source to the device, such as a DVD player or VCR.
+This will be captured to a file for testing the driver.  If an input source
+is unavailable, a test file can still be captured, but the video will be
+black and the audio will be silent.
+
+This application will auto-detect the V4L2 and ALSA/OSS device names of the
+hardware and will record video and audio to an AVI file for a specified
+number of seconds.  For example:
+
+       $ apps/gorecord -duration 60 capture.avi
+
+If this application does not successfully record an AVI file, the error
+messages produced by gorecord and recorded in the system log (usually in
+/var/log/messages) should provide information to help resolve the problem.
+
+Supplying no parameters to gorecord will cause it to probe the available
+devices and exit.  Use the -help flag for usage information.
+
+
+  5. USING THE DRIVER
+
+
+The V4L2 device implemented by the driver provides a standard compressed
+format API, within the following criteria:
+
+  * Applications that only support the original Video4Linux1 API will not
+    be able to communicate with this driver at all.
+
+  * No raw video modes are supported, so applications like xawtv that
+    expect only uncompressed video will not function.
+
+  * Supported compression formats are: Motion-JPEG, MPEG1, MPEG2 and MPEG4.
+
+  * MPEG video formats are delivered as Video Elementary Streams only.
+    Program Stream (PS), Transport Stream (TS) and Packetized Elementary
+    Stream (PES) formats are not supported.
+
+  * Video parameters such as format and input port may not be changed while
+    the encoder is active.
+
+  * The audio capture device only functions when the video encoder is
+    actively capturing video.  Attempts to read from the audio device when
+    the encoder is inactive will result in an I/O error.
+
+  * The native format of the audio device is 48Khz 2-channel 16-bit
+    little-endian PCM, delivered through the ALSA system.  No audio
+    compression is implemented in the hardware.  ALSA may convert to other
+    uncompressed formats on the fly.
+
+The include/ directory contains a C header file describing non-standard
+features of the GO7007SB encoder, which are described below:
+
+
+  GO7007IOC_S_COMP_PARAMS, GO7007IOC_G_COMP_PARAMS
+
+    These ioctls are used to negotiate general compression parameters.
+
+    To query the current parameters, call the GO7007IOC_G_COMP_PARAMS ioctl
+    with a pointer to a struct go7007_comp_params.  If the driver is not
+    set to MPEG format, the EINVAL error code will be returned.
+
+    To change the current parameters, initialize all fields of a struct
+    go7007_comp_params and call the GO7007_IOC_S_COMP_PARAMS ioctl with a
+    pointer to this structure.  The driver will return the current
+    parameters with any necessary changes to conform to the limitations of
+    the hardware or current compression mode.  Any or all fields can be set
+    to zero to request a reasonable default value.  If the driver is not
+    set to MPEG format, the EINVAL error code will be returned.  When I/O
+    is in progress, the EBUSY error code will be returned.
+
+    Fields in struct go7007_comp_params:
+
+       __u32                        The maximum number of frames in each
+         gop_size                   Group Of Pictures; i.e. the maximum
+                                    number of frames minus one between
+                                    each key frame.
+
+       __u32                        The maximum number of sequential
+         max_b_frames               bidirectionally-predicted frames.
+                                    (B-frames are not yet supported.)
+
+       enum go7007_aspect_ratio     The aspect ratio to be encoded in the
+         aspect_ratio               meta-data of the compressed format.
+
+                                    Choices are:
+                                       GO7007_ASPECT_RATIO_1_1
+                                       GO7007_ASPECT_RATIO_4_3_NTSC
+                                       GO7007_ASPECT_RATIO_4_3_PAL
+                                       GO7007_ASPECT_RATIO_16_9_NTSC
+                                       GO7007_ASPECT_RATIO_16_9_PAL
+
+       __u32                        Bit-wise OR of control flags (below)
+         flags
+
+    Flags in struct go7007_comp_params:
+
+       GO7007_COMP_CLOSED_GOP       Only produce self-contained GOPs, used
+                                    to produce streams appropriate for
+                                    random seeking.
+
+       GO7007_COMP_OMIT_SEQ_HEADER  Omit the stream sequence header.
+
+
+  GO7007IOC_S_MPEG_PARAMS, GO7007IOC_G_MPEG_PARAMS
+
+    These ioctls are used to negotiate MPEG-specific stream parameters when
+    the pixelformat has been set to V4L2_PIX_FMT_MPEG.
+
+    To query the current parameters, call the GO7007IOC_G_MPEG_PARAMS ioctl
+    with a pointer to a struct go7007_mpeg_params.  If the driver is not
+    set to MPEG format, the EINVAL error code will be returned.
+
+    To change the current parameters, initialize all fields of a struct
+    go7007_mpeg_params and call the GO7007_IOC_S_MPEG_PARAMS ioctl with a
+    pointer to this structure.  The driver will return the current
+    parameters with any necessary changes to conform to the limitations of
+    the hardware or selected MPEG mode.  Any or all fields can be set to
+    zero to request a reasonable default value.  If the driver is not set
+    to MPEG format, the EINVAL error code will be returned.  When I/O is in
+    progress, the EBUSY error code will be returned.
+
+    Fields in struct go7007_mpeg_params:
+
+       enum go7007_mpeg_video_standard
+         mpeg_video_standard        The MPEG video standard in which to
+                                    compress the video.
+
+                                    Choices are:
+                                       GO7007_MPEG_VIDEO_MPEG1
+                                       GO7007_MPEG_VIDEO_MPEG2
+                                       GO7007_MPEG_VIDEO_MPEG4
+
+       __u32                        Bit-wise OR of control flags (below)
+         flags
+
+       __u32                        The profile and level indication to be
+         pali                       stored in the sequence header.  This
+                                    is only used as an indicator to the
+                                    decoder, and does not affect the MPEG
+                                    features used in the video stream.
+                                    Not valid for MPEG1.
+
+                                    Choices for MPEG2 are:
+                                       GO7007_MPEG2_PROFILE_MAIN_MAIN
+
+                                    Choices for MPEG4 are:
+                                       GO7007_MPEG4_PROFILE_S_L0
+                                       GO7007_MPEG4_PROFILE_S_L1
+                                       GO7007_MPEG4_PROFILE_S_L2
+                                       GO7007_MPEG4_PROFILE_S_L3
+                                       GO7007_MPEG4_PROFILE_ARTS_L1
+                                       GO7007_MPEG4_PROFILE_ARTS_L2
+                                       GO7007_MPEG4_PROFILE_ARTS_L3
+                                       GO7007_MPEG4_PROFILE_ARTS_L4
+                                       GO7007_MPEG4_PROFILE_AS_L0
+                                       GO7007_MPEG4_PROFILE_AS_L1
+                                       GO7007_MPEG4_PROFILE_AS_L2
+                                       GO7007_MPEG4_PROFILE_AS_L3
+                                       GO7007_MPEG4_PROFILE_AS_L4
+                                       GO7007_MPEG4_PROFILE_AS_L5
+
+    Flags in struct go7007_mpeg_params:
+
+       GO7007_MPEG_FORCE_DVD_MODE   Force all compression parameters and
+                                    bitrate control settings to comply
+                                    with DVD MPEG2 stream requirements.
+                                    This overrides most compression and
+                                    bitrate settings!
+
+       GO7007_MPEG_OMIT_GOP_HEADER  Omit the GOP header.
+
+       GO7007_MPEG_REPEAT_SEQHEADER Repeat the MPEG sequence header at
+                                    the start of each GOP.
+
+
+  GO7007IOC_S_BITRATE, GO7007IOC_G_BITRATE
+
+    These ioctls are used to set and query the target bitrate value for the
+    compressed video stream.  The bitrate may be selected by storing the
+    target bits per second in an int and calling GO7007IOC_S_BITRATE with a
+    pointer to the int.  The bitrate may be queried by calling
+    GO7007IOC_G_BITRATE with a pointer to an int where the current bitrate
+    will be stored.
+
+    Note that this is the primary means of controlling the video quality
+    for all compression modes, including V4L2_PIX_FMT_MJPEG.  The
+    VIDIOC_S_JPEGCOMP ioctl is not supported.
+
+
+----------------------------------------------------------------------------
+                  Installing the WIS PCI Voyager Driver
+---------------------------------------------------------------------------
+
+The WIS PCI Voyager driver requires several patches to the Linux 2.6.11.x
+kernel source tree before compiling the driver.  These patches update the
+in-kernel SAA7134 driver to the newest development version and patch bugs
+in the TDA8290/TDA8275 tuner driver.
+
+The following patches must be downloaded from Gerd Knorr's website and
+applied in the order listed:
+
+       http://dl.bytesex.org/patches/2.6.11-2/i2c-tuner
+       http://dl.bytesex.org/patches/2.6.11-2/i2c-tuner2
+       http://dl.bytesex.org/patches/2.6.11-2/v4l2-api-mpeg
+       http://dl.bytesex.org/patches/2.6.11-2/saa7134-update
+
+The following patches are included with this SDK and can be applied in any
+order:
+
+       patches/2.6.11/saa7134-voyager.diff
+       patches/2.6.11/tda8275-newaddr.diff
+       patches/2.6.11/tda8290-ntsc.diff
+
+Check to make sure the CONFIG_VIDEO_SAA7134 option is enabled in the kernel
+configuration, and build and install the kernel.
+
+After rebooting into the new kernel, the GO7007 driver can be compiled and
+installed:
+
+       $ make SAA7134_BUILD=y
+       $ make install
+       $ modprobe saa7134-go7007
+
+There will be two V4L video devices associated with the PCI Voyager.  The
+first device (most likely /dev/video0) provides access to the raw video
+capture mode of the SAA7133 device and is used to configure the source
+video parameters and tune the TV tuner.  This device can be used with xawtv
+or other V4L(2) video software as a standard uncompressed device.
+
+The second device (most likely /dev/video1) provides access to the
+compression functions of the GO7007.  It can be tested using the gorecord
+application in the apps/ directory of this SDK:
+
+       $ apps/gorecord -vdevice /dev/video1 -noaudio test.avi
+
+Currently the frame resolution is fixed at 720x480 (NTSC) or 720x576 (PAL),
+and the video standard must be specified to both the raw and the compressed
+video devices (xawtv and gorecord, for example).
+
+
+--------------------------------------------------------------------------
+RELEASE NOTES FOR WIS GO7007SB LINUX DRIVER
+---------------------------------------------------------------------------
+
+Last updated: 5 November 2005
+
+ - Release 0.9.7 includes new support for using udev to run fxload.  The
+   install script should automatically detect whether the old hotplug
+   scripts or the new udev rules should be used.  To force the use of
+   hotplug, run "make install USE_UDEV=n".  To force the use of udev, run
+   "make install USE_UDEV=y".
+
+ - Motion detection is supported but undocumented.  Try the `modet` app
+   for a demonstration of how to use the facility.
+
+ - Using USB2.0 devices such as the TV402U with USB1.1 HCDs or hubs can
+   cause buffer overruns and frame drops, even at low framerates, due to
+   inconsistency in the bitrate control mechanism.
+
+ - On devices with an SAA7115, including the Plextor ConvertX, video height
+   values of 96, 128, 160, 192, 256, 320, and 384 do not work in NTSC mode.
+   All valid heights up to 512 work correctly in PAL mode.
+
+ - The WIS Star Trek and PCI Voyager boards have no support yet for audio
+   or the TV tuner.
diff --git a/drivers/staging/media/go7007/s2250-board.c b/drivers/staging/media/go7007/s2250-board.c
new file mode 100644 (file)
index 0000000..e7736a9
--- /dev/null
@@ -0,0 +1,698 @@
+/*
+ * Copyright (C) 2008 Sensoray Company Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-subdev.h>
+#include "go7007-priv.h"
+
+MODULE_DESCRIPTION("Sensoray 2250/2251 i2c v4l2 subdev driver");
+MODULE_LICENSE("GPL v2");
+
+#define TLV320_ADDRESS      0x34
+#define VPX322_ADDR_ANALOGCONTROL1     0x02
+#define VPX322_ADDR_BRIGHTNESS0                0x0127
+#define VPX322_ADDR_BRIGHTNESS1                0x0131
+#define VPX322_ADDR_CONTRAST0          0x0128
+#define VPX322_ADDR_CONTRAST1          0x0132
+#define VPX322_ADDR_HUE                        0x00dc
+#define VPX322_ADDR_SAT                        0x0030
+
+struct go7007_usb_board {
+       unsigned int flags;
+       struct go7007_board_info main_info;
+};
+
+struct go7007_usb {
+       struct go7007_usb_board *board;
+       struct mutex i2c_lock;
+       struct usb_device *usbdev;
+       struct urb *video_urbs[8];
+       struct urb *audio_urbs[8];
+       struct urb *intr_urb;
+};
+
+static unsigned char aud_regs[] = {
+       0x1e, 0x00,
+       0x00, 0x17,
+       0x02, 0x17,
+       0x04, 0xf9,
+       0x06, 0xf9,
+       0x08, 0x02,
+       0x0a, 0x00,
+       0x0c, 0x00,
+       0x0a, 0x00,
+       0x0c, 0x00,
+       0x0e, 0x02,
+       0x10, 0x00,
+       0x12, 0x01,
+       0x00, 0x00,
+};
+
+
+static unsigned char vid_regs[] = {
+       0xF2, 0x0f,
+       0xAA, 0x00,
+       0xF8, 0xff,
+       0x00, 0x00,
+};
+
+static u16 vid_regs_fp[] = {
+       0x028, 0x067,
+       0x120, 0x016,
+       0x121, 0xcF2,
+       0x122, 0x0F2,
+       0x123, 0x00c,
+       0x124, 0x2d0,
+       0x125, 0x2e0,
+       0x126, 0x004,
+       0x128, 0x1E0,
+       0x12A, 0x016,
+       0x12B, 0x0F2,
+       0x12C, 0x0F2,
+       0x12D, 0x00c,
+       0x12E, 0x2d0,
+       0x12F, 0x2e0,
+       0x130, 0x004,
+       0x132, 0x1E0,
+       0x140, 0x060,
+       0x153, 0x00C,
+       0x154, 0x200,
+       0x150, 0x801,
+       0x000, 0x000
+};
+
+/* PAL specific values */
+static u16 vid_regs_fp_pal[] =
+{
+       0x120, 0x017,
+       0x121, 0xd22,
+       0x122, 0x122,
+       0x12A, 0x017,
+       0x12B, 0x122,
+       0x12C, 0x122,
+       0x140, 0x060,
+       0x000, 0x000,
+};
+
+struct s2250 {
+       struct v4l2_subdev sd;
+       v4l2_std_id std;
+       int input;
+       int brightness;
+       int contrast;
+       int saturation;
+       int hue;
+       int reg12b_val;
+       int audio_input;
+       struct i2c_client *audio;
+};
+
+static inline struct s2250 *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct s2250, sd);
+}
+
+/* from go7007-usb.c which is Copyright (C) 2005-2006 Micronas USA Inc.*/
+static int go7007_usb_vendor_request(struct go7007 *go, u16 request,
+       u16 value, u16 index, void *transfer_buffer, int length, int in)
+{
+       struct go7007_usb *usb = go->hpi_context;
+       int timeout = 5000;
+
+       if (in) {
+               return usb_control_msg(usb->usbdev,
+                               usb_rcvctrlpipe(usb->usbdev, 0), request,
+                               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                               value, index, transfer_buffer, length, timeout);
+       } else {
+               return usb_control_msg(usb->usbdev,
+                               usb_sndctrlpipe(usb->usbdev, 0), request,
+                               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               value, index, transfer_buffer, length, timeout);
+       }
+}
+/* end from go7007-usb.c which is Copyright (C) 2005-2006 Micronas USA Inc.*/
+
+static int write_reg(struct i2c_client *client, u8 reg, u8 value)
+{
+       struct go7007 *go = i2c_get_adapdata(client->adapter);
+       struct go7007_usb *usb;
+       int rc;
+       int dev_addr = client->addr << 1;  /* firmware wants 8-bit address */
+       u8 *buf;
+
+       if (go == NULL)
+               return -ENODEV;
+
+       if (go->status == STATUS_SHUTDOWN)
+               return -EBUSY;
+
+       buf = kzalloc(16, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       usb = go->hpi_context;
+       if (mutex_lock_interruptible(&usb->i2c_lock) != 0) {
+               printk(KERN_INFO "i2c lock failed\n");
+               kfree(buf);
+               return -EINTR;
+       }
+       rc = go7007_usb_vendor_request(go, 0x55, dev_addr,
+                                      (reg<<8 | value),
+                                      buf,
+                                      16, 1);
+
+       mutex_unlock(&usb->i2c_lock);
+       kfree(buf);
+       return rc;
+}
+
+static int write_reg_fp(struct i2c_client *client, u16 addr, u16 val)
+{
+       struct go7007 *go = i2c_get_adapdata(client->adapter);
+       struct go7007_usb *usb;
+       u8 *buf;
+       struct s2250 *dec = i2c_get_clientdata(client);
+
+       if (go == NULL)
+               return -ENODEV;
+
+       if (go->status == STATUS_SHUTDOWN)
+               return -EBUSY;
+
+       buf = kzalloc(16, GFP_KERNEL);
+
+       if (buf == NULL)
+               return -ENOMEM;
+
+
+
+       memset(buf, 0xcd, 6);
+
+       usb = go->hpi_context;
+       if (mutex_lock_interruptible(&usb->i2c_lock) != 0) {
+               printk(KERN_INFO "i2c lock failed\n");
+               kfree(buf);
+               return -EINTR;
+       }
+       if (go7007_usb_vendor_request(go, 0x57, addr, val, buf, 16, 1) < 0) {
+               kfree(buf);
+               return -EFAULT;
+       }
+
+       mutex_unlock(&usb->i2c_lock);
+       if (buf[0] == 0) {
+               unsigned int subaddr, val_read;
+
+               subaddr = (buf[4] << 8) + buf[5];
+               val_read = (buf[2] << 8) + buf[3];
+               kfree(buf);
+               if (val_read != val) {
+                       printk(KERN_INFO "invalid fp write %x %x\n",
+                              val_read, val);
+                       return -EFAULT;
+               }
+               if (subaddr != addr) {
+                       printk(KERN_INFO "invalid fp write addr %x %x\n",
+                              subaddr, addr);
+                       return -EFAULT;
+               }
+       } else {
+               kfree(buf);
+               return -EFAULT;
+       }
+
+       /* save last 12b value */
+       if (addr == 0x12b)
+               dec->reg12b_val = val;
+
+       return 0;
+}
+
+static int read_reg_fp(struct i2c_client *client, u16 addr, u16 *val)
+{
+       struct go7007 *go = i2c_get_adapdata(client->adapter);
+       struct go7007_usb *usb;
+       u8 *buf;
+
+       if (go == NULL)
+               return -ENODEV;
+
+       if (go->status == STATUS_SHUTDOWN)
+               return -EBUSY;
+
+       buf = kzalloc(16, GFP_KERNEL);
+
+       if (buf == NULL)
+               return -ENOMEM;
+
+
+
+       memset(buf, 0xcd, 6);
+       usb = go->hpi_context;
+       if (mutex_lock_interruptible(&usb->i2c_lock) != 0) {
+               printk(KERN_INFO "i2c lock failed\n");
+               kfree(buf);
+               return -EINTR;
+       }
+       if (go7007_usb_vendor_request(go, 0x58, addr, 0, buf, 16, 1) < 0) {
+               kfree(buf);
+               return -EFAULT;
+       }
+       mutex_unlock(&usb->i2c_lock);
+
+       *val = (buf[0] << 8) | buf[1];
+       kfree(buf);
+
+       return 0;
+}
+
+
+static int write_regs(struct i2c_client *client, u8 *regs)
+{
+       int i;
+
+       for (i = 0; !((regs[i] == 0x00) && (regs[i+1] == 0x00)); i += 2) {
+               if (write_reg(client, regs[i], regs[i+1]) < 0) {
+                       printk(KERN_INFO "s2250: failed\n");
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+static int write_regs_fp(struct i2c_client *client, u16 *regs)
+{
+       int i;
+
+       for (i = 0; !((regs[i] == 0x00) && (regs[i+1] == 0x00)); i += 2) {
+               if (write_reg_fp(client, regs[i], regs[i+1]) < 0) {
+                       printk(KERN_INFO "s2250: failed fp\n");
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+static int s2250_s_video_routing(struct v4l2_subdev *sd, u32 input, u32 output,
+                                u32 config)
+{
+       struct s2250 *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int vidsys;
+
+       vidsys = (state->std == V4L2_STD_NTSC) ? 0x01 : 0x00;
+       if (input == 0) {
+               /* composite */
+               write_reg_fp(client, 0x20, 0x020 | vidsys);
+               write_reg_fp(client, 0x21, 0x662);
+               write_reg_fp(client, 0x140, 0x060);
+       } else if (input == 1) {
+               /* S-Video */
+               write_reg_fp(client, 0x20, 0x040 | vidsys);
+               write_reg_fp(client, 0x21, 0x666);
+               write_reg_fp(client, 0x140, 0x060);
+       } else {
+               return -EINVAL;
+       }
+       state->input = input;
+       return 0;
+}
+
+static int s2250_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+       struct s2250 *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u16 vidsource;
+
+       vidsource = (state->input == 1) ? 0x040 : 0x020;
+       switch (norm) {
+       case V4L2_STD_NTSC:
+               write_regs_fp(client, vid_regs_fp);
+               write_reg_fp(client, 0x20, vidsource | 1);
+               break;
+       case V4L2_STD_PAL:
+               write_regs_fp(client, vid_regs_fp);
+               write_regs_fp(client, vid_regs_fp_pal);
+               write_reg_fp(client, 0x20, vidsource);
+               break;
+       default:
+               return -EINVAL;
+       }
+       state->std = norm;
+       return 0;
+}
+
+static int s2250_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *query)
+{
+       switch (query->id) {
+       case V4L2_CID_BRIGHTNESS:
+               return v4l2_ctrl_query_fill(query, 0, 100, 1, 50);
+       case V4L2_CID_CONTRAST:
+               return v4l2_ctrl_query_fill(query, 0, 100, 1, 50);
+       case V4L2_CID_SATURATION:
+               return v4l2_ctrl_query_fill(query, 0, 100, 1, 50);
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill(query, -50, 50, 1, 0);
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s2250_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct s2250 *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int value1;
+       u16 oldvalue;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               if (ctrl->value > 100)
+                       state->brightness = 100;
+               else if (ctrl->value < 0)
+                       state->brightness = 0;
+               else
+                       state->brightness = ctrl->value;
+               value1 = (state->brightness - 50) * 255 / 100;
+               read_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, &oldvalue);
+               write_reg_fp(client, VPX322_ADDR_BRIGHTNESS0,
+                            value1 | (oldvalue & ~0xff));
+               read_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, &oldvalue);
+               write_reg_fp(client, VPX322_ADDR_BRIGHTNESS1,
+                            value1 | (oldvalue & ~0xff));
+               write_reg_fp(client, 0x140, 0x60);
+               break;
+       case V4L2_CID_CONTRAST:
+               if (ctrl->value > 100)
+                       state->contrast = 100;
+               else if (ctrl->value < 0)
+                       state->contrast = 0;
+               else
+                       state->contrast = ctrl->value;
+               value1 = state->contrast * 0x40 / 100;
+               if (value1 > 0x3f)
+                       value1 = 0x3f; /* max */
+               read_reg_fp(client, VPX322_ADDR_CONTRAST0, &oldvalue);
+               write_reg_fp(client, VPX322_ADDR_CONTRAST0,
+                            value1 | (oldvalue & ~0x3f));
+               read_reg_fp(client, VPX322_ADDR_CONTRAST1, &oldvalue);
+               write_reg_fp(client, VPX322_ADDR_CONTRAST1,
+                            value1 | (oldvalue & ~0x3f));
+               write_reg_fp(client, 0x140, 0x60);
+               break;
+       case V4L2_CID_SATURATION:
+               if (ctrl->value > 100)
+                       state->saturation = 100;
+               else if (ctrl->value < 0)
+                       state->saturation = 0;
+               else
+                       state->saturation = ctrl->value;
+               value1 = state->saturation * 4140 / 100;
+               if (value1 > 4094)
+                       value1 = 4094;
+               write_reg_fp(client, VPX322_ADDR_SAT, value1);
+               break;
+       case V4L2_CID_HUE:
+               if (ctrl->value > 50)
+                       state->hue = 50;
+               else if (ctrl->value < -50)
+                       state->hue = -50;
+               else
+                       state->hue = ctrl->value;
+               /* clamp the hue range */
+               value1 = state->hue * 280 / 50;
+               write_reg_fp(client, VPX322_ADDR_HUE, value1);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s2250_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct s2250 *state = to_state(sd);
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ctrl->value = state->brightness;
+               break;
+       case V4L2_CID_CONTRAST:
+               ctrl->value = state->contrast;
+               break;
+       case V4L2_CID_SATURATION:
+               ctrl->value = state->saturation;
+               break;
+       case V4L2_CID_HUE:
+               ctrl->value = state->hue;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s2250_s_mbus_fmt(struct v4l2_subdev *sd,
+                       struct v4l2_mbus_framefmt *fmt)
+{
+       struct s2250 *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (fmt->height < 640) {
+               write_reg_fp(client, 0x12b, state->reg12b_val | 0x400);
+               write_reg_fp(client, 0x140, 0x060);
+       } else {
+               write_reg_fp(client, 0x12b, state->reg12b_val & ~0x400);
+               write_reg_fp(client, 0x140, 0x060);
+       }
+       return 0;
+}
+
+static int s2250_s_audio_routing(struct v4l2_subdev *sd, u32 input, u32 output,
+                                u32 config)
+{
+       struct s2250 *state = to_state(sd);
+
+       switch (input) {
+       case 0:
+               write_reg(state->audio, 0x08, 0x02); /* Line In */
+               break;
+       case 1:
+               write_reg(state->audio, 0x08, 0x04); /* Mic */
+               break;
+       case 2:
+               write_reg(state->audio, 0x08, 0x05); /* Mic Boost */
+               break;
+       default:
+               return -EINVAL;
+       }
+       state->audio_input = input;
+       return 0;
+}
+
+
+static int s2250_log_status(struct v4l2_subdev *sd)
+{
+       struct s2250 *state = to_state(sd);
+
+       v4l2_info(sd, "Standard: %s\n", state->std == V4L2_STD_NTSC ? "NTSC" :
+                                       state->std == V4L2_STD_PAL ? "PAL" :
+                                       state->std == V4L2_STD_SECAM ? "SECAM" :
+                                       "unknown");
+       v4l2_info(sd, "Input: %s\n", state->input == 0 ? "Composite" :
+                                       state->input == 1 ? "S-video" :
+                                       "error");
+       v4l2_info(sd, "Brightness: %d\n", state->brightness);
+       v4l2_info(sd, "Contrast: %d\n", state->contrast);
+       v4l2_info(sd, "Saturation: %d\n", state->saturation);
+       v4l2_info(sd, "Hue: %d\n", state->hue); return 0;
+       v4l2_info(sd, "Audio input: %s\n", state->audio_input == 0 ? "Line In" :
+                                       state->audio_input == 1 ? "Mic" :
+                                       state->audio_input == 2 ? "Mic Boost" :
+                                       "error");
+       return 0;
+}
+
+/* --------------------------------------------------------------------------*/
+
+static const struct v4l2_subdev_core_ops s2250_core_ops = {
+       .log_status = s2250_log_status,
+       .g_ctrl = s2250_g_ctrl,
+       .s_ctrl = s2250_s_ctrl,
+       .queryctrl = s2250_queryctrl,
+       .s_std = s2250_s_std,
+};
+
+static const struct v4l2_subdev_audio_ops s2250_audio_ops = {
+       .s_routing = s2250_s_audio_routing,
+};
+
+static const struct v4l2_subdev_video_ops s2250_video_ops = {
+       .s_routing = s2250_s_video_routing,
+       .s_mbus_fmt = s2250_s_mbus_fmt,
+};
+
+static const struct v4l2_subdev_ops s2250_ops = {
+       .core = &s2250_core_ops,
+       .audio = &s2250_audio_ops,
+       .video = &s2250_video_ops,
+};
+
+/* --------------------------------------------------------------------------*/
+
+static int s2250_probe(struct i2c_client *client,
+                      const struct i2c_device_id *id)
+{
+       struct i2c_client *audio;
+       struct i2c_adapter *adapter = client->adapter;
+       struct s2250 *state;
+       struct v4l2_subdev *sd;
+       u8 *data;
+       struct go7007 *go = i2c_get_adapdata(adapter);
+       struct go7007_usb *usb = go->hpi_context;
+
+       audio = i2c_new_dummy(adapter, TLV320_ADDRESS >> 1);
+       if (audio == NULL)
+               return -ENOMEM;
+
+       state = kmalloc(sizeof(struct s2250), GFP_KERNEL);
+       if (state == NULL) {
+               i2c_unregister_device(audio);
+               return -ENOMEM;
+       }
+
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &s2250_ops);
+
+       v4l2_info(sd, "initializing %s at address 0x%x on %s\n",
+              "Sensoray 2250/2251", client->addr, client->adapter->name);
+
+       state->std = V4L2_STD_NTSC;
+       state->brightness = 50;
+       state->contrast = 50;
+       state->saturation = 50;
+       state->hue = 0;
+       state->audio = audio;
+
+       /* initialize the audio */
+       if (write_regs(audio, aud_regs) < 0) {
+               printk(KERN_ERR
+                      "s2250: error initializing audio\n");
+               i2c_unregister_device(audio);
+               kfree(state);
+               return 0;
+       }
+
+       if (write_regs(client, vid_regs) < 0) {
+               printk(KERN_ERR
+                      "s2250: error initializing decoder\n");
+               i2c_unregister_device(audio);
+               kfree(state);
+               return 0;
+       }
+       if (write_regs_fp(client, vid_regs_fp) < 0) {
+               printk(KERN_ERR
+                      "s2250: error initializing decoder\n");
+               i2c_unregister_device(audio);
+               kfree(state);
+               return 0;
+       }
+       /* set default channel */
+       /* composite */
+       write_reg_fp(client, 0x20, 0x020 | 1);
+       write_reg_fp(client, 0x21, 0x662);
+       write_reg_fp(client, 0x140, 0x060);
+
+       /* set default audio input */
+       state->audio_input = 0;
+       write_reg(client, 0x08, 0x02); /* Line In */
+
+       if (mutex_lock_interruptible(&usb->i2c_lock) == 0) {
+               data = kzalloc(16, GFP_KERNEL);
+               if (data != NULL) {
+                       int rc;
+                       rc = go7007_usb_vendor_request(go, 0x41, 0, 0,
+                                                      data, 16, 1);
+                       if (rc > 0) {
+                               u8 mask;
+                               data[0] = 0;
+                               mask = 1<<5;
+                               data[0] &= ~mask;
+                               data[1] |= mask;
+                               go7007_usb_vendor_request(go, 0x40, 0,
+                                                         (data[1]<<8)
+                                                         + data[1],
+                                                         data, 16, 0);
+                       }
+                       kfree(data);
+               }
+               mutex_unlock(&usb->i2c_lock);
+       }
+
+       v4l2_info(sd, "initialized successfully\n");
+       return 0;
+}
+
+static int s2250_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
+       return 0;
+}
+
+static const struct i2c_device_id s2250_id[] = {
+       { "s2250", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, s2250_id);
+
+static struct i2c_driver s2250_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "s2250",
+       },
+       .probe          = s2250_probe,
+       .remove         = s2250_remove,
+       .id_table       = s2250_id,
+};
+
+static __init int init_s2250(void)
+{
+       return i2c_add_driver(&s2250_driver);
+}
+
+static __exit void exit_s2250(void)
+{
+       i2c_del_driver(&s2250_driver);
+}
+
+module_init(init_s2250);
+module_exit(exit_s2250);
diff --git a/drivers/staging/media/go7007/s2250-loader.c b/drivers/staging/media/go7007/s2250-loader.c
new file mode 100644 (file)
index 0000000..4e13251
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2008 Sensoray Company Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <dvb-usb.h>
+
+#define S2250_LOADER_FIRMWARE  "s2250_loader.fw"
+#define S2250_FIRMWARE         "s2250.fw"
+
+typedef struct device_extension_s {
+    struct kref     kref;
+    int minor;
+    struct usb_device *usbdev;
+} device_extension_t, *pdevice_extension_t;
+
+#define USB_s2250loader_MAJOR 240
+#define USB_s2250loader_MINOR_BASE 0
+#define MAX_DEVICES 256
+
+static pdevice_extension_t s2250_dev_table[MAX_DEVICES];
+static DEFINE_MUTEX(s2250_dev_table_mutex);
+
+#define to_s2250loader_dev_common(d) container_of(d, device_extension_t, kref)
+static void s2250loader_delete(struct kref *kref)
+{
+       pdevice_extension_t s = to_s2250loader_dev_common(kref);
+       s2250_dev_table[s->minor] = NULL;
+       kfree(s);
+}
+
+static int s2250loader_probe(struct usb_interface *interface,
+                               const struct usb_device_id *id)
+{
+       struct usb_device *usbdev;
+       int minor, ret;
+       pdevice_extension_t s = NULL;
+       const struct firmware *fw;
+
+       usbdev = usb_get_dev(interface_to_usbdev(interface));
+       if (!usbdev) {
+               printk(KERN_ERR "Enter s2250loader_probe failed\n");
+               return -1;
+       }
+       printk(KERN_INFO "Enter s2250loader_probe 2.6 kernel\n");
+       printk(KERN_INFO "vendor id 0x%x, device id 0x%x devnum:%d\n",
+          usbdev->descriptor.idVendor, usbdev->descriptor.idProduct,
+          usbdev->devnum);
+
+       if (usbdev->descriptor.bNumConfigurations != 1) {
+               printk(KERN_ERR "can't handle multiple config\n");
+               return -1;
+       }
+       mutex_lock(&s2250_dev_table_mutex);
+
+       for (minor = 0; minor < MAX_DEVICES; minor++) {
+               if (s2250_dev_table[minor] == NULL)
+                       break;
+       }
+
+       if (minor < 0 || minor >= MAX_DEVICES) {
+               printk(KERN_ERR "Invalid minor: %d\n", minor);
+               goto failed;
+       }
+
+       /* Allocate dev data structure */
+       s = kmalloc(sizeof(device_extension_t), GFP_KERNEL);
+       if (s == NULL) {
+               printk(KERN_ERR "Out of memory\n");
+               goto failed;
+       }
+       s2250_dev_table[minor] = s;
+
+       printk(KERN_INFO "s2250loader_probe: Device %d on Bus %d Minor %d\n",
+               usbdev->devnum, usbdev->bus->busnum, minor);
+
+       memset(s, 0, sizeof(device_extension_t));
+       s->usbdev = usbdev;
+       printk(KERN_INFO "loading 2250 loader\n");
+
+       kref_init(&(s->kref));
+
+       mutex_unlock(&s2250_dev_table_mutex);
+
+       if (request_firmware(&fw, S2250_LOADER_FIRMWARE, &usbdev->dev)) {
+               printk(KERN_ERR
+                       "s2250: unable to load firmware from file \"%s\"\n",
+                       S2250_LOADER_FIRMWARE);
+               goto failed2;
+       }
+       ret = usb_cypress_load_firmware(usbdev, fw, CYPRESS_FX2);
+       release_firmware(fw);
+       if (0 != ret) {
+               printk(KERN_ERR "loader download failed\n");
+               goto failed2;
+       }
+
+       if (request_firmware(&fw, S2250_FIRMWARE, &usbdev->dev)) {
+               printk(KERN_ERR
+                       "s2250: unable to load firmware from file \"%s\"\n",
+                       S2250_FIRMWARE);
+               goto failed2;
+       }
+       ret = usb_cypress_load_firmware(usbdev, fw, CYPRESS_FX2);
+       release_firmware(fw);
+       if (0 != ret) {
+               printk(KERN_ERR "firmware_s2250 download failed\n");
+               goto failed2;
+       }
+
+       usb_set_intfdata(interface, s);
+       return 0;
+
+failed:
+       mutex_unlock(&s2250_dev_table_mutex);
+failed2:
+       if (s)
+               kref_put(&(s->kref), s2250loader_delete);
+
+       printk(KERN_ERR "probe failed\n");
+       return -1;
+}
+
+static void s2250loader_disconnect(struct usb_interface *interface)
+{
+       pdevice_extension_t s;
+       printk(KERN_INFO "s2250: disconnect\n");
+       s = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+       kref_put(&(s->kref), s2250loader_delete);
+}
+
+static const struct usb_device_id s2250loader_ids[] = {
+       {USB_DEVICE(0x1943, 0xa250)},
+       {}                          /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, s2250loader_ids);
+
+static struct usb_driver s2250loader_driver = {
+       .name           = "s2250-loader",
+       .probe          = s2250loader_probe,
+       .disconnect     = s2250loader_disconnect,
+       .id_table       = s2250loader_ids,
+};
+
+static int __init s2250loader_init(void)
+{
+       int r;
+       unsigned i = 0;
+
+       for (i = 0; i < MAX_DEVICES; i++)
+               s2250_dev_table[i] = NULL;
+
+       r = usb_register(&s2250loader_driver);
+       if (r) {
+               printk(KERN_ERR "usb_register failed. Error number %d\n", r);
+               return -1;
+       }
+
+       printk(KERN_INFO "s2250loader_init: driver registered\n");
+       return 0;
+}
+module_init(s2250loader_init);
+
+static void __exit s2250loader_cleanup(void)
+{
+       printk(KERN_INFO "s2250loader_cleanup\n");
+       usb_deregister(&s2250loader_driver);
+}
+module_exit(s2250loader_cleanup);
+
+MODULE_AUTHOR("");
+MODULE_DESCRIPTION("firmware loader for Sensoray 2250/2251");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/s2250-loader.h b/drivers/staging/media/go7007/s2250-loader.h
new file mode 100644 (file)
index 0000000..b7c301a
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#ifndef _S2250_LOADER_H_
+#define _S2250_LOADER_H_
+
+extern int s2250loader_init(void);
+extern void s2250loader_cleanup(void);
+
+#endif
diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c
new file mode 100644 (file)
index 0000000..cf7c34a
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <asm/byteorder.h>
+#include <media/v4l2-common.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+#include "go7007-priv.h"
+
+#define GO7007_HPI_DEBUG
+
+enum hpi_address {
+       HPI_ADDR_VIDEO_BUFFER = 0xe4,
+       HPI_ADDR_INIT_BUFFER = 0xea,
+       HPI_ADDR_INTR_RET_VALUE = 0xee,
+       HPI_ADDR_INTR_RET_DATA = 0xec,
+       HPI_ADDR_INTR_STATUS = 0xf4,
+       HPI_ADDR_INTR_WR_PARAM = 0xf6,
+       HPI_ADDR_INTR_WR_INDEX = 0xf8,
+};
+
+enum gpio_command {
+       GPIO_COMMAND_RESET = 0x00, /* 000b */
+       GPIO_COMMAND_REQ1  = 0x04, /* 001b */
+       GPIO_COMMAND_WRITE = 0x20, /* 010b */
+       GPIO_COMMAND_REQ2  = 0x24, /* 011b */
+       GPIO_COMMAND_READ  = 0x80, /* 100b */
+       GPIO_COMMAND_VIDEO = 0x84, /* 101b */
+       GPIO_COMMAND_IDLE  = 0xA0, /* 110b */
+       GPIO_COMMAND_ADDR  = 0xA4, /* 111b */
+};
+
+struct saa7134_go7007 {
+       struct saa7134_dev *dev;
+       u8 *top;
+       u8 *bottom;
+       dma_addr_t top_dma;
+       dma_addr_t bottom_dma;
+};
+
+static struct go7007_board_info board_voyager = {
+       .firmware        = "go7007tv.bin",
+       .flags           = 0,
+       .sensor_flags    = GO7007_SENSOR_656 |
+                               GO7007_SENSOR_VALID_ENABLE |
+                               GO7007_SENSOR_TV |
+                               GO7007_SENSOR_VBI,
+       .audio_flags    = GO7007_AUDIO_I2S_MODE_1 |
+                               GO7007_AUDIO_WORD_16,
+       .audio_rate      = 48000,
+       .audio_bclk_div  = 8,
+       .audio_main_div  = 2,
+       .hpi_buffer_cap  = 7,
+       .num_inputs      = 1,
+       .inputs          = {
+               {
+                       .name           = "SAA7134",
+               },
+       },
+};
+MODULE_FIRMWARE("go7007tv.bin");
+
+/********************* Driver for GPIO HPI interface *********************/
+
+static int gpio_write(struct saa7134_dev *dev, u8 addr, u16 data)
+{
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+       /* Write HPI address */
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       /* Write low byte */
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, data & 0xff);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       /* Write high byte */
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, data >> 8);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       return 0;
+}
+
+static int gpio_read(struct saa7134_dev *dev, u8 addr, u16 *data)
+{
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+       /* Write HPI address */
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
+
+       /* Read low byte */
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
+       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       *data = saa_readb(SAA7134_GPIO_GPSTATUS0);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       /* Read high byte */
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
+       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       *data |= saa_readb(SAA7134_GPIO_GPSTATUS0) << 8;
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+       return 0;
+}
+
+static int saa7134_go7007_interface_reset(struct go7007 *go)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+       u32 status;
+       u16 intr_val, intr_data;
+       int count = 20;
+
+       saa_clearb(SAA7134_TS_PARALLEL, 0x80); /* Disable TS interface */
+       saa_writeb(SAA7134_GPIO_GPMODE2, 0xa4);
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_RESET);
+       msleep(1);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
+       msleep(10);
+
+       saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+       saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+       status = saa_readb(SAA7134_GPIO_GPSTATUS2);
+       /*printk(KERN_DEBUG "status is %s\n", status & 0x40 ? "OK" : "not OK"); */
+
+       /* enter command mode...(?) */
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
+
+       do {
+               saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+               saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+               status = saa_readb(SAA7134_GPIO_GPSTATUS2);
+               /*printk(KERN_INFO "gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */
+       } while (--count > 0);
+
+       /* Wait for an interrupt to indicate successful hardware reset */
+       if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
+                       (intr_val & ~0x1) != 0x55aa) {
+               printk(KERN_ERR
+                       "saa7134-go7007: unable to reset the GO7007\n");
+               return -1;
+       }
+       return 0;
+}
+
+static int saa7134_go7007_write_interrupt(struct go7007 *go, int addr, int data)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+       int i;
+       u16 status_reg;
+
+#ifdef GO7007_HPI_DEBUG
+       printk(KERN_DEBUG
+               "saa7134-go7007: WriteInterrupt: %04x %04x\n", addr, data);
+#endif
+
+       for (i = 0; i < 100; ++i) {
+               gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
+               if (!(status_reg & 0x0010))
+                       break;
+               msleep(10);
+       }
+       if (i == 100) {
+               printk(KERN_ERR
+                       "saa7134-go7007: device is hung, status reg = 0x%04x\n",
+                       status_reg);
+               return -1;
+       }
+       gpio_write(dev, HPI_ADDR_INTR_WR_PARAM, data);
+       gpio_write(dev, HPI_ADDR_INTR_WR_INDEX, addr);
+
+       return 0;
+}
+
+static int saa7134_go7007_read_interrupt(struct go7007 *go)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+
+       /* XXX we need to wait if there is no interrupt available */
+       go->interrupt_available = 1;
+       gpio_read(dev, HPI_ADDR_INTR_RET_VALUE, &go->interrupt_value);
+       gpio_read(dev, HPI_ADDR_INTR_RET_DATA, &go->interrupt_data);
+#ifdef GO7007_HPI_DEBUG
+       printk(KERN_DEBUG "saa7134-go7007: ReadInterrupt: %04x %04x\n",
+                       go->interrupt_value, go->interrupt_data);
+#endif
+       return 0;
+}
+
+static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev,
+                                               unsigned long status)
+{
+       struct go7007 *go = video_get_drvdata(dev->empress_dev);
+       struct saa7134_go7007 *saa = go->hpi_context;
+
+       if (!go->streaming)
+               return;
+       if (0 != (status & 0x000f0000))
+               printk(KERN_DEBUG "saa7134-go7007: irq: lost %ld\n",
+                               (status >> 16) & 0x0f);
+       if (status & 0x100000) {
+               dma_sync_single_for_cpu(&dev->pci->dev,
+                                       saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+               go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE);
+               saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma));
+       } else {
+               dma_sync_single_for_cpu(&dev->pci->dev,
+                                       saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+               go7007_parse_video_stream(go, saa->top, PAGE_SIZE);
+               saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma));
+       }
+}
+
+static int saa7134_go7007_stream_start(struct go7007 *go)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+
+       saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top),
+                       0, PAGE_SIZE, DMA_FROM_DEVICE);
+       if (!saa->top_dma)
+               return -ENOMEM;
+       saa->bottom_dma = dma_map_page(&dev->pci->dev,
+                       virt_to_page(saa->bottom),
+                       0, PAGE_SIZE, DMA_FROM_DEVICE);
+       if (!saa->bottom_dma) {
+               dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
+                               DMA_FROM_DEVICE);
+               return -ENOMEM;
+       }
+
+       saa_writel(SAA7134_VIDEO_PORT_CTRL0 >> 2, 0xA300B000);
+       saa_writel(SAA7134_VIDEO_PORT_CTRL4 >> 2, 0x40000200);
+
+       /* Set HPI interface for video */
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+       saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_VIDEO_BUFFER);
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+       saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
+
+       /* Enable TS interface */
+       saa_writeb(SAA7134_TS_PARALLEL, 0xe6);
+
+       /* Reset TS interface */
+       saa_setb(SAA7134_TS_SERIAL1, 0x01);
+       saa_clearb(SAA7134_TS_SERIAL1, 0x01);
+
+       /* Set up transfer block size */
+       saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1);
+       saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1);
+       saa_writeb(SAA7134_TS_DMA1, 0);
+       saa_writeb(SAA7134_TS_DMA2, 0);
+
+       /* Enable video streaming mode */
+       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO);
+
+       saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma));
+       saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma));
+       saa_writel(SAA7134_RS_PITCH(5), 128);
+       saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX);
+
+       /* Enable TS FIFO */
+       saa_setl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
+
+       /* Enable DMA IRQ */
+       saa_setl(SAA7134_IRQ1,
+                       SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
+
+       return 0;
+}
+
+static int saa7134_go7007_stream_stop(struct go7007 *go)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev;
+
+       if (!saa)
+               return -EINVAL;
+       dev = saa->dev;
+       if (!dev)
+               return -EINVAL;
+
+       /* Shut down TS FIFO */
+       saa_clearl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
+
+       /* Disable DMA IRQ */
+       saa_clearl(SAA7134_IRQ1,
+                       SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
+
+       /* Disable TS interface */
+       saa_clearb(SAA7134_TS_PARALLEL, 0x80);
+
+       dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
+                       DMA_FROM_DEVICE);
+       dma_unmap_page(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE,
+                       DMA_FROM_DEVICE);
+
+       return 0;
+}
+
+static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+       u16 status_reg;
+       int i;
+
+#ifdef GO7007_HPI_DEBUG
+       printk(KERN_DEBUG "saa7134-go7007: DownloadBuffer "
+                       "sending %d bytes\n", len);
+#endif
+
+       while (len > 0) {
+               i = len > 64 ? 64 : len;
+               saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+               saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_INIT_BUFFER);
+               saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+               saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+               while (i-- > 0) {
+                       saa_writeb(SAA7134_GPIO_GPSTATUS0, *data);
+                       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+                       saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+                       ++data;
+                       --len;
+               }
+               for (i = 0; i < 100; ++i) {
+                       gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
+                       if (!(status_reg & 0x0002))
+                               break;
+               }
+               if (i == 100) {
+                       printk(KERN_ERR "saa7134-go7007: device is hung, "
+                                       "status reg = 0x%04x\n", status_reg);
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+static int saa7134_go7007_send_command(struct go7007 *go, unsigned int cmd,
+                                       void *arg)
+{
+       struct saa7134_go7007 *saa = go->hpi_context;
+       struct saa7134_dev *dev = saa->dev;
+
+       switch (cmd) {
+       case VIDIOC_S_STD:
+       {
+               v4l2_std_id *std = arg;
+               return saa7134_s_std_internal(dev, NULL, std);
+       }
+       case VIDIOC_G_STD:
+       {
+               v4l2_std_id *std = arg;
+               *std = dev->tvnorm->id;
+               return 0;
+       }
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *ctrl = arg;
+               if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER)
+                       return saa7134_queryctrl(NULL, NULL, ctrl);
+       }
+       case VIDIOC_G_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+               if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER)
+                       return saa7134_g_ctrl_internal(dev, NULL, ctrl);
+       }
+       case VIDIOC_S_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+               if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER)
+                       return saa7134_s_ctrl_internal(dev, NULL, ctrl);
+       }
+       }
+       return -EINVAL;
+
+}
+
+static struct go7007_hpi_ops saa7134_go7007_hpi_ops = {
+       .interface_reset        = saa7134_go7007_interface_reset,
+       .write_interrupt        = saa7134_go7007_write_interrupt,
+       .read_interrupt         = saa7134_go7007_read_interrupt,
+       .stream_start           = saa7134_go7007_stream_start,
+       .stream_stop            = saa7134_go7007_stream_stop,
+       .send_firmware          = saa7134_go7007_send_firmware,
+       .send_command           = saa7134_go7007_send_command,
+};
+
+/********************* Add/remove functions *********************/
+
+static int saa7134_go7007_init(struct saa7134_dev *dev)
+{
+       struct go7007 *go;
+       struct saa7134_go7007 *saa;
+
+       printk(KERN_DEBUG "saa7134-go7007: probing new SAA713X board\n");
+
+       saa = kzalloc(sizeof(struct saa7134_go7007), GFP_KERNEL);
+       if (saa == NULL)
+               return -ENOMEM;
+
+       /* Allocate a couple pages for receiving the compressed stream */
+       saa->top = (u8 *)get_zeroed_page(GFP_KERNEL);
+       if (!saa->top)
+               goto allocfail;
+       saa->bottom = (u8 *)get_zeroed_page(GFP_KERNEL);
+       if (!saa->bottom)
+               goto allocfail;
+
+       go = go7007_alloc(&board_voyager, &dev->pci->dev);
+       if (go == NULL)
+               goto allocfail;
+       go->board_id = GO7007_BOARDID_PCI_VOYAGER;
+       strncpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name));
+       go->hpi_ops = &saa7134_go7007_hpi_ops;
+       go->hpi_context = saa;
+       saa->dev = dev;
+
+       /* Boot the GO7007 */
+       if (go7007_boot_encoder(go, go->board_info->flags &
+                                       GO7007_BOARD_USE_ONBOARD_I2C) < 0)
+               goto initfail;
+
+       /* Do any final GO7007 initialization, then register the
+        * V4L2 and ALSA interfaces */
+       if (go7007_register_encoder(go) < 0)
+               goto initfail;
+       dev->empress_dev = go->video_dev;
+       video_set_drvdata(dev->empress_dev, go);
+
+       go->status = STATUS_ONLINE;
+       return 0;
+
+initfail:
+       go->status = STATUS_SHUTDOWN;
+       return 0;
+
+allocfail:
+       if (saa->top)
+               free_page((unsigned long)saa->top);
+       if (saa->bottom)
+               free_page((unsigned long)saa->bottom);
+       kfree(saa);
+       return -ENOMEM;
+}
+
+static int saa7134_go7007_fini(struct saa7134_dev *dev)
+{
+       struct go7007 *go;
+       struct saa7134_go7007 *saa;
+
+       if (NULL == dev->empress_dev)
+               return 0;
+
+       go = video_get_drvdata(dev->empress_dev);
+       saa = go->hpi_context;
+       go->status = STATUS_SHUTDOWN;
+       free_page((unsigned long)saa->top);
+       free_page((unsigned long)saa->bottom);
+       kfree(saa);
+       go7007_remove(go);
+       dev->empress_dev = NULL;
+
+       return 0;
+}
+
+static struct saa7134_mpeg_ops saa7134_go7007_ops = {
+       .type          = SAA7134_MPEG_GO7007,
+       .init          = saa7134_go7007_init,
+       .fini          = saa7134_go7007_fini,
+       .irq_ts_done   = saa7134_go7007_irq_ts_done,
+};
+
+static int __init saa7134_go7007_mod_init(void)
+{
+       return saa7134_ts_register(&saa7134_go7007_ops);
+}
+
+static void __exit saa7134_go7007_mod_cleanup(void)
+{
+       saa7134_ts_unregister(&saa7134_go7007_ops);
+}
+
+module_init(saa7134_go7007_mod_init);
+module_exit(saa7134_go7007_mod_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/snd-go7007.c b/drivers/staging/media/go7007/snd-go7007.c
new file mode 100644 (file)
index 0000000..deac938
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <asm/system.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+
+#include "go7007-priv.h"
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+module_param_array(id, charp, NULL, 0444);
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for the go7007 audio driver");
+MODULE_PARM_DESC(id, "ID string for the go7007 audio driver");
+MODULE_PARM_DESC(enable, "Enable for the go7007 audio driver");
+
+struct go7007_snd {
+       struct snd_card *card;
+       struct snd_pcm *pcm;
+       struct snd_pcm_substream *substream;
+       spinlock_t lock;
+       int w_idx;
+       int hw_ptr;
+       int avail;
+       int capturing;
+};
+
+static struct snd_pcm_hardware go7007_snd_capture_hw = {
+       .info                   = (SNDRV_PCM_INFO_MMAP |
+                                       SNDRV_PCM_INFO_INTERLEAVED |
+                                       SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                       SNDRV_PCM_INFO_MMAP_VALID),
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
+       .rates                  = SNDRV_PCM_RATE_48000,
+       .rate_min               = 48000,
+       .rate_max               = 48000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = (128*1024),
+       .period_bytes_min       = 4096,
+       .period_bytes_max       = (128*1024),
+       .periods_min            = 1,
+       .periods_max            = 32,
+};
+
+static void parse_audio_stream_data(struct go7007 *go, u8 *buf, int length)
+{
+       struct go7007_snd *gosnd = go->snd_context;
+       struct snd_pcm_runtime *runtime = gosnd->substream->runtime;
+       int frames = bytes_to_frames(runtime, length);
+
+       spin_lock(&gosnd->lock);
+       gosnd->hw_ptr += frames;
+       if (gosnd->hw_ptr >= runtime->buffer_size)
+               gosnd->hw_ptr -= runtime->buffer_size;
+       gosnd->avail += frames;
+       spin_unlock(&gosnd->lock);
+       if (gosnd->w_idx + length > runtime->dma_bytes) {
+               int cpy = runtime->dma_bytes - gosnd->w_idx;
+
+               memcpy(runtime->dma_area + gosnd->w_idx, buf, cpy);
+               length -= cpy;
+               buf += cpy;
+               gosnd->w_idx = 0;
+       }
+       memcpy(runtime->dma_area + gosnd->w_idx, buf, length);
+       gosnd->w_idx += length;
+       spin_lock(&gosnd->lock);
+       if (gosnd->avail < runtime->period_size) {
+               spin_unlock(&gosnd->lock);
+               return;
+       }
+       gosnd->avail -= runtime->period_size;
+       spin_unlock(&gosnd->lock);
+       if (gosnd->capturing)
+               snd_pcm_period_elapsed(gosnd->substream);
+}
+
+static int go7007_snd_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *hw_params)
+{
+       struct go7007 *go = snd_pcm_substream_chip(substream);
+       unsigned int bytes;
+
+       bytes = params_buffer_bytes(hw_params);
+       if (substream->runtime->dma_bytes > 0)
+               vfree(substream->runtime->dma_area);
+       substream->runtime->dma_bytes = 0;
+       substream->runtime->dma_area = vmalloc(bytes);
+       if (substream->runtime->dma_area == NULL)
+               return -ENOMEM;
+       substream->runtime->dma_bytes = bytes;
+       go->audio_deliver = parse_audio_stream_data;
+       return 0;
+}
+
+static int go7007_snd_hw_free(struct snd_pcm_substream *substream)
+{
+       struct go7007 *go = snd_pcm_substream_chip(substream);
+
+       go->audio_deliver = NULL;
+       if (substream->runtime->dma_bytes > 0)
+               vfree(substream->runtime->dma_area);
+       substream->runtime->dma_bytes = 0;
+       return 0;
+}
+
+static int go7007_snd_capture_open(struct snd_pcm_substream *substream)
+{
+       struct go7007 *go = snd_pcm_substream_chip(substream);
+       struct go7007_snd *gosnd = go->snd_context;
+       unsigned long flags;
+       int r;
+
+       spin_lock_irqsave(&gosnd->lock, flags);
+       if (gosnd->substream == NULL) {
+               gosnd->substream = substream;
+               substream->runtime->hw = go7007_snd_capture_hw;
+               r = 0;
+       } else
+               r = -EBUSY;
+       spin_unlock_irqrestore(&gosnd->lock, flags);
+       return r;
+}
+
+static int go7007_snd_capture_close(struct snd_pcm_substream *substream)
+{
+       struct go7007 *go = snd_pcm_substream_chip(substream);
+       struct go7007_snd *gosnd = go->snd_context;
+
+       gosnd->substream = NULL;
+       return 0;
+}
+
+static int go7007_snd_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       return 0;
+}
+
+static int go7007_snd_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct go7007 *go = snd_pcm_substream_chip(substream);
+       struct go7007_snd *gosnd = go->snd_context;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               /* Just set a flag to indicate we should signal ALSA when
+                * sound comes in */
+               gosnd->capturing = 1;
+               return 0;
+       case SNDRV_PCM_TRIGGER_STOP:
+               gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0;
+               gosnd->capturing = 0;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static snd_pcm_uframes_t go7007_snd_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct go7007 *go = snd_pcm_substream_chip(substream);
+       struct go7007_snd *gosnd = go->snd_context;
+
+       return gosnd->hw_ptr;
+}
+
+static struct page *go7007_snd_pcm_page(struct snd_pcm_substream *substream,
+                                       unsigned long offset)
+{
+       return vmalloc_to_page(substream->runtime->dma_area + offset);
+}
+
+static struct snd_pcm_ops go7007_snd_capture_ops = {
+       .open           = go7007_snd_capture_open,
+       .close          = go7007_snd_capture_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = go7007_snd_hw_params,
+       .hw_free        = go7007_snd_hw_free,
+       .prepare        = go7007_snd_pcm_prepare,
+       .trigger        = go7007_snd_pcm_trigger,
+       .pointer        = go7007_snd_pcm_pointer,
+       .page           = go7007_snd_pcm_page,
+};
+
+static int go7007_snd_free(struct snd_device *device)
+{
+       struct go7007 *go = device->device_data;
+
+       kfree(go->snd_context);
+       go->snd_context = NULL;
+       if (--go->ref_count == 0)
+               kfree(go);
+       return 0;
+}
+
+static struct snd_device_ops go7007_snd_device_ops = {
+       .dev_free       = go7007_snd_free,
+};
+
+int go7007_snd_init(struct go7007 *go)
+{
+       static int dev;
+       struct go7007_snd *gosnd;
+       int ret = 0;
+
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev]) {
+               dev++;
+               return -ENOENT;
+       }
+       gosnd = kmalloc(sizeof(struct go7007_snd), GFP_KERNEL);
+       if (gosnd == NULL)
+               return -ENOMEM;
+       spin_lock_init(&gosnd->lock);
+       gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0;
+       gosnd->capturing = 0;
+       ret = snd_card_create(index[dev], id[dev], THIS_MODULE, 0,
+                             &gosnd->card);
+       if (ret < 0) {
+               kfree(gosnd);
+               return ret;
+       }
+       ret = snd_device_new(gosnd->card, SNDRV_DEV_LOWLEVEL, go,
+                       &go7007_snd_device_ops);
+       if (ret < 0) {
+               kfree(gosnd);
+               return ret;
+       }
+       snd_card_set_dev(gosnd->card, go->dev);
+       ret = snd_pcm_new(gosnd->card, "go7007", 0, 0, 1, &gosnd->pcm);
+       if (ret < 0) {
+               snd_card_free(gosnd->card);
+               kfree(gosnd);
+               return ret;
+       }
+       strncpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver));
+       strncpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->driver));
+       strncpy(gosnd->card->longname, gosnd->card->shortname,
+                       sizeof(gosnd->card->longname));
+
+       gosnd->pcm->private_data = go;
+       snd_pcm_set_ops(gosnd->pcm, SNDRV_PCM_STREAM_CAPTURE,
+                       &go7007_snd_capture_ops);
+
+       ret = snd_card_register(gosnd->card);
+       if (ret < 0) {
+               snd_card_free(gosnd->card);
+               kfree(gosnd);
+               return ret;
+       }
+
+       gosnd->substream = NULL;
+       go->snd_context = gosnd;
+       ++dev;
+       ++go->ref_count;
+
+       return 0;
+}
+EXPORT_SYMBOL(go7007_snd_init);
+
+int go7007_snd_remove(struct go7007 *go)
+{
+       struct go7007_snd *gosnd = go->snd_context;
+
+       snd_card_disconnect(gosnd->card);
+       snd_card_free_when_closed(gosnd->card);
+       return 0;
+}
+EXPORT_SYMBOL(go7007_snd_remove);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/wis-i2c.h b/drivers/staging/media/go7007/wis-i2c.h
new file mode 100644 (file)
index 0000000..3c2b9be
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+/* Temporary I2C IDs -- these need to be replaced with real registered IDs */
+#define        I2C_DRIVERID_WIS_SAA7115        0xf0f0
+#define        I2C_DRIVERID_WIS_UDA1342        0xf0f1
+#define        I2C_DRIVERID_WIS_SONY_TUNER     0xf0f2
+#define        I2C_DRIVERID_WIS_TW9903         0xf0f3
+#define        I2C_DRIVERID_WIS_SAA7113        0xf0f4
+#define        I2C_DRIVERID_WIS_OV7640         0xf0f5
+#define        I2C_DRIVERID_WIS_TW2804         0xf0f6
+#define        I2C_DRIVERID_S2250              0xf0f7
+
+/* Flag to indicate that the client needs to be accessed with SCCB semantics */
+/* We re-use the I2C_M_TEN value so the flag passes through the masks in the
+ * core I2C code.  Major kludge, but the I2C layer ain't exactly flexible. */
+#define        I2C_CLIENT_SCCB                 0x10
+
+/* Definitions for new video decoder commands */
+
+struct video_decoder_resolution {
+       unsigned int width;
+       unsigned int height;
+};
+
+#define        DECODER_SET_RESOLUTION  _IOW('d', 200, struct video_decoder_resolution)
+#define        DECODER_SET_CHANNEL     _IOW('d', 201, int)
+
+/* Sony tuner types */
+
+#define TUNER_SONY_BTF_PG472Z          200
+#define TUNER_SONY_BTF_PK467Z          201
+#define TUNER_SONY_BTF_PB463Z          202
diff --git a/drivers/staging/media/go7007/wis-ov7640.c b/drivers/staging/media/go7007/wis-ov7640.c
new file mode 100644 (file)
index 0000000..6bc9470
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+
+#include "wis-i2c.h"
+
+struct wis_ov7640 {
+       int brightness;
+       int contrast;
+       int saturation;
+       int hue;
+};
+
+static u8 initial_registers[] =
+{
+       0x12, 0x80,
+       0x12, 0x54,
+       0x14, 0x24,
+       0x15, 0x01,
+       0x28, 0x20,
+       0x75, 0x82,
+       0xFF, 0xFF, /* Terminator (reg 0xFF is unused) */
+};
+
+static int write_regs(struct i2c_client *client, u8 *regs)
+{
+       int i;
+
+       for (i = 0; regs[i] != 0xFF; i += 2)
+               if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
+                       return -1;
+       return 0;
+}
+
+static int wis_ov7640_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = client->adapter;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       client->flags = I2C_CLIENT_SCCB;
+
+       printk(KERN_DEBUG
+               "wis-ov7640: initializing OV7640 at address %d on %s\n",
+               client->addr, adapter->name);
+
+       if (write_regs(client, initial_registers) < 0) {
+               printk(KERN_ERR "wis-ov7640: error initializing OV7640\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int wis_ov7640_remove(struct i2c_client *client)
+{
+       return 0;
+}
+
+static const struct i2c_device_id wis_ov7640_id[] = {
+       { "wis_ov7640", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wis_ov7640_id);
+
+static struct i2c_driver wis_ov7640_driver = {
+       .driver = {
+               .name   = "WIS OV7640 I2C driver",
+       },
+       .probe          = wis_ov7640_probe,
+       .remove         = wis_ov7640_remove,
+       .id_table       = wis_ov7640_id,
+};
+
+static int __init wis_ov7640_init(void)
+{
+       return i2c_add_driver(&wis_ov7640_driver);
+}
+
+static void __exit wis_ov7640_cleanup(void)
+{
+       i2c_del_driver(&wis_ov7640_driver);
+}
+
+module_init(wis_ov7640_init);
+module_exit(wis_ov7640_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/wis-saa7113.c b/drivers/staging/media/go7007/wis-saa7113.c
new file mode 100644 (file)
index 0000000..05e0e10
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+
+#include "wis-i2c.h"
+
+struct wis_saa7113 {
+       int norm;
+       int brightness;
+       int contrast;
+       int saturation;
+       int hue;
+};
+
+static u8 initial_registers[] =
+{
+       0x01, 0x08,
+       0x02, 0xc0,
+       0x03, 0x33,
+       0x04, 0x00,
+       0x05, 0x00,
+       0x06, 0xe9,
+       0x07, 0x0d,
+       0x08, 0xd8,
+       0x09, 0x40,
+       0x0a, 0x80,
+       0x0b, 0x47,
+       0x0c, 0x40,
+       0x0d, 0x00,
+       0x0e, 0x01,
+       0x0f, 0x2a,
+       0x10, 0x40,
+       0x11, 0x0c,
+       0x12, 0xfe,
+       0x13, 0x00,
+       0x14, 0x00,
+       0x15, 0x04,
+       0x16, 0x00,
+       0x17, 0x00,
+       0x18, 0x00,
+       0x19, 0x00,
+       0x1a, 0x00,
+       0x1b, 0x00,
+       0x1c, 0x00,
+       0x1d, 0x00,
+       0x1e, 0x00,
+       0x1f, 0xc8,
+       0x40, 0x00,
+       0x41, 0xff,
+       0x42, 0xff,
+       0x43, 0xff,
+       0x44, 0xff,
+       0x45, 0xff,
+       0x46, 0xff,
+       0x47, 0xff,
+       0x48, 0xff,
+       0x49, 0xff,
+       0x4a, 0xff,
+       0x4b, 0xff,
+       0x4c, 0xff,
+       0x4d, 0xff,
+       0x4e, 0xff,
+       0x4f, 0xff,
+       0x50, 0xff,
+       0x51, 0xff,
+       0x52, 0xff,
+       0x53, 0xff,
+       0x54, 0xff,
+       0x55, 0xff,
+       0x56, 0xff,
+       0x57, 0xff,
+       0x58, 0x00,
+       0x59, 0x54,
+       0x5a, 0x07,
+       0x5b, 0x83,
+       0x5c, 0x00,
+       0x5d, 0x00,
+       0x5e, 0x00,
+       0x5f, 0x00,
+       0x60, 0x00,
+       0x61, 0x00,
+       0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
+};
+
+static int write_reg(struct i2c_client *client, u8 reg, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int write_regs(struct i2c_client *client, u8 *regs)
+{
+       int i;
+
+       for (i = 0; regs[i] != 0x00; i += 2)
+               if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
+                       return -1;
+       return 0;
+}
+
+static int wis_saa7113_command(struct i2c_client *client,
+                               unsigned int cmd, void *arg)
+{
+       struct wis_saa7113 *dec = i2c_get_clientdata(client);
+
+       switch (cmd) {
+       case VIDIOC_S_INPUT:
+       {
+               int *input = arg;
+
+               i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input);
+               i2c_smbus_write_byte_data(client, 0x09,
+                               *input < 6 ? 0x40 : 0x80);
+               break;
+       }
+       case VIDIOC_S_STD:
+       {
+               v4l2_std_id *input = arg;
+               dec->norm = *input;
+               if (dec->norm & V4L2_STD_NTSC) {
+                       write_reg(client, 0x0e, 0x01);
+                       write_reg(client, 0x10, 0x40);
+               } else if (dec->norm & V4L2_STD_PAL) {
+                       write_reg(client, 0x0e, 0x01);
+                       write_reg(client, 0x10, 0x48);
+               } else if (dec->norm * V4L2_STD_SECAM) {
+                       write_reg(client, 0x0e, 0x50);
+                       write_reg(client, 0x10, 0x48);
+               }
+               break;
+       }
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *ctrl = arg;
+
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
+                       ctrl->minimum = 0;
+                       ctrl->maximum = 255;
+                       ctrl->step = 1;
+                       ctrl->default_value = 128;
+                       ctrl->flags = 0;
+                       break;
+               case V4L2_CID_CONTRAST:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
+                       ctrl->minimum = 0;
+                       ctrl->maximum = 127;
+                       ctrl->step = 1;
+                       ctrl->default_value = 71;
+                       ctrl->flags = 0;
+                       break;
+               case V4L2_CID_SATURATION:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
+                       ctrl->minimum = 0;
+                       ctrl->maximum = 127;
+                       ctrl->step = 1;
+                       ctrl->default_value = 64;
+                       ctrl->flags = 0;
+                       break;
+               case V4L2_CID_HUE:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
+                       ctrl->minimum = -128;
+                       ctrl->maximum = 127;
+                       ctrl->step = 1;
+                       ctrl->default_value = 0;
+                       ctrl->flags = 0;
+                       break;
+               }
+               break;
+       }
+       case VIDIOC_S_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       if (ctrl->value > 255)
+                               dec->brightness = 255;
+                       else if (ctrl->value < 0)
+                               dec->brightness = 0;
+                       else
+                               dec->brightness = ctrl->value;
+                       write_reg(client, 0x0a, dec->brightness);
+                       break;
+               case V4L2_CID_CONTRAST:
+                       if (ctrl->value > 127)
+                               dec->contrast = 127;
+                       else if (ctrl->value < 0)
+                               dec->contrast = 0;
+                       else
+                               dec->contrast = ctrl->value;
+                       write_reg(client, 0x0b, dec->contrast);
+                       break;
+               case V4L2_CID_SATURATION:
+                       if (ctrl->value > 127)
+                               dec->saturation = 127;
+                       else if (ctrl->value < 0)
+                               dec->saturation = 0;
+                       else
+                               dec->saturation = ctrl->value;
+                       write_reg(client, 0x0c, dec->saturation);
+                       break;
+               case V4L2_CID_HUE:
+                       if (ctrl->value > 127)
+                               dec->hue = 127;
+                       else if (ctrl->value < -128)
+                               dec->hue = -128;
+                       else
+                               dec->hue = ctrl->value;
+                       write_reg(client, 0x0d, dec->hue);
+                       break;
+               }
+               break;
+       }
+       case VIDIOC_G_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       ctrl->value = dec->brightness;
+                       break;
+               case V4L2_CID_CONTRAST:
+                       ctrl->value = dec->contrast;
+                       break;
+               case V4L2_CID_SATURATION:
+                       ctrl->value = dec->saturation;
+                       break;
+               case V4L2_CID_HUE:
+                       ctrl->value = dec->hue;
+                       break;
+               }
+               break;
+       }
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int wis_saa7113_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       struct wis_saa7113 *dec;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       dec = kmalloc(sizeof(struct wis_saa7113), GFP_KERNEL);
+       if (dec == NULL)
+               return -ENOMEM;
+
+       dec->norm = V4L2_STD_NTSC;
+       dec->brightness = 128;
+       dec->contrast = 71;
+       dec->saturation = 64;
+       dec->hue = 0;
+       i2c_set_clientdata(client, dec);
+
+       printk(KERN_DEBUG
+               "wis-saa7113: initializing SAA7113 at address %d on %s\n",
+               client->addr, adapter->name);
+
+       if (write_regs(client, initial_registers) < 0) {
+               printk(KERN_ERR
+                       "wis-saa7113: error initializing SAA7113\n");
+               kfree(dec);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int wis_saa7113_remove(struct i2c_client *client)
+{
+       struct wis_saa7113 *dec = i2c_get_clientdata(client);
+
+       kfree(dec);
+       return 0;
+}
+
+static const struct i2c_device_id wis_saa7113_id[] = {
+       { "wis_saa7113", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wis_saa7113_id);
+
+static struct i2c_driver wis_saa7113_driver = {
+       .driver = {
+               .name   = "WIS SAA7113 I2C driver",
+       },
+       .probe          = wis_saa7113_probe,
+       .remove         = wis_saa7113_remove,
+       .command        = wis_saa7113_command,
+       .id_table       = wis_saa7113_id,
+};
+
+static int __init wis_saa7113_init(void)
+{
+       return i2c_add_driver(&wis_saa7113_driver);
+}
+
+static void __exit wis_saa7113_cleanup(void)
+{
+       i2c_del_driver(&wis_saa7113_driver);
+}
+
+module_init(wis_saa7113_init);
+module_exit(wis_saa7113_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/wis-saa7115.c b/drivers/staging/media/go7007/wis-saa7115.c
new file mode 100644 (file)
index 0000000..46cff59
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+
+#include "wis-i2c.h"
+
+struct wis_saa7115 {
+       int norm;
+       int brightness;
+       int contrast;
+       int saturation;
+       int hue;
+};
+
+static u8 initial_registers[] =
+{
+       0x01, 0x08,
+       0x02, 0xc0,
+       0x03, 0x20,
+       0x04, 0x80,
+       0x05, 0x80,
+       0x06, 0xeb,
+       0x07, 0xe0,
+       0x08, 0xf0,     /* always toggle FID */
+       0x09, 0x40,
+       0x0a, 0x80,
+       0x0b, 0x40,
+       0x0c, 0x40,
+       0x0d, 0x00,
+       0x0e, 0x03,
+       0x0f, 0x2a,
+       0x10, 0x0e,
+       0x11, 0x00,
+       0x12, 0x8d,
+       0x13, 0x00,
+       0x14, 0x00,
+       0x15, 0x11,
+       0x16, 0x01,
+       0x17, 0xda,
+       0x18, 0x40,
+       0x19, 0x80,
+       0x1a, 0x00,
+       0x1b, 0x42,
+       0x1c, 0xa9,
+       0x30, 0x66,
+       0x31, 0x90,
+       0x32, 0x01,
+       0x34, 0x00,
+       0x35, 0x00,
+       0x36, 0x20,
+       0x38, 0x03,
+       0x39, 0x20,
+       0x3a, 0x88,
+       0x40, 0x00,
+       0x41, 0xff,
+       0x42, 0xff,
+       0x43, 0xff,
+       0x44, 0xff,
+       0x45, 0xff,
+       0x46, 0xff,
+       0x47, 0xff,
+       0x48, 0xff,
+       0x49, 0xff,
+       0x4a, 0xff,
+       0x4b, 0xff,
+       0x4c, 0xff,
+       0x4d, 0xff,
+       0x4e, 0xff,
+       0x4f, 0xff,
+       0x50, 0xff,
+       0x51, 0xff,
+       0x52, 0xff,
+       0x53, 0xff,
+       0x54, 0xf4 /*0xff*/,
+       0x55, 0xff,
+       0x56, 0xff,
+       0x57, 0xff,
+       0x58, 0x40,
+       0x59, 0x47,
+       0x5a, 0x06 /*0x03*/,
+       0x5b, 0x83,
+       0x5d, 0x06,
+       0x5e, 0x00,
+       0x80, 0x30, /* window defined scaler operation, task A and B enabled */
+       0x81, 0x03, /* use scaler datapath generated V */
+       0x83, 0x00,
+       0x84, 0x00,
+       0x85, 0x00,
+       0x86, 0x45,
+       0x87, 0x31,
+       0x88, 0xc0,
+       0x90, 0x02, /* task A process top field */
+       0x91, 0x08,
+       0x92, 0x09,
+       0x93, 0x80,
+       0x94, 0x06,
+       0x95, 0x00,
+       0x96, 0xc0,
+       0x97, 0x02,
+       0x98, 0x12,
+       0x99, 0x00,
+       0x9a, 0xf2,
+       0x9b, 0x00,
+       0x9c, 0xd0,
+       0x9d, 0x02,
+       0x9e, 0xf2,
+       0x9f, 0x00,
+       0xa0, 0x01,
+       0xa1, 0x01,
+       0xa2, 0x01,
+       0xa4, 0x80,
+       0xa5, 0x40,
+       0xa6, 0x40,
+       0xa8, 0x00,
+       0xa9, 0x04,
+       0xaa, 0x00,
+       0xac, 0x00,
+       0xad, 0x02,
+       0xae, 0x00,
+       0xb0, 0x00,
+       0xb1, 0x04,
+       0xb2, 0x00,
+       0xb3, 0x04,
+       0xb4, 0x00,
+       0xb8, 0x00,
+       0xbc, 0x00,
+       0xc0, 0x03,     /* task B process bottom field */
+       0xc1, 0x08,
+       0xc2, 0x09,
+       0xc3, 0x80,
+       0xc4, 0x06,
+       0xc5, 0x00,
+       0xc6, 0xc0,
+       0xc7, 0x02,
+       0xc8, 0x12,
+       0xc9, 0x00,
+       0xca, 0xf2,
+       0xcb, 0x00,
+       0xcc, 0xd0,
+       0xcd, 0x02,
+       0xce, 0xf2,
+       0xcf, 0x00,
+       0xd0, 0x01,
+       0xd1, 0x01,
+       0xd2, 0x01,
+       0xd4, 0x80,
+       0xd5, 0x40,
+       0xd6, 0x40,
+       0xd8, 0x00,
+       0xd9, 0x04,
+       0xda, 0x00,
+       0xdc, 0x00,
+       0xdd, 0x02,
+       0xde, 0x00,
+       0xe0, 0x00,
+       0xe1, 0x04,
+       0xe2, 0x00,
+       0xe3, 0x04,
+       0xe4, 0x00,
+       0xe8, 0x00,
+       0x88, 0xf0, /* End of original static list */
+       0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
+};
+
+static int write_reg(struct i2c_client *client, u8 reg, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int write_regs(struct i2c_client *client, u8 *regs)
+{
+       int i;
+
+       for (i = 0; regs[i] != 0x00; i += 2)
+               if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
+                       return -1;
+       return 0;
+}
+
+static int wis_saa7115_command(struct i2c_client *client,
+                               unsigned int cmd, void *arg)
+{
+       struct wis_saa7115 *dec = i2c_get_clientdata(client);
+
+       switch (cmd) {
+       case VIDIOC_S_INPUT:
+       {
+               int *input = arg;
+
+               i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input);
+               i2c_smbus_write_byte_data(client, 0x09,
+                               *input < 6 ? 0x40 : 0xC0);
+               break;
+       }
+       case DECODER_SET_RESOLUTION:
+       {
+               struct video_decoder_resolution *res = arg;
+               /* Course-grained scaler */
+               int h_integer_scaler = res->width < 704 ? 704 / res->width : 1;
+               /* Fine-grained scaler to take care of remainder */
+               int h_scaling_increment = (704 / h_integer_scaler) *
+                                       1024 / res->width;
+               /* Fine-grained scaler only */
+               int v_scaling_increment = (dec->norm & V4L2_STD_NTSC ?
+                               240 : 288) * 1024 / res->height;
+               u8 regs[] = {
+                       0x88,   0xc0,
+                       0x9c,   res->width & 0xff,
+                       0x9d,   res->width >> 8,
+                       0x9e,   res->height & 0xff,
+                       0x9f,   res->height >> 8,
+                       0xa0,   h_integer_scaler,
+                       0xa1,   1,
+                       0xa2,   1,
+                       0xa8,   h_scaling_increment & 0xff,
+                       0xa9,   h_scaling_increment >> 8,
+                       0xac,   (h_scaling_increment / 2) & 0xff,
+                       0xad,   (h_scaling_increment / 2) >> 8,
+                       0xb0,   v_scaling_increment & 0xff,
+                       0xb1,   v_scaling_increment >> 8,
+                       0xb2,   v_scaling_increment & 0xff,
+                       0xb3,   v_scaling_increment >> 8,
+                       0xcc,   res->width & 0xff,
+                       0xcd,   res->width >> 8,
+                       0xce,   res->height & 0xff,
+                       0xcf,   res->height >> 8,
+                       0xd0,   h_integer_scaler,
+                       0xd1,   1,
+                       0xd2,   1,
+                       0xd8,   h_scaling_increment & 0xff,
+                       0xd9,   h_scaling_increment >> 8,
+                       0xdc,   (h_scaling_increment / 2) & 0xff,
+                       0xdd,   (h_scaling_increment / 2) >> 8,
+                       0xe0,   v_scaling_increment & 0xff,
+                       0xe1,   v_scaling_increment >> 8,
+                       0xe2,   v_scaling_increment & 0xff,
+                       0xe3,   v_scaling_increment >> 8,
+                       0x88,   0xf0,
+                       0,      0,
+               };
+               write_regs(client, regs);
+               break;
+       }
+       case VIDIOC_S_STD:
+       {
+               v4l2_std_id *input = arg;
+               u8 regs[] = {
+                       0x88,   0xc0,
+                       0x98,   *input & V4L2_STD_NTSC ? 0x12 : 0x16,
+                       0x9a,   *input & V4L2_STD_NTSC ? 0xf2 : 0x20,
+                       0x9b,   *input & V4L2_STD_NTSC ? 0x00 : 0x01,
+                       0xc8,   *input & V4L2_STD_NTSC ? 0x12 : 0x16,
+                       0xca,   *input & V4L2_STD_NTSC ? 0xf2 : 0x20,
+                       0xcb,   *input & V4L2_STD_NTSC ? 0x00 : 0x01,
+                       0x88,   0xf0,
+                       0x30,   *input & V4L2_STD_NTSC ? 0x66 : 0x00,
+                       0x31,   *input & V4L2_STD_NTSC ? 0x90 : 0xe0,
+                       0,      0,
+               };
+               write_regs(client, regs);
+               dec->norm = *input;
+               break;
+       }
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *ctrl = arg;
+
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
+                       ctrl->minimum = 0;
+                       ctrl->maximum = 255;
+                       ctrl->step = 1;
+                       ctrl->default_value = 128;
+                       ctrl->flags = 0;
+                       break;
+               case V4L2_CID_CONTRAST:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
+                       ctrl->minimum = 0;
+                       ctrl->maximum = 127;
+                       ctrl->step = 1;
+                       ctrl->default_value = 64;
+                       ctrl->flags = 0;
+                       break;
+               case V4L2_CID_SATURATION:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
+                       ctrl->minimum = 0;
+                       ctrl->maximum = 127;
+                       ctrl->step = 1;
+                       ctrl->default_value = 64;
+                       ctrl->flags = 0;
+                       break;
+               case V4L2_CID_HUE:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
+                       ctrl->minimum = -128;
+                       ctrl->maximum = 127;
+                       ctrl->step = 1;
+                       ctrl->default_value = 0;
+                       ctrl->flags = 0;
+                       break;
+               }
+               break;
+       }
+       case VIDIOC_S_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       if (ctrl->value > 255)
+                               dec->brightness = 255;
+                       else if (ctrl->value < 0)
+                               dec->brightness = 0;
+                       else
+                               dec->brightness = ctrl->value;
+                       write_reg(client, 0x0a, dec->brightness);
+                       break;
+               case V4L2_CID_CONTRAST:
+                       if (ctrl->value > 127)
+                               dec->contrast = 127;
+                       else if (ctrl->value < 0)
+                               dec->contrast = 0;
+                       else
+                               dec->contrast = ctrl->value;
+                       write_reg(client, 0x0b, dec->contrast);
+                       break;
+               case V4L2_CID_SATURATION:
+                       if (ctrl->value > 127)
+                               dec->saturation = 127;
+                       else if (ctrl->value < 0)
+                               dec->saturation = 0;
+                       else
+                               dec->saturation = ctrl->value;
+                       write_reg(client, 0x0c, dec->saturation);
+                       break;
+               case V4L2_CID_HUE:
+                       if (ctrl->value > 127)
+                               dec->hue = 127;
+                       else if (ctrl->value < -128)
+                               dec->hue = -128;
+                       else
+                               dec->hue = ctrl->value;
+                       write_reg(client, 0x0d, dec->hue);
+                       break;
+               }
+               break;
+       }
+       case VIDIOC_G_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       ctrl->value = dec->brightness;
+                       break;
+               case V4L2_CID_CONTRAST:
+                       ctrl->value = dec->contrast;
+                       break;
+               case V4L2_CID_SATURATION:
+                       ctrl->value = dec->saturation;
+                       break;
+               case V4L2_CID_HUE:
+                       ctrl->value = dec->hue;
+                       break;
+               }
+               break;
+       }
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int wis_saa7115_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       struct wis_saa7115 *dec;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       dec = kmalloc(sizeof(struct wis_saa7115), GFP_KERNEL);
+       if (dec == NULL)
+               return -ENOMEM;
+
+       dec->norm = V4L2_STD_NTSC;
+       dec->brightness = 128;
+       dec->contrast = 64;
+       dec->saturation = 64;
+       dec->hue = 0;
+       i2c_set_clientdata(client, dec);
+
+       printk(KERN_DEBUG
+               "wis-saa7115: initializing SAA7115 at address %d on %s\n",
+               client->addr, adapter->name);
+
+       if (write_regs(client, initial_registers) < 0) {
+               printk(KERN_ERR
+                       "wis-saa7115: error initializing SAA7115\n");
+               kfree(dec);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int wis_saa7115_remove(struct i2c_client *client)
+{
+       struct wis_saa7115 *dec = i2c_get_clientdata(client);
+
+       kfree(dec);
+       return 0;
+}
+
+static const struct i2c_device_id wis_saa7115_id[] = {
+       { "wis_saa7115", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wis_saa7115_id);
+
+static struct i2c_driver wis_saa7115_driver = {
+       .driver = {
+               .name   = "WIS SAA7115 I2C driver",
+       },
+       .probe          = wis_saa7115_probe,
+       .remove         = wis_saa7115_remove,
+       .command        = wis_saa7115_command,
+       .id_table       = wis_saa7115_id,
+};
+
+static int __init wis_saa7115_init(void)
+{
+       return i2c_add_driver(&wis_saa7115_driver);
+}
+
+static void __exit wis_saa7115_cleanup(void)
+{
+       i2c_del_driver(&wis_saa7115_driver);
+}
+
+module_init(wis_saa7115_init);
+module_exit(wis_saa7115_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/wis-sony-tuner.c b/drivers/staging/media/go7007/wis-sony-tuner.c
new file mode 100644 (file)
index 0000000..8f1b7d4
--- /dev/null
@@ -0,0 +1,720 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <media/tuner.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+#include "wis-i2c.h"
+
+/* #define MPX_DEBUG */
+
+/* AS(IF/MPX) pin:      LOW      HIGH/OPEN
+ * IF/MPX address:   0x42/0x40   0x43/0x44
+ */
+#define IF_I2C_ADDR    0x43
+#define MPX_I2C_ADDR   0x44
+
+static v4l2_std_id force_band;
+static char force_band_str[] = "-";
+module_param_string(force_band, force_band_str, sizeof(force_band_str), 0644);
+static int force_mpx_mode = -1;
+module_param(force_mpx_mode, int, 0644);
+
+/* Store tuner info in the same format as tuner.c, so maybe we can put the
+ * Sony tuner support in there. */
+struct sony_tunertype {
+       char *name;
+       unsigned char Vendor; /* unused here */
+       unsigned char Type; /* unused here */
+
+       unsigned short thresh1; /*  band switch VHF_LO <=> VHF_HI */
+       unsigned short thresh2; /*  band switch VHF_HI <=> UHF */
+       unsigned char VHF_L;
+       unsigned char VHF_H;
+       unsigned char UHF;
+       unsigned char config;
+       unsigned short IFPCoff;
+};
+
+/* This array is indexed by (tuner_type - 200) */
+static struct sony_tunertype sony_tuners[] = {
+       { "Sony PAL+SECAM (BTF-PG472Z)", 0, 0,
+         16*144.25, 16*427.25, 0x01, 0x02, 0x04, 0xc6, 623},
+       { "Sony NTSC_JP (BTF-PK467Z)", 0, 0,
+         16*220.25, 16*467.25, 0x01, 0x02, 0x04, 0xc6, 940},
+       { "Sony NTSC (BTF-PB463Z)", 0, 0,
+         16*130.25, 16*364.25, 0x01, 0x02, 0x04, 0xc6, 732},
+};
+
+struct wis_sony_tuner {
+       int type;
+       v4l2_std_id std;
+       unsigned int freq;
+       int mpxmode;
+       u32 audmode;
+};
+
+/* Basically the same as default_set_tv_freq() in tuner.c */
+static int set_freq(struct i2c_client *client, int freq)
+{
+       struct wis_sony_tuner *t = i2c_get_clientdata(client);
+       char *band_name;
+       int n;
+       int band_select;
+       struct sony_tunertype *tun;
+       u8 buffer[4];
+
+       tun = &sony_tuners[t->type - 200];
+       if (freq < tun->thresh1) {
+               band_name = "VHF_L";
+               band_select = tun->VHF_L;
+       } else if (freq < tun->thresh2) {
+               band_name = "VHF_H";
+               band_select = tun->VHF_H;
+       } else {
+               band_name = "UHF";
+               band_select = tun->UHF;
+       }
+       printk(KERN_DEBUG "wis-sony-tuner: tuning to frequency %d.%04d (%s)\n",
+                       freq / 16, (freq % 16) * 625, band_name);
+       n = freq + tun->IFPCoff;
+
+       buffer[0] = n >> 8;
+       buffer[1] = n & 0xff;
+       buffer[2] = tun->config;
+       buffer[3] = band_select;
+       i2c_master_send(client, buffer, 4);
+
+       return 0;
+}
+
+static int mpx_write(struct i2c_client *client, int dev, int addr, int val)
+{
+       u8 buffer[5];
+       struct i2c_msg msg;
+
+       buffer[0] = dev;
+       buffer[1] = addr >> 8;
+       buffer[2] = addr & 0xff;
+       buffer[3] = val >> 8;
+       buffer[4] = val & 0xff;
+       msg.addr = MPX_I2C_ADDR;
+       msg.flags = 0;
+       msg.len = 5;
+       msg.buf = buffer;
+       i2c_transfer(client->adapter, &msg, 1);
+       return 0;
+}
+
+/*
+ * MPX register values for the BTF-PG472Z:
+ *
+ *                                 FM_     NICAM_  SCART_
+ *          MODUS  SOURCE    ACB   PRESCAL PRESCAL PRESCAL SYSTEM  VOLUME
+ *         10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000
+ *         ---------------------------------------------------------------
+ * Auto     1003    0020    0100    2603    5000    XXXX    0001    7500
+ *
+ * B/G
+ *  Mono    1003    0020    0100    2603    5000    XXXX    0003    7500
+ *  A2      1003    0020    0100    2601    5000    XXXX    0003    7500
+ *  NICAM   1003    0120    0100    2603    5000    XXXX    0008    7500
+ *
+ * I
+ *  Mono    1003    0020    0100    2603    7900    XXXX    000A    7500
+ *  NICAM   1003    0120    0100    2603    7900    XXXX    000A    7500
+ *
+ * D/K
+ *  Mono    1003    0020    0100    2603    5000    XXXX    0004    7500
+ *  A2-1    1003    0020    0100    2601    5000    XXXX    0004    7500
+ *  A2-2    1003    0020    0100    2601    5000    XXXX    0005    7500
+ *  A2-3    1003    0020    0100    2601    5000    XXXX    0007    7500
+ *  NICAM   1003    0120    0100    2603    5000    XXXX    000B    7500
+ *
+ * L/L'
+ *  Mono    0003    0200    0100    7C03    5000    2200    0009    7500
+ *  NICAM   0003    0120    0100    7C03    5000    XXXX    0009    7500
+ *
+ * M
+ *  Mono    1003    0200    0100    2B03    5000    2B00    0002    7500
+ *
+ * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX.
+ *
+ * Bilingual selection in A2/NICAM:
+ *
+ *         High byte of SOURCE     Left chan   Right chan
+ *                 0x01              MAIN         SUB
+ *                 0x03              MAIN         MAIN
+ *                 0x04              SUB          SUB
+ *
+ * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or
+ * 0x00 (all other bands).  Force mono in A2 with FMONO_A2:
+ *
+ *                      FMONO_A2
+ *                      10/0022
+ *                      --------
+ *     Forced mono ON     07F0
+ *     Forced mono OFF    0190
+ */
+
+static struct {
+       enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode;
+       u16 modus;
+       u16 source;
+       u16 acb;
+       u16 fm_prescale;
+       u16 nicam_prescale;
+       u16 scart_prescale;
+       u16 system;
+       u16 volume;
+} mpx_audio_modes[] = {
+       /* Auto */      { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
+                                       0x5000, 0x0000, 0x0001, 0x7500 },
+       /* B/G Mono */  { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
+                                       0x5000, 0x0000, 0x0003, 0x7500 },
+       /* B/G A2 */    { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
+                                       0x5000, 0x0000, 0x0003, 0x7500 },
+       /* B/G NICAM */ { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
+                                       0x5000, 0x0000, 0x0008, 0x7500 },
+       /* I Mono */    { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
+                                       0x7900, 0x0000, 0x000A, 0x7500 },
+       /* I NICAM */   { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
+                                       0x7900, 0x0000, 0x000A, 0x7500 },
+       /* D/K Mono */  { AUD_MONO,     0x1003, 0x0020, 0x0100, 0x2603,
+                                       0x5000, 0x0000, 0x0004, 0x7500 },
+       /* D/K A2-1 */  { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
+                                       0x5000, 0x0000, 0x0004, 0x7500 },
+       /* D/K A2-2 */  { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
+                                       0x5000, 0x0000, 0x0005, 0x7500 },
+       /* D/K A2-3 */  { AUD_A2,       0x1003, 0x0020, 0x0100, 0x2601,
+                                       0x5000, 0x0000, 0x0007, 0x7500 },
+       /* D/K NICAM */ { AUD_NICAM,    0x1003, 0x0120, 0x0100, 0x2603,
+                                       0x5000, 0x0000, 0x000B, 0x7500 },
+       /* L/L' Mono */ { AUD_MONO,     0x0003, 0x0200, 0x0100, 0x7C03,
+                                       0x5000, 0x2200, 0x0009, 0x7500 },
+       /* L/L' NICAM */{ AUD_NICAM_L,  0x0003, 0x0120, 0x0100, 0x7C03,
+                                       0x5000, 0x0000, 0x0009, 0x7500 },
+};
+
+#define MPX_NUM_MODES  ARRAY_SIZE(mpx_audio_modes)
+
+static int mpx_setup(struct i2c_client *client)
+{
+       struct wis_sony_tuner *t = i2c_get_clientdata(client);
+       u16 source = 0;
+       u8 buffer[3];
+       struct i2c_msg msg;
+
+       /* reset MPX */
+       buffer[0] = 0x00;
+       buffer[1] = 0x80;
+       buffer[2] = 0x00;
+       msg.addr = MPX_I2C_ADDR;
+       msg.flags = 0;
+       msg.len = 3;
+       msg.buf = buffer;
+       i2c_transfer(client->adapter, &msg, 1);
+       buffer[1] = 0x00;
+       i2c_transfer(client->adapter, &msg, 1);
+
+       if (mpx_audio_modes[t->mpxmode].audio_mode != AUD_MONO) {
+               switch (t->audmode) {
+               case V4L2_TUNER_MODE_MONO:
+                       switch (mpx_audio_modes[t->mpxmode].audio_mode) {
+                       case AUD_A2:
+                               source = mpx_audio_modes[t->mpxmode].source;
+                               break;
+                       case AUD_NICAM:
+                               source = 0x0000;
+                               break;
+                       case AUD_NICAM_L:
+                               source = 0x0200;
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+               case V4L2_TUNER_MODE_STEREO:
+                       source = mpx_audio_modes[t->mpxmode].source;
+                       break;
+               case V4L2_TUNER_MODE_LANG1:
+                       source = 0x0300;
+                       break;
+               case V4L2_TUNER_MODE_LANG2:
+                       source = 0x0400;
+                       break;
+               }
+               source |= mpx_audio_modes[t->mpxmode].source & 0x00ff;
+       } else
+               source = mpx_audio_modes[t->mpxmode].source;
+
+       mpx_write(client, 0x10, 0x0030, mpx_audio_modes[t->mpxmode].modus);
+       mpx_write(client, 0x12, 0x0008, source);
+       mpx_write(client, 0x12, 0x0013, mpx_audio_modes[t->mpxmode].acb);
+       mpx_write(client, 0x12, 0x000e,
+                       mpx_audio_modes[t->mpxmode].fm_prescale);
+       mpx_write(client, 0x12, 0x0010,
+                       mpx_audio_modes[t->mpxmode].nicam_prescale);
+       mpx_write(client, 0x12, 0x000d,
+                       mpx_audio_modes[t->mpxmode].scart_prescale);
+       mpx_write(client, 0x10, 0x0020, mpx_audio_modes[t->mpxmode].system);
+       mpx_write(client, 0x12, 0x0000, mpx_audio_modes[t->mpxmode].volume);
+       if (mpx_audio_modes[t->mpxmode].audio_mode == AUD_A2)
+               mpx_write(client, 0x10, 0x0022,
+                       t->audmode == V4L2_TUNER_MODE_MONO ?  0x07f0 : 0x0190);
+
+#ifdef MPX_DEBUG
+       {
+               u8 buf1[3], buf2[2];
+               struct i2c_msg msgs[2];
+
+               printk(KERN_DEBUG "wis-sony-tuner: MPX registers: %04x %04x "
+                               "%04x %04x %04x %04x %04x %04x\n",
+                               mpx_audio_modes[t->mpxmode].modus,
+                               source,
+                               mpx_audio_modes[t->mpxmode].acb,
+                               mpx_audio_modes[t->mpxmode].fm_prescale,
+                               mpx_audio_modes[t->mpxmode].nicam_prescale,
+                               mpx_audio_modes[t->mpxmode].scart_prescale,
+                               mpx_audio_modes[t->mpxmode].system,
+                               mpx_audio_modes[t->mpxmode].volume);
+               buf1[0] = 0x11;
+               buf1[1] = 0x00;
+               buf1[2] = 0x7e;
+               msgs[0].addr = MPX_I2C_ADDR;
+               msgs[0].flags = 0;
+               msgs[0].len = 3;
+               msgs[0].buf = buf1;
+               msgs[1].addr = MPX_I2C_ADDR;
+               msgs[1].flags = I2C_M_RD;
+               msgs[1].len = 2;
+               msgs[1].buf = buf2;
+               i2c_transfer(client->adapter, msgs, 2);
+               printk(KERN_DEBUG "wis-sony-tuner: MPX system: %02x%02x\n",
+                               buf2[0], buf2[1]);
+               buf1[0] = 0x11;
+               buf1[1] = 0x02;
+               buf1[2] = 0x00;
+               i2c_transfer(client->adapter, msgs, 2);
+               printk(KERN_DEBUG "wis-sony-tuner: MPX status: %02x%02x\n",
+                               buf2[0], buf2[1]);
+       }
+#endif
+       return 0;
+}
+
+/*
+ * IF configuration values for the BTF-PG472Z:
+ *
+ *     B/G: 0x94 0x70 0x49
+ *     I:   0x14 0x70 0x4a
+ *     D/K: 0x14 0x70 0x4b
+ *     L:   0x04 0x70 0x4b
+ *     L':  0x44 0x70 0x53
+ *     M:   0x50 0x30 0x4c
+ */
+
+static int set_if(struct i2c_client *client)
+{
+       struct wis_sony_tuner *t = i2c_get_clientdata(client);
+       u8 buffer[4];
+       struct i2c_msg msg;
+       int default_mpx_mode = 0;
+
+       /* configure IF */
+       buffer[0] = 0;
+       if (t->std & V4L2_STD_PAL_BG) {
+               buffer[1] = 0x94;
+               buffer[2] = 0x70;
+               buffer[3] = 0x49;
+               default_mpx_mode = 1;
+       } else if (t->std & V4L2_STD_PAL_I) {
+               buffer[1] = 0x14;
+               buffer[2] = 0x70;
+               buffer[3] = 0x4a;
+               default_mpx_mode = 4;
+       } else if (t->std & V4L2_STD_PAL_DK) {
+               buffer[1] = 0x14;
+               buffer[2] = 0x70;
+               buffer[3] = 0x4b;
+               default_mpx_mode = 6;
+       } else if (t->std & V4L2_STD_SECAM_L) {
+               buffer[1] = 0x04;
+               buffer[2] = 0x70;
+               buffer[3] = 0x4b;
+               default_mpx_mode = 11;
+       }
+       msg.addr = IF_I2C_ADDR;
+       msg.flags = 0;
+       msg.len = 4;
+       msg.buf = buffer;
+       i2c_transfer(client->adapter, &msg, 1);
+
+       /* Select MPX mode if not forced by the user */
+       if (force_mpx_mode >= 0 && force_mpx_mode < MPX_NUM_MODES)
+               t->mpxmode = force_mpx_mode;
+       else
+               t->mpxmode = default_mpx_mode;
+       printk(KERN_DEBUG "wis-sony-tuner: setting MPX to mode %d\n",
+                       t->mpxmode);
+       mpx_setup(client);
+
+       return 0;
+}
+
+static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+       struct wis_sony_tuner *t = i2c_get_clientdata(client);
+
+       switch (cmd) {
+#if 0
+#ifdef TUNER_SET_TYPE_ADDR
+       case TUNER_SET_TYPE_ADDR:
+       {
+               struct tuner_setup *tun_setup = arg;
+               int *type = &tun_setup->type;
+#else
+       case TUNER_SET_TYPE:
+       {
+               int *type = arg;
+#endif
+
+               if (t->type >= 0) {
+                       if (t->type != *type)
+                               printk(KERN_ERR "wis-sony-tuner: type already "
+                                       "set to %d, ignoring request for %d\n",
+                                       t->type, *type);
+                       break;
+               }
+               t->type = *type;
+               switch (t->type) {
+               case TUNER_SONY_BTF_PG472Z:
+                       switch (force_band_str[0]) {
+                       case 'b':
+                       case 'B':
+                       case 'g':
+                       case 'G':
+                               printk(KERN_INFO "wis-sony-tuner: forcing "
+                                               "tuner to PAL-B/G bands\n");
+                               force_band = V4L2_STD_PAL_BG;
+                               break;
+                       case 'i':
+                       case 'I':
+                               printk(KERN_INFO "wis-sony-tuner: forcing "
+                                               "tuner to PAL-I band\n");
+                               force_band = V4L2_STD_PAL_I;
+                               break;
+                       case 'd':
+                       case 'D':
+                       case 'k':
+                       case 'K':
+                               printk(KERN_INFO "wis-sony-tuner: forcing "
+                                               "tuner to PAL-D/K bands\n");
+                               force_band = V4L2_STD_PAL_I;
+                               break;
+                       case 'l':
+                       case 'L':
+                               printk(KERN_INFO "wis-sony-tuner: forcing "
+                                               "tuner to SECAM-L band\n");
+                               force_band = V4L2_STD_SECAM_L;
+                               break;
+                       default:
+                               force_band = 0;
+                               break;
+                       }
+                       if (force_band)
+                               t->std = force_band;
+                       else
+                               t->std = V4L2_STD_PAL_BG;
+                       set_if(client);
+                       break;
+               case TUNER_SONY_BTF_PK467Z:
+                       t->std = V4L2_STD_NTSC_M_JP;
+                       break;
+               case TUNER_SONY_BTF_PB463Z:
+                       t->std = V4L2_STD_NTSC_M;
+                       break;
+               default:
+                       printk(KERN_ERR "wis-sony-tuner: tuner type %d is not "
+                                       "supported by this module\n", *type);
+                       break;
+               }
+               if (type >= 0)
+                       printk(KERN_INFO
+                               "wis-sony-tuner: type set to %d (%s)\n",
+                               t->type, sony_tuners[t->type - 200].name);
+               break;
+       }
+#endif
+       case VIDIOC_G_FREQUENCY:
+       {
+               struct v4l2_frequency *f = arg;
+
+               f->frequency = t->freq;
+               break;
+       }
+       case VIDIOC_S_FREQUENCY:
+       {
+               struct v4l2_frequency *f = arg;
+
+               t->freq = f->frequency;
+               set_freq(client, t->freq);
+               break;
+       }
+       case VIDIOC_ENUMSTD:
+       {
+               struct v4l2_standard *std = arg;
+
+               switch (t->type) {
+               case TUNER_SONY_BTF_PG472Z:
+                       switch (std->index) {
+                       case 0:
+                               v4l2_video_std_construct(std,
+                                               V4L2_STD_PAL_BG, "PAL-B/G");
+                               break;
+                       case 1:
+                               v4l2_video_std_construct(std,
+                                               V4L2_STD_PAL_I, "PAL-I");
+                               break;
+                       case 2:
+                               v4l2_video_std_construct(std,
+                                               V4L2_STD_PAL_DK, "PAL-D/K");
+                               break;
+                       case 3:
+                               v4l2_video_std_construct(std,
+                                               V4L2_STD_SECAM_L, "SECAM-L");
+                               break;
+                       default:
+                               std->id = 0; /* hack to indicate EINVAL */
+                               break;
+                       }
+                       break;
+               case TUNER_SONY_BTF_PK467Z:
+                       if (std->index != 0) {
+                               std->id = 0; /* hack to indicate EINVAL */
+                               break;
+                       }
+                       v4l2_video_std_construct(std,
+                                       V4L2_STD_NTSC_M_JP, "NTSC-J");
+                       break;
+               case TUNER_SONY_BTF_PB463Z:
+                       if (std->index != 0) {
+                               std->id = 0; /* hack to indicate EINVAL */
+                               break;
+                       }
+                       v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC");
+                       break;
+               }
+               break;
+       }
+       case VIDIOC_G_STD:
+       {
+               v4l2_std_id *std = arg;
+
+               *std = t->std;
+               break;
+       }
+       case VIDIOC_S_STD:
+       {
+               v4l2_std_id *std = arg;
+               v4l2_std_id old = t->std;
+
+               switch (t->type) {
+               case TUNER_SONY_BTF_PG472Z:
+                       if (force_band && (*std & force_band) != *std &&
+                                       *std != V4L2_STD_PAL &&
+                                       *std != V4L2_STD_SECAM) {
+                               printk(KERN_DEBUG "wis-sony-tuner: ignoring "
+                                               "requested TV standard in "
+                                               "favor of force_band value\n");
+                               t->std = force_band;
+                       } else if (*std & V4L2_STD_PAL_BG) { /* default */
+                               t->std = V4L2_STD_PAL_BG;
+                       } else if (*std & V4L2_STD_PAL_I) {
+                               t->std = V4L2_STD_PAL_I;
+                       } else if (*std & V4L2_STD_PAL_DK) {
+                               t->std = V4L2_STD_PAL_DK;
+                       } else if (*std & V4L2_STD_SECAM_L) {
+                               t->std = V4L2_STD_SECAM_L;
+                       } else {
+                               printk(KERN_ERR "wis-sony-tuner: TV standard "
+                                               "not supported\n");
+                               *std = 0; /* hack to indicate EINVAL */
+                               break;
+                       }
+                       if (old != t->std)
+                               set_if(client);
+                       break;
+               case TUNER_SONY_BTF_PK467Z:
+                       if (!(*std & V4L2_STD_NTSC_M_JP)) {
+                               printk(KERN_ERR "wis-sony-tuner: TV standard "
+                                               "not supported\n");
+                               *std = 0; /* hack to indicate EINVAL */
+                       }
+                       break;
+               case TUNER_SONY_BTF_PB463Z:
+                       if (!(*std & V4L2_STD_NTSC_M)) {
+                               printk(KERN_ERR "wis-sony-tuner: TV standard "
+                                               "not supported\n");
+                               *std = 0; /* hack to indicate EINVAL */
+                       }
+                       break;
+               }
+               break;
+       }
+       case VIDIOC_QUERYSTD:
+       {
+               v4l2_std_id *std = arg;
+
+               switch (t->type) {
+               case TUNER_SONY_BTF_PG472Z:
+                       if (force_band)
+                               *std = force_band;
+                       else
+                               *std = V4L2_STD_PAL_BG | V4L2_STD_PAL_I |
+                                       V4L2_STD_PAL_DK | V4L2_STD_SECAM_L;
+                       break;
+               case TUNER_SONY_BTF_PK467Z:
+                       *std = V4L2_STD_NTSC_M_JP;
+                       break;
+               case TUNER_SONY_BTF_PB463Z:
+                       *std = V4L2_STD_NTSC_M;
+                       break;
+               }
+               break;
+       }
+       case VIDIOC_G_TUNER:
+       {
+               struct v4l2_tuner *tun = arg;
+
+               memset(tun, 0, sizeof(*tun));
+               strcpy(tun->name, "Television");
+               tun->type = V4L2_TUNER_ANALOG_TV;
+               tun->rangelow = 0UL; /* does anything use these? */
+               tun->rangehigh = 0xffffffffUL;
+               switch (t->type) {
+               case TUNER_SONY_BTF_PG472Z:
+                       tun->capability = V4L2_TUNER_CAP_NORM |
+                               V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+                               V4L2_TUNER_CAP_LANG2;
+                       tun->rxsubchans = V4L2_TUNER_SUB_MONO |
+                               V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 |
+                               V4L2_TUNER_SUB_LANG2;
+                       break;
+               case TUNER_SONY_BTF_PK467Z:
+               case TUNER_SONY_BTF_PB463Z:
+                       tun->capability = V4L2_TUNER_CAP_STEREO;
+                       tun->rxsubchans = V4L2_TUNER_SUB_MONO |
+                                               V4L2_TUNER_SUB_STEREO;
+                       break;
+               }
+               tun->audmode = t->audmode;
+               return 0;
+       }
+       case VIDIOC_S_TUNER:
+       {
+               struct v4l2_tuner *tun = arg;
+
+               switch (t->type) {
+               case TUNER_SONY_BTF_PG472Z:
+                       if (tun->audmode != t->audmode) {
+                               t->audmode = tun->audmode;
+                               mpx_setup(client);
+                       }
+                       break;
+               case TUNER_SONY_BTF_PK467Z:
+               case TUNER_SONY_BTF_PB463Z:
+                       break;
+               }
+               return 0;
+       }
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int wis_sony_tuner_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       struct wis_sony_tuner *t;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
+               return -ENODEV;
+
+       t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL);
+       if (t == NULL)
+               return -ENOMEM;
+
+       t->type = -1;
+       t->freq = 0;
+       t->mpxmode = 0;
+       t->audmode = V4L2_TUNER_MODE_STEREO;
+       i2c_set_clientdata(client, t);
+
+       printk(KERN_DEBUG
+               "wis-sony-tuner: initializing tuner at address %d on %s\n",
+               client->addr, adapter->name);
+
+       return 0;
+}
+
+static int wis_sony_tuner_remove(struct i2c_client *client)
+{
+       struct wis_sony_tuner *t = i2c_get_clientdata(client);
+
+       kfree(t);
+       return 0;
+}
+
+static const struct i2c_device_id wis_sony_tuner_id[] = {
+       { "wis_sony_tuner", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wis_sony_tuner_id);
+
+static struct i2c_driver wis_sony_tuner_driver = {
+       .driver = {
+               .name   = "WIS Sony TV Tuner I2C driver",
+       },
+       .probe          = wis_sony_tuner_probe,
+       .remove         = wis_sony_tuner_remove,
+       .command        = tuner_command,
+       .id_table       = wis_sony_tuner_id,
+};
+
+static int __init wis_sony_tuner_init(void)
+{
+       return i2c_add_driver(&wis_sony_tuner_driver);
+}
+
+static void __exit wis_sony_tuner_cleanup(void)
+{
+       i2c_del_driver(&wis_sony_tuner_driver);
+}
+
+module_init(wis_sony_tuner_init);
+module_exit(wis_sony_tuner_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/wis-tw2804.c b/drivers/staging/media/go7007/wis-tw2804.c
new file mode 100644 (file)
index 0000000..9134f03
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+
+#include "wis-i2c.h"
+
+struct wis_tw2804 {
+       int channel;
+       int norm;
+       int brightness;
+       int contrast;
+       int saturation;
+       int hue;
+};
+
+static u8 global_registers[] = {
+       0x39, 0x00,
+       0x3a, 0xff,
+       0x3b, 0x84,
+       0x3c, 0x80,
+       0x3d, 0x80,
+       0x3e, 0x82,
+       0x3f, 0x82,
+       0xff, 0xff, /* Terminator (reg 0xff does not exist) */
+};
+
+static u8 channel_registers[] = {
+       0x01, 0xc4,
+       0x02, 0xa5,
+       0x03, 0x20,
+       0x04, 0xd0,
+       0x05, 0x20,
+       0x06, 0xd0,
+       0x07, 0x88,
+       0x08, 0x20,
+       0x09, 0x07,
+       0x0a, 0xf0,
+       0x0b, 0x07,
+       0x0c, 0xf0,
+       0x0d, 0x40,
+       0x0e, 0xd2,
+       0x0f, 0x80,
+       0x10, 0x80,
+       0x11, 0x80,
+       0x12, 0x80,
+       0x13, 0x1f,
+       0x14, 0x00,
+       0x15, 0x00,
+       0x16, 0x00,
+       0x17, 0x00,
+       0x18, 0xff,
+       0x19, 0xff,
+       0x1a, 0xff,
+       0x1b, 0xff,
+       0x1c, 0xff,
+       0x1d, 0xff,
+       0x1e, 0xff,
+       0x1f, 0xff,
+       0x20, 0x07,
+       0x21, 0x07,
+       0x22, 0x00,
+       0x23, 0x91,
+       0x24, 0x51,
+       0x25, 0x03,
+       0x26, 0x00,
+       0x27, 0x00,
+       0x28, 0x00,
+       0x29, 0x00,
+       0x2a, 0x00,
+       0x2b, 0x00,
+       0x2c, 0x00,
+       0x2d, 0x00,
+       0x2e, 0x00,
+       0x2f, 0x00,
+       0x30, 0x00,
+       0x31, 0x00,
+       0x32, 0x00,
+       0x33, 0x00,
+       0x34, 0x00,
+       0x35, 0x00,
+       0x36, 0x00,
+       0x37, 0x00,
+       0xff, 0xff, /* Terminator (reg 0xff does not exist) */
+};
+
+static int write_reg(struct i2c_client *client, u8 reg, u8 value, int channel)
+{
+       return i2c_smbus_write_byte_data(client, reg | (channel << 6), value);
+}
+
+static int write_regs(struct i2c_client *client, u8 *regs, int channel)
+{
+       int i;
+
+       for (i = 0; regs[i] != 0xff; i += 2)
+               if (i2c_smbus_write_byte_data(client,
+                               regs[i] | (channel << 6), regs[i + 1]) < 0)
+                       return -1;
+       return 0;
+}
+
+static int wis_tw2804_command(struct i2c_client *client,
+                               unsigned int cmd, void *arg)
+{
+       struct wis_tw2804 *dec = i2c_get_clientdata(client);
+
+       if (cmd == DECODER_SET_CHANNEL) {
+               int *input = arg;
+
+               if (*input < 0 || *input > 3) {
+                       printk(KERN_ERR "wis-tw2804: channel %d is not "
+                                       "between 0 and 3!\n", *input);
+                       return 0;
+               }
+               dec->channel = *input;
+               printk(KERN_DEBUG "wis-tw2804: initializing TW2804 "
+                               "channel %d\n", dec->channel);
+               if (dec->channel == 0 &&
+                               write_regs(client, global_registers, 0) < 0) {
+                       printk(KERN_ERR "wis-tw2804: error initializing "
+                                       "TW2804 global registers\n");
+                       return 0;
+               }
+               if (write_regs(client, channel_registers, dec->channel) < 0) {
+                       printk(KERN_ERR "wis-tw2804: error initializing "
+                                       "TW2804 channel %d\n", dec->channel);
+                       return 0;
+               }
+               return 0;
+       }
+
+       if (dec->channel < 0) {
+               printk(KERN_DEBUG "wis-tw2804: ignoring command %08x until "
+                               "channel number is set\n", cmd);
+               return 0;
+       }
+
+       switch (cmd) {
+       case VIDIOC_S_STD:
+       {
+               v4l2_std_id *input = arg;
+               u8 regs[] = {
+                       0x01, *input & V4L2_STD_NTSC ? 0xc4 : 0x84,
+                       0x09, *input & V4L2_STD_NTSC ? 0x07 : 0x04,
+                       0x0a, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
+                       0x0b, *input & V4L2_STD_NTSC ? 0x07 : 0x04,
+                       0x0c, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
+                       0x0d, *input & V4L2_STD_NTSC ? 0x40 : 0x4a,
+                       0x16, *input & V4L2_STD_NTSC ? 0x00 : 0x40,
+                       0x17, *input & V4L2_STD_NTSC ? 0x00 : 0x40,
+                       0x20, *input & V4L2_STD_NTSC ? 0x07 : 0x0f,
+                       0x21, *input & V4L2_STD_NTSC ? 0x07 : 0x0f,
+                       0xff,   0xff,
+               };
+               write_regs(client, regs, dec->channel);
+               dec->norm = *input;
+               break;
+       }
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *ctrl = arg;
+
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
+                       ctrl->minimum = 0;
+                       ctrl->maximum = 255;
+                       ctrl->step = 1;
+                       ctrl->default_value = 128;
+                       ctrl->flags = 0;
+                       break;
+               case V4L2_CID_CONTRAST:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
+                       ctrl->minimum = 0;
+                       ctrl->maximum = 255;
+                       ctrl->step = 1;
+                       ctrl->default_value = 128;
+                       ctrl->flags = 0;
+                       break;
+               case V4L2_CID_SATURATION:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
+                       ctrl->minimum = 0;
+                       ctrl->maximum = 255;
+                       ctrl->step = 1;
+                       ctrl->default_value = 128;
+                       ctrl->flags = 0;
+                       break;
+               case V4L2_CID_HUE:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
+                       ctrl->minimum = 0;
+                       ctrl->maximum = 255;
+                       ctrl->step = 1;
+                       ctrl->default_value = 128;
+                       ctrl->flags = 0;
+                       break;
+               }
+               break;
+       }
+       case VIDIOC_S_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       if (ctrl->value > 255)
+                               dec->brightness = 255;
+                       else if (ctrl->value < 0)
+                               dec->brightness = 0;
+                       else
+                               dec->brightness = ctrl->value;
+                       write_reg(client, 0x12, dec->brightness, dec->channel);
+                       break;
+               case V4L2_CID_CONTRAST:
+                       if (ctrl->value > 255)
+                               dec->contrast = 255;
+                       else if (ctrl->value < 0)
+                               dec->contrast = 0;
+                       else
+                               dec->contrast = ctrl->value;
+                       write_reg(client, 0x11, dec->contrast, dec->channel);
+                       break;
+               case V4L2_CID_SATURATION:
+                       if (ctrl->value > 255)
+                               dec->saturation = 255;
+                       else if (ctrl->value < 0)
+                               dec->saturation = 0;
+                       else
+                               dec->saturation = ctrl->value;
+                       write_reg(client, 0x10, dec->saturation, dec->channel);
+                       break;
+               case V4L2_CID_HUE:
+                       if (ctrl->value > 255)
+                               dec->hue = 255;
+                       else if (ctrl->value < 0)
+                               dec->hue = 0;
+                       else
+                               dec->hue = ctrl->value;
+                       write_reg(client, 0x0f, dec->hue, dec->channel);
+                       break;
+               }
+               break;
+       }
+       case VIDIOC_G_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       ctrl->value = dec->brightness;
+                       break;
+               case V4L2_CID_CONTRAST:
+                       ctrl->value = dec->contrast;
+                       break;
+               case V4L2_CID_SATURATION:
+                       ctrl->value = dec->saturation;
+                       break;
+               case V4L2_CID_HUE:
+                       ctrl->value = dec->hue;
+                       break;
+               }
+               break;
+       }
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int wis_tw2804_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       struct wis_tw2804 *dec;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       dec = kmalloc(sizeof(struct wis_tw2804), GFP_KERNEL);
+       if (dec == NULL)
+               return -ENOMEM;
+
+       dec->channel = -1;
+       dec->norm = V4L2_STD_NTSC;
+       dec->brightness = 128;
+       dec->contrast = 128;
+       dec->saturation = 128;
+       dec->hue = 128;
+       i2c_set_clientdata(client, dec);
+
+       printk(KERN_DEBUG "wis-tw2804: creating TW2804 at address %d on %s\n",
+               client->addr, adapter->name);
+
+       return 0;
+}
+
+static int wis_tw2804_remove(struct i2c_client *client)
+{
+       struct wis_tw2804 *dec = i2c_get_clientdata(client);
+
+       kfree(dec);
+       return 0;
+}
+
+static const struct i2c_device_id wis_tw2804_id[] = {
+       { "wis_tw2804", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wis_tw2804_id);
+
+static struct i2c_driver wis_tw2804_driver = {
+       .driver = {
+               .name   = "WIS TW2804 I2C driver",
+       },
+       .probe          = wis_tw2804_probe,
+       .remove         = wis_tw2804_remove,
+       .command        = wis_tw2804_command,
+       .id_table       = wis_tw2804_id,
+};
+
+static int __init wis_tw2804_init(void)
+{
+       return i2c_add_driver(&wis_tw2804_driver);
+}
+
+static void __exit wis_tw2804_cleanup(void)
+{
+       i2c_del_driver(&wis_tw2804_driver);
+}
+
+module_init(wis_tw2804_init);
+module_exit(wis_tw2804_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/wis-tw9903.c b/drivers/staging/media/go7007/wis-tw9903.c
new file mode 100644 (file)
index 0000000..9230f4a
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+
+#include "wis-i2c.h"
+
+struct wis_tw9903 {
+       int norm;
+       int brightness;
+       int contrast;
+       int hue;
+};
+
+static u8 initial_registers[] =
+{
+       0x02, 0x44, /* input 1, composite */
+       0x03, 0x92, /* correct digital format */
+       0x04, 0x00,
+       0x05, 0x80, /* or 0x00 for PAL */
+       0x06, 0x40, /* second internal current reference */
+       0x07, 0x02, /* window */
+       0x08, 0x14, /* window */
+       0x09, 0xf0, /* window */
+       0x0a, 0x81, /* window */
+       0x0b, 0xd0, /* window */
+       0x0c, 0x8c,
+       0x0d, 0x00, /* scaling */
+       0x0e, 0x11, /* scaling */
+       0x0f, 0x00, /* scaling */
+       0x10, 0x00, /* brightness */
+       0x11, 0x60, /* contrast */
+       0x12, 0x01, /* sharpness */
+       0x13, 0x7f, /* U gain */
+       0x14, 0x5a, /* V gain */
+       0x15, 0x00, /* hue */
+       0x16, 0xc3, /* sharpness */
+       0x18, 0x00,
+       0x19, 0x58, /* vbi */
+       0x1a, 0x80,
+       0x1c, 0x0f, /* video norm */
+       0x1d, 0x7f, /* video norm */
+       0x20, 0xa0, /* clamping gain (working 0x50) */
+       0x21, 0x22,
+       0x22, 0xf0,
+       0x23, 0xfe,
+       0x24, 0x3c,
+       0x25, 0x38,
+       0x26, 0x44,
+       0x27, 0x20,
+       0x28, 0x00,
+       0x29, 0x15,
+       0x2a, 0xa0,
+       0x2b, 0x44,
+       0x2c, 0x37,
+       0x2d, 0x00,
+       0x2e, 0xa5, /* burst PLL control (working: a9) */
+       0x2f, 0xe0, /* 0xea is blue test frame -- 0xe0 for normal */
+       0x31, 0x00,
+       0x33, 0x22,
+       0x34, 0x11,
+       0x35, 0x35,
+       0x3b, 0x05,
+       0x06, 0xc0, /* reset device */
+       0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
+};
+
+static int write_reg(struct i2c_client *client, u8 reg, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int write_regs(struct i2c_client *client, u8 *regs)
+{
+       int i;
+
+       for (i = 0; regs[i] != 0x00; i += 2)
+               if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
+                       return -1;
+       return 0;
+}
+
+static int wis_tw9903_command(struct i2c_client *client,
+                               unsigned int cmd, void *arg)
+{
+       struct wis_tw9903 *dec = i2c_get_clientdata(client);
+
+       switch (cmd) {
+       case VIDIOC_S_INPUT:
+       {
+               int *input = arg;
+
+               i2c_smbus_write_byte_data(client, 0x02, 0x40 | (*input << 1));
+               break;
+       }
+#if 0
+       /* The scaler on this thing seems to be horribly broken */
+       case DECODER_SET_RESOLUTION:
+       {
+               struct video_decoder_resolution *res = arg;
+               /*int hscale = 256 * 720 / res->width;*/
+               int hscale = 256 * 720 / (res->width - (res->width > 704 ? 0 : 8));
+               int vscale = 256 * (dec->norm & V4L2_STD_NTSC ?  240 : 288)
+                               / res->height;
+               u8 regs[] = {
+                       0x0d, vscale & 0xff,
+                       0x0f, hscale & 0xff,
+                       0x0e, ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8),
+                       0x06, 0xc0, /* reset device */
+                       0,      0,
+               };
+               printk(KERN_DEBUG "vscale is %04x, hscale is %04x\n",
+                               vscale, hscale);
+               /*write_regs(client, regs);*/
+               break;
+       }
+#endif
+       case VIDIOC_S_STD:
+       {
+               v4l2_std_id *input = arg;
+               u8 regs[] = {
+                       0x05, *input & V4L2_STD_NTSC ? 0x80 : 0x00,
+                       0x07, *input & V4L2_STD_NTSC ? 0x02 : 0x12,
+                       0x08, *input & V4L2_STD_NTSC ? 0x14 : 0x18,
+                       0x09, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
+                       0,      0,
+               };
+               write_regs(client, regs);
+               dec->norm = *input;
+               break;
+       }
+       case VIDIOC_QUERYCTRL:
+       {
+               struct v4l2_queryctrl *ctrl = arg;
+
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
+                       ctrl->minimum = -128;
+                       ctrl->maximum = 127;
+                       ctrl->step = 1;
+                       ctrl->default_value = 0x00;
+                       ctrl->flags = 0;
+                       break;
+               case V4L2_CID_CONTRAST:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
+                       ctrl->minimum = 0;
+                       ctrl->maximum = 255;
+                       ctrl->step = 1;
+                       ctrl->default_value = 0x60;
+                       ctrl->flags = 0;
+                       break;
+#if 0
+               /* I don't understand how the Chroma Gain registers work... */
+               case V4L2_CID_SATURATION:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
+                       ctrl->minimum = 0;
+                       ctrl->maximum = 127;
+                       ctrl->step = 1;
+                       ctrl->default_value = 64;
+                       ctrl->flags = 0;
+                       break;
+#endif
+               case V4L2_CID_HUE:
+                       ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+                       strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
+                       ctrl->minimum = -128;
+                       ctrl->maximum = 127;
+                       ctrl->step = 1;
+                       ctrl->default_value = 0;
+                       ctrl->flags = 0;
+                       break;
+               }
+               break;
+       }
+       case VIDIOC_S_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       if (ctrl->value > 127)
+                               dec->brightness = 127;
+                       else if (ctrl->value < -128)
+                               dec->brightness = -128;
+                       else
+                               dec->brightness = ctrl->value;
+                       write_reg(client, 0x10, dec->brightness);
+                       break;
+               case V4L2_CID_CONTRAST:
+                       if (ctrl->value > 255)
+                               dec->contrast = 255;
+                       else if (ctrl->value < 0)
+                               dec->contrast = 0;
+                       else
+                               dec->contrast = ctrl->value;
+                       write_reg(client, 0x11, dec->contrast);
+                       break;
+#if 0
+               case V4L2_CID_SATURATION:
+                       if (ctrl->value > 127)
+                               dec->saturation = 127;
+                       else if (ctrl->value < 0)
+                               dec->saturation = 0;
+                       else
+                               dec->saturation = ctrl->value;
+                       /*write_reg(client, 0x0c, dec->saturation);*/
+                       break;
+#endif
+               case V4L2_CID_HUE:
+                       if (ctrl->value > 127)
+                               dec->hue = 127;
+                       else if (ctrl->value < -128)
+                               dec->hue = -128;
+                       else
+                               dec->hue = ctrl->value;
+                       write_reg(client, 0x15, dec->hue);
+                       break;
+               }
+               break;
+       }
+       case VIDIOC_G_CTRL:
+       {
+               struct v4l2_control *ctrl = arg;
+
+               switch (ctrl->id) {
+               case V4L2_CID_BRIGHTNESS:
+                       ctrl->value = dec->brightness;
+                       break;
+               case V4L2_CID_CONTRAST:
+                       ctrl->value = dec->contrast;
+                       break;
+#if 0
+               case V4L2_CID_SATURATION:
+                       ctrl->value = dec->saturation;
+                       break;
+#endif
+               case V4L2_CID_HUE:
+                       ctrl->value = dec->hue;
+                       break;
+               }
+               break;
+       }
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int wis_tw9903_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       struct wis_tw9903 *dec;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       dec = kmalloc(sizeof(struct wis_tw9903), GFP_KERNEL);
+       if (dec == NULL)
+               return -ENOMEM;
+
+       dec->norm = V4L2_STD_NTSC;
+       dec->brightness = 0;
+       dec->contrast = 0x60;
+       dec->hue = 0;
+       i2c_set_clientdata(client, dec);
+
+       printk(KERN_DEBUG
+               "wis-tw9903: initializing TW9903 at address %d on %s\n",
+               client->addr, adapter->name);
+
+       if (write_regs(client, initial_registers) < 0) {
+               printk(KERN_ERR "wis-tw9903: error initializing TW9903\n");
+               kfree(dec);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int wis_tw9903_remove(struct i2c_client *client)
+{
+       struct wis_tw9903 *dec = i2c_get_clientdata(client);
+
+       kfree(dec);
+       return 0;
+}
+
+static const struct i2c_device_id wis_tw9903_id[] = {
+       { "wis_tw9903", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wis_tw9903_id);
+
+static struct i2c_driver wis_tw9903_driver = {
+       .driver = {
+               .name   = "WIS TW9903 I2C driver",
+       },
+       .probe          = wis_tw9903_probe,
+       .remove         = wis_tw9903_remove,
+       .command        = wis_tw9903_command,
+       .id_table       = wis_tw9903_id,
+};
+
+static int __init wis_tw9903_init(void)
+{
+       return i2c_add_driver(&wis_tw9903_driver);
+}
+
+static void __exit wis_tw9903_cleanup(void)
+{
+       i2c_del_driver(&wis_tw9903_driver);
+}
+
+module_init(wis_tw9903_init);
+module_exit(wis_tw9903_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/wis-uda1342.c b/drivers/staging/media/go7007/wis-uda1342.c
new file mode 100644 (file)
index 0000000..0127be2
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/tvaudio.h>
+#include <media/v4l2-common.h>
+
+#include "wis-i2c.h"
+
+static int write_reg(struct i2c_client *client, int reg, int value)
+{
+       /* UDA1342 wants MSB first, but SMBus sends LSB first */
+       i2c_smbus_write_word_data(client, reg, swab16(value));
+       return 0;
+}
+
+static int wis_uda1342_command(struct i2c_client *client,
+                               unsigned int cmd, void *arg)
+{
+       switch (cmd) {
+       case VIDIOC_S_AUDIO:
+       {
+               int *inp = arg;
+
+               switch (*inp) {
+               case TVAUDIO_INPUT_TUNER:
+                       write_reg(client, 0x00, 0x1441); /* select input 2 */
+                       break;
+               case TVAUDIO_INPUT_EXTERN:
+                       write_reg(client, 0x00, 0x1241); /* select input 1 */
+                       break;
+               default:
+                       printk(KERN_ERR "wis-uda1342: input %d not supported\n",
+                                       *inp);
+                       break;
+               }
+               break;
+       }
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int wis_uda1342_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = client->adapter;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+               return -ENODEV;
+
+       printk(KERN_DEBUG
+               "wis-uda1342: initializing UDA1342 at address %d on %s\n",
+               client->addr, adapter->name);
+
+       write_reg(client, 0x00, 0x8000); /* reset registers */
+       write_reg(client, 0x00, 0x1241); /* select input 1 */
+
+       return 0;
+}
+
+static int wis_uda1342_remove(struct i2c_client *client)
+{
+       return 0;
+}
+
+static const struct i2c_device_id wis_uda1342_id[] = {
+       { "wis_uda1342", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wis_uda1342_id);
+
+static struct i2c_driver wis_uda1342_driver = {
+       .driver = {
+               .name   = "WIS UDA1342 I2C driver",
+       },
+       .probe          = wis_uda1342_probe,
+       .remove         = wis_uda1342_remove,
+       .command        = wis_uda1342_command,
+       .id_table       = wis_uda1342_id,
+};
+
+static int __init wis_uda1342_init(void)
+{
+       return i2c_add_driver(&wis_uda1342_driver);
+}
+
+static void __exit wis_uda1342_cleanup(void)
+{
+       i2c_del_driver(&wis_uda1342_driver);
+}
+
+module_init(wis_uda1342_init);
+module_exit(wis_uda1342_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/lirc/Kconfig b/drivers/staging/media/lirc/Kconfig
new file mode 100644 (file)
index 0000000..526ec0f
--- /dev/null
@@ -0,0 +1,78 @@
+#
+# LIRC driver(s) configuration
+#
+menuconfig LIRC_STAGING
+       bool "Linux Infrared Remote Control IR receiver/transmitter drivers"
+       depends on LIRC
+       help
+         Say Y here, and all supported Linux Infrared Remote Control IR and
+         RF receiver and transmitter drivers will be displayed. When paired
+         with a remote control and the lirc daemon, the receiver drivers
+         allow control of your Linux system via remote control.
+
+if LIRC_STAGING
+
+config LIRC_BT829
+        tristate "BT829 based hardware"
+       depends on LIRC && PCI
+       help
+         Driver for the IR interface on BT829-based hardware
+
+config LIRC_IGORPLUGUSB
+       tristate "Igor Cesko's USB IR Receiver"
+       depends on LIRC && USB
+       help
+         Driver for Igor Cesko's USB IR Receiver
+
+config LIRC_IMON
+       tristate "Legacy SoundGraph iMON Receiver and Display"
+       depends on LIRC && USB
+       help
+         Driver for the original SoundGraph iMON IR Receiver and Display
+
+         Current generation iMON devices use the input layer imon driver.
+
+config LIRC_PARALLEL
+       tristate "Homebrew Parallel Port Receiver"
+       depends on LIRC && PARPORT
+       help
+         Driver for Homebrew Parallel Port Receivers
+
+config LIRC_SASEM
+       tristate "Sasem USB IR Remote"
+       depends on LIRC && USB
+       help
+         Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module
+
+config LIRC_SERIAL
+       tristate "Homebrew Serial Port Receiver"
+       depends on LIRC
+       help
+         Driver for Homebrew Serial Port Receivers
+
+config LIRC_SERIAL_TRANSMITTER
+       bool "Serial Port Transmitter"
+       default y
+       depends on LIRC_SERIAL
+       help
+         Serial Port Transmitter support
+
+config LIRC_SIR
+       tristate "Built-in SIR IrDA port"
+       depends on LIRC
+       help
+         Driver for the SIR IrDA port
+
+config LIRC_TTUSBIR
+       tristate "Technotrend USB IR Receiver"
+       depends on LIRC && USB
+       help
+         Driver for the Technotrend USB IR Receiver
+
+config LIRC_ZILOG
+       tristate "Zilog/Hauppauge IR Transmitter"
+       depends on LIRC && I2C
+       help
+         Driver for the Zilog/Hauppauge IR Transmitter, found on
+         PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards
+endif
diff --git a/drivers/staging/media/lirc/Makefile b/drivers/staging/media/lirc/Makefile
new file mode 100644 (file)
index 0000000..d76b0fa
--- /dev/null
@@ -0,0 +1,14 @@
+# Makefile for the lirc drivers.
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_LIRC_BT829)       += lirc_bt829.o
+obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o
+obj-$(CONFIG_LIRC_IMON)                += lirc_imon.o
+obj-$(CONFIG_LIRC_PARALLEL)    += lirc_parallel.o
+obj-$(CONFIG_LIRC_SASEM)       += lirc_sasem.o
+obj-$(CONFIG_LIRC_SERIAL)      += lirc_serial.o
+obj-$(CONFIG_LIRC_SIR)         += lirc_sir.o
+obj-$(CONFIG_LIRC_TTUSBIR)     += lirc_ttusbir.o
+obj-$(CONFIG_LIRC_ZILOG)       += lirc_zilog.o
diff --git a/drivers/staging/media/lirc/TODO b/drivers/staging/media/lirc/TODO
new file mode 100644 (file)
index 0000000..b6cb593
--- /dev/null
@@ -0,0 +1,8 @@
+- All drivers should either be ported to ir-core, or dropped entirely
+  (see drivers/media/IR/mceusb.c vs. lirc_mceusb.c in lirc cvs for an
+  example of a previously completed port).
+
+Please send patches to:
+Jarod Wilson <jarod@wilsonet.com>
+Greg Kroah-Hartman <greg@kroah.com>
+
diff --git a/drivers/staging/media/lirc/TODO.lirc_zilog b/drivers/staging/media/lirc/TODO.lirc_zilog
new file mode 100644 (file)
index 0000000..a97800a
--- /dev/null
@@ -0,0 +1,36 @@
+1. Both ir-kbd-i2c and lirc_zilog provide support for RX events for
+the chips supported by lirc_zilog.  Before moving lirc_zilog out of staging:
+
+a. ir-kbd-i2c needs a module parameter added to allow the user to tell
+   ir-kbd-i2c to ignore Z8 IR units.
+
+b. lirc_zilog should provide Rx key presses to the rc core like ir-kbd-i2c
+   does.
+
+
+2. lirc_zilog module ref-counting need examination.  It has not been
+verified that cdev and lirc_dev will take the proper module references on
+lirc_zilog to prevent removal of lirc_zilog when the /dev/lircN device node
+is open.
+
+(The good news is ref-counting of lirc_zilog internal structures appears to be
+complete.  Testing has shown the cx18 module can be unloaded out from under
+irw + lircd + lirc_dev, with the /dev/lirc0 device node open, with no adverse
+effects.  The cx18 module could then be reloaded and irw properly began
+receiving button presses again and ir_send worked without error.)
+
+
+3. Bridge drivers, if able, should provide a chip reset() callback
+to lirc_zilog via struct IR_i2c_init_data.  cx18 and ivtv already have routines
+to perform Z8 chip resets via GPIO manipulations.  This would allow lirc_zilog
+to bring the chip back to normal when it hangs, in the same places the
+original lirc_pvr150 driver code does.  This is not strictly needed, so it
+is not required to move lirc_zilog out of staging.
+
+Note: Both lirc_zilog and ir-kbd-i2c support the Zilog Z8 for IR, as programmed
+and installed on Hauppauge products.  When working on either module, developers
+must consider at least the following bridge drivers which mention an IR Rx unit
+at address 0x71 (indicative of a Z8):
+
+       ivtv cx18 hdpvr pvrusb2 bt8xx cx88 saa7134
+
diff --git a/drivers/staging/media/lirc/lirc_bt829.c b/drivers/staging/media/lirc/lirc_bt829.c
new file mode 100644 (file)
index 0000000..c5a0d27
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * Remote control driver for the TV-card based on bt829
+ *
+ *  by Leonid Froenchenko <lfroen@galileo.co.il>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/threads.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include <media/lirc_dev.h>
+
+static int poll_main(void);
+static int atir_init_start(void);
+
+static void write_index(unsigned char index, unsigned int value);
+static unsigned int read_index(unsigned char index);
+
+static void do_i2c_start(void);
+static void do_i2c_stop(void);
+
+static void seems_wr_byte(unsigned char al);
+static unsigned char seems_rd_byte(void);
+
+static unsigned int read_index(unsigned char al);
+static void write_index(unsigned char ah, unsigned int edx);
+
+static void cycle_delay(int cycle);
+
+static void do_set_bits(unsigned char bl);
+static unsigned char do_get_bits(void);
+
+#define DATA_PCI_OFF 0x7FFC00
+#define WAIT_CYCLE   20
+
+#define DRIVER_NAME "lirc_bt829"
+
+static int debug;
+#define dprintk(fmt, args...)                                           \
+       do {                                                             \
+               if (debug)                                               \
+                       printk(KERN_DEBUG DRIVER_NAME ": "fmt, ## args); \
+       } while (0)
+
+static int atir_minor;
+static unsigned long pci_addr_phys;
+static unsigned char *pci_addr_lin;
+
+static struct lirc_driver atir_driver;
+
+static struct pci_dev *do_pci_probe(void)
+{
+       struct pci_dev *my_dev;
+       my_dev = pci_get_device(PCI_VENDOR_ID_ATI,
+                               PCI_DEVICE_ID_ATI_264VT, NULL);
+       if (my_dev) {
+               printk(KERN_ERR DRIVER_NAME ": Using device: %s\n",
+                      pci_name(my_dev));
+               pci_addr_phys = 0;
+               if (my_dev->resource[0].flags & IORESOURCE_MEM) {
+                       pci_addr_phys = my_dev->resource[0].start;
+                       printk(KERN_INFO DRIVER_NAME ": memory at 0x%08X\n",
+                              (unsigned int)pci_addr_phys);
+               }
+               if (pci_addr_phys == 0) {
+                       printk(KERN_ERR DRIVER_NAME ": no memory resource ?\n");
+                       return NULL;
+               }
+       } else {
+               printk(KERN_ERR DRIVER_NAME ": pci_probe failed\n");
+               return NULL;
+       }
+       return my_dev;
+}
+
+static int atir_add_to_buf(void *data, struct lirc_buffer *buf)
+{
+       unsigned char key;
+       int status;
+       status = poll_main();
+       key = (status >> 8) & 0xFF;
+       if (status & 0xFF) {
+               dprintk("reading key %02X\n", key);
+               lirc_buffer_write(buf, &key);
+               return 0;
+       }
+       return -ENODATA;
+}
+
+static int atir_set_use_inc(void *data)
+{
+       dprintk("driver is opened\n");
+       return 0;
+}
+
+static void atir_set_use_dec(void *data)
+{
+       dprintk("driver is closed\n");
+}
+
+int init_module(void)
+{
+       struct pci_dev *pdev;
+
+       pdev = do_pci_probe();
+       if (pdev == NULL)
+               return -ENODEV;
+
+       if (!atir_init_start())
+               return -ENODEV;
+
+       strcpy(atir_driver.name, "ATIR");
+       atir_driver.minor       = -1;
+       atir_driver.code_length = 8;
+       atir_driver.sample_rate = 10;
+       atir_driver.data        = 0;
+       atir_driver.add_to_buf  = atir_add_to_buf;
+       atir_driver.set_use_inc = atir_set_use_inc;
+       atir_driver.set_use_dec = atir_set_use_dec;
+       atir_driver.dev         = &pdev->dev;
+       atir_driver.owner       = THIS_MODULE;
+
+       atir_minor = lirc_register_driver(&atir_driver);
+       if (atir_minor < 0) {
+               printk(KERN_ERR DRIVER_NAME ": failed to register driver!\n");
+               return atir_minor;
+       }
+       dprintk("driver is registered on minor %d\n", atir_minor);
+
+       return 0;
+}
+
+
+void cleanup_module(void)
+{
+       lirc_unregister_driver(atir_minor);
+}
+
+
+static int atir_init_start(void)
+{
+       pci_addr_lin = ioremap(pci_addr_phys + DATA_PCI_OFF, 0x400);
+       if (pci_addr_lin == 0) {
+               printk(KERN_INFO DRIVER_NAME ": pci mem must be mapped\n");
+               return 0;
+       }
+       return 1;
+}
+
+static void cycle_delay(int cycle)
+{
+       udelay(WAIT_CYCLE*cycle);
+}
+
+
+static int poll_main()
+{
+       unsigned char status_high, status_low;
+
+       do_i2c_start();
+
+       seems_wr_byte(0xAA);
+       seems_wr_byte(0x01);
+
+       do_i2c_start();
+
+       seems_wr_byte(0xAB);
+
+       status_low = seems_rd_byte();
+       status_high = seems_rd_byte();
+
+       do_i2c_stop();
+
+       return (status_high << 8) | status_low;
+}
+
+static void do_i2c_start(void)
+{
+       do_set_bits(3);
+       cycle_delay(4);
+
+       do_set_bits(1);
+       cycle_delay(7);
+
+       do_set_bits(0);
+       cycle_delay(2);
+}
+
+static void do_i2c_stop(void)
+{
+       unsigned char bits;
+       bits =  do_get_bits() & 0xFD;
+       do_set_bits(bits);
+       cycle_delay(1);
+
+       bits |= 1;
+       do_set_bits(bits);
+       cycle_delay(2);
+
+       bits |= 2;
+       do_set_bits(bits);
+       bits = 3;
+       do_set_bits(bits);
+       cycle_delay(2);
+}
+
+static void seems_wr_byte(unsigned char value)
+{
+       int i;
+       unsigned char reg;
+
+       reg = do_get_bits();
+       for (i = 0; i < 8; i++) {
+               if (value & 0x80)
+                       reg |= 0x02;
+               else
+                       reg &= 0xFD;
+
+               do_set_bits(reg);
+               cycle_delay(1);
+
+               reg |= 1;
+               do_set_bits(reg);
+               cycle_delay(1);
+
+               reg &= 0xFE;
+               do_set_bits(reg);
+               cycle_delay(1);
+               value <<= 1;
+       }
+       cycle_delay(2);
+
+       reg |= 2;
+       do_set_bits(reg);
+
+       reg |= 1;
+       do_set_bits(reg);
+
+       cycle_delay(1);
+       do_get_bits();
+
+       reg &= 0xFE;
+       do_set_bits(reg);
+       cycle_delay(3);
+}
+
+static unsigned char seems_rd_byte(void)
+{
+       int i;
+       int rd_byte;
+       unsigned char bits_2, bits_1;
+
+       bits_1 = do_get_bits() | 2;
+       do_set_bits(bits_1);
+
+       rd_byte = 0;
+       for (i = 0; i < 8; i++) {
+               bits_1 &= 0xFE;
+               do_set_bits(bits_1);
+               cycle_delay(2);
+
+               bits_1 |= 1;
+               do_set_bits(bits_1);
+               cycle_delay(1);
+
+               bits_2 = do_get_bits();
+               if (bits_2 & 2)
+                       rd_byte |= 1;
+
+               rd_byte <<= 1;
+       }
+
+       bits_1 = 0;
+       if (bits_2 == 0)
+               bits_1 |= 2;
+
+       do_set_bits(bits_1);
+       cycle_delay(2);
+
+       bits_1 |= 1;
+       do_set_bits(bits_1);
+       cycle_delay(3);
+
+       bits_1 &= 0xFE;
+       do_set_bits(bits_1);
+       cycle_delay(2);
+
+       rd_byte >>= 1;
+       rd_byte &= 0xFF;
+       return rd_byte;
+}
+
+static void do_set_bits(unsigned char new_bits)
+{
+       int reg_val;
+       reg_val = read_index(0x34);
+       if (new_bits & 2) {
+               reg_val &= 0xFFFFFFDF;
+               reg_val |= 1;
+       } else {
+               reg_val &= 0xFFFFFFFE;
+               reg_val |= 0x20;
+       }
+       reg_val |= 0x10;
+       write_index(0x34, reg_val);
+
+       reg_val = read_index(0x31);
+       if (new_bits & 1)
+               reg_val |= 0x1000000;
+       else
+               reg_val &= 0xFEFFFFFF;
+
+       reg_val |= 0x8000000;
+       write_index(0x31, reg_val);
+}
+
+static unsigned char do_get_bits(void)
+{
+       unsigned char bits;
+       int reg_val;
+
+       reg_val = read_index(0x34);
+       reg_val |= 0x10;
+       reg_val &= 0xFFFFFFDF;
+       write_index(0x34, reg_val);
+
+       reg_val = read_index(0x34);
+       bits = 0;
+       if (reg_val & 8)
+               bits |= 2;
+       else
+               bits &= 0xFD;
+
+       reg_val = read_index(0x31);
+       if (reg_val & 0x1000000)
+               bits |= 1;
+       else
+               bits &= 0xFE;
+
+       return bits;
+}
+
+static unsigned int read_index(unsigned char index)
+{
+       unsigned char *addr;
+       unsigned int value;
+       /*  addr = pci_addr_lin + DATA_PCI_OFF + ((index & 0xFF) << 2); */
+       addr = pci_addr_lin + ((index & 0xFF) << 2);
+       value = readl(addr);
+       return value;
+}
+
+static void write_index(unsigned char index, unsigned int reg_val)
+{
+       unsigned char *addr;
+       addr = pci_addr_lin + ((index & 0xFF) << 2);
+       writel(reg_val, addr);
+}
+
+MODULE_AUTHOR("Froenchenko Leonid");
+MODULE_DESCRIPTION("IR remote driver for bt829 based TV cards");
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/staging/media/lirc/lirc_ene0100.h b/drivers/staging/media/lirc/lirc_ene0100.h
new file mode 100644 (file)
index 0000000..06bebd6
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * driver for ENE KB3926 B/C/D CIR (also known as ENE0100)
+ *
+ * Copyright (C) 2009 Maxim Levitsky <maximlevitsky@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+/* hardware address */
+#define ENE_STATUS             0        /* hardware status - unused */
+#define ENE_ADDR_HI            1        /* hi byte of register address */
+#define ENE_ADDR_LO            2        /* low byte of register address */
+#define ENE_IO                 3        /* read/write window */
+#define ENE_MAX_IO             4
+
+/* 8 bytes of samples, divided in 2 halfs*/
+#define ENE_SAMPLE_BUFFER      0xF8F0   /* regular sample buffer */
+#define ENE_SAMPLE_SPC_MASK    (1 << 7) /* sample is space */
+#define ENE_SAMPLE_VALUE_MASK  0x7F
+#define ENE_SAMPLE_OVERFLOW    0x7F
+#define ENE_SAMPLES_SIZE       4
+
+/* fan input sample buffer */
+#define ENE_SAMPLE_BUFFER_FAN  0xF8FB   /* this buffer holds high byte of */
+                                        /* each sample of normal buffer */
+
+#define ENE_FAN_SMPL_PULS_MSK  0x8000   /* this bit of combined sample */
+                                        /* if set, says that sample is pulse */
+#define ENE_FAN_VALUE_MASK     0x0FFF   /* mask for valid bits of the value */
+
+/* first firmware register */
+#define ENE_FW1                        0xF8F8
+#define        ENE_FW1_ENABLE          (1 << 0) /* enable fw processing */
+#define ENE_FW1_TXIRQ          (1 << 1) /* TX interrupt pending */
+#define ENE_FW1_WAKE           (1 << 6) /* enable wake from S3 */
+#define ENE_FW1_IRQ            (1 << 7) /* enable interrupt */
+
+/* second firmware register */
+#define ENE_FW2                        0xF8F9
+#define ENE_FW2_BUF_HIGH       (1 << 0) /* which half of the buffer to read */
+#define ENE_FW2_IRQ_CLR                (1 << 2) /* clear this on IRQ */
+#define ENE_FW2_GP40_AS_LEARN  (1 << 4) /* normal input is used as */
+                                        /* learning input */
+#define ENE_FW2_FAN_AS_NRML_IN (1 << 6) /* fan is used as normal input */
+#define ENE_FW2_LEARNING       (1 << 7) /* hardware supports learning and TX */
+
+/* fan as input settings - only if learning capable */
+#define ENE_FAN_AS_IN1         0xFE30   /* fan init reg 1 */
+#define ENE_FAN_AS_IN1_EN      0xCD
+#define ENE_FAN_AS_IN2         0xFE31   /* fan init reg 2 */
+#define ENE_FAN_AS_IN2_EN      0x03
+#define ENE_SAMPLE_PERIOD_FAN   61      /* fan input has fixed sample period */
+
+/* IRQ registers block (for revision B) */
+#define ENEB_IRQ               0xFD09   /* IRQ number */
+#define ENEB_IRQ_UNK1          0xFD17   /* unknown setting = 1 */
+#define ENEB_IRQ_STATUS                0xFD80   /* irq status */
+#define ENEB_IRQ_STATUS_IR     (1 << 5) /* IR irq */
+
+/* IRQ registers block (for revision C,D) */
+#define ENEC_IRQ               0xFE9B   /* new irq settings register */
+#define ENEC_IRQ_MASK          0x0F     /* irq number mask */
+#define ENEC_IRQ_UNK_EN                (1 << 4) /* always enabled */
+#define ENEC_IRQ_STATUS                (1 << 5) /* irq status and ACK */
+
+/* CIR block settings */
+#define ENE_CIR_CONF1          0xFEC0
+#define ENE_CIR_CONF1_ADC_ON   0x7      /* receiver on gpio40 enabled */
+#define ENE_CIR_CONF1_LEARN1   (1 << 3) /* enabled on learning mode */
+#define ENE_CIR_CONF1_TX_ON    0x30     /* enabled on transmit */
+#define ENE_CIR_CONF1_TX_CARR  (1 << 7) /* send TX carrier or not */
+
+#define ENE_CIR_CONF2          0xFEC1   /* unknown setting = 0 */
+#define ENE_CIR_CONF2_LEARN2   (1 << 4) /* set on enable learning */
+#define ENE_CIR_CONF2_GPIO40DIS        (1 << 5) /* disable normal input via gpio40 */
+
+#define ENE_CIR_SAMPLE_PERIOD  0xFEC8   /* sample period in us */
+#define ENE_CIR_SAMPLE_OVERFLOW        (1 << 7) /* interrupt on overflows if set */
+
+
+/* transmitter - not implemented yet */
+/* KB3926C and higher */
+/* transmission is very similar to receiving, a byte is written to */
+/* ENE_TX_INPUT, in same manner as it is read from sample buffer */
+/* sample period is fixed*/
+
+
+/* transmitter ports */
+#define ENE_TX_PORT1           0xFC01   /* this enables one or both */
+#define ENE_TX_PORT1_EN                (1 << 5) /* TX ports */
+#define ENE_TX_PORT2           0xFC08
+#define ENE_TX_PORT2_EN                (1 << 1)
+
+#define ENE_TX_INPUT           0xFEC9   /* next byte to transmit */
+#define ENE_TX_SPC_MASK                (1 << 7) /* Transmitted sample is space */
+#define ENE_TX_UNK1            0xFECB   /* set to 0x63 */
+#define ENE_TX_SMPL_PERIOD     50       /* transmit sample period */
+
+
+#define ENE_TX_CARRIER         0xFECE   /* TX carrier * 2 (khz) */
+#define ENE_TX_CARRIER_UNKBIT  0x80     /* This bit set on transmit */
+#define ENE_TX_CARRIER_LOW     0xFECF   /* TX carrier / 2 */
+
+/* Hardware versions */
+#define ENE_HW_VERSION         0xFF00   /* hardware revision */
+#define ENE_HW_UNK             0xFF1D
+#define ENE_HW_UNK_CLR         (1 << 2)
+#define ENE_HW_VER_MAJOR       0xFF1E   /* chip version */
+#define ENE_HW_VER_MINOR       0xFF1F
+#define ENE_HW_VER_OLD         0xFD00
+
+#define same_sign(a, b) ((((a) > 0) && (b) > 0) || ((a) < 0 && (b) < 0))
+
+#define ENE_DRIVER_NAME                "enecir"
+#define ENE_MAXGAP             250000   /* this is amount of time we wait
+                                        before turning the sampler, chosen
+                                        arbitry */
+
+#define space(len)            (-(len))  /* add a space */
+
+/* software defines */
+#define ENE_IRQ_RX             1
+#define ENE_IRQ_TX             2
+
+#define  ENE_HW_B              1       /* 3926B */
+#define  ENE_HW_C              2       /* 3926C */
+#define  ENE_HW_D              3       /* 3926D */
+
+#define ene_printk(level, text, ...) \
+       printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__)
+
+struct ene_device {
+       struct pnp_dev *pnp_dev;
+       struct lirc_driver *lirc_driver;
+
+       /* hw settings */
+       unsigned long hw_io;
+       int irq;
+
+       int hw_revision;                        /* hardware revision */
+       int hw_learning_and_tx_capable;         /* learning capable */
+       int hw_gpio40_learning;                 /* gpio40 is learning */
+       int hw_fan_as_normal_input;     /* fan input is used as regular input */
+
+       /* device data */
+       int idle;
+       int fan_input_inuse;
+
+       int sample;
+       int in_use;
+
+       struct timeval gap_start;
+};
diff --git a/drivers/staging/media/lirc/lirc_igorplugusb.c b/drivers/staging/media/lirc/lirc_igorplugusb.c
new file mode 100644 (file)
index 0000000..0dc2c2b
--- /dev/null
@@ -0,0 +1,577 @@
+/*
+ * lirc_igorplugusb - USB remote support for LIRC
+ *
+ * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware.
+ * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm
+ *
+ * The device can only record bursts of up to 36 pulses/spaces.
+ * Works fine with RC5. Longer commands lead to device buffer overrun.
+ * (Maybe a better firmware or a microcontroller with more ram can help?)
+ *
+ * Version 0.1  [beta status]
+ *
+ * Copyright (C) 2004 Jan M. Hochstein
+ *     <hochstein@algo.informatik.tu-darmstadt.de>
+ *
+ * This driver was derived from:
+ *   Paul Miller <pmiller9@users.sourceforge.net>
+ *      "lirc_atiusb" module
+ *   Vladimir Dergachev <volodya@minspring.com>'s 2002
+ *      "USB ATI Remote support" (input device)
+ *   Adrian Dewhurst <sailor-lk@sailorfrag.net>'s 2002
+ *      "USB StreamZap remote driver" (LIRC)
+ *   Artur Lipowski <alipowski@kki.net.pl>'s 2002
+ *      "lirc_dev" and "lirc_gpio" LIRC modules
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/usb.h>
+#include <linux/time.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+
+/* module identification */
+#define DRIVER_VERSION         "0.2"
+#define DRIVER_AUTHOR          \
+       "Jan M. Hochstein <hochstein@algo.informatik.tu-darmstadt.de>"
+#define DRIVER_DESC            "Igorplug USB remote driver for LIRC"
+#define DRIVER_NAME            "lirc_igorplugusb"
+
+/* debugging support */
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+#define dprintk(fmt, args...)                                  \
+       do {                                                    \
+               if (debug)                                      \
+                       printk(KERN_DEBUG fmt, ## args);        \
+       } while (0)
+
+/* One mode2 pulse/space has 4 bytes. */
+#define CODE_LENGTH         sizeof(int)
+
+/* Igor's firmware cannot record bursts longer than 36. */
+#define DEVICE_BUFLEN     36
+
+/*
+ * Header at the beginning of the device's buffer:
+ *     unsigned char data_length
+ *     unsigned char data_start    (!=0 means ring-buffer overrun)
+ *     unsigned char counter       (incremented by each burst)
+ */
+#define DEVICE_HEADERLEN       3
+
+/* This is for the gap */
+#define ADDITIONAL_LIRC_BYTES   2
+
+/* times to poll per second */
+#define SAMPLE_RATE         100
+static int sample_rate = SAMPLE_RATE;
+
+
+/**** Igor's USB Request Codes */
+
+#define SET_INFRABUFFER_EMPTY   1
+/**
+ * Params: none
+ * Answer: empty
+ */
+
+#define GET_INFRACODE     2
+/**
+ * Params:
+ *   wValue: offset to begin reading infra buffer
+ *
+ * Answer: infra data
+ */
+
+#define SET_DATAPORT_DIRECTION  3
+/**
+ * Params:
+ *   wValue: (byte) 1 bit for each data port pin (0=in, 1=out)
+ *
+ * Answer: empty
+ */
+
+#define GET_DATAPORT_DIRECTION  4
+/**
+ * Params: none
+ *
+ * Answer: (byte) 1 bit for each data port pin (0=in, 1=out)
+ */
+
+#define SET_OUT_DATAPORT       5
+/**
+ * Params:
+ *   wValue: byte to write to output data port
+ *
+ * Answer: empty
+ */
+
+#define GET_OUT_DATAPORT       6
+/**
+ * Params: none
+ *
+ * Answer: least significant 3 bits read from output data port
+ */
+
+#define GET_IN_DATAPORT         7
+/**
+ * Params: none
+ *
+ * Answer: least significant 3 bits read from input data port
+ */
+
+#define READ_EEPROM         8
+/**
+ * Params:
+ *   wValue: offset to begin reading EEPROM
+ *
+ * Answer: EEPROM bytes
+ */
+
+#define WRITE_EEPROM       9
+/**
+ * Params:
+ *   wValue: offset to EEPROM byte
+ *   wIndex: byte to write
+ *
+ * Answer: empty
+ */
+
+#define SEND_RS232           10
+/**
+ * Params:
+ *   wValue: byte to send
+ *
+ * Answer: empty
+ */
+
+#define RECV_RS232           11
+/**
+ * Params: none
+ *
+ * Answer: byte received
+ */
+
+#define SET_RS232_BAUD   12
+/**
+ * Params:
+ *   wValue: byte to write to UART bit rate register (UBRR)
+ *
+ * Answer: empty
+ */
+
+#define GET_RS232_BAUD   13
+/**
+ * Params: none
+ *
+ * Answer: byte read from UART bit rate register (UBRR)
+ */
+
+
+/* data structure for each usb remote */
+struct igorplug {
+
+       /* usb */
+       struct usb_device *usbdev;
+       int devnum;
+
+       unsigned char *buf_in;
+       unsigned int len_in;
+       int in_space;
+       struct timeval last_time;
+
+       dma_addr_t dma_in;
+
+       /* lirc */
+       struct lirc_driver *d;
+
+       /* handle sending (init strings) */
+       int send_flags;
+};
+
+static int unregister_from_lirc(struct igorplug *ir)
+{
+       struct lirc_driver *d;
+       int devnum;
+
+       if (!ir) {
+               printk(KERN_ERR "%s: called with NULL device struct!\n",
+                      __func__);
+               return -EINVAL;
+       }
+
+       devnum = ir->devnum;
+       d = ir->d;
+
+       if (!d) {
+               printk(KERN_ERR "%s: called with NULL lirc driver struct!\n",
+                      __func__);
+               return -EINVAL;
+       }
+
+       dprintk(DRIVER_NAME "[%d]: calling lirc_unregister_driver\n", devnum);
+       lirc_unregister_driver(d->minor);
+
+       kfree(d);
+       ir->d = NULL;
+       kfree(ir);
+
+       return devnum;
+}
+
+static int set_use_inc(void *data)
+{
+       struct igorplug *ir = data;
+
+       if (!ir) {
+               printk(DRIVER_NAME "[?]: set_use_inc called with no context\n");
+               return -EIO;
+       }
+
+       dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum);
+
+       if (!ir->usbdev)
+               return -ENODEV;
+
+       return 0;
+}
+
+static void set_use_dec(void *data)
+{
+       struct igorplug *ir = data;
+
+       if (!ir) {
+               printk(DRIVER_NAME "[?]: set_use_dec called with no context\n");
+               return;
+       }
+
+       dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum);
+}
+
+static void send_fragment(struct igorplug *ir, struct lirc_buffer *buf,
+                          int i, int max)
+{
+       int code;
+
+       /* MODE2: pulse/space (PULSE_BIT) in 1us units */
+       while (i < max) {
+               /* 1 Igor-tick = 85.333333 us */
+               code = (unsigned int)ir->buf_in[i] * 85 +
+                       (unsigned int)ir->buf_in[i] / 3;
+               ir->last_time.tv_usec += code;
+               if (ir->in_space)
+                       code |= PULSE_BIT;
+               lirc_buffer_write(buf, (unsigned char *)&code);
+               /* 1 chunk = CODE_LENGTH bytes */
+               ir->in_space ^= 1;
+               ++i;
+       }
+}
+
+/**
+ * Called in user context.
+ * return 0 if data was added to the buffer and
+ * -ENODATA if none was available. This should add some number of bits
+ * evenly divisible by code_length to the buffer
+ */
+static int igorplugusb_remote_poll(void *data, struct lirc_buffer *buf)
+{
+       int ret;
+       struct igorplug *ir = (struct igorplug *)data;
+
+       if (!ir || !ir->usbdev)  /* Has the device been removed? */
+               return -ENODEV;
+
+       memset(ir->buf_in, 0, ir->len_in);
+
+       ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+                             GET_INFRACODE, USB_TYPE_VENDOR | USB_DIR_IN,
+                             0/* offset */, /*unused*/0,
+                             ir->buf_in, ir->len_in,
+                             /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
+       if (ret > 0) {
+               int code, timediff;
+               struct timeval now;
+
+               /* ACK packet has 1 byte --> ignore */
+               if (ret < DEVICE_HEADERLEN)
+                       return -ENODATA;
+
+               dprintk(DRIVER_NAME ": Got %d bytes. Header: %02x %02x %02x\n",
+                       ret, ir->buf_in[0], ir->buf_in[1], ir->buf_in[2]);
+
+               do_gettimeofday(&now);
+               timediff = now.tv_sec - ir->last_time.tv_sec;
+               if (timediff + 1 > PULSE_MASK / 1000000)
+                       timediff = PULSE_MASK;
+               else {
+                       timediff *= 1000000;
+                       timediff += now.tv_usec - ir->last_time.tv_usec;
+               }
+               ir->last_time.tv_sec = now.tv_sec;
+               ir->last_time.tv_usec = now.tv_usec;
+
+               /* create leading gap  */
+               code = timediff;
+               lirc_buffer_write(buf, (unsigned char *)&code);
+               ir->in_space = 1;   /* next comes a pulse */
+
+               if (ir->buf_in[2] == 0)
+                       send_fragment(ir, buf, DEVICE_HEADERLEN, ret);
+               else {
+                       printk(KERN_WARNING DRIVER_NAME
+                              "[%d]: Device buffer overrun.\n", ir->devnum);
+                       /* HHHNNNNNNNNNNNOOOOOOOO H = header
+                             <---[2]--->         N = newer
+                          <---------ret--------> O = older */
+                       ir->buf_in[2] %= ret - DEVICE_HEADERLEN; /* sanitize */
+                       /* keep even-ness to not desync pulse/pause */
+                       send_fragment(ir, buf, DEVICE_HEADERLEN +
+                                     ir->buf_in[2] - (ir->buf_in[2] & 1), ret);
+                       send_fragment(ir, buf, DEVICE_HEADERLEN,
+                                     DEVICE_HEADERLEN + ir->buf_in[2]);
+               }
+
+               ret = usb_control_msg(
+                     ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+                     SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN,
+                     /*unused*/0, /*unused*/0,
+                     /*dummy*/ir->buf_in, /*dummy*/ir->len_in,
+                     /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
+               if (ret < 0)
+                       printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: "
+                              "error %d\n", ir->devnum, ret);
+               return 0;
+       } else if (ret < 0)
+               printk(DRIVER_NAME "[%d]: GET_INFRACODE: error %d\n",
+                       ir->devnum, ret);
+
+       return -ENODATA;
+}
+
+
+
+static int igorplugusb_remote_probe(struct usb_interface *intf,
+                                   const struct usb_device_id *id)
+{
+       struct usb_device *dev = NULL;
+       struct usb_host_interface *idesc = NULL;
+       struct usb_endpoint_descriptor *ep;
+       struct igorplug *ir = NULL;
+       struct lirc_driver *driver = NULL;
+       int devnum, pipe, maxp;
+       int minor = 0;
+       char buf[63], name[128] = "";
+       int mem_failure = 0;
+       int ret;
+
+       dprintk(DRIVER_NAME ": usb probe called.\n");
+
+       dev = interface_to_usbdev(intf);
+
+       idesc = intf->cur_altsetting;
+
+       if (idesc->desc.bNumEndpoints != 1)
+               return -ENODEV;
+
+       ep = &idesc->endpoint->desc;
+       if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+           != USB_DIR_IN)
+           || (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+           != USB_ENDPOINT_XFER_CONTROL)
+               return -ENODEV;
+
+       pipe = usb_rcvctrlpipe(dev, ep->bEndpointAddress);
+       devnum = dev->devnum;
+       maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+       dprintk(DRIVER_NAME "[%d]: bytes_in_key=%zu maxp=%d\n",
+               devnum, CODE_LENGTH, maxp);
+
+       mem_failure = 0;
+       ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL);
+       if (!ir) {
+               mem_failure = 1;
+               goto mem_failure_switch;
+       }
+       driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+       if (!driver) {
+               mem_failure = 2;
+               goto mem_failure_switch;
+       }
+
+       ir->buf_in = usb_alloc_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN,
+                                       GFP_ATOMIC, &ir->dma_in);
+       if (!ir->buf_in) {
+               mem_failure = 3;
+               goto mem_failure_switch;
+       }
+
+       strcpy(driver->name, DRIVER_NAME " ");
+       driver->minor = -1;
+       driver->code_length = CODE_LENGTH * 8; /* in bits */
+       driver->features = LIRC_CAN_REC_MODE2;
+       driver->data = ir;
+       driver->chunk_size = CODE_LENGTH;
+       driver->buffer_size = DEVICE_BUFLEN + ADDITIONAL_LIRC_BYTES;
+       driver->set_use_inc = &set_use_inc;
+       driver->set_use_dec = &set_use_dec;
+       driver->sample_rate = sample_rate;    /* per second */
+       driver->add_to_buf = &igorplugusb_remote_poll;
+       driver->dev = &intf->dev;
+       driver->owner = THIS_MODULE;
+
+       minor = lirc_register_driver(driver);
+       if (minor < 0)
+               mem_failure = 9;
+
+mem_failure_switch:
+
+       switch (mem_failure) {
+       case 9:
+               usb_free_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN,
+                       ir->buf_in, ir->dma_in);
+       case 3:
+               kfree(driver);
+       case 2:
+               kfree(ir);
+       case 1:
+               printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n",
+                       devnum, mem_failure);
+               return -ENOMEM;
+       }
+
+       driver->minor = minor;
+       ir->d = driver;
+       ir->devnum = devnum;
+       ir->usbdev = dev;
+       ir->len_in = DEVICE_BUFLEN + DEVICE_HEADERLEN;
+       ir->in_space = 1; /* First mode2 event is a space. */
+       do_gettimeofday(&ir->last_time);
+
+       if (dev->descriptor.iManufacturer
+           && usb_string(dev, dev->descriptor.iManufacturer,
+                         buf, sizeof(buf)) > 0)
+               strlcpy(name, buf, sizeof(name));
+       if (dev->descriptor.iProduct
+           && usb_string(dev, dev->descriptor.iProduct, buf, sizeof(buf)) > 0)
+               snprintf(name + strlen(name), sizeof(name) - strlen(name),
+                        " %s", buf);
+       printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", devnum, name,
+              dev->bus->busnum, devnum);
+
+       /* clear device buffer */
+       ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+               SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN,
+               /*unused*/0, /*unused*/0,
+               /*dummy*/ir->buf_in, /*dummy*/ir->len_in,
+               /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
+       if (ret < 0)
+               printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: error %d\n",
+                       devnum, ret);
+
+       usb_set_intfdata(intf, ir);
+       return 0;
+}
+
+
+static void igorplugusb_remote_disconnect(struct usb_interface *intf)
+{
+       struct usb_device *usbdev = interface_to_usbdev(intf);
+       struct igorplug *ir = usb_get_intfdata(intf);
+       struct device *dev = &intf->dev;
+       int devnum;
+
+       usb_set_intfdata(intf, NULL);
+
+       if (!ir || !ir->d)
+               return;
+
+       ir->usbdev = NULL;
+
+       usb_free_coherent(usbdev, ir->len_in, ir->buf_in, ir->dma_in);
+
+       devnum = unregister_from_lirc(ir);
+
+       dev_info(dev, DRIVER_NAME "[%d]: %s done\n", devnum, __func__);
+}
+
+static struct usb_device_id igorplugusb_remote_id_table[] = {
+       /* Igor Plug USB (Atmel's Manufact. ID) */
+       { USB_DEVICE(0x03eb, 0x0002) },
+       /* Fit PC2 Infrared Adapter */
+       { USB_DEVICE(0x03eb, 0x21fe) },
+
+       /* Terminating entry */
+       { }
+};
+
+static struct usb_driver igorplugusb_remote_driver = {
+       .name =         DRIVER_NAME,
+       .probe =        igorplugusb_remote_probe,
+       .disconnect =   igorplugusb_remote_disconnect,
+       .id_table =     igorplugusb_remote_id_table
+};
+
+static int __init igorplugusb_remote_init(void)
+{
+       int ret = 0;
+
+       dprintk(DRIVER_NAME ": loaded, debug mode enabled\n");
+
+       ret = usb_register(&igorplugusb_remote_driver);
+       if (ret)
+               printk(KERN_ERR DRIVER_NAME ": usb register failed!\n");
+
+       return ret;
+}
+
+static void __exit igorplugusb_remote_exit(void)
+{
+       usb_deregister(&igorplugusb_remote_driver);
+}
+
+module_init(igorplugusb_remote_init);
+module_exit(igorplugusb_remote_exit);
+
+#include <linux/vermagic.h>
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, igorplugusb_remote_id_table);
+
+module_param(sample_rate, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/staging/media/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c
new file mode 100644 (file)
index 0000000..f5308d5
--- /dev/null
@@ -0,0 +1,1050 @@
+/*
+ *   lirc_imon.c:  LIRC/VFD/LCD driver for SoundGraph iMON IR/VFD/LCD
+ *                including the iMON PAD model
+ *
+ *   Copyright(C) 2004  Venky Raju(dev@venky.ws)
+ *   Copyright(C) 2009  Jarod Wilson <jarod@wilsonet.com>
+ *
+ *   lirc_imon is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+
+#define MOD_AUTHOR     "Venky Raju <dev@venky.ws>"
+#define MOD_DESC       "Driver for SoundGraph iMON MultiMedia IR/Display"
+#define MOD_NAME       "lirc_imon"
+#define MOD_VERSION    "0.8"
+
+#define DISPLAY_MINOR_BASE     144
+#define DEVICE_NAME    "lcd%d"
+
+#define BUF_CHUNK_SIZE 4
+#define BUF_SIZE       128
+
+#define BIT_DURATION   250     /* each bit received is 250us */
+
+/*** P R O T O T Y P E S ***/
+
+/* USB Callback prototypes */
+static int imon_probe(struct usb_interface *interface,
+                     const struct usb_device_id *id);
+static void imon_disconnect(struct usb_interface *interface);
+static void usb_rx_callback(struct urb *urb);
+static void usb_tx_callback(struct urb *urb);
+
+/* suspend/resume support */
+static int imon_resume(struct usb_interface *intf);
+static int imon_suspend(struct usb_interface *intf, pm_message_t message);
+
+/* Display file_operations function prototypes */
+static int display_open(struct inode *inode, struct file *file);
+static int display_close(struct inode *inode, struct file *file);
+
+/* VFD write operation */
+static ssize_t vfd_write(struct file *file, const char *buf,
+                        size_t n_bytes, loff_t *pos);
+
+/* LIRC driver function prototypes */
+static int ir_open(void *data);
+static void ir_close(void *data);
+
+/* Driver init/exit prototypes */
+static int __init imon_init(void);
+static void __exit imon_exit(void);
+
+/*** G L O B A L S ***/
+#define IMON_DATA_BUF_SZ       35
+
+struct imon_context {
+       struct usb_device *usbdev;
+       /* Newer devices have two interfaces */
+       int display;                    /* not all controllers do */
+       int display_isopen;             /* display port has been opened */
+       int ir_isopen;                  /* IR port open */
+       int dev_present;                /* USB device presence */
+       struct mutex ctx_lock;          /* to lock this object */
+       wait_queue_head_t remove_ok;    /* For unexpected USB disconnects */
+
+       int vfd_proto_6p;               /* some VFD require a 6th packet */
+
+       struct lirc_driver *driver;
+       struct usb_endpoint_descriptor *rx_endpoint;
+       struct usb_endpoint_descriptor *tx_endpoint;
+       struct urb *rx_urb;
+       struct urb *tx_urb;
+       unsigned char usb_rx_buf[8];
+       unsigned char usb_tx_buf[8];
+
+       struct rx_data {
+               int count;              /* length of 0 or 1 sequence */
+               int prev_bit;           /* logic level of sequence */
+               int initial_space;      /* initial space flag */
+       } rx;
+
+       struct tx_t {
+               unsigned char data_buf[IMON_DATA_BUF_SZ]; /* user data buffer */
+               struct completion finished;     /* wait for write to finish */
+               atomic_t busy;                  /* write in progress */
+               int status;                     /* status of tx completion */
+       } tx;
+};
+
+static const struct file_operations display_fops = {
+       .owner          = THIS_MODULE,
+       .open           = &display_open,
+       .write          = &vfd_write,
+       .release        = &display_close,
+       .llseek         = noop_llseek,
+};
+
+/*
+ * USB Device ID for iMON USB Control Boards
+ *
+ * The Windows drivers contain 6 different inf files, more or less one for
+ * each new device until the 0x0034-0x0046 devices, which all use the same
+ * driver. Some of the devices in the 34-46 range haven't been definitively
+ * identified yet. Early devices have either a TriGem Computer, Inc. or a
+ * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later
+ * devices use the SoundGraph vendor ID (0x15c2).
+ */
+static struct usb_device_id imon_usb_id_table[] = {
+       /* TriGem iMON (IR only) -- TG_iMON.inf */
+       { USB_DEVICE(0x0aa8, 0x8001) },
+
+       /* SoundGraph iMON (IR only) -- sg_imon.inf */
+       { USB_DEVICE(0x04e8, 0xff30) },
+
+       /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */
+       { USB_DEVICE(0x0aa8, 0xffda) },
+
+       /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */
+       { USB_DEVICE(0x15c2, 0xffda) },
+
+       {}
+};
+
+/* Some iMON VFD models requires a 6th packet for VFD writes */
+static struct usb_device_id vfd_proto_6p_list[] = {
+       { USB_DEVICE(0x15c2, 0xffda) },
+       {}
+};
+
+/* Some iMON devices have no lcd/vfd, don't set one up */
+static struct usb_device_id ir_only_list[] = {
+       { USB_DEVICE(0x0aa8, 0x8001) },
+       { USB_DEVICE(0x04e8, 0xff30) },
+       {}
+};
+
+/* USB Device data */
+static struct usb_driver imon_driver = {
+       .name           = MOD_NAME,
+       .probe          = imon_probe,
+       .disconnect     = imon_disconnect,
+       .suspend        = imon_suspend,
+       .resume         = imon_resume,
+       .id_table       = imon_usb_id_table,
+};
+
+static struct usb_class_driver imon_class = {
+       .name           = DEVICE_NAME,
+       .fops           = &display_fops,
+       .minor_base     = DISPLAY_MINOR_BASE,
+};
+
+/* to prevent races between open() and disconnect(), probing, etc */
+static DEFINE_MUTEX(driver_lock);
+
+static int debug;
+
+/***  M O D U L E   C O D E ***/
+
+MODULE_AUTHOR(MOD_AUTHOR);
+MODULE_DESCRIPTION(MOD_DESC);
+MODULE_VERSION(MOD_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, imon_usb_id_table);
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)");
+
+static void free_imon_context(struct imon_context *context)
+{
+       struct device *dev = context->driver->dev;
+       usb_free_urb(context->tx_urb);
+       usb_free_urb(context->rx_urb);
+       lirc_buffer_free(context->driver->rbuf);
+       kfree(context->driver->rbuf);
+       kfree(context->driver);
+       kfree(context);
+
+       dev_dbg(dev, "%s: iMON context freed\n", __func__);
+}
+
+static void deregister_from_lirc(struct imon_context *context)
+{
+       int retval;
+       int minor = context->driver->minor;
+
+       retval = lirc_unregister_driver(minor);
+       if (retval)
+               err("%s: unable to deregister from lirc(%d)",
+                       __func__, retval);
+       else
+               printk(KERN_INFO MOD_NAME ": Deregistered iMON driver "
+                      "(minor:%d)\n", minor);
+
+}
+
+/**
+ * Called when the Display device (e.g. /dev/lcd0)
+ * is opened by the application.
+ */
+static int display_open(struct inode *inode, struct file *file)
+{
+       struct usb_interface *interface;
+       struct imon_context *context = NULL;
+       int subminor;
+       int retval = 0;
+
+       /* prevent races with disconnect */
+       mutex_lock(&driver_lock);
+
+       subminor = iminor(inode);
+       interface = usb_find_interface(&imon_driver, subminor);
+       if (!interface) {
+               err("%s: could not find interface for minor %d",
+                   __func__, subminor);
+               retval = -ENODEV;
+               goto exit;
+       }
+       context = usb_get_intfdata(interface);
+
+       if (!context) {
+               err("%s: no context found for minor %d",
+                                       __func__, subminor);
+               retval = -ENODEV;
+               goto exit;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       if (!context->display) {
+               err("%s: display not supported by device", __func__);
+               retval = -ENODEV;
+       } else if (context->display_isopen) {
+               err("%s: display port is already open", __func__);
+               retval = -EBUSY;
+       } else {
+               context->display_isopen = 1;
+               file->private_data = context;
+               dev_info(context->driver->dev, "display port opened\n");
+       }
+
+       mutex_unlock(&context->ctx_lock);
+
+exit:
+       mutex_unlock(&driver_lock);
+       return retval;
+}
+
+/**
+ * Called when the display device (e.g. /dev/lcd0)
+ * is closed by the application.
+ */
+static int display_close(struct inode *inode, struct file *file)
+{
+       struct imon_context *context = NULL;
+       int retval = 0;
+
+       context = file->private_data;
+
+       if (!context) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       if (!context->display) {
+               err("%s: display not supported by device", __func__);
+               retval = -ENODEV;
+       } else if (!context->display_isopen) {
+               err("%s: display is not open", __func__);
+               retval = -EIO;
+       } else {
+               context->display_isopen = 0;
+               dev_info(context->driver->dev, "display port closed\n");
+               if (!context->dev_present && !context->ir_isopen) {
+                       /*
+                        * Device disconnected before close and IR port is not
+                        * open. If IR port is open, context will be deleted by
+                        * ir_close.
+                        */
+                       mutex_unlock(&context->ctx_lock);
+                       free_imon_context(context);
+                       return retval;
+               }
+       }
+
+       mutex_unlock(&context->ctx_lock);
+       return retval;
+}
+
+/**
+ * Sends a packet to the device -- this function must be called
+ * with context->ctx_lock held.
+ */
+static int send_packet(struct imon_context *context)
+{
+       unsigned int pipe;
+       int interval = 0;
+       int retval = 0;
+
+       /* Check if we need to use control or interrupt urb */
+       pipe = usb_sndintpipe(context->usbdev,
+                             context->tx_endpoint->bEndpointAddress);
+       interval = context->tx_endpoint->bInterval;
+
+       usb_fill_int_urb(context->tx_urb, context->usbdev, pipe,
+                        context->usb_tx_buf,
+                        sizeof(context->usb_tx_buf),
+                        usb_tx_callback, context, interval);
+
+       context->tx_urb->actual_length = 0;
+
+       init_completion(&context->tx.finished);
+       atomic_set(&(context->tx.busy), 1);
+
+       retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
+       if (retval) {
+               atomic_set(&(context->tx.busy), 0);
+               err("%s: error submitting urb(%d)", __func__, retval);
+       } else {
+               /* Wait for transmission to complete (or abort) */
+               mutex_unlock(&context->ctx_lock);
+               retval = wait_for_completion_interruptible(
+                               &context->tx.finished);
+               if (retval)
+                       err("%s: task interrupted", __func__);
+               mutex_lock(&context->ctx_lock);
+
+               retval = context->tx.status;
+               if (retval)
+                       err("%s: packet tx failed (%d)", __func__, retval);
+       }
+
+       return retval;
+}
+
+/**
+ * Writes data to the VFD.  The iMON VFD is 2x16 characters
+ * and requires data in 5 consecutive USB interrupt packets,
+ * each packet but the last carrying 7 bytes.
+ *
+ * I don't know if the VFD board supports features such as
+ * scrolling, clearing rows, blanking, etc. so at
+ * the caller must provide a full screen of data.  If fewer
+ * than 32 bytes are provided spaces will be appended to
+ * generate a full screen.
+ */
+static ssize_t vfd_write(struct file *file, const char *buf,
+                        size_t n_bytes, loff_t *pos)
+{
+       int i;
+       int offset;
+       int seq;
+       int retval = 0;
+       struct imon_context *context;
+       const unsigned char vfd_packet6[] = {
+               0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
+       int *data_buf = NULL;
+
+       context = file->private_data;
+       if (!context) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       if (!context->dev_present) {
+               err("%s: no iMON device present", __func__);
+               retval = -ENODEV;
+               goto exit;
+       }
+
+       if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) {
+               err("%s: invalid payload size", __func__);
+               retval = -EINVAL;
+               goto exit;
+       }
+
+       data_buf = memdup_user(buf, n_bytes);
+       if (IS_ERR(data_buf)) {
+               retval = PTR_ERR(data_buf);
+               goto exit;
+       }
+
+       memcpy(context->tx.data_buf, data_buf, n_bytes);
+
+       /* Pad with spaces */
+       for (i = n_bytes; i < IMON_DATA_BUF_SZ - 3; ++i)
+               context->tx.data_buf[i] = ' ';
+
+       for (i = IMON_DATA_BUF_SZ - 3; i < IMON_DATA_BUF_SZ; ++i)
+               context->tx.data_buf[i] = 0xFF;
+
+       offset = 0;
+       seq = 0;
+
+       do {
+               memcpy(context->usb_tx_buf, context->tx.data_buf + offset, 7);
+               context->usb_tx_buf[7] = (unsigned char) seq;
+
+               retval = send_packet(context);
+               if (retval) {
+                       err("%s: send packet failed for packet #%d",
+                                       __func__, seq/2);
+                       goto exit;
+               } else {
+                       seq += 2;
+                       offset += 7;
+               }
+
+       } while (offset < IMON_DATA_BUF_SZ);
+
+       if (context->vfd_proto_6p) {
+               /* Send packet #6 */
+               memcpy(context->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6));
+               context->usb_tx_buf[7] = (unsigned char) seq;
+               retval = send_packet(context);
+               if (retval)
+                       err("%s: send packet failed for packet #%d",
+                                       __func__, seq/2);
+       }
+
+exit:
+       mutex_unlock(&context->ctx_lock);
+       kfree(data_buf);
+
+       return (!retval) ? n_bytes : retval;
+}
+
+/**
+ * Callback function for USB core API: transmit data
+ */
+static void usb_tx_callback(struct urb *urb)
+{
+       struct imon_context *context;
+
+       if (!urb)
+               return;
+       context = (struct imon_context *)urb->context;
+       if (!context)
+               return;
+
+       context->tx.status = urb->status;
+
+       /* notify waiters that write has finished */
+       atomic_set(&context->tx.busy, 0);
+       complete(&context->tx.finished);
+
+       return;
+}
+
+/**
+ * Called by lirc_dev when the application opens /dev/lirc
+ */
+static int ir_open(void *data)
+{
+       int retval = 0;
+       struct imon_context *context;
+
+       /* prevent races with disconnect */
+       mutex_lock(&driver_lock);
+
+       context = (struct imon_context *)data;
+
+       /* initial IR protocol decode variables */
+       context->rx.count = 0;
+       context->rx.initial_space = 1;
+       context->rx.prev_bit = 0;
+
+       context->ir_isopen = 1;
+       dev_info(context->driver->dev, "IR port opened\n");
+
+       mutex_unlock(&driver_lock);
+       return retval;
+}
+
+/**
+ * Called by lirc_dev when the application closes /dev/lirc
+ */
+static void ir_close(void *data)
+{
+       struct imon_context *context;
+
+       context = (struct imon_context *)data;
+       if (!context) {
+               err("%s: no context for device", __func__);
+               return;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       context->ir_isopen = 0;
+       dev_info(context->driver->dev, "IR port closed\n");
+
+       if (!context->dev_present) {
+               /*
+                * Device disconnected while IR port was still open. Driver
+                * was not deregistered at disconnect time, so do it now.
+                */
+               deregister_from_lirc(context);
+
+               if (!context->display_isopen) {
+                       mutex_unlock(&context->ctx_lock);
+                       free_imon_context(context);
+                       return;
+               }
+               /*
+                * If display port is open, context will be deleted by
+                * display_close
+                */
+       }
+
+       mutex_unlock(&context->ctx_lock);
+       return;
+}
+
+/**
+ * Convert bit count to time duration (in us) and submit
+ * the value to lirc_dev.
+ */
+static void submit_data(struct imon_context *context)
+{
+       unsigned char buf[4];
+       int value = context->rx.count;
+       int i;
+
+       dev_dbg(context->driver->dev, "submitting data to LIRC\n");
+
+       value *= BIT_DURATION;
+       value &= PULSE_MASK;
+       if (context->rx.prev_bit)
+               value |= PULSE_BIT;
+
+       for (i = 0; i < 4; ++i)
+               buf[i] = value>>(i*8);
+
+       lirc_buffer_write(context->driver->rbuf, buf);
+       wake_up(&context->driver->rbuf->wait_poll);
+       return;
+}
+
+static inline int tv2int(const struct timeval *a, const struct timeval *b)
+{
+       int usecs = 0;
+       int sec   = 0;
+
+       if (b->tv_usec > a->tv_usec) {
+               usecs = 1000000;
+               sec--;
+       }
+
+       usecs += a->tv_usec - b->tv_usec;
+
+       sec += a->tv_sec - b->tv_sec;
+       sec *= 1000;
+       usecs /= 1000;
+       sec += usecs;
+
+       if (sec < 0)
+               sec = 1000;
+
+       return sec;
+}
+
+/**
+ * Process the incoming packet
+ */
+static void imon_incoming_packet(struct imon_context *context,
+                                struct urb *urb, int intf)
+{
+       int len = urb->actual_length;
+       unsigned char *buf = urb->transfer_buffer;
+       struct device *dev = context->driver->dev;
+       int octet, bit;
+       unsigned char mask;
+       int i;
+
+       /*
+        * just bail out if no listening IR client
+        */
+       if (!context->ir_isopen)
+               return;
+
+       if (len != 8) {
+               dev_warn(dev, "imon %s: invalid incoming packet "
+                        "size (len = %d, intf%d)\n", __func__, len, intf);
+               return;
+       }
+
+       if (debug) {
+               printk(KERN_INFO "raw packet: ");
+               for (i = 0; i < len; ++i)
+                       printk("%02x ", buf[i]);
+               printk("\n");
+       }
+
+       /*
+        * Translate received data to pulse and space lengths.
+        * Received data is active low, i.e. pulses are 0 and
+        * spaces are 1.
+        *
+        * My original algorithm was essentially similar to
+        * Changwoo Ryu's with the exception that he switched
+        * the incoming bits to active high and also fed an
+        * initial space to LIRC at the start of a new sequence
+        * if the previous bit was a pulse.
+        *
+        * I've decided to adopt his algorithm.
+        */
+
+       if (buf[7] == 1 && context->rx.initial_space) {
+               /* LIRC requires a leading space */
+               context->rx.prev_bit = 0;
+               context->rx.count = 4;
+               submit_data(context);
+               context->rx.count = 0;
+       }
+
+       for (octet = 0; octet < 5; ++octet) {
+               mask = 0x80;
+               for (bit = 0; bit < 8; ++bit) {
+                       int curr_bit = !(buf[octet] & mask);
+                       if (curr_bit != context->rx.prev_bit) {
+                               if (context->rx.count) {
+                                       submit_data(context);
+                                       context->rx.count = 0;
+                               }
+                               context->rx.prev_bit = curr_bit;
+                       }
+                       ++context->rx.count;
+                       mask >>= 1;
+               }
+       }
+
+       if (buf[7] == 10) {
+               if (context->rx.count) {
+                       submit_data(context);
+                       context->rx.count = 0;
+               }
+               context->rx.initial_space = context->rx.prev_bit;
+       }
+}
+
+/**
+ * Callback function for USB core API: receive data
+ */
+static void usb_rx_callback(struct urb *urb)
+{
+       struct imon_context *context;
+       int intfnum = 0;
+
+       if (!urb)
+               return;
+
+       context = (struct imon_context *)urb->context;
+       if (!context)
+               return;
+
+       switch (urb->status) {
+       case -ENOENT:           /* usbcore unlink successful! */
+               return;
+
+       case 0:
+               imon_incoming_packet(context, urb, intfnum);
+               break;
+
+       default:
+               dev_warn(context->driver->dev, "imon %s: status(%d): ignored\n",
+                        __func__, urb->status);
+               break;
+       }
+
+       usb_submit_urb(context->rx_urb, GFP_ATOMIC);
+
+       return;
+}
+
+/**
+ * Callback function for USB core API: Probe
+ */
+static int imon_probe(struct usb_interface *interface,
+                     const struct usb_device_id *id)
+{
+       struct usb_device *usbdev = NULL;
+       struct usb_host_interface *iface_desc = NULL;
+       struct usb_endpoint_descriptor *rx_endpoint = NULL;
+       struct usb_endpoint_descriptor *tx_endpoint = NULL;
+       struct urb *rx_urb = NULL;
+       struct urb *tx_urb = NULL;
+       struct lirc_driver *driver = NULL;
+       struct lirc_buffer *rbuf = NULL;
+       struct device *dev = &interface->dev;
+       int ifnum;
+       int lirc_minor = 0;
+       int num_endpts;
+       int retval = 0;
+       int display_ep_found = 0;
+       int ir_ep_found = 0;
+       int alloc_status = 0;
+       int vfd_proto_6p = 0;
+       struct imon_context *context = NULL;
+       int i;
+       u16 vendor, product;
+
+       /* prevent races probing devices w/multiple interfaces */
+       mutex_lock(&driver_lock);
+
+       context = kzalloc(sizeof(struct imon_context), GFP_KERNEL);
+       if (!context) {
+               err("%s: kzalloc failed for context", __func__);
+               alloc_status = 1;
+               goto alloc_status_switch;
+       }
+
+       /*
+        * Try to auto-detect the type of display if the user hasn't set
+        * it by hand via the display_type modparam. Default is VFD.
+        */
+       if (usb_match_id(interface, ir_only_list))
+               context->display = 0;
+       else
+               context->display = 1;
+
+       usbdev     = usb_get_dev(interface_to_usbdev(interface));
+       iface_desc = interface->cur_altsetting;
+       num_endpts = iface_desc->desc.bNumEndpoints;
+       ifnum      = iface_desc->desc.bInterfaceNumber;
+       vendor     = le16_to_cpu(usbdev->descriptor.idVendor);
+       product    = le16_to_cpu(usbdev->descriptor.idProduct);
+
+       dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n",
+               __func__, vendor, product, ifnum);
+
+       /*
+        * Scan the endpoint list and set:
+        *      first input endpoint = IR endpoint
+        *      first output endpoint = display endpoint
+        */
+       for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) {
+               struct usb_endpoint_descriptor *ep;
+               int ep_dir;
+               int ep_type;
+               ep = &iface_desc->endpoint[i].desc;
+               ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+               ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+               if (!ir_ep_found &&
+                       ep_dir == USB_DIR_IN &&
+                       ep_type == USB_ENDPOINT_XFER_INT) {
+
+                       rx_endpoint = ep;
+                       ir_ep_found = 1;
+                       dev_dbg(dev, "%s: found IR endpoint\n", __func__);
+
+               } else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
+                          ep_type == USB_ENDPOINT_XFER_INT) {
+                       tx_endpoint = ep;
+                       display_ep_found = 1;
+                       dev_dbg(dev, "%s: found display endpoint\n", __func__);
+               }
+       }
+
+       /*
+        * Some iMON receivers have no display. Unfortunately, it seems
+        * that SoundGraph recycles device IDs between devices both with
+        * and without... :\
+        */
+       if (context->display == 0) {
+               display_ep_found = 0;
+               dev_dbg(dev, "%s: device has no display\n", __func__);
+       }
+
+       /* Input endpoint is mandatory */
+       if (!ir_ep_found) {
+               err("%s: no valid input (IR) endpoint found.", __func__);
+               retval = -ENODEV;
+               alloc_status = 2;
+               goto alloc_status_switch;
+       }
+
+       /* Determine if display requires 6 packets */
+       if (display_ep_found) {
+               if (usb_match_id(interface, vfd_proto_6p_list))
+                       vfd_proto_6p = 1;
+
+               dev_dbg(dev, "%s: vfd_proto_6p: %d\n",
+                       __func__, vfd_proto_6p);
+       }
+
+       driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+       if (!driver) {
+               err("%s: kzalloc failed for lirc_driver", __func__);
+               alloc_status = 2;
+               goto alloc_status_switch;
+       }
+       rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+       if (!rbuf) {
+               err("%s: kmalloc failed for lirc_buffer", __func__);
+               alloc_status = 3;
+               goto alloc_status_switch;
+       }
+       if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
+               err("%s: lirc_buffer_init failed", __func__);
+               alloc_status = 4;
+               goto alloc_status_switch;
+       }
+       rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!rx_urb) {
+               err("%s: usb_alloc_urb failed for IR urb", __func__);
+               alloc_status = 5;
+               goto alloc_status_switch;
+       }
+       tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!tx_urb) {
+               err("%s: usb_alloc_urb failed for display urb",
+                   __func__);
+               alloc_status = 6;
+               goto alloc_status_switch;
+       }
+
+       mutex_init(&context->ctx_lock);
+       context->vfd_proto_6p = vfd_proto_6p;
+
+       strcpy(driver->name, MOD_NAME);
+       driver->minor = -1;
+       driver->code_length = BUF_CHUNK_SIZE * 8;
+       driver->sample_rate = 0;
+       driver->features = LIRC_CAN_REC_MODE2;
+       driver->data = context;
+       driver->rbuf = rbuf;
+       driver->set_use_inc = ir_open;
+       driver->set_use_dec = ir_close;
+       driver->dev = &interface->dev;
+       driver->owner = THIS_MODULE;
+
+       mutex_lock(&context->ctx_lock);
+
+       context->driver = driver;
+       /* start out in keyboard mode */
+
+       lirc_minor = lirc_register_driver(driver);
+       if (lirc_minor < 0) {
+               err("%s: lirc_register_driver failed", __func__);
+               alloc_status = 7;
+               goto unlock;
+       } else
+               dev_info(dev, "Registered iMON driver "
+                        "(lirc minor: %d)\n", lirc_minor);
+
+       /* Needed while unregistering! */
+       driver->minor = lirc_minor;
+
+       context->usbdev = usbdev;
+       context->dev_present = 1;
+       context->rx_endpoint = rx_endpoint;
+       context->rx_urb = rx_urb;
+
+       /*
+        * tx is used to send characters to lcd/vfd, associate RF
+        * remotes, set IR protocol, and maybe more...
+        */
+       context->tx_endpoint = tx_endpoint;
+       context->tx_urb = tx_urb;
+
+       if (display_ep_found)
+               context->display = 1;
+
+       usb_fill_int_urb(context->rx_urb, context->usbdev,
+               usb_rcvintpipe(context->usbdev,
+                       context->rx_endpoint->bEndpointAddress),
+               context->usb_rx_buf, sizeof(context->usb_rx_buf),
+               usb_rx_callback, context,
+               context->rx_endpoint->bInterval);
+
+       retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
+
+       if (retval) {
+               err("%s: usb_submit_urb failed for intf0 (%d)",
+                   __func__, retval);
+               mutex_unlock(&context->ctx_lock);
+               goto exit;
+       }
+
+       usb_set_intfdata(interface, context);
+
+       if (context->display && ifnum == 0) {
+               dev_dbg(dev, "%s: Registering iMON display with sysfs\n",
+                       __func__);
+
+               if (usb_register_dev(interface, &imon_class)) {
+                       /* Not a fatal error, so ignore */
+                       dev_info(dev, "%s: could not get a minor number for "
+                                "display\n", __func__);
+               }
+       }
+
+       dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
+                "usb<%d:%d> initialized\n", vendor, product, ifnum,
+                usbdev->bus->busnum, usbdev->devnum);
+
+unlock:
+       mutex_unlock(&context->ctx_lock);
+alloc_status_switch:
+
+       switch (alloc_status) {
+       case 7:
+               usb_free_urb(tx_urb);
+       case 6:
+               usb_free_urb(rx_urb);
+       case 5:
+               if (rbuf)
+                       lirc_buffer_free(rbuf);
+       case 4:
+               kfree(rbuf);
+       case 3:
+               kfree(driver);
+       case 2:
+               kfree(context);
+               context = NULL;
+       case 1:
+               if (retval != -ENODEV)
+                       retval = -ENOMEM;
+               break;
+       case 0:
+               retval = 0;
+       }
+
+exit:
+       mutex_unlock(&driver_lock);
+
+       return retval;
+}
+
+/**
+ * Callback function for USB core API: disconnect
+ */
+static void imon_disconnect(struct usb_interface *interface)
+{
+       struct imon_context *context;
+       int ifnum;
+
+       /* prevent races with ir_open()/display_open() */
+       mutex_lock(&driver_lock);
+
+       context = usb_get_intfdata(interface);
+       ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
+
+       mutex_lock(&context->ctx_lock);
+
+       usb_set_intfdata(interface, NULL);
+
+       /* Abort ongoing write */
+       if (atomic_read(&context->tx.busy)) {
+               usb_kill_urb(context->tx_urb);
+               complete_all(&context->tx.finished);
+       }
+
+       context->dev_present = 0;
+       usb_kill_urb(context->rx_urb);
+       if (context->display)
+               usb_deregister_dev(interface, &imon_class);
+
+       if (!context->ir_isopen && !context->dev_present) {
+               deregister_from_lirc(context);
+               mutex_unlock(&context->ctx_lock);
+               if (!context->display_isopen)
+                       free_imon_context(context);
+       } else
+               mutex_unlock(&context->ctx_lock);
+
+       mutex_unlock(&driver_lock);
+
+       printk(KERN_INFO "%s: iMON device (intf%d) disconnected\n",
+              __func__, ifnum);
+}
+
+static int imon_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct imon_context *context = usb_get_intfdata(intf);
+
+       usb_kill_urb(context->rx_urb);
+
+       return 0;
+}
+
+static int imon_resume(struct usb_interface *intf)
+{
+       int rc = 0;
+       struct imon_context *context = usb_get_intfdata(intf);
+
+       usb_fill_int_urb(context->rx_urb, context->usbdev,
+               usb_rcvintpipe(context->usbdev,
+                       context->rx_endpoint->bEndpointAddress),
+               context->usb_rx_buf, sizeof(context->usb_rx_buf),
+               usb_rx_callback, context,
+               context->rx_endpoint->bInterval);
+
+       rc = usb_submit_urb(context->rx_urb, GFP_ATOMIC);
+
+       return rc;
+}
+
+static int __init imon_init(void)
+{
+       int rc;
+
+       printk(KERN_INFO MOD_NAME ": " MOD_DESC ", v" MOD_VERSION "\n");
+
+       rc = usb_register(&imon_driver);
+       if (rc) {
+               err("%s: usb register failed(%d)", __func__, rc);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void __exit imon_exit(void)
+{
+       usb_deregister(&imon_driver);
+       printk(KERN_INFO MOD_NAME ": module removed. Goodbye!\n");
+}
+
+module_init(imon_init);
+module_exit(imon_exit);
diff --git a/drivers/staging/media/lirc/lirc_parallel.c b/drivers/staging/media/lirc/lirc_parallel.c
new file mode 100644 (file)
index 0000000..792aac0
--- /dev/null
@@ -0,0 +1,755 @@
+/*
+ * lirc_parallel.c
+ *
+ * lirc_parallel - device driver for infra-red signal receiving and
+ *                 transmitting unit built by the author
+ *
+ * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*** Includes ***/
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+#include <asm/div64.h>
+
+#include <linux/poll.h>
+#include <linux/parport.h>
+#include <linux/platform_device.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#include "lirc_parallel.h"
+
+#define LIRC_DRIVER_NAME "lirc_parallel"
+
+#ifndef LIRC_IRQ
+#define LIRC_IRQ 7
+#endif
+#ifndef LIRC_PORT
+#define LIRC_PORT 0x378
+#endif
+#ifndef LIRC_TIMER
+#define LIRC_TIMER 65536
+#endif
+
+/*** Global Variables ***/
+
+static int debug;
+static int check_pselecd;
+
+unsigned int irq = LIRC_IRQ;
+unsigned int io = LIRC_PORT;
+#ifdef LIRC_TIMER
+unsigned int timer;
+unsigned int default_timer = LIRC_TIMER;
+#endif
+
+#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */
+
+static int rbuf[RBUF_SIZE];
+
+DECLARE_WAIT_QUEUE_HEAD(lirc_wait);
+
+unsigned int rptr;
+unsigned int wptr;
+unsigned int lost_irqs;
+int is_open;
+
+struct parport *pport;
+struct pardevice *ppdevice;
+int is_claimed;
+
+unsigned int tx_mask = 1;
+
+/*** Internal Functions ***/
+
+static unsigned int in(int offset)
+{
+       switch (offset) {
+       case LIRC_LP_BASE:
+               return parport_read_data(pport);
+       case LIRC_LP_STATUS:
+               return parport_read_status(pport);
+       case LIRC_LP_CONTROL:
+               return parport_read_control(pport);
+       }
+       return 0; /* make compiler happy */
+}
+
+static void out(int offset, int value)
+{
+       switch (offset) {
+       case LIRC_LP_BASE:
+               parport_write_data(pport, value);
+               break;
+       case LIRC_LP_CONTROL:
+               parport_write_control(pport, value);
+               break;
+       case LIRC_LP_STATUS:
+               printk(KERN_INFO "%s: attempt to write to status register\n",
+                      LIRC_DRIVER_NAME);
+               break;
+       }
+}
+
+static unsigned int lirc_get_timer(void)
+{
+       return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT;
+}
+
+static unsigned int lirc_get_signal(void)
+{
+       return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT;
+}
+
+static void lirc_on(void)
+{
+       out(LIRC_PORT_DATA, tx_mask);
+}
+
+static void lirc_off(void)
+{
+       out(LIRC_PORT_DATA, 0);
+}
+
+static unsigned int init_lirc_timer(void)
+{
+       struct timeval tv, now;
+       unsigned int level, newlevel, timeelapsed, newtimer;
+       int count = 0;
+
+       do_gettimeofday(&tv);
+       tv.tv_sec++;                     /* wait max. 1 sec. */
+       level = lirc_get_timer();
+       do {
+               newlevel = lirc_get_timer();
+               if (level == 0 && newlevel != 0)
+                       count++;
+               level = newlevel;
+               do_gettimeofday(&now);
+       } while (count < 1000 && (now.tv_sec < tv.tv_sec
+                            || (now.tv_sec == tv.tv_sec
+                                && now.tv_usec < tv.tv_usec)));
+
+       timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000
+                    + (now.tv_usec - tv.tv_usec));
+       if (count >= 1000 && timeelapsed > 0) {
+               if (default_timer == 0) {
+                       /* autodetect timer */
+                       newtimer = (1000000*count)/timeelapsed;
+                       printk(KERN_INFO "%s: %u Hz timer detected\n",
+                              LIRC_DRIVER_NAME, newtimer);
+                       return newtimer;
+               }  else {
+                       newtimer = (1000000*count)/timeelapsed;
+                       if (abs(newtimer - default_timer) > default_timer/10) {
+                               /* bad timer */
+                               printk(KERN_NOTICE "%s: bad timer: %u Hz\n",
+                                      LIRC_DRIVER_NAME, newtimer);
+                               printk(KERN_NOTICE "%s: using default timer: "
+                                      "%u Hz\n",
+                                      LIRC_DRIVER_NAME, default_timer);
+                               return default_timer;
+                       } else {
+                               printk(KERN_INFO "%s: %u Hz timer detected\n",
+                                      LIRC_DRIVER_NAME, newtimer);
+                               return newtimer; /* use detected value */
+                       }
+               }
+       } else {
+               printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME);
+               return 0;
+       }
+}
+
+static int lirc_claim(void)
+{
+       if (parport_claim(ppdevice) != 0) {
+               printk(KERN_WARNING "%s: could not claim port\n",
+                      LIRC_DRIVER_NAME);
+               printk(KERN_WARNING "%s: waiting for port becoming available"
+                      "\n", LIRC_DRIVER_NAME);
+               if (parport_claim_or_block(ppdevice) < 0) {
+                       printk(KERN_NOTICE "%s: could not claim port, giving"
+                              " up\n", LIRC_DRIVER_NAME);
+                       return 0;
+               }
+       }
+       out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
+       is_claimed = 1;
+       return 1;
+}
+
+/*** interrupt handler ***/
+
+static void rbuf_write(int signal)
+{
+       unsigned int nwptr;
+
+       nwptr = (wptr + 1) & (RBUF_SIZE - 1);
+       if (nwptr == rptr) {
+               /* no new signals will be accepted */
+               lost_irqs++;
+               printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME);
+               return;
+       }
+       rbuf[wptr] = signal;
+       wptr = nwptr;
+}
+
+static void irq_handler(void *blah)
+{
+       struct timeval tv;
+       static struct timeval lasttv;
+       static int init;
+       long signal;
+       int data;
+       unsigned int level, newlevel;
+       unsigned int timeout;
+
+       if (!is_open)
+               return;
+
+       if (!is_claimed)
+               return;
+
+#if 0
+       /* disable interrupt */
+         disable_irq(irq);
+         out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN));
+#endif
+       if (check_pselecd && (in(1) & LP_PSELECD))
+               return;
+
+#ifdef LIRC_TIMER
+       if (init) {
+               do_gettimeofday(&tv);
+
+               signal = tv.tv_sec - lasttv.tv_sec;
+               if (signal > 15)
+                       /* really long time */
+                       data = PULSE_MASK;
+               else
+                       data = (int) (signal*1000000 +
+                                        tv.tv_usec - lasttv.tv_usec +
+                                        LIRC_SFH506_DELAY);
+
+               rbuf_write(data); /* space */
+       } else {
+               if (timer == 0) {
+                       /*
+                        * wake up; we'll lose this signal, but it will be
+                        * garbage if the device is turned on anyway
+                        */
+                       timer = init_lirc_timer();
+                       /* enable_irq(irq); */
+                       return;
+               }
+               init = 1;
+       }
+
+       timeout = timer/10;     /* timeout after 1/10 sec. */
+       signal = 1;
+       level = lirc_get_timer();
+       do {
+               newlevel = lirc_get_timer();
+               if (level == 0 && newlevel != 0)
+                       signal++;
+               level = newlevel;
+
+               /* giving up */
+               if (signal > timeout
+                   || (check_pselecd && (in(1) & LP_PSELECD))) {
+                       signal = 0;
+                       printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME);
+                       break;
+               }
+       } while (lirc_get_signal());
+
+       if (signal != 0) {
+               /* adjust value to usecs */
+               __u64 helper;
+
+               helper = ((__u64) signal)*1000000;
+               do_div(helper, timer);
+               signal = (long) helper;
+
+               if (signal > LIRC_SFH506_DELAY)
+                       data = signal - LIRC_SFH506_DELAY;
+               else
+                       data = 1;
+               rbuf_write(PULSE_BIT|data); /* pulse */
+       }
+       do_gettimeofday(&lasttv);
+#else
+       /* add your code here */
+#endif
+
+       wake_up_interruptible(&lirc_wait);
+
+       /* enable interrupt */
+       /*
+         enable_irq(irq);
+         out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN);
+       */
+}
+
+/*** file operations ***/
+
+static loff_t lirc_lseek(struct file *filep, loff_t offset, int orig)
+{
+       return -ESPIPE;
+}
+
+static ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos)
+{
+       int result = 0;
+       int count = 0;
+       DECLARE_WAITQUEUE(wait, current);
+
+       if (n % sizeof(int))
+               return -EINVAL;
+
+       add_wait_queue(&lirc_wait, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+       while (count < n) {
+               if (rptr != wptr) {
+                       if (copy_to_user(buf+count, (char *) &rbuf[rptr],
+                                        sizeof(int))) {
+                               result = -EFAULT;
+                               break;
+                       }
+                       rptr = (rptr + 1) & (RBUF_SIZE - 1);
+                       count += sizeof(int);
+               } else {
+                       if (filep->f_flags & O_NONBLOCK) {
+                               result = -EAGAIN;
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               result = -ERESTARTSYS;
+                               break;
+                       }
+                       schedule();
+                       set_current_state(TASK_INTERRUPTIBLE);
+               }
+       }
+       remove_wait_queue(&lirc_wait, &wait);
+       set_current_state(TASK_RUNNING);
+       return count ? count : result;
+}
+
+static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
+                         loff_t *ppos)
+{
+       int count;
+       unsigned int i;
+       unsigned int level, newlevel;
+       unsigned long flags;
+       int counttimer;
+       int *wbuf;
+       ssize_t ret;
+
+       if (!is_claimed)
+               return -EBUSY;
+
+       count = n / sizeof(int);
+
+       if (n % sizeof(int) || count % 2 == 0)
+               return -EINVAL;
+
+       wbuf = memdup_user(buf, n);
+       if (IS_ERR(wbuf))
+               return PTR_ERR(wbuf);
+
+#ifdef LIRC_TIMER
+       if (timer == 0) {
+               /* try again if device is ready */
+               timer = init_lirc_timer();
+               if (timer == 0) {
+                       ret = -EIO;
+                       goto out;
+               }
+       }
+
+       /* adjust values from usecs */
+       for (i = 0; i < count; i++) {
+               __u64 helper;
+
+               helper = ((__u64) wbuf[i])*timer;
+               do_div(helper, 1000000);
+               wbuf[i] = (int) helper;
+       }
+
+       local_irq_save(flags);
+       i = 0;
+       while (i < count) {
+               level = lirc_get_timer();
+               counttimer = 0;
+               lirc_on();
+               do {
+                       newlevel = lirc_get_timer();
+                       if (level == 0 && newlevel != 0)
+                               counttimer++;
+                       level = newlevel;
+                       if (check_pselecd && (in(1) & LP_PSELECD)) {
+                               lirc_off();
+                               local_irq_restore(flags);
+                               ret = -EIO;
+                               goto out;
+                       }
+               } while (counttimer < wbuf[i]);
+               i++;
+
+               lirc_off();
+               if (i == count)
+                       break;
+               counttimer = 0;
+               do {
+                       newlevel = lirc_get_timer();
+                       if (level == 0 && newlevel != 0)
+                               counttimer++;
+                       level = newlevel;
+                       if (check_pselecd && (in(1) & LP_PSELECD)) {
+                               local_irq_restore(flags);
+                               ret = -EIO;
+                               goto out;
+                       }
+               } while (counttimer < wbuf[i]);
+               i++;
+       }
+       local_irq_restore(flags);
+#else
+       /* place code that handles write without external timer here */
+#endif
+       ret = n;
+out:
+       kfree(wbuf);
+
+       return ret;
+}
+
+static unsigned int lirc_poll(struct file *file, poll_table *wait)
+{
+       poll_wait(file, &lirc_wait, wait);
+       if (rptr != wptr)
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+       int result;
+       __u32 features = LIRC_CAN_SET_TRANSMITTER_MASK |
+                        LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
+       __u32 mode;
+       __u32 value;
+
+       switch (cmd) {
+       case LIRC_GET_FEATURES:
+               result = put_user(features, (__u32 *) arg);
+               if (result)
+                       return result;
+               break;
+       case LIRC_GET_SEND_MODE:
+               result = put_user(LIRC_MODE_PULSE, (__u32 *) arg);
+               if (result)
+                       return result;
+               break;
+       case LIRC_GET_REC_MODE:
+               result = put_user(LIRC_MODE_MODE2, (__u32 *) arg);
+               if (result)
+                       return result;
+               break;
+       case LIRC_SET_SEND_MODE:
+               result = get_user(mode, (__u32 *) arg);
+               if (result)
+                       return result;
+               if (mode != LIRC_MODE_PULSE)
+                       return -EINVAL;
+               break;
+       case LIRC_SET_REC_MODE:
+               result = get_user(mode, (__u32 *) arg);
+               if (result)
+                       return result;
+               if (mode != LIRC_MODE_MODE2)
+                       return -ENOSYS;
+               break;
+       case LIRC_SET_TRANSMITTER_MASK:
+               result = get_user(value, (__u32 *) arg);
+               if (result)
+                       return result;
+               if ((value & LIRC_PARALLEL_TRANSMITTER_MASK) != value)
+                       return LIRC_PARALLEL_MAX_TRANSMITTERS;
+               tx_mask = value;
+               break;
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static int lirc_open(struct inode *node, struct file *filep)
+{
+       if (is_open || !lirc_claim())
+               return -EBUSY;
+
+       parport_enable_irq(pport);
+
+       /* init read ptr */
+       rptr = 0;
+       wptr = 0;
+       lost_irqs = 0;
+
+       is_open = 1;
+       return 0;
+}
+
+static int lirc_close(struct inode *node, struct file *filep)
+{
+       if (is_claimed) {
+               is_claimed = 0;
+               parport_release(ppdevice);
+       }
+       is_open = 0;
+       return 0;
+}
+
+static const struct file_operations lirc_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = lirc_lseek,
+       .read           = lirc_read,
+       .write          = lirc_write,
+       .poll           = lirc_poll,
+       .unlocked_ioctl = lirc_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = lirc_ioctl,
+#endif
+       .open           = lirc_open,
+       .release        = lirc_close
+};
+
+static int set_use_inc(void *data)
+{
+       return 0;
+}
+
+static void set_use_dec(void *data)
+{
+}
+
+static struct lirc_driver driver = {
+       .name           = LIRC_DRIVER_NAME,
+       .minor          = -1,
+       .code_length    = 1,
+       .sample_rate    = 0,
+       .data           = NULL,
+       .add_to_buf     = NULL,
+       .set_use_inc    = set_use_inc,
+       .set_use_dec    = set_use_dec,
+       .fops           = &lirc_fops,
+       .dev            = NULL,
+       .owner          = THIS_MODULE,
+};
+
+static struct platform_device *lirc_parallel_dev;
+
+static int __devinit lirc_parallel_probe(struct platform_device *dev)
+{
+       return 0;
+}
+
+static int __devexit lirc_parallel_remove(struct platform_device *dev)
+{
+       return 0;
+}
+
+static int lirc_parallel_suspend(struct platform_device *dev,
+                                       pm_message_t state)
+{
+       return 0;
+}
+
+static int lirc_parallel_resume(struct platform_device *dev)
+{
+       return 0;
+}
+
+static struct platform_driver lirc_parallel_driver = {
+       .probe  = lirc_parallel_probe,
+       .remove = __devexit_p(lirc_parallel_remove),
+       .suspend        = lirc_parallel_suspend,
+       .resume = lirc_parallel_resume,
+       .driver = {
+               .name   = LIRC_DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int pf(void *handle)
+{
+       parport_disable_irq(pport);
+       is_claimed = 0;
+       return 0;
+}
+
+static void kf(void *handle)
+{
+       if (!is_open)
+               return;
+       if (!lirc_claim())
+               return;
+       parport_enable_irq(pport);
+       lirc_off();
+       /* this is a bit annoying when you actually print...*/
+       /*
+       printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME);
+       */
+}
+
+/*** module initialization and cleanup ***/
+
+static int __init lirc_parallel_init(void)
+{
+       int result;
+
+       result = platform_driver_register(&lirc_parallel_driver);
+       if (result) {
+               printk(KERN_NOTICE "platform_driver_register"
+                                       " returned %d\n", result);
+               return result;
+       }
+
+       lirc_parallel_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
+       if (!lirc_parallel_dev) {
+               result = -ENOMEM;
+               goto exit_driver_unregister;
+       }
+
+       result = platform_device_add(lirc_parallel_dev);
+       if (result)
+               goto exit_device_put;
+
+       pport = parport_find_base(io);
+       if (pport == NULL) {
+               printk(KERN_NOTICE "%s: no port at %x found\n",
+                      LIRC_DRIVER_NAME, io);
+               result = -ENXIO;
+               goto exit_device_put;
+       }
+       ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME,
+                                          pf, kf, irq_handler, 0, NULL);
+       parport_put_port(pport);
+       if (ppdevice == NULL) {
+               printk(KERN_NOTICE "%s: parport_register_device() failed\n",
+                      LIRC_DRIVER_NAME);
+               result = -ENXIO;
+               goto exit_device_put;
+       }
+       if (parport_claim(ppdevice) != 0)
+               goto skip_init;
+       is_claimed = 1;
+       out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP);
+
+#ifdef LIRC_TIMER
+       if (debug)
+               out(LIRC_PORT_DATA, tx_mask);
+
+       timer = init_lirc_timer();
+
+#if 0  /* continue even if device is offline */
+       if (timer == 0) {
+               is_claimed = 0;
+               parport_release(pport);
+               parport_unregister_device(ppdevice);
+               result = -EIO;
+               goto exit_device_put;
+       }
+
+#endif
+       if (debug)
+               out(LIRC_PORT_DATA, 0);
+#endif
+
+       is_claimed = 0;
+       parport_release(ppdevice);
+ skip_init:
+       driver.dev = &lirc_parallel_dev->dev;
+       driver.minor = lirc_register_driver(&driver);
+       if (driver.minor < 0) {
+               printk(KERN_NOTICE "%s: register_chrdev() failed\n",
+                      LIRC_DRIVER_NAME);
+               parport_unregister_device(ppdevice);
+               result = -EIO;
+               goto exit_device_put;
+       }
+       printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n",
+              LIRC_DRIVER_NAME, io, irq);
+       return 0;
+
+exit_device_put:
+       platform_device_put(lirc_parallel_dev);
+exit_driver_unregister:
+       platform_driver_unregister(&lirc_parallel_driver);
+       return result;
+}
+
+static void __exit lirc_parallel_exit(void)
+{
+       parport_unregister_device(ppdevice);
+       lirc_unregister_driver(driver.minor);
+
+       platform_device_unregister(lirc_parallel_dev);
+       platform_driver_unregister(&lirc_parallel_driver);
+}
+
+module_init(lirc_parallel_init);
+module_exit(lirc_parallel_exit);
+
+MODULE_DESCRIPTION("Infrared receiver driver for parallel ports.");
+MODULE_AUTHOR("Christoph Bartelmus");
+MODULE_LICENSE("GPL");
+
+module_param(io, int, S_IRUGO);
+MODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)");
+
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (7 or 5)");
+
+module_param(tx_mask, int, S_IRUGO);
+MODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
+
+module_param(check_pselecd, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Check for printer (default: 0)");
diff --git a/drivers/staging/media/lirc/lirc_parallel.h b/drivers/staging/media/lirc/lirc_parallel.h
new file mode 100644 (file)
index 0000000..4bed6af
--- /dev/null
@@ -0,0 +1,26 @@
+/* lirc_parallel.h */
+
+#ifndef _LIRC_PARALLEL_H
+#define _LIRC_PARALLEL_H
+
+#include <linux/lp.h>
+
+#define LIRC_PORT_LEN 3
+
+#define LIRC_LP_BASE    0
+#define LIRC_LP_STATUS  1
+#define LIRC_LP_CONTROL 2
+
+#define LIRC_PORT_DATA           LIRC_LP_BASE    /* base */
+#define LIRC_PORT_TIMER        LIRC_LP_STATUS    /* status port */
+#define LIRC_PORT_TIMER_BIT          LP_PBUSY    /* busy signal */
+#define LIRC_PORT_SIGNAL       LIRC_LP_STATUS    /* status port */
+#define LIRC_PORT_SIGNAL_BIT          LP_PACK    /* ack signal */
+#define LIRC_PORT_IRQ         LIRC_LP_CONTROL    /* control port */
+
+#define LIRC_SFH506_DELAY 0             /* delay t_phl in usecs */
+
+#define LIRC_PARALLEL_MAX_TRANSMITTERS 8
+#define LIRC_PARALLEL_TRANSMITTER_MASK ((1<<LIRC_PARALLEL_MAX_TRANSMITTERS) - 1)
+
+#endif
diff --git a/drivers/staging/media/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c
new file mode 100644 (file)
index 0000000..a2d18b0
--- /dev/null
@@ -0,0 +1,939 @@
+/*
+ * lirc_sasem.c - USB remote support for LIRC
+ * Version 0.5
+ *
+ * Copyright (C) 2004-2005 Oliver Stabel <oliver.stabel@gmx.de>
+ *                      Tim Davies <tim@opensystems.net.au>
+ *
+ * This driver was derived from:
+ *   Venky Raju <dev@venky.ws>
+ *      "lirc_imon - "LIRC/VFD driver for Ahanix/Soundgraph IMON IR/VFD"
+ *   Paul Miller <pmiller9@users.sourceforge.net>'s 2003-2004
+ *      "lirc_atiusb - USB remote support for LIRC"
+ *   Culver Consulting Services <henry@culcon.com>'s 2003
+ *      "Sasem OnAir VFD/IR USB driver"
+ *
+ *
+ * NOTE - The LCDproc iMon driver should work with this module.  More info at
+ *     http://www.frogstorm.info/sasem
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+
+#define MOD_AUTHOR     "Oliver Stabel <oliver.stabel@gmx.de>, " \
+                       "Tim Davies <tim@opensystems.net.au>"
+#define MOD_DESC       "USB Driver for Sasem Remote Controller V1.1"
+#define MOD_NAME       "lirc_sasem"
+#define MOD_VERSION    "0.5"
+
+#define VFD_MINOR_BASE 144     /* Same as LCD */
+#define DEVICE_NAME    "lcd%d"
+
+#define BUF_CHUNK_SIZE 8
+#define BUF_SIZE       128
+
+#define IOCTL_LCD_CONTRAST 1
+
+/*** P R O T O T Y P E S ***/
+
+/* USB Callback prototypes */
+static int sasem_probe(struct usb_interface *interface,
+                       const struct usb_device_id *id);
+static void sasem_disconnect(struct usb_interface *interface);
+static void usb_rx_callback(struct urb *urb);
+static void usb_tx_callback(struct urb *urb);
+
+/* VFD file_operations function prototypes */
+static int vfd_open(struct inode *inode, struct file *file);
+static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg);
+static int vfd_close(struct inode *inode, struct file *file);
+static ssize_t vfd_write(struct file *file, const char *buf,
+                               size_t n_bytes, loff_t *pos);
+
+/* LIRC driver function prototypes */
+static int ir_open(void *data);
+static void ir_close(void *data);
+
+/* Driver init/exit prototypes */
+static int __init sasem_init(void);
+static void __exit sasem_exit(void);
+
+/*** G L O B A L S ***/
+#define SASEM_DATA_BUF_SZ      32
+
+struct sasem_context {
+
+       struct usb_device *dev;
+       int vfd_isopen;                 /* VFD port has been opened       */
+       unsigned int vfd_contrast;      /* VFD contrast            */
+       int ir_isopen;                  /* IR port has been opened      */
+       int dev_present;                /* USB device presence      */
+       struct mutex ctx_lock;          /* to lock this object      */
+       wait_queue_head_t remove_ok;    /* For unexpected USB disconnects */
+
+       struct lirc_driver *driver;
+       struct usb_endpoint_descriptor *rx_endpoint;
+       struct usb_endpoint_descriptor *tx_endpoint;
+       struct urb *rx_urb;
+       struct urb *tx_urb;
+       unsigned char usb_rx_buf[8];
+       unsigned char usb_tx_buf[8];
+
+       struct tx_t {
+               unsigned char data_buf[SASEM_DATA_BUF_SZ]; /* user data buffer */
+               struct completion finished;  /* wait for write to finish  */
+               atomic_t busy;               /* write in progress        */
+               int status;                  /* status of tx completion   */
+       } tx;
+
+       /* for dealing with repeat codes (wish there was a toggle bit!) */
+       struct timeval presstime;
+       char lastcode[8];
+       int codesaved;
+};
+
+/* VFD file operations */
+static const struct file_operations vfd_fops = {
+       .owner          = THIS_MODULE,
+       .open           = &vfd_open,
+       .write          = &vfd_write,
+       .unlocked_ioctl = &vfd_ioctl,
+       .release        = &vfd_close,
+       .llseek         = noop_llseek,
+};
+
+/* USB Device ID for Sasem USB Control Board */
+static struct usb_device_id sasem_usb_id_table[] = {
+       /* Sasem USB Control Board */
+       { USB_DEVICE(0x11ba, 0x0101) },
+       /* Terminating entry */
+       {}
+};
+
+/* USB Device data */
+static struct usb_driver sasem_driver = {
+       .name           = MOD_NAME,
+       .probe          = sasem_probe,
+       .disconnect     = sasem_disconnect,
+       .id_table       = sasem_usb_id_table,
+};
+
+static struct usb_class_driver sasem_class = {
+       .name           = DEVICE_NAME,
+       .fops           = &vfd_fops,
+       .minor_base     = VFD_MINOR_BASE,
+};
+
+/* to prevent races between open() and disconnect() */
+static DEFINE_MUTEX(disconnect_lock);
+
+static int debug;
+
+
+/*** M O D U L E   C O D E ***/
+
+MODULE_AUTHOR(MOD_AUTHOR);
+MODULE_DESCRIPTION(MOD_DESC);
+MODULE_LICENSE("GPL");
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)");
+
+static void delete_context(struct sasem_context *context)
+{
+       usb_free_urb(context->tx_urb);  /* VFD */
+       usb_free_urb(context->rx_urb);  /* IR */
+       lirc_buffer_free(context->driver->rbuf);
+       kfree(context->driver->rbuf);
+       kfree(context->driver);
+       kfree(context);
+
+       if (debug)
+               printk(KERN_INFO "%s: context deleted\n", __func__);
+}
+
+static void deregister_from_lirc(struct sasem_context *context)
+{
+       int retval;
+       int minor = context->driver->minor;
+
+       retval = lirc_unregister_driver(minor);
+       if (retval)
+               err("%s: unable to deregister from lirc (%d)",
+                       __func__, retval);
+       else
+               printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n",
+                      minor);
+
+}
+
+/**
+ * Called when the VFD device (e.g. /dev/usb/lcd)
+ * is opened by the application.
+ */
+static int vfd_open(struct inode *inode, struct file *file)
+{
+       struct usb_interface *interface;
+       struct sasem_context *context = NULL;
+       int subminor;
+       int retval = 0;
+
+       /* prevent races with disconnect */
+       mutex_lock(&disconnect_lock);
+
+       subminor = iminor(inode);
+       interface = usb_find_interface(&sasem_driver, subminor);
+       if (!interface) {
+               err("%s: could not find interface for minor %d",
+                   __func__, subminor);
+               retval = -ENODEV;
+               goto exit;
+       }
+       context = usb_get_intfdata(interface);
+
+       if (!context) {
+               err("%s: no context found for minor %d",
+                                       __func__, subminor);
+               retval = -ENODEV;
+               goto exit;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       if (context->vfd_isopen) {
+               err("%s: VFD port is already open", __func__);
+               retval = -EBUSY;
+       } else {
+               context->vfd_isopen = 1;
+               file->private_data = context;
+               printk(KERN_INFO "VFD port opened\n");
+       }
+
+       mutex_unlock(&context->ctx_lock);
+
+exit:
+       mutex_unlock(&disconnect_lock);
+       return retval;
+}
+
+/**
+ * Called when the VFD device (e.g. /dev/usb/lcd)
+ * is closed by the application.
+ */
+static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+       struct sasem_context *context = NULL;
+
+       context = (struct sasem_context *) file->private_data;
+
+       if (!context) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       switch (cmd) {
+       case IOCTL_LCD_CONTRAST:
+               if (arg > 1000)
+                       arg = 1000;
+               context->vfd_contrast = (unsigned int)arg;
+               break;
+       default:
+               printk(KERN_INFO "Unknown IOCTL command\n");
+               mutex_unlock(&context->ctx_lock);
+               return -ENOIOCTLCMD;  /* not supported */
+       }
+
+       mutex_unlock(&context->ctx_lock);
+       return 0;
+}
+
+/**
+ * Called when the VFD device (e.g. /dev/usb/lcd)
+ * is closed by the application.
+ */
+static int vfd_close(struct inode *inode, struct file *file)
+{
+       struct sasem_context *context = NULL;
+       int retval = 0;
+
+       context = (struct sasem_context *) file->private_data;
+
+       if (!context) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       if (!context->vfd_isopen) {
+               err("%s: VFD is not open", __func__);
+               retval = -EIO;
+       } else {
+               context->vfd_isopen = 0;
+               printk(KERN_INFO "VFD port closed\n");
+               if (!context->dev_present && !context->ir_isopen) {
+
+                       /* Device disconnected before close and IR port is
+                        * not open. If IR port is open, context will be
+                        * deleted by ir_close. */
+                       mutex_unlock(&context->ctx_lock);
+                       delete_context(context);
+                       return retval;
+               }
+       }
+
+       mutex_unlock(&context->ctx_lock);
+       return retval;
+}
+
+/**
+ * Sends a packet to the VFD.
+ */
+static int send_packet(struct sasem_context *context)
+{
+       unsigned int pipe;
+       int interval = 0;
+       int retval = 0;
+
+       pipe = usb_sndintpipe(context->dev,
+                       context->tx_endpoint->bEndpointAddress);
+       interval = context->tx_endpoint->bInterval;
+
+       usb_fill_int_urb(context->tx_urb, context->dev, pipe,
+               context->usb_tx_buf, sizeof(context->usb_tx_buf),
+               usb_tx_callback, context, interval);
+
+       context->tx_urb->actual_length = 0;
+
+       init_completion(&context->tx.finished);
+       atomic_set(&(context->tx.busy), 1);
+
+       retval =  usb_submit_urb(context->tx_urb, GFP_KERNEL);
+       if (retval) {
+               atomic_set(&(context->tx.busy), 0);
+               err("%s: error submitting urb (%d)", __func__, retval);
+       } else {
+               /* Wait for transmission to complete (or abort) */
+               mutex_unlock(&context->ctx_lock);
+               wait_for_completion(&context->tx.finished);
+               mutex_lock(&context->ctx_lock);
+
+               retval = context->tx.status;
+               if (retval)
+                       err("%s: packet tx failed (%d)", __func__, retval);
+       }
+
+       return retval;
+}
+
+/**
+ * Writes data to the VFD.  The Sasem VFD is 2x16 characters
+ * and requires data in 9 consecutive USB interrupt packets,
+ * each packet carrying 8 bytes.
+ */
+static ssize_t vfd_write(struct file *file, const char *buf,
+                               size_t n_bytes, loff_t *pos)
+{
+       int i;
+       int retval = 0;
+       struct sasem_context *context;
+       int *data_buf = NULL;
+
+       context = (struct sasem_context *) file->private_data;
+       if (!context) {
+               err("%s: no context for device", __func__);
+               return -ENODEV;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       if (!context->dev_present) {
+               err("%s: no Sasem device present", __func__);
+               retval = -ENODEV;
+               goto exit;
+       }
+
+       if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) {
+               err("%s: invalid payload size", __func__);
+               retval = -EINVAL;
+               goto exit;
+       }
+
+       data_buf = memdup_user(buf, n_bytes);
+       if (IS_ERR(data_buf)) {
+               retval = PTR_ERR(data_buf);
+               goto exit;
+       }
+
+       memcpy(context->tx.data_buf, data_buf, n_bytes);
+
+       /* Pad with spaces */
+       for (i = n_bytes; i < SASEM_DATA_BUF_SZ; ++i)
+               context->tx.data_buf[i] = ' ';
+
+       /* Nine 8 byte packets to be sent */
+       /* NOTE: "\x07\x01\0\0\0\0\0\0" or "\x0c\0\0\0\0\0\0\0"
+        *       will clear the VFD */
+       for (i = 0; i < 9; i++) {
+               switch (i) {
+               case 0:
+                       memcpy(context->usb_tx_buf, "\x07\0\0\0\0\0\0\0", 8);
+                       context->usb_tx_buf[1] = (context->vfd_contrast) ?
+                               (0x2B - (context->vfd_contrast - 1) / 250)
+                               : 0x2B;
+                       break;
+               case 1:
+                       memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8);
+                       break;
+               case 2:
+                       memcpy(context->usb_tx_buf, "\x0b\x01\0\0\0\0\0\0", 8);
+                       break;
+               case 3:
+                       memcpy(context->usb_tx_buf, context->tx.data_buf, 8);
+                       break;
+               case 4:
+                       memcpy(context->usb_tx_buf,
+                              context->tx.data_buf + 8, 8);
+                       break;
+               case 5:
+                       memcpy(context->usb_tx_buf, "\x09\x01\0\0\0\0\0\0", 8);
+                       break;
+               case 6:
+                       memcpy(context->usb_tx_buf, "\x0b\x02\0\0\0\0\0\0", 8);
+                       break;
+               case 7:
+                       memcpy(context->usb_tx_buf,
+                              context->tx.data_buf + 16, 8);
+                       break;
+               case 8:
+                       memcpy(context->usb_tx_buf,
+                              context->tx.data_buf + 24, 8);
+                       break;
+               }
+               retval = send_packet(context);
+               if (retval) {
+
+                       err("%s: send packet failed for packet #%d",
+                                       __func__, i);
+                       goto exit;
+               }
+       }
+exit:
+
+       mutex_unlock(&context->ctx_lock);
+       kfree(data_buf);
+
+       return (!retval) ? n_bytes : retval;
+}
+
+/**
+ * Callback function for USB core API: transmit data
+ */
+static void usb_tx_callback(struct urb *urb)
+{
+       struct sasem_context *context;
+
+       if (!urb)
+               return;
+       context = (struct sasem_context *) urb->context;
+       if (!context)
+               return;
+
+       context->tx.status = urb->status;
+
+       /* notify waiters that write has finished */
+       atomic_set(&context->tx.busy, 0);
+       complete(&context->tx.finished);
+
+       return;
+}
+
+/**
+ * Called by lirc_dev when the application opens /dev/lirc
+ */
+static int ir_open(void *data)
+{
+       int retval = 0;
+       struct sasem_context *context;
+
+       /* prevent races with disconnect */
+       mutex_lock(&disconnect_lock);
+
+       context = (struct sasem_context *) data;
+
+       mutex_lock(&context->ctx_lock);
+
+       if (context->ir_isopen) {
+               err("%s: IR port is already open", __func__);
+               retval = -EBUSY;
+               goto exit;
+       }
+
+       usb_fill_int_urb(context->rx_urb, context->dev,
+               usb_rcvintpipe(context->dev,
+                               context->rx_endpoint->bEndpointAddress),
+               context->usb_rx_buf, sizeof(context->usb_rx_buf),
+               usb_rx_callback, context, context->rx_endpoint->bInterval);
+
+       retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
+
+       if (retval)
+               err("%s: usb_submit_urb failed for ir_open (%d)",
+                   __func__, retval);
+       else {
+               context->ir_isopen = 1;
+               printk(KERN_INFO "IR port opened\n");
+       }
+
+exit:
+       mutex_unlock(&context->ctx_lock);
+
+       mutex_unlock(&disconnect_lock);
+       return retval;
+}
+
+/**
+ * Called by lirc_dev when the application closes /dev/lirc
+ */
+static void ir_close(void *data)
+{
+       struct sasem_context *context;
+
+       context = (struct sasem_context *)data;
+       if (!context) {
+               err("%s: no context for device", __func__);
+               return;
+       }
+
+       mutex_lock(&context->ctx_lock);
+
+       usb_kill_urb(context->rx_urb);
+       context->ir_isopen = 0;
+       printk(KERN_INFO "IR port closed\n");
+
+       if (!context->dev_present) {
+
+               /*
+                * Device disconnected while IR port was
+                * still open. Driver was not deregistered
+                * at disconnect time, so do it now.
+                */
+               deregister_from_lirc(context);
+
+               if (!context->vfd_isopen) {
+
+                       mutex_unlock(&context->ctx_lock);
+                       delete_context(context);
+                       return;
+               }
+               /* If VFD port is open, context will be deleted by vfd_close */
+       }
+
+       mutex_unlock(&context->ctx_lock);
+       return;
+}
+
+/**
+ * Process the incoming packet
+ */
+static void incoming_packet(struct sasem_context *context,
+                                  struct urb *urb)
+{
+       int len = urb->actual_length;
+       unsigned char *buf = urb->transfer_buffer;
+       long ms;
+       struct timeval tv;
+       int i;
+
+       if (len != 8) {
+               printk(KERN_WARNING "%s: invalid incoming packet size (%d)\n",
+                    __func__, len);
+               return;
+       }
+
+       if (debug) {
+               printk(KERN_INFO "Incoming data: ");
+               for (i = 0; i < 8; ++i)
+                       printk(KERN_CONT "%02x ", buf[i]);
+               printk(KERN_CONT "\n");
+       }
+
+       /*
+        * Lirc could deal with the repeat code, but we really need to block it
+        * if it arrives too late.  Otherwise we could repeat the wrong code.
+        */
+
+       /* get the time since the last button press */
+       do_gettimeofday(&tv);
+       ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 +
+            (tv.tv_usec - context->presstime.tv_usec) / 1000;
+
+       if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) {
+               /*
+                * the repeat code is being sent, so we copy
+                * the old code to LIRC
+                */
+
+               /*
+                * NOTE: Only if the last code was less than 250ms ago
+                * - no one should be able to push another (undetected) button
+                *   in that time and then get a false repeat of the previous
+                *   press but it is long enough for a genuine repeat
+                */
+               if ((ms < 250) && (context->codesaved != 0)) {
+                       memcpy(buf, &context->lastcode, 8);
+                       context->presstime.tv_sec = tv.tv_sec;
+                       context->presstime.tv_usec = tv.tv_usec;
+               }
+       } else {
+               /* save the current valid code for repeats */
+               memcpy(&context->lastcode, buf, 8);
+               /*
+                * set flag to signal a valid code was save;
+                * just for safety reasons
+                */
+               context->codesaved = 1;
+               context->presstime.tv_sec = tv.tv_sec;
+               context->presstime.tv_usec = tv.tv_usec;
+       }
+
+       lirc_buffer_write(context->driver->rbuf, buf);
+       wake_up(&context->driver->rbuf->wait_poll);
+}
+
+/**
+ * Callback function for USB core API: receive data
+ */
+static void usb_rx_callback(struct urb *urb)
+{
+       struct sasem_context *context;
+
+       if (!urb)
+               return;
+       context = (struct sasem_context *) urb->context;
+       if (!context)
+               return;
+
+       switch (urb->status) {
+
+       case -ENOENT:           /* usbcore unlink successful! */
+               return;
+
+       case 0:
+               if (context->ir_isopen)
+                       incoming_packet(context, urb);
+               break;
+
+       default:
+               printk(KERN_WARNING "%s: status (%d): ignored",
+                        __func__, urb->status);
+               break;
+       }
+
+       usb_submit_urb(context->rx_urb, GFP_ATOMIC);
+       return;
+}
+
+
+
+/**
+ * Callback function for USB core API: Probe
+ */
+static int sasem_probe(struct usb_interface *interface,
+                       const struct usb_device_id *id)
+{
+       struct usb_device *dev = NULL;
+       struct usb_host_interface *iface_desc = NULL;
+       struct usb_endpoint_descriptor *rx_endpoint = NULL;
+       struct usb_endpoint_descriptor *tx_endpoint = NULL;
+       struct urb *rx_urb = NULL;
+       struct urb *tx_urb = NULL;
+       struct lirc_driver *driver = NULL;
+       struct lirc_buffer *rbuf = NULL;
+       int lirc_minor = 0;
+       int num_endpoints;
+       int retval = 0;
+       int vfd_ep_found;
+       int ir_ep_found;
+       int alloc_status;
+       struct sasem_context *context = NULL;
+       int i;
+
+       printk(KERN_INFO "%s: found Sasem device\n", __func__);
+
+
+       dev = usb_get_dev(interface_to_usbdev(interface));
+       iface_desc = interface->cur_altsetting;
+       num_endpoints = iface_desc->desc.bNumEndpoints;
+
+       /*
+        * Scan the endpoint list and set:
+        *      first input endpoint = IR endpoint
+        *      first output endpoint = VFD endpoint
+        */
+
+       ir_ep_found = 0;
+       vfd_ep_found = 0;
+
+       for (i = 0; i < num_endpoints && !(ir_ep_found && vfd_ep_found); ++i) {
+
+               struct usb_endpoint_descriptor *ep;
+               int ep_dir;
+               int ep_type;
+               ep = &iface_desc->endpoint [i].desc;
+               ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+               ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+               if (!ir_ep_found &&
+                       ep_dir == USB_DIR_IN &&
+                       ep_type == USB_ENDPOINT_XFER_INT) {
+
+                       rx_endpoint = ep;
+                       ir_ep_found = 1;
+                       if (debug)
+                               printk(KERN_INFO "%s: found IR endpoint\n",
+                                      __func__);
+
+               } else if (!vfd_ep_found &&
+                       ep_dir == USB_DIR_OUT &&
+                       ep_type == USB_ENDPOINT_XFER_INT) {
+
+                       tx_endpoint = ep;
+                       vfd_ep_found = 1;
+                       if (debug)
+                               printk(KERN_INFO "%s: found VFD endpoint\n",
+                                      __func__);
+               }
+       }
+
+       /* Input endpoint is mandatory */
+       if (!ir_ep_found) {
+
+               err("%s: no valid input (IR) endpoint found.", __func__);
+               retval = -ENODEV;
+               goto exit;
+       }
+
+       if (!vfd_ep_found)
+               printk(KERN_INFO "%s: no valid output (VFD) endpoint found.\n",
+                      __func__);
+
+
+       /* Allocate memory */
+       alloc_status = 0;
+
+       context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL);
+       if (!context) {
+               err("%s: kzalloc failed for context", __func__);
+               alloc_status = 1;
+               goto alloc_status_switch;
+       }
+       driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+       if (!driver) {
+               err("%s: kzalloc failed for lirc_driver", __func__);
+               alloc_status = 2;
+               goto alloc_status_switch;
+       }
+       rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+       if (!rbuf) {
+               err("%s: kmalloc failed for lirc_buffer", __func__);
+               alloc_status = 3;
+               goto alloc_status_switch;
+       }
+       if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
+               err("%s: lirc_buffer_init failed", __func__);
+               alloc_status = 4;
+               goto alloc_status_switch;
+       }
+       rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!rx_urb) {
+               err("%s: usb_alloc_urb failed for IR urb", __func__);
+               alloc_status = 5;
+               goto alloc_status_switch;
+       }
+       if (vfd_ep_found) {
+               tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!tx_urb) {
+                       err("%s: usb_alloc_urb failed for VFD urb",
+                           __func__);
+                       alloc_status = 6;
+                       goto alloc_status_switch;
+               }
+       }
+
+       mutex_init(&context->ctx_lock);
+
+       strcpy(driver->name, MOD_NAME);
+       driver->minor = -1;
+       driver->code_length = 64;
+       driver->sample_rate = 0;
+       driver->features = LIRC_CAN_REC_LIRCCODE;
+       driver->data = context;
+       driver->rbuf = rbuf;
+       driver->set_use_inc = ir_open;
+       driver->set_use_dec = ir_close;
+       driver->dev   = &interface->dev;
+       driver->owner = THIS_MODULE;
+
+       mutex_lock(&context->ctx_lock);
+
+       lirc_minor = lirc_register_driver(driver);
+       if (lirc_minor < 0) {
+               err("%s: lirc_register_driver failed", __func__);
+               alloc_status = 7;
+               retval = lirc_minor;
+               goto unlock;
+       } else
+               printk(KERN_INFO "%s: Registered Sasem driver (minor:%d)\n",
+                       __func__, lirc_minor);
+
+       /* Needed while unregistering! */
+       driver->minor = lirc_minor;
+
+       context->dev = dev;
+       context->dev_present = 1;
+       context->rx_endpoint = rx_endpoint;
+       context->rx_urb = rx_urb;
+       if (vfd_ep_found) {
+               context->tx_endpoint = tx_endpoint;
+               context->tx_urb = tx_urb;
+               context->vfd_contrast = 1000;   /* range 0 - 1000 */
+       }
+       context->driver = driver;
+
+       usb_set_intfdata(interface, context);
+
+       if (vfd_ep_found) {
+
+               if (debug)
+                       printk(KERN_INFO "Registering VFD with sysfs\n");
+               if (usb_register_dev(interface, &sasem_class))
+                       /* Not a fatal error, so ignore */
+                       printk(KERN_INFO "%s: could not get a minor number "
+                              "for VFD\n", __func__);
+       }
+
+       printk(KERN_INFO "%s: Sasem device on usb<%d:%d> initialized\n",
+                       __func__, dev->bus->busnum, dev->devnum);
+unlock:
+       mutex_unlock(&context->ctx_lock);
+
+alloc_status_switch:
+       switch (alloc_status) {
+
+       case 7:
+               if (vfd_ep_found)
+                       usb_free_urb(tx_urb);
+       case 6:
+               usb_free_urb(rx_urb);
+       case 5:
+               lirc_buffer_free(rbuf);
+       case 4:
+               kfree(rbuf);
+       case 3:
+               kfree(driver);
+       case 2:
+               kfree(context);
+               context = NULL;
+       case 1:
+               if (retval == 0)
+                       retval = -ENOMEM;
+       }
+
+exit:
+       return retval;
+}
+
+/**
+ * Callback function for USB core API: disonnect
+ */
+static void sasem_disconnect(struct usb_interface *interface)
+{
+       struct sasem_context *context;
+
+       /* prevent races with ir_open()/vfd_open() */
+       mutex_lock(&disconnect_lock);
+
+       context = usb_get_intfdata(interface);
+       mutex_lock(&context->ctx_lock);
+
+       printk(KERN_INFO "%s: Sasem device disconnected\n", __func__);
+
+       usb_set_intfdata(interface, NULL);
+       context->dev_present = 0;
+
+       /* Stop reception */
+       usb_kill_urb(context->rx_urb);
+
+       /* Abort ongoing write */
+       if (atomic_read(&context->tx.busy)) {
+
+               usb_kill_urb(context->tx_urb);
+               wait_for_completion(&context->tx.finished);
+       }
+
+       /* De-register from lirc_dev if IR port is not open */
+       if (!context->ir_isopen)
+               deregister_from_lirc(context);
+
+       usb_deregister_dev(interface, &sasem_class);
+
+       mutex_unlock(&context->ctx_lock);
+
+       if (!context->ir_isopen && !context->vfd_isopen)
+               delete_context(context);
+
+       mutex_unlock(&disconnect_lock);
+}
+
+static int __init sasem_init(void)
+{
+       int rc;
+
+       printk(KERN_INFO MOD_DESC ", v" MOD_VERSION "\n");
+       printk(KERN_INFO MOD_AUTHOR "\n");
+
+       rc = usb_register(&sasem_driver);
+       if (rc < 0) {
+               err("%s: usb register failed (%d)", __func__, rc);
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static void __exit sasem_exit(void)
+{
+       usb_deregister(&sasem_driver);
+       printk(KERN_INFO "module removed. Goodbye!\n");
+}
+
+
+module_init(sasem_init);
+module_exit(sasem_exit);
diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c
new file mode 100644 (file)
index 0000000..8a060a8
--- /dev/null
@@ -0,0 +1,1315 @@
+/*
+ * lirc_serial.c
+ *
+ * lirc_serial - Device driver that records pulse- and pause-lengths
+ *            (space-lengths) between DDCD event on a serial port.
+ *
+ * Copyright (C) 1996,97 Ralph Metzler <rjkm@thp.uni-koeln.de>
+ * Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu>
+ * Copyright (C) 1998 Ben Pfaff <blp@gnu.org>
+ * Copyright (C) 1999 Christoph Bartelmus <lirc@bartelmus.de>
+ * Copyright (C) 2007 Andrei Tanas <andrei@tanas.ca> (suspend/resume support)
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * Steve's changes to improve transmission fidelity:
+ *   - for systems with the rdtsc instruction and the clock counter, a
+ *     send_pule that times the pulses directly using the counter.
+ *     This means that the LIRC_SERIAL_TRANSMITTER_LATENCY fudge is
+ *     not needed. Measurement shows very stable waveform, even where
+ *     PCI activity slows the access to the UART, which trips up other
+ *     versions.
+ *   - For other system, non-integer-microsecond pulse/space lengths,
+ *     done using fixed point binary. So, much more accurate carrier
+ *     frequency.
+ *   - fine tuned transmitter latency, taking advantage of fractional
+ *     microseconds in previous change
+ *   - Fixed bug in the way transmitter latency was accounted for by
+ *     tuning the pulse lengths down - the send_pulse routine ignored
+ *     this overhead as it timed the overall pulse length - so the
+ *     pulse frequency was right but overall pulse length was too
+ *     long. Fixed by accounting for latency on each pulse/space
+ *     iteration.
+ *
+ * Steve Davies <steve@daviesfam.org>  July 2001
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/serial_reg.h>
+#include <linux/time.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+
+#include <asm/system.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/fcntl.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+#include <asm/hardware.h>
+#endif
+/* From Intel IXP42X Developer's Manual (#252480-005): */
+/* ftp://download.intel.com/design/network/manuals/25248005.pdf */
+#define UART_IE_IXP42X_UUE   0x40 /* IXP42X UART Unit enable */
+#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+#define LIRC_DRIVER_NAME "lirc_serial"
+
+struct lirc_serial {
+       int signal_pin;
+       int signal_pin_change;
+       u8 on;
+       u8 off;
+       long (*send_pulse)(unsigned long length);
+       void (*send_space)(long length);
+       int features;
+       spinlock_t lock;
+};
+
+#define LIRC_HOMEBREW          0
+#define LIRC_IRDEO             1
+#define LIRC_IRDEO_REMOTE      2
+#define LIRC_ANIMAX            3
+#define LIRC_IGOR              4
+#define LIRC_NSLU2             5
+
+/*** module parameters ***/
+static int type;
+static int io;
+static int irq;
+static int iommap;
+static int ioshift;
+static int softcarrier = 1;
+static int share_irq;
+static int debug;
+static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */
+static int txsense;    /* 0 = active high, 1 = active low */
+
+#define dprintk(fmt, args...)                                  \
+       do {                                                    \
+               if (debug)                                      \
+                       printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
+                              fmt, ## args);                   \
+       } while (0)
+
+/* forward declarations */
+static long send_pulse_irdeo(unsigned long length);
+static long send_pulse_homebrew(unsigned long length);
+static void send_space_irdeo(long length);
+static void send_space_homebrew(long length);
+
+static struct lirc_serial hardware[] = {
+       [LIRC_HOMEBREW] = {
+               .signal_pin        = UART_MSR_DCD,
+               .signal_pin_change = UART_MSR_DDCD,
+               .on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
+               .off = (UART_MCR_RTS | UART_MCR_OUT2),
+               .send_pulse = send_pulse_homebrew,
+               .send_space = send_space_homebrew,
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+                               LIRC_CAN_SET_SEND_CARRIER |
+                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+#else
+               .features    = LIRC_CAN_REC_MODE2
+#endif
+       },
+
+       [LIRC_IRDEO] = {
+               .signal_pin        = UART_MSR_DSR,
+               .signal_pin_change = UART_MSR_DDSR,
+               .on  = UART_MCR_OUT2,
+               .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+               .send_pulse  = send_pulse_irdeo,
+               .send_space  = send_space_irdeo,
+               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+       },
+
+       [LIRC_IRDEO_REMOTE] = {
+               .signal_pin        = UART_MSR_DSR,
+               .signal_pin_change = UART_MSR_DDSR,
+               .on  = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+               .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+               .send_pulse  = send_pulse_irdeo,
+               .send_space  = send_space_irdeo,
+               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+       },
+
+       [LIRC_ANIMAX] = {
+               .signal_pin        = UART_MSR_DCD,
+               .signal_pin_change = UART_MSR_DDCD,
+               .on  = 0,
+               .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2),
+               .send_pulse = NULL,
+               .send_space = NULL,
+               .features   = LIRC_CAN_REC_MODE2
+       },
+
+       [LIRC_IGOR] = {
+               .signal_pin        = UART_MSR_DSR,
+               .signal_pin_change = UART_MSR_DDSR,
+               .on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
+               .off = (UART_MCR_RTS | UART_MCR_OUT2),
+               .send_pulse = send_pulse_homebrew,
+               .send_space = send_space_homebrew,
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+                               LIRC_CAN_SET_SEND_CARRIER |
+                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+#else
+               .features    = LIRC_CAN_REC_MODE2
+#endif
+       },
+
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+       /*
+        * Modified Linksys Network Storage Link USB 2.0 (NSLU2):
+        * We receive on CTS of the 2nd serial port (R142,LHS), we
+        * transmit with a IR diode between GPIO[1] (green status LED),
+        * and ground (Matthias Goebl <matthias.goebl@goebl.net>).
+        * See also http://www.nslu2-linux.org for this device
+        */
+       [LIRC_NSLU2] = {
+               .signal_pin        = UART_MSR_CTS,
+               .signal_pin_change = UART_MSR_DCTS,
+               .on  = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR),
+               .off = (UART_MCR_RTS | UART_MCR_OUT2),
+               .send_pulse = send_pulse_homebrew,
+               .send_space = send_space_homebrew,
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+               .features    = (LIRC_CAN_SET_SEND_DUTY_CYCLE |
+                               LIRC_CAN_SET_SEND_CARRIER |
+                               LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2)
+#else
+               .features    = LIRC_CAN_REC_MODE2
+#endif
+       },
+#endif
+
+};
+
+#define RS_ISR_PASS_LIMIT 256
+
+/*
+ * A long pulse code from a remote might take up to 300 bytes.  The
+ * daemon should read the bytes as soon as they are generated, so take
+ * the number of keys you think you can push before the daemon runs
+ * and multiply by 300.  The driver will warn you if you overrun this
+ * buffer.  If you have a slow computer or non-busmastering IDE disks,
+ * maybe you will need to increase this.
+ */
+
+/* This MUST be a power of two!  It has to be larger than 1 as well. */
+
+#define RBUF_LEN 256
+
+static struct timeval lasttv = {0, 0};
+
+static struct lirc_buffer rbuf;
+
+static unsigned int freq = 38000;
+static unsigned int duty_cycle = 50;
+
+/* Initialized in init_timing_params() */
+static unsigned long period;
+static unsigned long pulse_width;
+static unsigned long space_width;
+
+#if defined(__i386__)
+/*
+ * From:
+ * Linux I/O port programming mini-HOWTO
+ * Author: Riku Saikkonen <Riku.Saikkonen@hut.fi>
+ * v, 28 December 1997
+ *
+ * [...]
+ * Actually, a port I/O instruction on most ports in the 0-0x3ff range
+ * takes almost exactly 1 microsecond, so if you're, for example, using
+ * the parallel port directly, just do additional inb()s from that port
+ * to delay.
+ * [...]
+ */
+/* transmitter latency 1.5625us 0x1.90 - this figure arrived at from
+ * comment above plus trimming to match actual measured frequency.
+ * This will be sensitive to cpu speed, though hopefully most of the 1.5us
+ * is spent in the uart access.  Still - for reference test machine was a
+ * 1.13GHz Athlon system - Steve
+ */
+
+/*
+ * changed from 400 to 450 as this works better on slower machines;
+ * faster machines will use the rdtsc code anyway
+ */
+#define LIRC_SERIAL_TRANSMITTER_LATENCY 450
+
+#else
+
+/* does anybody have information on other platforms ? */
+/* 256 = 1<<8 */
+#define LIRC_SERIAL_TRANSMITTER_LATENCY 256
+
+#endif  /* __i386__ */
+/*
+ * FIXME: should we be using hrtimers instead of this
+ * LIRC_SERIAL_TRANSMITTER_LATENCY nonsense?
+ */
+
+/* fetch serial input packet (1 byte) from register offset */
+static u8 sinp(int offset)
+{
+       if (iommap != 0)
+               /* the register is memory-mapped */
+               offset <<= ioshift;
+
+       return inb(io + offset);
+}
+
+/* write serial output packet (1 byte) of value to register offset */
+static void soutp(int offset, u8 value)
+{
+       if (iommap != 0)
+               /* the register is memory-mapped */
+               offset <<= ioshift;
+
+       outb(value, io + offset);
+}
+
+static void on(void)
+{
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+       /*
+        * On NSLU2, we put the transmit diode between the output of the green
+        * status LED and ground
+        */
+       if (type == LIRC_NSLU2) {
+               gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_LOW);
+               return;
+       }
+#endif
+       if (txsense)
+               soutp(UART_MCR, hardware[type].off);
+       else
+               soutp(UART_MCR, hardware[type].on);
+}
+
+static void off(void)
+{
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+       if (type == LIRC_NSLU2) {
+               gpio_line_set(NSLU2_LED_GRN, IXP4XX_GPIO_HIGH);
+               return;
+       }
+#endif
+       if (txsense)
+               soutp(UART_MCR, hardware[type].on);
+       else
+               soutp(UART_MCR, hardware[type].off);
+}
+
+#ifndef MAX_UDELAY_MS
+#define MAX_UDELAY_US 5000
+#else
+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
+#endif
+
+static void safe_udelay(unsigned long usecs)
+{
+       while (usecs > MAX_UDELAY_US) {
+               udelay(MAX_UDELAY_US);
+               usecs -= MAX_UDELAY_US;
+       }
+       udelay(usecs);
+}
+
+#ifdef USE_RDTSC
+/*
+ * This is an overflow/precision juggle, complicated in that we can't
+ * do long long divide in the kernel
+ */
+
+/*
+ * When we use the rdtsc instruction to measure clocks, we keep the
+ * pulse and space widths as clock cycles.  As this is CPU speed
+ * dependent, the widths must be calculated in init_port and ioctl
+ * time
+ */
+
+/* So send_pulse can quickly convert microseconds to clocks */
+static unsigned long conv_us_to_clocks;
+
+static int init_timing_params(unsigned int new_duty_cycle,
+               unsigned int new_freq)
+{
+       __u64 loops_per_sec, work;
+
+       duty_cycle = new_duty_cycle;
+       freq = new_freq;
+
+       loops_per_sec = __this_cpu_read(cpu.info.loops_per_jiffy);
+       loops_per_sec *= HZ;
+
+       /* How many clocks in a microsecond?, avoiding long long divide */
+       work = loops_per_sec;
+       work *= 4295;  /* 4295 = 2^32 / 1e6 */
+       conv_us_to_clocks = (work >> 32);
+
+       /*
+        * Carrier period in clocks, approach good up to 32GHz clock,
+        * gets carrier frequency within 8Hz
+        */
+       period = loops_per_sec >> 3;
+       period /= (freq >> 3);
+
+       /* Derive pulse and space from the period */
+       pulse_width = period * duty_cycle / 100;
+       space_width = period - pulse_width;
+       dprintk("in init_timing_params, freq=%d, duty_cycle=%d, "
+               "clk/jiffy=%ld, pulse=%ld, space=%ld, "
+               "conv_us_to_clocks=%ld\n",
+               freq, duty_cycle, __this_cpu_read(cpu_info.loops_per_jiffy),
+               pulse_width, space_width, conv_us_to_clocks);
+       return 0;
+}
+#else /* ! USE_RDTSC */
+static int init_timing_params(unsigned int new_duty_cycle,
+               unsigned int new_freq)
+{
+/*
+ * period, pulse/space width are kept with 8 binary places -
+ * IE multiplied by 256.
+ */
+       if (256 * 1000000L / new_freq * new_duty_cycle / 100 <=
+           LIRC_SERIAL_TRANSMITTER_LATENCY)
+               return -EINVAL;
+       if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <=
+           LIRC_SERIAL_TRANSMITTER_LATENCY)
+               return -EINVAL;
+       duty_cycle = new_duty_cycle;
+       freq = new_freq;
+       period = 256 * 1000000L / freq;
+       pulse_width = period * duty_cycle / 100;
+       space_width = period - pulse_width;
+       dprintk("in init_timing_params, freq=%d pulse=%ld, "
+               "space=%ld\n", freq, pulse_width, space_width);
+       return 0;
+}
+#endif /* USE_RDTSC */
+
+
+/* return value: space length delta */
+
+static long send_pulse_irdeo(unsigned long length)
+{
+       long rawbits, ret;
+       int i;
+       unsigned char output;
+       unsigned char chunk, shifted;
+
+       /* how many bits have to be sent ? */
+       rawbits = length * 1152 / 10000;
+       if (duty_cycle > 50)
+               chunk = 3;
+       else
+               chunk = 1;
+       for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) {
+               shifted = chunk << (i * 3);
+               shifted >>= 1;
+               output &= (~shifted);
+               i++;
+               if (i == 3) {
+                       soutp(UART_TX, output);
+                       while (!(sinp(UART_LSR) & UART_LSR_THRE))
+                               ;
+                       output = 0x7f;
+                       i = 0;
+               }
+       }
+       if (i != 0) {
+               soutp(UART_TX, output);
+               while (!(sinp(UART_LSR) & UART_LSR_TEMT))
+                       ;
+       }
+
+       if (i == 0)
+               ret = (-rawbits) * 10000 / 1152;
+       else
+               ret = (3 - i) * 3 * 10000 / 1152 + (-rawbits) * 10000 / 1152;
+
+       return ret;
+}
+
+#ifdef USE_RDTSC
+/* Version that uses Pentium rdtsc instruction to measure clocks */
+
+/*
+ * This version does sub-microsecond timing using rdtsc instruction,
+ * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY
+ * Implicitly i586 architecture...  - Steve
+ */
+
+static long send_pulse_homebrew_softcarrier(unsigned long length)
+{
+       int flag;
+       unsigned long target, start, now;
+
+       /* Get going quick as we can */
+       rdtscl(start);
+       on();
+       /* Convert length from microseconds to clocks */
+       length *= conv_us_to_clocks;
+       /* And loop till time is up - flipping at right intervals */
+       now = start;
+       target = pulse_width;
+       flag = 1;
+       /*
+        * FIXME: This looks like a hard busy wait, without even an occasional,
+        * polite, cpu_relax() call.  There's got to be a better way?
+        *
+        * The i2c code has the result of a lot of bit-banging work, I wonder if
+        * there's something there which could be helpful here.
+        */
+       while ((now - start) < length) {
+               /* Delay till flip time */
+               do {
+                       rdtscl(now);
+               } while ((now - start) < target);
+
+               /* flip */
+               if (flag) {
+                       rdtscl(now);
+                       off();
+                       target += space_width;
+               } else {
+                       rdtscl(now); on();
+                       target += pulse_width;
+               }
+               flag = !flag;
+       }
+       rdtscl(now);
+       return ((now - start) - length) / conv_us_to_clocks;
+}
+#else /* ! USE_RDTSC */
+/* Version using udelay() */
+
+/*
+ * here we use fixed point arithmetic, with 8
+ * fractional bits.  that gets us within 0.1% or so of the right average
+ * frequency, albeit with some jitter in pulse length - Steve
+ */
+
+/* To match 8 fractional bits used for pulse/space length */
+
+static long send_pulse_homebrew_softcarrier(unsigned long length)
+{
+       int flag;
+       unsigned long actual, target, d;
+       length <<= 8;
+
+       actual = 0; target = 0; flag = 0;
+       while (actual < length) {
+               if (flag) {
+                       off();
+                       target += space_width;
+               } else {
+                       on();
+                       target += pulse_width;
+               }
+               d = (target - actual -
+                    LIRC_SERIAL_TRANSMITTER_LATENCY + 128) >> 8;
+               /*
+                * Note - we've checked in ioctl that the pulse/space
+                * widths are big enough so that d is > 0
+                */
+               udelay(d);
+               actual += (d << 8) + LIRC_SERIAL_TRANSMITTER_LATENCY;
+               flag = !flag;
+       }
+       return (actual-length) >> 8;
+}
+#endif /* USE_RDTSC */
+
+static long send_pulse_homebrew(unsigned long length)
+{
+       if (length <= 0)
+               return 0;
+
+       if (softcarrier)
+               return send_pulse_homebrew_softcarrier(length);
+       else {
+               on();
+               safe_udelay(length);
+               return 0;
+       }
+}
+
+static void send_space_irdeo(long length)
+{
+       if (length <= 0)
+               return;
+
+       safe_udelay(length);
+}
+
+static void send_space_homebrew(long length)
+{
+       off();
+       if (length <= 0)
+               return;
+       safe_udelay(length);
+}
+
+static void rbwrite(int l)
+{
+       if (lirc_buffer_full(&rbuf)) {
+               /* no new signals will be accepted */
+               dprintk("Buffer overrun\n");
+               return;
+       }
+       lirc_buffer_write(&rbuf, (void *)&l);
+}
+
+static void frbwrite(int l)
+{
+       /* simple noise filter */
+       static int pulse, space;
+       static unsigned int ptr;
+
+       if (ptr > 0 && (l & PULSE_BIT)) {
+               pulse += l & PULSE_MASK;
+               if (pulse > 250) {
+                       rbwrite(space);
+                       rbwrite(pulse | PULSE_BIT);
+                       ptr = 0;
+                       pulse = 0;
+               }
+               return;
+       }
+       if (!(l & PULSE_BIT)) {
+               if (ptr == 0) {
+                       if (l > 20000) {
+                               space = l;
+                               ptr++;
+                               return;
+                       }
+               } else {
+                       if (l > 20000) {
+                               space += pulse;
+                               if (space > PULSE_MASK)
+                                       space = PULSE_MASK;
+                               space += l;
+                               if (space > PULSE_MASK)
+                                       space = PULSE_MASK;
+                               pulse = 0;
+                               return;
+                       }
+                       rbwrite(space);
+                       rbwrite(pulse | PULSE_BIT);
+                       ptr = 0;
+                       pulse = 0;
+               }
+       }
+       rbwrite(l);
+}
+
+static irqreturn_t irq_handler(int i, void *blah)
+{
+       struct timeval tv;
+       int counter, dcd;
+       u8 status;
+       long deltv;
+       int data;
+       static int last_dcd = -1;
+
+       if ((sinp(UART_IIR) & UART_IIR_NO_INT)) {
+               /* not our interrupt */
+               return IRQ_NONE;
+       }
+
+       counter = 0;
+       do {
+               counter++;
+               status = sinp(UART_MSR);
+               if (counter > RS_ISR_PASS_LIMIT) {
+                       printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: "
+                              "We're caught!\n");
+                       break;
+               }
+               if ((status & hardware[type].signal_pin_change)
+                   && sense != -1) {
+                       /* get current time */
+                       do_gettimeofday(&tv);
+
+                       /* New mode, written by Trent Piepho
+                          <xyzzy@u.washington.edu>. */
+
+                       /*
+                        * The old format was not very portable.
+                        * We now use an int to pass pulses
+                        * and spaces to user space.
+                        *
+                        * If PULSE_BIT is set a pulse has been
+                        * received, otherwise a space has been
+                        * received.  The driver needs to know if your
+                        * receiver is active high or active low, or
+                        * the space/pulse sense could be
+                        * inverted. The bits denoted by PULSE_MASK are
+                        * the length in microseconds. Lengths greater
+                        * than or equal to 16 seconds are clamped to
+                        * PULSE_MASK.  All other bits are unused.
+                        * This is a much simpler interface for user
+                        * programs, as well as eliminating "out of
+                        * phase" errors with space/pulse
+                        * autodetection.
+                        */
+
+                       /* calc time since last interrupt in microseconds */
+                       dcd = (status & hardware[type].signal_pin) ? 1 : 0;
+
+                       if (dcd == last_dcd) {
+                               printk(KERN_WARNING LIRC_DRIVER_NAME
+                               ": ignoring spike: %d %d %lx %lx %lx %lx\n",
+                               dcd, sense,
+                               tv.tv_sec, lasttv.tv_sec,
+                               tv.tv_usec, lasttv.tv_usec);
+                               continue;
+                       }
+
+                       deltv = tv.tv_sec-lasttv.tv_sec;
+                       if (tv.tv_sec < lasttv.tv_sec ||
+                           (tv.tv_sec == lasttv.tv_sec &&
+                            tv.tv_usec < lasttv.tv_usec)) {
+                               printk(KERN_WARNING LIRC_DRIVER_NAME
+                                      ": AIEEEE: your clock just jumped "
+                                      "backwards\n");
+                               printk(KERN_WARNING LIRC_DRIVER_NAME
+                                      ": %d %d %lx %lx %lx %lx\n",
+                                      dcd, sense,
+                                      tv.tv_sec, lasttv.tv_sec,
+                                      tv.tv_usec, lasttv.tv_usec);
+                               data = PULSE_MASK;
+                       } else if (deltv > 15) {
+                               data = PULSE_MASK; /* really long time */
+                               if (!(dcd^sense)) {
+                                       /* sanity check */
+                                       printk(KERN_WARNING LIRC_DRIVER_NAME
+                                              ": AIEEEE: "
+                                              "%d %d %lx %lx %lx %lx\n",
+                                              dcd, sense,
+                                              tv.tv_sec, lasttv.tv_sec,
+                                              tv.tv_usec, lasttv.tv_usec);
+                                       /*
+                                        * detecting pulse while this
+                                        * MUST be a space!
+                                        */
+                                       sense = sense ? 0 : 1;
+                               }
+                       } else
+                               data = (int) (deltv*1000000 +
+                                              tv.tv_usec -
+                                              lasttv.tv_usec);
+                       frbwrite(dcd^sense ? data : (data|PULSE_BIT));
+                       lasttv = tv;
+                       last_dcd = dcd;
+                       wake_up_interruptible(&rbuf.wait_poll);
+               }
+       } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */
+       return IRQ_HANDLED;
+}
+
+
+static int hardware_init_port(void)
+{
+       u8 scratch, scratch2, scratch3;
+
+       /*
+        * This is a simple port existence test, borrowed from the autoconfig
+        * function in drivers/serial/8250.c
+        */
+       scratch = sinp(UART_IER);
+       soutp(UART_IER, 0);
+#ifdef __i386__
+       outb(0xff, 0x080);
+#endif
+       scratch2 = sinp(UART_IER) & 0x0f;
+       soutp(UART_IER, 0x0f);
+#ifdef __i386__
+       outb(0x00, 0x080);
+#endif
+       scratch3 = sinp(UART_IER) & 0x0f;
+       soutp(UART_IER, scratch);
+       if (scratch2 != 0 || scratch3 != 0x0f) {
+               /* we fail, there's nothing here */
+               printk(KERN_ERR LIRC_DRIVER_NAME ": port existence test "
+                      "failed, cannot continue\n");
+               return -EINVAL;
+       }
+
+
+
+       /* Set DLAB 0. */
+       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+       /* First of all, disable all interrupts */
+       soutp(UART_IER, sinp(UART_IER) &
+             (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+
+       /* Clear registers. */
+       sinp(UART_LSR);
+       sinp(UART_RX);
+       sinp(UART_IIR);
+       sinp(UART_MSR);
+
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+       if (type == LIRC_NSLU2) {
+               /* Setup NSLU2 UART */
+
+               /* Enable UART */
+               soutp(UART_IER, sinp(UART_IER) | UART_IE_IXP42X_UUE);
+               /* Disable Receiver data Time out interrupt */
+               soutp(UART_IER, sinp(UART_IER) & ~UART_IE_IXP42X_RTOIE);
+               /* set out2 = interrupt unmask; off() doesn't set MCR
+                  on NSLU2 */
+               soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+       }
+#endif
+
+       /* Set line for power source */
+       off();
+
+       /* Clear registers again to be sure. */
+       sinp(UART_LSR);
+       sinp(UART_RX);
+       sinp(UART_IIR);
+       sinp(UART_MSR);
+
+       switch (type) {
+       case LIRC_IRDEO:
+       case LIRC_IRDEO_REMOTE:
+               /* setup port to 7N1 @ 115200 Baud */
+               /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */
+
+               /* Set DLAB 1. */
+               soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+               /* Set divisor to 1 => 115200 Baud */
+               soutp(UART_DLM, 0);
+               soutp(UART_DLL, 1);
+               /* Set DLAB 0 +  7N1 */
+               soutp(UART_LCR, UART_LCR_WLEN7);
+               /* THR interrupt already disabled at this point */
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int init_port(void)
+{
+       int i, nlow, nhigh, result;
+
+       result = request_irq(irq, irq_handler,
+                            (share_irq ? IRQF_SHARED : 0),
+                            LIRC_DRIVER_NAME, (void *)&hardware);
+
+       switch (result) {
+       case -EBUSY:
+               printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq);
+               return -EBUSY;
+       case -EINVAL:
+               printk(KERN_ERR LIRC_DRIVER_NAME
+                      ": Bad irq number or handler\n");
+               return -EINVAL;
+       default:
+               break;
+       };
+
+       /* Reserve io region. */
+       /*
+        * Future MMAP-Developers: Attention!
+        * For memory mapped I/O you *might* need to use ioremap() first,
+        * for the NSLU2 it's done in boot code.
+        */
+       if (((iommap != 0)
+            && (request_mem_region(iommap, 8 << ioshift,
+                                   LIRC_DRIVER_NAME) == NULL))
+          || ((iommap == 0)
+              && (request_region(io, 8, LIRC_DRIVER_NAME) == NULL))) {
+               printk(KERN_ERR  LIRC_DRIVER_NAME
+                      ": port %04x already in use\n", io);
+               printk(KERN_WARNING LIRC_DRIVER_NAME
+                      ": use 'setserial /dev/ttySX uart none'\n");
+               printk(KERN_WARNING LIRC_DRIVER_NAME
+                      ": or compile the serial port driver as module and\n");
+               printk(KERN_WARNING LIRC_DRIVER_NAME
+                      ": make sure this module is loaded first\n");
+               return -EBUSY;
+       }
+
+       if (hardware_init_port() < 0)
+               return -EINVAL;
+
+       /* Initialize pulse/space widths */
+       init_timing_params(duty_cycle, freq);
+
+       /* If pin is high, then this must be an active low receiver. */
+       if (sense == -1) {
+               /* wait 1/2 sec for the power supply */
+               msleep(500);
+
+               /*
+                * probe 9 times every 0.04s, collect "votes" for
+                * active high/low
+                */
+               nlow = 0;
+               nhigh = 0;
+               for (i = 0; i < 9; i++) {
+                       if (sinp(UART_MSR) & hardware[type].signal_pin)
+                               nlow++;
+                       else
+                               nhigh++;
+                       msleep(40);
+               }
+               sense = (nlow >= nhigh ? 1 : 0);
+               printk(KERN_INFO LIRC_DRIVER_NAME  ": auto-detected active "
+                      "%s receiver\n", sense ? "low" : "high");
+       } else
+               printk(KERN_INFO LIRC_DRIVER_NAME  ": Manually using active "
+                      "%s receiver\n", sense ? "low" : "high");
+
+       dprintk("Interrupt %d, port %04x obtained\n", irq, io);
+       return 0;
+}
+
+static int set_use_inc(void *data)
+{
+       unsigned long flags;
+
+       /* initialize timestamp */
+       do_gettimeofday(&lasttv);
+
+       spin_lock_irqsave(&hardware[type].lock, flags);
+
+       /* Set DLAB 0. */
+       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+       soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI);
+
+       spin_unlock_irqrestore(&hardware[type].lock, flags);
+
+       return 0;
+}
+
+static void set_use_dec(void *data)
+{      unsigned long flags;
+
+       spin_lock_irqsave(&hardware[type].lock, flags);
+
+       /* Set DLAB 0. */
+       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+       /* First of all, disable all interrupts */
+       soutp(UART_IER, sinp(UART_IER) &
+             (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+       spin_unlock_irqrestore(&hardware[type].lock, flags);
+}
+
+static ssize_t lirc_write(struct file *file, const char *buf,
+                        size_t n, loff_t *ppos)
+{
+       int i, count;
+       unsigned long flags;
+       long delta = 0;
+       int *wbuf;
+
+       if (!(hardware[type].features & LIRC_CAN_SEND_PULSE))
+               return -EBADF;
+
+       count = n / sizeof(int);
+       if (n % sizeof(int) || count % 2 == 0)
+               return -EINVAL;
+       wbuf = memdup_user(buf, n);
+       if (IS_ERR(wbuf))
+               return PTR_ERR(wbuf);
+       spin_lock_irqsave(&hardware[type].lock, flags);
+       if (type == LIRC_IRDEO) {
+               /* DTR, RTS down */
+               on();
+       }
+       for (i = 0; i < count; i++) {
+               if (i%2)
+                       hardware[type].send_space(wbuf[i] - delta);
+               else
+                       delta = hardware[type].send_pulse(wbuf[i]);
+       }
+       off();
+       spin_unlock_irqrestore(&hardware[type].lock, flags);
+       kfree(wbuf);
+       return n;
+}
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+       int result;
+       __u32 value;
+
+       switch (cmd) {
+       case LIRC_GET_SEND_MODE:
+               if (!(hardware[type].features&LIRC_CAN_SEND_MASK))
+                       return -ENOIOCTLCMD;
+
+               result = put_user(LIRC_SEND2MODE
+                                 (hardware[type].features&LIRC_CAN_SEND_MASK),
+                                 (__u32 *) arg);
+               if (result)
+                       return result;
+               break;
+
+       case LIRC_SET_SEND_MODE:
+               if (!(hardware[type].features&LIRC_CAN_SEND_MASK))
+                       return -ENOIOCTLCMD;
+
+               result = get_user(value, (__u32 *) arg);
+               if (result)
+                       return result;
+               /* only LIRC_MODE_PULSE supported */
+               if (value != LIRC_MODE_PULSE)
+                       return -ENOSYS;
+               break;
+
+       case LIRC_GET_LENGTH:
+               return -ENOSYS;
+               break;
+
+       case LIRC_SET_SEND_DUTY_CYCLE:
+               dprintk("SET_SEND_DUTY_CYCLE\n");
+               if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE))
+                       return -ENOIOCTLCMD;
+
+               result = get_user(value, (__u32 *) arg);
+               if (result)
+                       return result;
+               if (value <= 0 || value > 100)
+                       return -EINVAL;
+               return init_timing_params(value, freq);
+               break;
+
+       case LIRC_SET_SEND_CARRIER:
+               dprintk("SET_SEND_CARRIER\n");
+               if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER))
+                       return -ENOIOCTLCMD;
+
+               result = get_user(value, (__u32 *) arg);
+               if (result)
+                       return result;
+               if (value > 500000 || value < 20000)
+                       return -EINVAL;
+               return init_timing_params(duty_cycle, value);
+               break;
+
+       default:
+               return lirc_dev_fop_ioctl(filep, cmd, arg);
+       }
+       return 0;
+}
+
+static const struct file_operations lirc_fops = {
+       .owner          = THIS_MODULE,
+       .write          = lirc_write,
+       .unlocked_ioctl = lirc_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = lirc_ioctl,
+#endif
+       .read           = lirc_dev_fop_read,
+       .poll           = lirc_dev_fop_poll,
+       .open           = lirc_dev_fop_open,
+       .release        = lirc_dev_fop_close,
+       .llseek         = no_llseek,
+};
+
+static struct lirc_driver driver = {
+       .name           = LIRC_DRIVER_NAME,
+       .minor          = -1,
+       .code_length    = 1,
+       .sample_rate    = 0,
+       .data           = NULL,
+       .add_to_buf     = NULL,
+       .rbuf           = &rbuf,
+       .set_use_inc    = set_use_inc,
+       .set_use_dec    = set_use_dec,
+       .fops           = &lirc_fops,
+       .dev            = NULL,
+       .owner          = THIS_MODULE,
+};
+
+static struct platform_device *lirc_serial_dev;
+
+static int __devinit lirc_serial_probe(struct platform_device *dev)
+{
+       return 0;
+}
+
+static int __devexit lirc_serial_remove(struct platform_device *dev)
+{
+       return 0;
+}
+
+static int lirc_serial_suspend(struct platform_device *dev,
+                              pm_message_t state)
+{
+       /* Set DLAB 0. */
+       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+       /* Disable all interrupts */
+       soutp(UART_IER, sinp(UART_IER) &
+             (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+
+       /* Clear registers. */
+       sinp(UART_LSR);
+       sinp(UART_RX);
+       sinp(UART_IIR);
+       sinp(UART_MSR);
+
+       return 0;
+}
+
+/* twisty maze... need a forward-declaration here... */
+static void lirc_serial_exit(void);
+
+static int lirc_serial_resume(struct platform_device *dev)
+{
+       unsigned long flags;
+
+       if (hardware_init_port() < 0) {
+               lirc_serial_exit();
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&hardware[type].lock, flags);
+       /* Enable Interrupt */
+       do_gettimeofday(&lasttv);
+       soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI);
+       off();
+
+       lirc_buffer_clear(&rbuf);
+
+       spin_unlock_irqrestore(&hardware[type].lock, flags);
+
+       return 0;
+}
+
+static struct platform_driver lirc_serial_driver = {
+       .probe          = lirc_serial_probe,
+       .remove         = __devexit_p(lirc_serial_remove),
+       .suspend        = lirc_serial_suspend,
+       .resume         = lirc_serial_resume,
+       .driver         = {
+               .name   = "lirc_serial",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init lirc_serial_init(void)
+{
+       int result;
+
+       /* Init read buffer. */
+       result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN);
+       if (result < 0)
+               return -ENOMEM;
+
+       result = platform_driver_register(&lirc_serial_driver);
+       if (result) {
+               printk("lirc register returned %d\n", result);
+               goto exit_buffer_free;
+       }
+
+       lirc_serial_dev = platform_device_alloc("lirc_serial", 0);
+       if (!lirc_serial_dev) {
+               result = -ENOMEM;
+               goto exit_driver_unregister;
+       }
+
+       result = platform_device_add(lirc_serial_dev);
+       if (result)
+               goto exit_device_put;
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(lirc_serial_dev);
+exit_driver_unregister:
+       platform_driver_unregister(&lirc_serial_driver);
+exit_buffer_free:
+       lirc_buffer_free(&rbuf);
+       return result;
+}
+
+static void lirc_serial_exit(void)
+{
+       platform_device_unregister(lirc_serial_dev);
+       platform_driver_unregister(&lirc_serial_driver);
+       lirc_buffer_free(&rbuf);
+}
+
+static int __init lirc_serial_init_module(void)
+{
+       int result;
+
+       result = lirc_serial_init();
+       if (result)
+               return result;
+
+       switch (type) {
+       case LIRC_HOMEBREW:
+       case LIRC_IRDEO:
+       case LIRC_IRDEO_REMOTE:
+       case LIRC_ANIMAX:
+       case LIRC_IGOR:
+               /* if nothing specified, use ttyS0/com1 and irq 4 */
+               io = io ? io : 0x3f8;
+               irq = irq ? irq : 4;
+               break;
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+       case LIRC_NSLU2:
+               io = io ? io : IRQ_IXP4XX_UART2;
+               irq = irq ? irq : (IXP4XX_UART2_BASE_VIRT + REG_OFFSET);
+               iommap = iommap ? iommap : IXP4XX_UART2_BASE_PHYS;
+               ioshift = ioshift ? ioshift : 2;
+               break;
+#endif
+       default:
+               result = -EINVAL;
+               goto exit_serial_exit;
+       }
+       if (!softcarrier) {
+               switch (type) {
+               case LIRC_HOMEBREW:
+               case LIRC_IGOR:
+#ifdef CONFIG_LIRC_SERIAL_NSLU2
+               case LIRC_NSLU2:
+#endif
+                       hardware[type].features &=
+                               ~(LIRC_CAN_SET_SEND_DUTY_CYCLE|
+                                 LIRC_CAN_SET_SEND_CARRIER);
+                       break;
+               }
+       }
+
+       result = init_port();
+       if (result < 0)
+               goto exit_serial_exit;
+       driver.features = hardware[type].features;
+       driver.dev = &lirc_serial_dev->dev;
+       driver.minor = lirc_register_driver(&driver);
+       if (driver.minor < 0) {
+               printk(KERN_ERR  LIRC_DRIVER_NAME
+                      ": register_chrdev failed!\n");
+               result = -EIO;
+               goto exit_release;
+       }
+       return 0;
+exit_release:
+       release_region(io, 8);
+exit_serial_exit:
+       lirc_serial_exit();
+       return result;
+}
+
+static void __exit lirc_serial_exit_module(void)
+{
+       lirc_serial_exit();
+
+       free_irq(irq, (void *)&hardware);
+
+       if (iommap != 0)
+               release_mem_region(iommap, 8 << ioshift);
+       else
+               release_region(io, 8);
+       lirc_unregister_driver(driver.minor);
+       dprintk("cleaned up module\n");
+}
+
+
+module_init(lirc_serial_init_module);
+module_exit(lirc_serial_exit_module);
+
+MODULE_DESCRIPTION("Infra-red receiver driver for serial ports.");
+MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, "
+             "Christoph Bartelmus, Andrei Tanas");
+MODULE_LICENSE("GPL");
+
+module_param(type, int, S_IRUGO);
+MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo,"
+                " 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug,"
+                " 5 = NSLU2 RX:CTS2/TX:GreenLED)");
+
+module_param(io, int, S_IRUGO);
+MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");
+
+/* some architectures (e.g. intel xscale) have memory mapped registers */
+module_param(iommap, bool, S_IRUGO);
+MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O"
+               " (0 = no memory mapped io)");
+
+/*
+ * some architectures (e.g. intel xscale) align the 8bit serial registers
+ * on 32bit word boundaries.
+ * See linux-kernel/serial/8250.c serial_in()/out()
+ */
+module_param(ioshift, int, S_IRUGO);
+MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)");
+
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");
+
+module_param(share_irq, bool, S_IRUGO);
+MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)");
+
+module_param(sense, bool, S_IRUGO);
+MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit"
+                " (0 = active high, 1 = active low )");
+
+#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER
+module_param(txsense, bool, S_IRUGO);
+MODULE_PARM_DESC(txsense, "Sense of transmitter circuit"
+                " (0 = active high, 1 = active low )");
+#endif
+
+module_param(softcarrier, bool, S_IRUGO);
+MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/media/lirc/lirc_sir.c b/drivers/staging/media/lirc/lirc_sir.c
new file mode 100644 (file)
index 0000000..6903d39
--- /dev/null
@@ -0,0 +1,1279 @@
+/*
+ * LIRC SIR driver, (C) 2000 Milan Pikula <www@fornax.sk>
+ *
+ * lirc_sir - Device driver for use with SIR (serial infra red)
+ * mode of IrDA on many notebooks.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *
+ * 2000/09/16 Frank Przybylski <mail@frankprzybylski.de> :
+ *  added timeout and relaxed pulse detection, removed gap bug
+ *
+ * 2000/12/15 Christoph Bartelmus <lirc@bartelmus.de> :
+ *   added support for Tekram Irmate 210 (sending does not work yet,
+ *   kind of disappointing that nobody was able to implement that
+ *   before),
+ *   major clean-up
+ *
+ * 2001/02/27 Christoph Bartelmus <lirc@bartelmus.de> :
+ *   added support for StrongARM SA1100 embedded microprocessor
+ *   parts cut'n'pasted from sa1100_ir.c (C) 2000 Russell King
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/serial_reg.h>
+#include <linux/time.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <asm/system.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <linux/fcntl.h>
+#ifdef LIRC_ON_SA1100
+#include <asm/hardware.h>
+#ifdef CONFIG_SA1100_COLLIE
+#include <asm/arch/tc35143.h>
+#include <asm/ucb1200.h>
+#endif
+#endif
+
+#include <linux/timer.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+/* SECTION: Definitions */
+
+/*** Tekram dongle ***/
+#ifdef LIRC_SIR_TEKRAM
+/* stolen from kernel source */
+/* definitions for Tekram dongle */
+#define TEKRAM_115200 0x00
+#define TEKRAM_57600  0x01
+#define TEKRAM_38400  0x02
+#define TEKRAM_19200  0x03
+#define TEKRAM_9600   0x04
+#define TEKRAM_2400   0x08
+
+#define TEKRAM_PW 0x10 /* Pulse select bit */
+
+/* 10bit * 1s/115200bit in milliseconds = 87ms*/
+#define TIME_CONST (10000000ul/115200ul)
+
+#endif
+
+#ifdef LIRC_SIR_ACTISYS_ACT200L
+static void init_act200(void);
+#elif defined(LIRC_SIR_ACTISYS_ACT220L)
+static void init_act220(void);
+#endif
+
+/*** SA1100 ***/
+#ifdef LIRC_ON_SA1100
+struct sa1100_ser2_registers {
+       /* HSSP control register */
+       unsigned char hscr0;
+       /* UART registers */
+       unsigned char utcr0;
+       unsigned char utcr1;
+       unsigned char utcr2;
+       unsigned char utcr3;
+       unsigned char utcr4;
+       unsigned char utdr;
+       unsigned char utsr0;
+       unsigned char utsr1;
+} sr;
+
+static int irq = IRQ_Ser2ICP;
+
+#define LIRC_ON_SA1100_TRANSMITTER_LATENCY 0
+
+/* pulse/space ratio of 50/50 */
+static unsigned long pulse_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY);
+/* 1000000/freq-pulse_width */
+static unsigned long space_width = (13-LIRC_ON_SA1100_TRANSMITTER_LATENCY);
+static unsigned int freq = 38000;      /* modulation frequency */
+static unsigned int duty_cycle = 50;   /* duty cycle of 50% */
+
+#endif
+
+#define RBUF_LEN 1024
+#define WBUF_LEN 1024
+
+#define LIRC_DRIVER_NAME "lirc_sir"
+
+#define PULSE '['
+
+#ifndef LIRC_SIR_TEKRAM
+/* 9bit * 1s/115200bit in milli seconds = 78.125ms*/
+#define TIME_CONST (9000000ul/115200ul)
+#endif
+
+
+/* timeout for sequences in jiffies (=5/100s), must be longer than TIME_CONST */
+#define SIR_TIMEOUT    (HZ*5/100)
+
+#ifndef LIRC_ON_SA1100
+#ifndef LIRC_IRQ
+#define LIRC_IRQ 4
+#endif
+#ifndef LIRC_PORT
+/* for external dongles, default to com1 */
+#if defined(LIRC_SIR_ACTISYS_ACT200L)         || \
+           defined(LIRC_SIR_ACTISYS_ACT220L) || \
+           defined(LIRC_SIR_TEKRAM)
+#define LIRC_PORT 0x3f8
+#else
+/* onboard sir ports are typically com3 */
+#define LIRC_PORT 0x3e8
+#endif
+#endif
+
+static int io = LIRC_PORT;
+static int irq = LIRC_IRQ;
+static int threshold = 3;
+#endif
+
+static DEFINE_SPINLOCK(timer_lock);
+static struct timer_list timerlist;
+/* time of last signal change detected */
+static struct timeval last_tv = {0, 0};
+/* time of last UART data ready interrupt */
+static struct timeval last_intr_tv = {0, 0};
+static int last_value;
+
+static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue);
+
+static DEFINE_SPINLOCK(hardware_lock);
+
+static int rx_buf[RBUF_LEN];
+static unsigned int rx_tail, rx_head;
+
+static int debug;
+#define dprintk(fmt, args...)                                          \
+       do {                                                            \
+               if (debug)                                              \
+                       printk(KERN_DEBUG LIRC_DRIVER_NAME ": "         \
+                               fmt, ## args);                          \
+       } while (0)
+
+/* SECTION: Prototypes */
+
+/* Communication with user-space */
+static unsigned int lirc_poll(struct file *file, poll_table *wait);
+static ssize_t lirc_read(struct file *file, char *buf, size_t count,
+               loff_t *ppos);
+static ssize_t lirc_write(struct file *file, const char *buf, size_t n,
+               loff_t *pos);
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
+static void add_read_queue(int flag, unsigned long val);
+static int init_chrdev(void);
+static void drop_chrdev(void);
+/* Hardware */
+static irqreturn_t sir_interrupt(int irq, void *dev_id);
+static void send_space(unsigned long len);
+static void send_pulse(unsigned long len);
+static int init_hardware(void);
+static void drop_hardware(void);
+/* Initialisation */
+static int init_port(void);
+static void drop_port(void);
+
+#ifdef LIRC_ON_SA1100
+static void on(void)
+{
+       PPSR |= PPC_TXD2;
+}
+
+static void off(void)
+{
+       PPSR &= ~PPC_TXD2;
+}
+#else
+static inline unsigned int sinp(int offset)
+{
+       return inb(io + offset);
+}
+
+static inline void soutp(int offset, int value)
+{
+       outb(value, io + offset);
+}
+#endif
+
+#ifndef MAX_UDELAY_MS
+#define MAX_UDELAY_US 5000
+#else
+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
+#endif
+
+static void safe_udelay(unsigned long usecs)
+{
+       while (usecs > MAX_UDELAY_US) {
+               udelay(MAX_UDELAY_US);
+               usecs -= MAX_UDELAY_US;
+       }
+       udelay(usecs);
+}
+
+/* SECTION: Communication with user-space */
+
+static unsigned int lirc_poll(struct file *file, poll_table *wait)
+{
+       poll_wait(file, &lirc_read_queue, wait);
+       if (rx_head != rx_tail)
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+static ssize_t lirc_read(struct file *file, char *buf, size_t count,
+               loff_t *ppos)
+{
+       int n = 0;
+       int retval = 0;
+       DECLARE_WAITQUEUE(wait, current);
+
+       if (count % sizeof(int))
+               return -EINVAL;
+
+       add_wait_queue(&lirc_read_queue, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+       while (n < count) {
+               if (rx_head != rx_tail) {
+                       if (copy_to_user((void *) buf + n,
+                                       (void *) (rx_buf + rx_head),
+                                       sizeof(int))) {
+                               retval = -EFAULT;
+                               break;
+                       }
+                       rx_head = (rx_head + 1) & (RBUF_LEN - 1);
+                       n += sizeof(int);
+               } else {
+                       if (file->f_flags & O_NONBLOCK) {
+                               retval = -EAGAIN;
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               retval = -ERESTARTSYS;
+                               break;
+                       }
+                       schedule();
+                       set_current_state(TASK_INTERRUPTIBLE);
+               }
+       }
+       remove_wait_queue(&lirc_read_queue, &wait);
+       set_current_state(TASK_RUNNING);
+       return n ? n : retval;
+}
+static ssize_t lirc_write(struct file *file, const char *buf, size_t n,
+                               loff_t *pos)
+{
+       unsigned long flags;
+       int i, count;
+       int *tx_buf;
+
+       count = n / sizeof(int);
+       if (n % sizeof(int) || count % 2 == 0)
+               return -EINVAL;
+       tx_buf = memdup_user(buf, n);
+       if (IS_ERR(tx_buf))
+               return PTR_ERR(tx_buf);
+       i = 0;
+#ifdef LIRC_ON_SA1100
+       /* disable receiver */
+       Ser2UTCR3 = 0;
+#endif
+       local_irq_save(flags);
+       while (1) {
+               if (i >= count)
+                       break;
+               if (tx_buf[i])
+                       send_pulse(tx_buf[i]);
+               i++;
+               if (i >= count)
+                       break;
+               if (tx_buf[i])
+                       send_space(tx_buf[i]);
+               i++;
+       }
+       local_irq_restore(flags);
+#ifdef LIRC_ON_SA1100
+       off();
+       udelay(1000); /* wait 1ms for IR diode to recover */
+       Ser2UTCR3 = 0;
+       /* clear status register to prevent unwanted interrupts */
+       Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+       /* enable receiver */
+       Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE;
+#endif
+       kfree(tx_buf);
+       return count;
+}
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+       int retval = 0;
+       __u32 value = 0;
+#ifdef LIRC_ON_SA1100
+
+       if (cmd == LIRC_GET_FEATURES)
+               value = LIRC_CAN_SEND_PULSE |
+                       LIRC_CAN_SET_SEND_DUTY_CYCLE |
+                       LIRC_CAN_SET_SEND_CARRIER |
+                       LIRC_CAN_REC_MODE2;
+       else if (cmd == LIRC_GET_SEND_MODE)
+               value = LIRC_MODE_PULSE;
+       else if (cmd == LIRC_GET_REC_MODE)
+               value = LIRC_MODE_MODE2;
+#else
+       if (cmd == LIRC_GET_FEATURES)
+               value = LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
+       else if (cmd == LIRC_GET_SEND_MODE)
+               value = LIRC_MODE_PULSE;
+       else if (cmd == LIRC_GET_REC_MODE)
+               value = LIRC_MODE_MODE2;
+#endif
+
+       switch (cmd) {
+       case LIRC_GET_FEATURES:
+       case LIRC_GET_SEND_MODE:
+       case LIRC_GET_REC_MODE:
+               retval = put_user(value, (__u32 *) arg);
+               break;
+
+       case LIRC_SET_SEND_MODE:
+       case LIRC_SET_REC_MODE:
+               retval = get_user(value, (__u32 *) arg);
+               break;
+#ifdef LIRC_ON_SA1100
+       case LIRC_SET_SEND_DUTY_CYCLE:
+               retval = get_user(value, (__u32 *) arg);
+               if (retval)
+                       return retval;
+               if (value <= 0 || value > 100)
+                       return -EINVAL;
+               /* (value/100)*(1000000/freq) */
+               duty_cycle = value;
+               pulse_width = (unsigned long) duty_cycle*10000/freq;
+               space_width = (unsigned long) 1000000L/freq-pulse_width;
+               if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+                       pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+               if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+                       space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+               break;
+       case LIRC_SET_SEND_CARRIER:
+               retval = get_user(value, (__u32 *) arg);
+               if (retval)
+                       return retval;
+               if (value > 500000 || value < 20000)
+                       return -EINVAL;
+               freq = value;
+               pulse_width = (unsigned long) duty_cycle*10000/freq;
+               space_width = (unsigned long) 1000000L/freq-pulse_width;
+               if (pulse_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+                       pulse_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+               if (space_width >= LIRC_ON_SA1100_TRANSMITTER_LATENCY)
+                       space_width -= LIRC_ON_SA1100_TRANSMITTER_LATENCY;
+               break;
+#endif
+       default:
+               retval = -ENOIOCTLCMD;
+
+       }
+
+       if (retval)
+               return retval;
+       if (cmd == LIRC_SET_REC_MODE) {
+               if (value != LIRC_MODE_MODE2)
+                       retval = -ENOSYS;
+       } else if (cmd == LIRC_SET_SEND_MODE) {
+               if (value != LIRC_MODE_PULSE)
+                       retval = -ENOSYS;
+       }
+
+       return retval;
+}
+
+static void add_read_queue(int flag, unsigned long val)
+{
+       unsigned int new_rx_tail;
+       int newval;
+
+       dprintk("add flag %d with val %lu\n", flag, val);
+
+       newval = val & PULSE_MASK;
+
+       /*
+        * statistically, pulses are ~TIME_CONST/2 too long. we could
+        * maybe make this more exact, but this is good enough
+        */
+       if (flag) {
+               /* pulse */
+               if (newval > TIME_CONST/2)
+                       newval -= TIME_CONST/2;
+               else /* should not ever happen */
+                       newval = 1;
+               newval |= PULSE_BIT;
+       } else {
+               newval += TIME_CONST/2;
+       }
+       new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1);
+       if (new_rx_tail == rx_head) {
+               dprintk("Buffer overrun.\n");
+               return;
+       }
+       rx_buf[rx_tail] = newval;
+       rx_tail = new_rx_tail;
+       wake_up_interruptible(&lirc_read_queue);
+}
+
+static const struct file_operations lirc_fops = {
+       .owner          = THIS_MODULE,
+       .read           = lirc_read,
+       .write          = lirc_write,
+       .poll           = lirc_poll,
+       .unlocked_ioctl = lirc_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = lirc_ioctl,
+#endif
+       .open           = lirc_dev_fop_open,
+       .release        = lirc_dev_fop_close,
+       .llseek         = no_llseek,
+};
+
+static int set_use_inc(void *data)
+{
+       return 0;
+}
+
+static void set_use_dec(void *data)
+{
+}
+
+static struct lirc_driver driver = {
+       .name           = LIRC_DRIVER_NAME,
+       .minor          = -1,
+       .code_length    = 1,
+       .sample_rate    = 0,
+       .data           = NULL,
+       .add_to_buf     = NULL,
+       .set_use_inc    = set_use_inc,
+       .set_use_dec    = set_use_dec,
+       .fops           = &lirc_fops,
+       .dev            = NULL,
+       .owner          = THIS_MODULE,
+};
+
+
+static int init_chrdev(void)
+{
+       driver.minor = lirc_register_driver(&driver);
+       if (driver.minor < 0) {
+               printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+static void drop_chrdev(void)
+{
+       lirc_unregister_driver(driver.minor);
+}
+
+/* SECTION: Hardware */
+static long delta(struct timeval *tv1, struct timeval *tv2)
+{
+       unsigned long deltv;
+
+       deltv = tv2->tv_sec - tv1->tv_sec;
+       if (deltv > 15)
+               deltv = 0xFFFFFF;
+       else
+               deltv = deltv*1000000 +
+                       tv2->tv_usec -
+                       tv1->tv_usec;
+       return deltv;
+}
+
+static void sir_timeout(unsigned long data)
+{
+       /*
+        * if last received signal was a pulse, but receiving stopped
+        * within the 9 bit frame, we need to finish this pulse and
+        * simulate a signal change to from pulse to space. Otherwise
+        * upper layers will receive two sequences next time.
+        */
+
+       unsigned long flags;
+       unsigned long pulse_end;
+
+       /* avoid interference with interrupt */
+       spin_lock_irqsave(&timer_lock, flags);
+       if (last_value) {
+#ifndef LIRC_ON_SA1100
+               /* clear unread bits in UART and restart */
+               outb(UART_FCR_CLEAR_RCVR, io + UART_FCR);
+#endif
+               /* determine 'virtual' pulse end: */
+               pulse_end = delta(&last_tv, &last_intr_tv);
+               dprintk("timeout add %d for %lu usec\n", last_value, pulse_end);
+               add_read_queue(last_value, pulse_end);
+               last_value = 0;
+               last_tv = last_intr_tv;
+       }
+       spin_unlock_irqrestore(&timer_lock, flags);
+}
+
+static irqreturn_t sir_interrupt(int irq, void *dev_id)
+{
+       unsigned char data;
+       struct timeval curr_tv;
+       static unsigned long deltv;
+#ifdef LIRC_ON_SA1100
+       int status;
+       static int n;
+
+       status = Ser2UTSR0;
+       /*
+        * Deal with any receive errors first.  The bytes in error may be
+        * the only bytes in the receive FIFO, so we do this first.
+        */
+       while (status & UTSR0_EIF) {
+               int bstat;
+
+               if (debug) {
+                       dprintk("EIF\n");
+                       bstat = Ser2UTSR1;
+
+                       if (bstat & UTSR1_FRE)
+                               dprintk("frame error\n");
+                       if (bstat & UTSR1_ROR)
+                               dprintk("receive fifo overrun\n");
+                       if (bstat & UTSR1_PRE)
+                               dprintk("parity error\n");
+               }
+
+               bstat = Ser2UTDR;
+               n++;
+               status = Ser2UTSR0;
+       }
+
+       if (status & (UTSR0_RFS | UTSR0_RID)) {
+               do_gettimeofday(&curr_tv);
+               deltv = delta(&last_tv, &curr_tv);
+               do {
+                       data = Ser2UTDR;
+                       dprintk("%d data: %u\n", n, (unsigned int) data);
+                       n++;
+               } while (status & UTSR0_RID && /* do not empty fifo in order to
+                                               * get UTSR0_RID in any case */
+                     Ser2UTSR1 & UTSR1_RNE); /* data ready */
+
+               if (status&UTSR0_RID) {
+                       add_read_queue(0 , deltv - n * TIME_CONST); /*space*/
+                       add_read_queue(1, n * TIME_CONST); /*pulse*/
+                       n = 0;
+                       last_tv = curr_tv;
+               }
+       }
+
+       if (status & UTSR0_TFS)
+               printk(KERN_ERR "transmit fifo not full, shouldn't happen\n");
+
+       /* We must clear certain bits. */
+       status &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+       if (status)
+               Ser2UTSR0 = status;
+#else
+       unsigned long deltintrtv;
+       unsigned long flags;
+       int iir, lsr;
+
+       while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) {
+               switch (iir&UART_IIR_ID) { /* FIXME toto treba preriedit */
+               case UART_IIR_MSI:
+                       (void) inb(io + UART_MSR);
+                       break;
+               case UART_IIR_RLSI:
+                       (void) inb(io + UART_LSR);
+                       break;
+               case UART_IIR_THRI:
+#if 0
+                       if (lsr & UART_LSR_THRE) /* FIFO is empty */
+                               outb(data, io + UART_TX)
+#endif
+                       break;
+               case UART_IIR_RDI:
+                       /* avoid interference with timer */
+                       spin_lock_irqsave(&timer_lock, flags);
+                       do {
+                               del_timer(&timerlist);
+                               data = inb(io + UART_RX);
+                               do_gettimeofday(&curr_tv);
+                               deltv = delta(&last_tv, &curr_tv);
+                               deltintrtv = delta(&last_intr_tv, &curr_tv);
+                               dprintk("t %lu, d %d\n", deltintrtv, (int)data);
+                               /*
+                                * if nothing came in last X cycles,
+                                * it was gap
+                                */
+                               if (deltintrtv > TIME_CONST * threshold) {
+                                       if (last_value) {
+                                               dprintk("GAP\n");
+                                               /* simulate signal change */
+                                               add_read_queue(last_value,
+                                                              deltv -
+                                                              deltintrtv);
+                                               last_value = 0;
+                                               last_tv.tv_sec =
+                                                       last_intr_tv.tv_sec;
+                                               last_tv.tv_usec =
+                                                       last_intr_tv.tv_usec;
+                                               deltv = deltintrtv;
+                                       }
+                               }
+                               data = 1;
+                               if (data ^ last_value) {
+                                       /*
+                                        * deltintrtv > 2*TIME_CONST, remember?
+                                        * the other case is timeout
+                                        */
+                                       add_read_queue(last_value,
+                                                      deltv-TIME_CONST);
+                                       last_value = data;
+                                       last_tv = curr_tv;
+                                       if (last_tv.tv_usec >= TIME_CONST) {
+                                               last_tv.tv_usec -= TIME_CONST;
+                                       } else {
+                                               last_tv.tv_sec--;
+                                               last_tv.tv_usec += 1000000 -
+                                                       TIME_CONST;
+                                       }
+                               }
+                               last_intr_tv = curr_tv;
+                               if (data) {
+                                       /*
+                                        * start timer for end of
+                                        * sequence detection
+                                        */
+                                       timerlist.expires = jiffies +
+                                                               SIR_TIMEOUT;
+                                       add_timer(&timerlist);
+                               }
+
+                               lsr = inb(io + UART_LSR);
+                       } while (lsr & UART_LSR_DR); /* data ready */
+                       spin_unlock_irqrestore(&timer_lock, flags);
+                       break;
+               default:
+                       break;
+               }
+       }
+#endif
+       return IRQ_RETVAL(IRQ_HANDLED);
+}
+
+#ifdef LIRC_ON_SA1100
+static void send_pulse(unsigned long length)
+{
+       unsigned long k, delay;
+       int flag;
+
+       if (length == 0)
+               return;
+       /*
+        * this won't give us the carrier frequency we really want
+        * due to integer arithmetic, but we can accept this inaccuracy
+        */
+
+       for (k = flag = 0; k < length; k += delay, flag = !flag) {
+               if (flag) {
+                       off();
+                       delay = space_width;
+               } else {
+                       on();
+                       delay = pulse_width;
+               }
+               safe_udelay(delay);
+       }
+       off();
+}
+
+static void send_space(unsigned long length)
+{
+       if (length == 0)
+               return;
+       off();
+       safe_udelay(length);
+}
+#else
+static void send_space(unsigned long len)
+{
+       safe_udelay(len);
+}
+
+static void send_pulse(unsigned long len)
+{
+       long bytes_out = len / TIME_CONST;
+
+       if (bytes_out == 0)
+               bytes_out++;
+
+       while (bytes_out--) {
+               outb(PULSE, io + UART_TX);
+               /* FIXME treba seriozne cakanie z char/serial.c */
+               while (!(inb(io + UART_LSR) & UART_LSR_THRE))
+                       ;
+       }
+}
+#endif
+
+#ifdef CONFIG_SA1100_COLLIE
+static int sa1100_irda_set_power_collie(int state)
+{
+       if (state) {
+               /*
+                *  0 - off
+                *  1 - short range, lowest power
+                *  2 - medium range, medium power
+                *  3 - maximum range, high power
+                */
+               ucb1200_set_io_direction(TC35143_GPIO_IR_ON,
+                                        TC35143_IODIR_OUTPUT);
+               ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_LOW);
+               udelay(100);
+       } else {
+               /* OFF */
+               ucb1200_set_io_direction(TC35143_GPIO_IR_ON,
+                                        TC35143_IODIR_OUTPUT);
+               ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_HIGH);
+       }
+       return 0;
+}
+#endif
+
+static int init_hardware(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hardware_lock, flags);
+       /* reset UART */
+#ifdef LIRC_ON_SA1100
+#ifdef CONFIG_SA1100_BITSY
+       if (machine_is_bitsy()) {
+               printk(KERN_INFO "Power on IR module\n");
+               set_bitsy_egpio(EGPIO_BITSY_IR_ON);
+       }
+#endif
+#ifdef CONFIG_SA1100_COLLIE
+       sa1100_irda_set_power_collie(3);        /* power on */
+#endif
+       sr.hscr0 = Ser2HSCR0;
+
+       sr.utcr0 = Ser2UTCR0;
+       sr.utcr1 = Ser2UTCR1;
+       sr.utcr2 = Ser2UTCR2;
+       sr.utcr3 = Ser2UTCR3;
+       sr.utcr4 = Ser2UTCR4;
+
+       sr.utdr = Ser2UTDR;
+       sr.utsr0 = Ser2UTSR0;
+       sr.utsr1 = Ser2UTSR1;
+
+       /* configure GPIO */
+       /* output */
+       PPDR |= PPC_TXD2;
+       PSDR |= PPC_TXD2;
+       /* set output to 0 */
+       off();
+
+       /* Enable HP-SIR modulation, and ensure that the port is disabled. */
+       Ser2UTCR3 = 0;
+       Ser2HSCR0 = sr.hscr0 & (~HSCR0_HSSP);
+
+       /* clear status register to prevent unwanted interrupts */
+       Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+
+       /* 7N1 */
+       Ser2UTCR0 = UTCR0_1StpBit|UTCR0_7BitData;
+       /* 115200 */
+       Ser2UTCR1 = 0;
+       Ser2UTCR2 = 1;
+       /* use HPSIR, 1.6 usec pulses */
+       Ser2UTCR4 = UTCR4_HPSIR|UTCR4_Z1_6us;
+
+       /* enable receiver, receive fifo interrupt */
+       Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE;
+
+       /* clear status register to prevent unwanted interrupts */
+       Ser2UTSR0 &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB);
+
+#elif defined(LIRC_SIR_TEKRAM)
+       /* disable FIFO */
+       soutp(UART_FCR,
+             UART_FCR_CLEAR_RCVR|
+             UART_FCR_CLEAR_XMIT|
+             UART_FCR_TRIGGER_1);
+
+       /* Set DLAB 0. */
+       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+       /* First of all, disable all interrupts */
+       soutp(UART_IER, sinp(UART_IER) &
+             (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI)));
+
+       /* Set DLAB 1. */
+       soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+
+       /* Set divisor to 12 => 9600 Baud */
+       soutp(UART_DLM, 0);
+       soutp(UART_DLL, 12);
+
+       /* Set DLAB 0. */
+       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+       /* power supply */
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+       safe_udelay(50*1000);
+
+       /* -DTR low -> reset PIC */
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+       udelay(1*1000);
+
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+       udelay(100);
+
+
+       /* -RTS low -> send control byte */
+       soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
+       udelay(7);
+       soutp(UART_TX, TEKRAM_115200|TEKRAM_PW);
+
+       /* one byte takes ~1042 usec to transmit at 9600,8N1 */
+       udelay(1500);
+
+       /* back to normal operation */
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+       udelay(50);
+
+       udelay(1500);
+
+       /* read previous control byte */
+       printk(KERN_INFO LIRC_DRIVER_NAME
+              ": 0x%02x\n", sinp(UART_RX));
+
+       /* Set DLAB 1. */
+       soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+
+       /* Set divisor to 1 => 115200 Baud */
+       soutp(UART_DLM, 0);
+       soutp(UART_DLL, 1);
+
+       /* Set DLAB 0, 8 Bit */
+       soutp(UART_LCR, UART_LCR_WLEN8);
+       /* enable interrupts */
+       soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI);
+#else
+       outb(0, io + UART_MCR);
+       outb(0, io + UART_IER);
+       /* init UART */
+       /* set DLAB, speed = 115200 */
+       outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR);
+       outb(1, io + UART_DLL); outb(0, io + UART_DLM);
+       /* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */
+       outb(UART_LCR_WLEN7, io + UART_LCR);
+       /* FIFO operation */
+       outb(UART_FCR_ENABLE_FIFO, io + UART_FCR);
+       /* interrupts */
+       /* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */
+       outb(UART_IER_RDI, io + UART_IER);
+       /* turn on UART */
+       outb(UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2, io + UART_MCR);
+#ifdef LIRC_SIR_ACTISYS_ACT200L
+       init_act200();
+#elif defined(LIRC_SIR_ACTISYS_ACT220L)
+       init_act220();
+#endif
+#endif
+       spin_unlock_irqrestore(&hardware_lock, flags);
+       return 0;
+}
+
+static void drop_hardware(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hardware_lock, flags);
+
+#ifdef LIRC_ON_SA1100
+       Ser2UTCR3 = 0;
+
+       Ser2UTCR0 = sr.utcr0;
+       Ser2UTCR1 = sr.utcr1;
+       Ser2UTCR2 = sr.utcr2;
+       Ser2UTCR4 = sr.utcr4;
+       Ser2UTCR3 = sr.utcr3;
+
+       Ser2HSCR0 = sr.hscr0;
+#ifdef CONFIG_SA1100_BITSY
+       if (machine_is_bitsy())
+               clr_bitsy_egpio(EGPIO_BITSY_IR_ON);
+#endif
+#ifdef CONFIG_SA1100_COLLIE
+       sa1100_irda_set_power_collie(0);        /* power off */
+#endif
+#else
+       /* turn off interrupts */
+       outb(0, io + UART_IER);
+#endif
+       spin_unlock_irqrestore(&hardware_lock, flags);
+}
+
+/* SECTION: Initialisation */
+
+static int init_port(void)
+{
+       int retval;
+
+       /* get I/O port access and IRQ line */
+#ifndef LIRC_ON_SA1100
+       if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) {
+               printk(KERN_ERR LIRC_DRIVER_NAME
+                      ": i/o port 0x%.4x already in use.\n", io);
+               return -EBUSY;
+       }
+#endif
+       retval = request_irq(irq, sir_interrupt, 0,
+                            LIRC_DRIVER_NAME, NULL);
+       if (retval < 0) {
+#               ifndef LIRC_ON_SA1100
+               release_region(io, 8);
+#               endif
+               printk(KERN_ERR LIRC_DRIVER_NAME
+                       ": IRQ %d already in use.\n",
+                       irq);
+               return retval;
+       }
+#ifndef LIRC_ON_SA1100
+       printk(KERN_INFO LIRC_DRIVER_NAME
+               ": I/O port 0x%.4x, IRQ %d.\n",
+               io, irq);
+#endif
+
+       init_timer(&timerlist);
+       timerlist.function = sir_timeout;
+       timerlist.data = 0xabadcafe;
+
+       return 0;
+}
+
+static void drop_port(void)
+{
+       free_irq(irq, NULL);
+       del_timer_sync(&timerlist);
+#ifndef LIRC_ON_SA1100
+       release_region(io, 8);
+#endif
+}
+
+#ifdef LIRC_SIR_ACTISYS_ACT200L
+/* Crystal/Cirrus CS8130 IR transceiver, used in Actisys Act200L dongle */
+/* some code borrowed from Linux IRDA driver */
+
+/* Register 0: Control register #1 */
+#define ACT200L_REG0    0x00
+#define ACT200L_TXEN    0x01 /* Enable transmitter */
+#define ACT200L_RXEN    0x02 /* Enable receiver */
+#define ACT200L_ECHO    0x08 /* Echo control chars */
+
+/* Register 1: Control register #2 */
+#define ACT200L_REG1    0x10
+#define ACT200L_LODB    0x01 /* Load new baud rate count value */
+#define ACT200L_WIDE    0x04 /* Expand the maximum allowable pulse */
+
+/* Register 3: Transmit mode register #2 */
+#define ACT200L_REG3    0x30
+#define ACT200L_B0      0x01 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P)  */
+#define ACT200L_B1      0x02 /* DataBits, 0=6, 1=7, 2=8, 3=9(8P)  */
+#define ACT200L_CHSY    0x04 /* StartBit Synced 0=bittime, 1=startbit */
+
+/* Register 4: Output Power register */
+#define ACT200L_REG4    0x40
+#define ACT200L_OP0     0x01 /* Enable LED1C output */
+#define ACT200L_OP1     0x02 /* Enable LED2C output */
+#define ACT200L_BLKR    0x04
+
+/* Register 5: Receive Mode register */
+#define ACT200L_REG5    0x50
+#define ACT200L_RWIDL   0x01 /* fixed 1.6us pulse mode */
+    /*.. other various IRDA bit modes, and TV remote modes..*/
+
+/* Register 6: Receive Sensitivity register #1 */
+#define ACT200L_REG6    0x60
+#define ACT200L_RS0     0x01 /* receive threshold bit 0 */
+#define ACT200L_RS1     0x02 /* receive threshold bit 1 */
+
+/* Register 7: Receive Sensitivity register #2 */
+#define ACT200L_REG7    0x70
+#define ACT200L_ENPOS   0x04 /* Ignore the falling edge */
+
+/* Register 8,9: Baud Rate Divider register #1,#2 */
+#define ACT200L_REG8    0x80
+#define ACT200L_REG9    0x90
+
+#define ACT200L_2400    0x5f
+#define ACT200L_9600    0x17
+#define ACT200L_19200   0x0b
+#define ACT200L_38400   0x05
+#define ACT200L_57600   0x03
+#define ACT200L_115200  0x01
+
+/* Register 13: Control register #3 */
+#define ACT200L_REG13   0xd0
+#define ACT200L_SHDW    0x01 /* Enable access to shadow registers */
+
+/* Register 15: Status register */
+#define ACT200L_REG15   0xf0
+
+/* Register 21: Control register #4 */
+#define ACT200L_REG21   0x50
+#define ACT200L_EXCK    0x02 /* Disable clock output driver */
+#define ACT200L_OSCL    0x04 /* oscillator in low power, medium accuracy mode */
+
+static void init_act200(void)
+{
+       int i;
+       __u8 control[] = {
+               ACT200L_REG15,
+               ACT200L_REG13 | ACT200L_SHDW,
+               ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL,
+               ACT200L_REG13,
+               ACT200L_REG7  | ACT200L_ENPOS,
+               ACT200L_REG6  | ACT200L_RS0  | ACT200L_RS1,
+               ACT200L_REG5  | ACT200L_RWIDL,
+               ACT200L_REG4  | ACT200L_OP0  | ACT200L_OP1 | ACT200L_BLKR,
+               ACT200L_REG3  | ACT200L_B0,
+               ACT200L_REG0  | ACT200L_TXEN | ACT200L_RXEN,
+               ACT200L_REG8 |  (ACT200L_115200       & 0x0f),
+               ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f),
+               ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE
+       };
+
+       /* Set DLAB 1. */
+       soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8);
+
+       /* Set divisor to 12 => 9600 Baud */
+       soutp(UART_DLM, 0);
+       soutp(UART_DLL, 12);
+
+       /* Set DLAB 0. */
+       soutp(UART_LCR, UART_LCR_WLEN8);
+       /* Set divisor to 12 => 9600 Baud */
+
+       /* power supply */
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+       for (i = 0; i < 50; i++)
+               safe_udelay(1000);
+
+               /* Reset the dongle : set RTS low for 25 ms */
+       soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
+       for (i = 0; i < 25; i++)
+               udelay(1000);
+
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+       udelay(100);
+
+       /* Clear DTR and set RTS to enter command mode */
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+       udelay(7);
+
+       /* send out the control register settings for 115K 7N1 SIR operation */
+       for (i = 0; i < sizeof(control); i++) {
+               soutp(UART_TX, control[i]);
+               /* one byte takes ~1042 usec to transmit at 9600,8N1 */
+               udelay(1500);
+       }
+
+       /* back to normal operation */
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+       udelay(50);
+
+       udelay(1500);
+       soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB);
+
+       /* Set DLAB 1. */
+       soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7);
+
+       /* Set divisor to 1 => 115200 Baud */
+       soutp(UART_DLM, 0);
+       soutp(UART_DLL, 1);
+
+       /* Set DLAB 0. */
+       soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB));
+
+       /* Set DLAB 0, 7 Bit */
+       soutp(UART_LCR, UART_LCR_WLEN7);
+
+       /* enable interrupts */
+       soutp(UART_IER, sinp(UART_IER)|UART_IER_RDI);
+}
+#endif
+
+#ifdef LIRC_SIR_ACTISYS_ACT220L
+/*
+ * Derived from linux IrDA driver (net/irda/actisys.c)
+ * Drop me a mail for any kind of comment: maxx@spaceboyz.net
+ */
+
+void init_act220(void)
+{
+       int i;
+
+       /* DLAB 1 */
+       soutp(UART_LCR, UART_LCR_DLAB|UART_LCR_WLEN7);
+
+       /* 9600 baud */
+       soutp(UART_DLM, 0);
+       soutp(UART_DLL, 12);
+
+       /* DLAB 0 */
+       soutp(UART_LCR, UART_LCR_WLEN7);
+
+       /* reset the dongle, set DTR low for 10us */
+       soutp(UART_MCR, UART_MCR_RTS|UART_MCR_OUT2);
+       udelay(10);
+
+       /* back to normal (still 9600) */
+       soutp(UART_MCR, UART_MCR_DTR|UART_MCR_RTS|UART_MCR_OUT2);
+
+       /*
+        * send RTS pulses until we reach 115200
+        * i hope this is really the same for act220l/act220l+
+        */
+       for (i = 0; i < 3; i++) {
+               udelay(10);
+               /* set RTS low for 10 us */
+               soutp(UART_MCR, UART_MCR_DTR|UART_MCR_OUT2);
+               udelay(10);
+               /* set RTS high for 10 us */
+               soutp(UART_MCR, UART_MCR_RTS|UART_MCR_DTR|UART_MCR_OUT2);
+       }
+
+       /* back to normal operation */
+       udelay(1500); /* better safe than sorry ;) */
+
+       /* Set DLAB 1. */
+       soutp(UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN7);
+
+       /* Set divisor to 1 => 115200 Baud */
+       soutp(UART_DLM, 0);
+       soutp(UART_DLL, 1);
+
+       /* Set DLAB 0, 7 Bit */
+       /* The dongle doesn't seem to have any problems with operation at 7N1 */
+       soutp(UART_LCR, UART_LCR_WLEN7);
+
+       /* enable interrupts */
+       soutp(UART_IER, UART_IER_RDI);
+}
+#endif
+
+static int init_lirc_sir(void)
+{
+       int retval;
+
+       init_waitqueue_head(&lirc_read_queue);
+       retval = init_port();
+       if (retval < 0)
+               return retval;
+       init_hardware();
+       printk(KERN_INFO LIRC_DRIVER_NAME
+               ": Installed.\n");
+       return 0;
+}
+
+
+static int __init lirc_sir_init(void)
+{
+       int retval;
+
+       retval = init_chrdev();
+       if (retval < 0)
+               return retval;
+       retval = init_lirc_sir();
+       if (retval) {
+               drop_chrdev();
+               return retval;
+       }
+       return 0;
+}
+
+static void __exit lirc_sir_exit(void)
+{
+       drop_hardware();
+       drop_chrdev();
+       drop_port();
+       printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
+}
+
+module_init(lirc_sir_init);
+module_exit(lirc_sir_exit);
+
+#ifdef LIRC_SIR_TEKRAM
+MODULE_DESCRIPTION("Infrared receiver driver for Tekram Irmate 210");
+MODULE_AUTHOR("Christoph Bartelmus");
+#elif defined(LIRC_ON_SA1100)
+MODULE_DESCRIPTION("LIRC driver for StrongARM SA1100 embedded microprocessor");
+MODULE_AUTHOR("Christoph Bartelmus");
+#elif defined(LIRC_SIR_ACTISYS_ACT200L)
+MODULE_DESCRIPTION("LIRC driver for Actisys Act200L");
+MODULE_AUTHOR("Karl Bongers");
+#elif defined(LIRC_SIR_ACTISYS_ACT220L)
+MODULE_DESCRIPTION("LIRC driver for Actisys Act220L(+)");
+MODULE_AUTHOR("Jan Roemisch");
+#else
+MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports");
+MODULE_AUTHOR("Milan Pikula");
+#endif
+MODULE_LICENSE("GPL");
+
+#ifdef LIRC_ON_SA1100
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (16)");
+#else
+module_param(io, int, S_IRUGO);
+MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");
+
+module_param(irq, int, S_IRUGO);
+MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");
+
+module_param(threshold, int, S_IRUGO);
+MODULE_PARM_DESC(threshold, "space detection threshold (3)");
+#endif
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/staging/media/lirc/lirc_ttusbir.c b/drivers/staging/media/lirc/lirc_ttusbir.c
new file mode 100644 (file)
index 0000000..e4b329b
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * lirc_ttusbir.c
+ *
+ * lirc_ttusbir - LIRC device driver for the TechnoTrend USB IR Receiver
+ *
+ * Copyright (C) 2007 Stefan Macher <st_maker-lirc@yahoo.de>
+ *
+ * This LIRC driver provides access to the TechnoTrend USB IR Receiver.
+ * The receiver delivers the IR signal as raw sampled true/false data in
+ * isochronous USB packets each of size 128 byte.
+ * Currently the driver reduces the sampling rate by factor of 8 as this
+ * is still more than enough to decode RC-5 - others should be analyzed.
+ * But the driver does not rely on RC-5 it should be able to decode every
+ * IR signal that is not too fast.
+ */
+
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+MODULE_DESCRIPTION("TechnoTrend USB IR device driver for LIRC");
+MODULE_AUTHOR("Stefan Macher (st_maker-lirc@yahoo.de)");
+MODULE_LICENSE("GPL");
+
+/* #define DEBUG */
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+#define DPRINTK(_x_, a...)
+#endif
+
+/* function declarations */
+static int probe(struct usb_interface *intf, const struct usb_device_id *id);
+static void disconnect(struct usb_interface *intf);
+static void urb_complete(struct urb *urb);
+static int set_use_inc(void *data);
+static void set_use_dec(void *data);
+
+static int num_urbs = 2;
+module_param(num_urbs, int, S_IRUGO);
+MODULE_PARM_DESC(num_urbs,
+                "Number of URBs in queue. Try to increase to 4 in case "
+                "of problems (default: 2; minimum: 2)");
+
+/* table of devices that work with this driver */
+static struct usb_device_id device_id_table[] = {
+       /* TechnoTrend USB IR Receiver */
+       { USB_DEVICE(0x0B48, 0x2003) },
+       /* Terminating entry */
+       { }
+};
+MODULE_DEVICE_TABLE(usb, device_id_table);
+
+/* USB driver definition */
+static struct usb_driver usb_driver = {
+       .name = "TTUSBIR",
+       .id_table = &(device_id_table[0]),
+       .probe = probe,
+       .disconnect = disconnect,
+};
+
+/* USB device definition */
+struct ttusbir_device {
+       struct usb_driver *usb_driver;
+       struct usb_device *udev;
+       struct usb_interface *interf;
+       struct usb_class_driver class_driver;
+       unsigned int ifnum; /* Interface number to use */
+       unsigned int alt_setting; /* alternate setting to use */
+       unsigned int endpoint; /* Endpoint to use */
+       struct urb **urb; /* num_urb URB pointers*/
+       char **buffer; /* 128 byte buffer for each URB */
+       struct lirc_buffer rbuf; /* Buffer towards LIRC */
+       struct lirc_driver driver;
+       int minor;
+       int last_pulse; /* remembers if last received byte was pulse or space */
+       int last_num; /* remembers how many last bytes appeared */
+       int opened;
+};
+
+/*** LIRC specific functions ***/
+static int set_use_inc(void *data)
+{
+       int i, retval;
+       struct ttusbir_device *ttusbir = data;
+
+       DPRINTK("Sending first URBs\n");
+       /* @TODO Do I need to check if I am already opened */
+       ttusbir->opened = 1;
+
+       for (i = 0; i < num_urbs; i++) {
+               retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL);
+               if (retval) {
+                       err("%s: usb_submit_urb failed on urb %d",
+                           __func__, i);
+                       return retval;
+               }
+       }
+       return 0;
+}
+
+static void set_use_dec(void *data)
+{
+       struct ttusbir_device *ttusbir = data;
+
+       DPRINTK("Device closed\n");
+
+       ttusbir->opened = 0;
+}
+
+/*** USB specific functions ***/
+
+/*
+ * This mapping table is used to do a very simple filtering of the
+ * input signal.
+ * For a value with at least 4 bits set it returns 0xFF otherwise
+ * 0x00.  For faster IR signals this can not be used. But for RC-5 we
+ * still have about 14 samples per pulse/space, i.e. we sample with 14
+ * times higher frequency than the signal frequency
+ */
+const unsigned char map_table[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
+       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+static void urb_complete(struct urb *urb)
+{
+       struct ttusbir_device *ttusbir;
+       unsigned char *buf;
+       int i;
+       int l;
+
+       ttusbir = urb->context;
+
+       if (!ttusbir->opened)
+               return;
+
+       buf = (unsigned char *)urb->transfer_buffer;
+
+       for (i = 0; i < 128; i++) {
+               /* Here we do the filtering and some kind of down sampling */
+               buf[i] = ~map_table[buf[i]];
+               if (ttusbir->last_pulse == buf[i]) {
+                       if (ttusbir->last_num < PULSE_MASK/63)
+                               ttusbir->last_num++;
+               /*
+                * else we are in a idle period and do not need to
+                * increment any longer
+                */
+               } else {
+                       l = ttusbir->last_num * 62; /* about 62 = us/byte */
+                       if (ttusbir->last_pulse) /* pulse or space? */
+                               l |= PULSE_BIT;
+                       if (!lirc_buffer_full(&ttusbir->rbuf)) {
+                               lirc_buffer_write(&ttusbir->rbuf, (void *)&l);
+                               wake_up_interruptible(&ttusbir->rbuf.wait_poll);
+                       }
+                       ttusbir->last_num = 0;
+                       ttusbir->last_pulse = buf[i];
+               }
+       }
+       usb_submit_urb(urb, GFP_ATOMIC); /* keep data rolling :-) */
+}
+
+/*
+ * Called whenever the USB subsystem thinks we could be the right driver
+ * to handle this device
+ */
+static int probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       int alt_set, endp;
+       int found = 0;
+       int i, j;
+       int struct_size;
+       struct usb_host_interface *host_interf;
+       struct usb_interface_descriptor *interf_desc;
+       struct usb_host_endpoint *host_endpoint;
+       struct ttusbir_device *ttusbir;
+
+       DPRINTK("Module ttusbir probe\n");
+
+       /* To reduce memory fragmentation we use only one allocation */
+       struct_size =  sizeof(struct ttusbir_device) +
+               (sizeof(struct urb *) * num_urbs) +
+               (sizeof(char *) * num_urbs) +
+               (num_urbs * 128);
+       ttusbir = kzalloc(struct_size, GFP_KERNEL);
+       if (!ttusbir)
+               return -ENOMEM;
+
+       ttusbir->urb = (struct urb **)((char *)ttusbir +
+                                     sizeof(struct ttusbir_device));
+       ttusbir->buffer = (char **)((char *)ttusbir->urb +
+                                  (sizeof(struct urb *) * num_urbs));
+       for (i = 0; i < num_urbs; i++)
+               ttusbir->buffer[i] = (char *)ttusbir->buffer +
+                       (sizeof(char *)*num_urbs) + (i * 128);
+
+       ttusbir->usb_driver = &usb_driver;
+       ttusbir->alt_setting = -1;
+       /* @TODO check if error can be returned */
+       ttusbir->udev = usb_get_dev(interface_to_usbdev(intf));
+       ttusbir->interf = intf;
+       ttusbir->last_pulse = 0x00;
+       ttusbir->last_num = 0;
+
+       /*
+        * Now look for interface setting we can handle
+        * We are searching for the alt setting where end point
+        * 0x82 has max packet size 16
+        */
+       for (alt_set = 0; alt_set < intf->num_altsetting && !found; alt_set++) {
+               host_interf = &intf->altsetting[alt_set];
+               interf_desc = &host_interf->desc;
+               for (endp = 0; endp < interf_desc->bNumEndpoints; endp++) {
+                       host_endpoint = &host_interf->endpoint[endp];
+                       if ((host_endpoint->desc.bEndpointAddress == 0x82) &&
+                           (host_endpoint->desc.wMaxPacketSize == 0x10)) {
+                               ttusbir->alt_setting = alt_set;
+                               ttusbir->endpoint = endp;
+                               found = 1;
+                               break;
+                       }
+               }
+       }
+       if (ttusbir->alt_setting != -1)
+               DPRINTK("alt setting: %d\n", ttusbir->alt_setting);
+       else {
+               err("Could not find alternate setting\n");
+               kfree(ttusbir);
+               return -EINVAL;
+       }
+
+       /* OK lets setup this interface setting */
+       usb_set_interface(ttusbir->udev, 0, ttusbir->alt_setting);
+
+       /* Store device info in interface structure */
+       usb_set_intfdata(intf, ttusbir);
+
+       /* Register as a LIRC driver */
+       if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) {
+               err("Could not get memory for LIRC data buffer\n");
+               usb_set_intfdata(intf, NULL);
+               kfree(ttusbir);
+               return -ENOMEM;
+       }
+       strcpy(ttusbir->driver.name, "TTUSBIR");
+       ttusbir->driver.minor = -1;
+       ttusbir->driver.code_length = 1;
+       ttusbir->driver.sample_rate = 0;
+       ttusbir->driver.data = ttusbir;
+       ttusbir->driver.add_to_buf = NULL;
+       ttusbir->driver.rbuf = &ttusbir->rbuf;
+       ttusbir->driver.set_use_inc = set_use_inc;
+       ttusbir->driver.set_use_dec = set_use_dec;
+       ttusbir->driver.dev = &intf->dev;
+       ttusbir->driver.owner = THIS_MODULE;
+       ttusbir->driver.features = LIRC_CAN_REC_MODE2;
+       ttusbir->minor = lirc_register_driver(&ttusbir->driver);
+       if (ttusbir->minor < 0) {
+               err("Error registering as LIRC driver\n");
+               usb_set_intfdata(intf, NULL);
+               lirc_buffer_free(&ttusbir->rbuf);
+               kfree(ttusbir);
+               return -EIO;
+       }
+
+       /* Allocate and setup the URB that we will use to talk to the device */
+       for (i = 0; i < num_urbs; i++) {
+               ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL);
+               if (!ttusbir->urb[i]) {
+                       err("Could not allocate memory for the URB\n");
+                       for (j = i - 1; j >= 0; j--)
+                               kfree(ttusbir->urb[j]);
+                       lirc_buffer_free(&ttusbir->rbuf);
+                       lirc_unregister_driver(ttusbir->minor);
+                       kfree(ttusbir);
+                       usb_set_intfdata(intf, NULL);
+                       return -ENOMEM;
+               }
+               ttusbir->urb[i]->dev = ttusbir->udev;
+               ttusbir->urb[i]->context = ttusbir;
+               ttusbir->urb[i]->pipe = usb_rcvisocpipe(ttusbir->udev,
+                                                       ttusbir->endpoint);
+               ttusbir->urb[i]->interval = 1;
+               ttusbir->urb[i]->transfer_flags = URB_ISO_ASAP;
+               ttusbir->urb[i]->transfer_buffer = &ttusbir->buffer[i][0];
+               ttusbir->urb[i]->complete = urb_complete;
+               ttusbir->urb[i]->number_of_packets = 8;
+               ttusbir->urb[i]->transfer_buffer_length = 128;
+               for (j = 0; j < 8; j++) {
+                       ttusbir->urb[i]->iso_frame_desc[j].offset = j*16;
+                       ttusbir->urb[i]->iso_frame_desc[j].length = 16;
+               }
+       }
+       return 0;
+}
+
+/**
+ * Called when the driver is unloaded or the device is unplugged
+ */
+static void disconnect(struct usb_interface *intf)
+{
+       int i;
+       struct ttusbir_device *ttusbir;
+
+       DPRINTK("Module ttusbir disconnect\n");
+
+       ttusbir = (struct ttusbir_device *) usb_get_intfdata(intf);
+       usb_set_intfdata(intf, NULL);
+       lirc_unregister_driver(ttusbir->minor);
+       DPRINTK("unregistered\n");
+
+       for (i = 0; i < num_urbs; i++) {
+               usb_kill_urb(ttusbir->urb[i]);
+               usb_free_urb(ttusbir->urb[i]);
+       }
+       DPRINTK("URBs killed\n");
+       lirc_buffer_free(&ttusbir->rbuf);
+       kfree(ttusbir);
+}
+
+static int ttusbir_init_module(void)
+{
+       int result;
+
+       DPRINTK(KERN_DEBUG "Module ttusbir init\n");
+
+       /* register this driver with the USB subsystem */
+       result = usb_register(&usb_driver);
+       if (result)
+               err("usb_register failed. Error number %d", result);
+       return result;
+}
+
+static void ttusbir_exit_module(void)
+{
+       printk(KERN_DEBUG "Module ttusbir exit\n");
+       usb_deregister(&usb_driver);
+}
+
+module_init(ttusbir_init_module);
+module_exit(ttusbir_exit_module);
diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c
new file mode 100644 (file)
index 0000000..0302d82
--- /dev/null
@@ -0,0 +1,1676 @@
+/*
+ * i2c IR lirc driver for devices with zilog IR processors
+ *
+ * Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ * modified for PixelView (BT878P+W/FM) by
+ *      Michal Kochanowicz <mkochano@pld.org.pl>
+ *      Christoph Bartelmus <lirc@bartelmus.de>
+ * modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
+ *      Ulrich Mueller <ulrich.mueller42@web.de>
+ * modified for Asus TV-Box and Creative/VisionTek BreakOut-Box by
+ *      Stefan Jahn <stefan@lkcc.org>
+ * modified for inclusion into kernel sources by
+ *      Jerome Brock <jbrock@users.sourceforge.net>
+ * modified for Leadtek Winfast PVR2000 by
+ *      Thomas Reitmayr (treitmayr@yahoo.com)
+ * modified for Hauppauge PVR-150 IR TX device by
+ *      Mark Weaver <mark@npsl.co.uk>
+ * changed name from lirc_pvr150 to lirc_zilog, works on more than pvr-150
+ *     Jarod Wilson <jarod@redhat.com>
+ *
+ * parts are cut&pasted from the lirc_i2c.c driver
+ *
+ * Numerous changes updating lirc_zilog.c in kernel 2.6.38 and later are
+ * Copyright (C) 2011 Andy Walls <awalls@md.metrocast.net>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+
+#include <media/lirc_dev.h>
+#include <media/lirc.h>
+
+struct IR;
+
+struct IR_rx {
+       struct kref ref;
+       struct IR *ir;
+
+       /* RX device */
+       struct mutex client_lock;
+       struct i2c_client *c;
+
+       /* RX polling thread data */
+       struct task_struct *task;
+
+       /* RX read data */
+       unsigned char b[3];
+       bool hdpvr_data_fmt;
+};
+
+struct IR_tx {
+       struct kref ref;
+       struct IR *ir;
+
+       /* TX device */
+       struct mutex client_lock;
+       struct i2c_client *c;
+
+       /* TX additional actions needed */
+       int need_boot;
+       bool post_tx_ready_poll;
+};
+
+struct IR {
+       struct kref ref;
+       struct list_head list;
+
+       /* FIXME spinlock access to l.features */
+       struct lirc_driver l;
+       struct lirc_buffer rbuf;
+
+       struct mutex ir_lock;
+       atomic_t open_count;
+
+       struct i2c_adapter *adapter;
+
+       spinlock_t rx_ref_lock; /* struct IR_rx kref get()/put() */
+       struct IR_rx *rx;
+
+       spinlock_t tx_ref_lock; /* struct IR_tx kref get()/put() */
+       struct IR_tx *tx;
+};
+
+/* IR transceiver instance object list */
+/*
+ * This lock is used for the following:
+ * a. ir_devices_list access, insertions, deletions
+ * b. struct IR kref get()s and put()s
+ * c. serialization of ir_probe() for the two i2c_clients for a Z8
+ */
+static DEFINE_MUTEX(ir_devices_lock);
+static LIST_HEAD(ir_devices_list);
+
+/* Block size for IR transmitter */
+#define TX_BLOCK_SIZE  99
+
+/* Hauppauge IR transmitter data */
+struct tx_data_struct {
+       /* Boot block */
+       unsigned char *boot_data;
+
+       /* Start of binary data block */
+       unsigned char *datap;
+
+       /* End of binary data block */
+       unsigned char *endp;
+
+       /* Number of installed codesets */
+       unsigned int num_code_sets;
+
+       /* Pointers to codesets */
+       unsigned char **code_sets;
+
+       /* Global fixed data template */
+       int fixed[TX_BLOCK_SIZE];
+};
+
+static struct tx_data_struct *tx_data;
+static struct mutex tx_data_lock;
+
+#define zilog_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, \
+                                       ## args)
+#define zilog_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
+#define zilog_info(s, args...) printk(KERN_INFO KBUILD_MODNAME ": " s, ## args)
+
+/* module parameters */
+static int debug;      /* debug output */
+static int tx_only;    /* only handle the IR Tx function */
+static int minor = -1; /* minor number */
+
+#define dprintk(fmt, args...)                                          \
+       do {                                                            \
+               if (debug)                                              \
+                       printk(KERN_DEBUG KBUILD_MODNAME ": " fmt,      \
+                                ## args);                              \
+       } while (0)
+
+
+/* struct IR reference counting */
+static struct IR *get_ir_device(struct IR *ir, bool ir_devices_lock_held)
+{
+       if (ir_devices_lock_held) {
+               kref_get(&ir->ref);
+       } else {
+               mutex_lock(&ir_devices_lock);
+               kref_get(&ir->ref);
+               mutex_unlock(&ir_devices_lock);
+       }
+       return ir;
+}
+
+static void release_ir_device(struct kref *ref)
+{
+       struct IR *ir = container_of(ref, struct IR, ref);
+
+       /*
+        * Things should be in this state by now:
+        * ir->rx set to NULL and deallocated - happens before ir->rx->ir put()
+        * ir->rx->task kthread stopped - happens before ir->rx->ir put()
+        * ir->tx set to NULL and deallocated - happens before ir->tx->ir put()
+        * ir->open_count ==  0 - happens on final close()
+        * ir_lock, tx_ref_lock, rx_ref_lock, all released
+        */
+       if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) {
+               lirc_unregister_driver(ir->l.minor);
+               ir->l.minor = MAX_IRCTL_DEVICES;
+       }
+       if (ir->rbuf.fifo_initialized)
+               lirc_buffer_free(&ir->rbuf);
+       list_del(&ir->list);
+       kfree(ir);
+}
+
+static int put_ir_device(struct IR *ir, bool ir_devices_lock_held)
+{
+       int released;
+
+       if (ir_devices_lock_held)
+               return kref_put(&ir->ref, release_ir_device);
+
+       mutex_lock(&ir_devices_lock);
+       released = kref_put(&ir->ref, release_ir_device);
+       mutex_unlock(&ir_devices_lock);
+
+       return released;
+}
+
+/* struct IR_rx reference counting */
+static struct IR_rx *get_ir_rx(struct IR *ir)
+{
+       struct IR_rx *rx;
+
+       spin_lock(&ir->rx_ref_lock);
+       rx = ir->rx;
+       if (rx != NULL)
+               kref_get(&rx->ref);
+       spin_unlock(&ir->rx_ref_lock);
+       return rx;
+}
+
+static void destroy_rx_kthread(struct IR_rx *rx, bool ir_devices_lock_held)
+{
+       /* end up polling thread */
+       if (!IS_ERR_OR_NULL(rx->task)) {
+               kthread_stop(rx->task);
+               rx->task = NULL;
+               /* Put the ir ptr that ir_probe() gave to the rx poll thread */
+               put_ir_device(rx->ir, ir_devices_lock_held);
+       }
+}
+
+static void release_ir_rx(struct kref *ref)
+{
+       struct IR_rx *rx = container_of(ref, struct IR_rx, ref);
+       struct IR *ir = rx->ir;
+
+       /*
+        * This release function can't do all the work, as we want
+        * to keep the rx_ref_lock a spinlock, and killing the poll thread
+        * and releasing the ir reference can cause a sleep.  That work is
+        * performed by put_ir_rx()
+        */
+       ir->l.features &= ~LIRC_CAN_REC_LIRCCODE;
+       /* Don't put_ir_device(rx->ir) here; lock can't be freed yet */
+       ir->rx = NULL;
+       /* Don't do the kfree(rx) here; we still need to kill the poll thread */
+       return;
+}
+
+static int put_ir_rx(struct IR_rx *rx, bool ir_devices_lock_held)
+{
+       int released;
+       struct IR *ir = rx->ir;
+
+       spin_lock(&ir->rx_ref_lock);
+       released = kref_put(&rx->ref, release_ir_rx);
+       spin_unlock(&ir->rx_ref_lock);
+       /* Destroy the rx kthread while not holding the spinlock */
+       if (released) {
+               destroy_rx_kthread(rx, ir_devices_lock_held);
+               kfree(rx);
+               /* Make sure we're not still in a poll_table somewhere */
+               wake_up_interruptible(&ir->rbuf.wait_poll);
+       }
+       /* Do a reference put() for the rx->ir reference, if we released rx */
+       if (released)
+               put_ir_device(ir, ir_devices_lock_held);
+       return released;
+}
+
+/* struct IR_tx reference counting */
+static struct IR_tx *get_ir_tx(struct IR *ir)
+{
+       struct IR_tx *tx;
+
+       spin_lock(&ir->tx_ref_lock);
+       tx = ir->tx;
+       if (tx != NULL)
+               kref_get(&tx->ref);
+       spin_unlock(&ir->tx_ref_lock);
+       return tx;
+}
+
+static void release_ir_tx(struct kref *ref)
+{
+       struct IR_tx *tx = container_of(ref, struct IR_tx, ref);
+       struct IR *ir = tx->ir;
+
+       ir->l.features &= ~LIRC_CAN_SEND_PULSE;
+       /* Don't put_ir_device(tx->ir) here, so our lock doesn't get freed */
+       ir->tx = NULL;
+       kfree(tx);
+}
+
+static int put_ir_tx(struct IR_tx *tx, bool ir_devices_lock_held)
+{
+       int released;
+       struct IR *ir = tx->ir;
+
+       spin_lock(&ir->tx_ref_lock);
+       released = kref_put(&tx->ref, release_ir_tx);
+       spin_unlock(&ir->tx_ref_lock);
+       /* Do a reference put() for the tx->ir reference, if we released tx */
+       if (released)
+               put_ir_device(ir, ir_devices_lock_held);
+       return released;
+}
+
+static int add_to_buf(struct IR *ir)
+{
+       __u16 code;
+       unsigned char codes[2];
+       unsigned char keybuf[6];
+       int got_data = 0;
+       int ret;
+       int failures = 0;
+       unsigned char sendbuf[1] = { 0 };
+       struct lirc_buffer *rbuf = ir->l.rbuf;
+       struct IR_rx *rx;
+       struct IR_tx *tx;
+
+       if (lirc_buffer_full(rbuf)) {
+               dprintk("buffer overflow\n");
+               return -EOVERFLOW;
+       }
+
+       rx = get_ir_rx(ir);
+       if (rx == NULL)
+               return -ENXIO;
+
+       /* Ensure our rx->c i2c_client remains valid for the duration */
+       mutex_lock(&rx->client_lock);
+       if (rx->c == NULL) {
+               mutex_unlock(&rx->client_lock);
+               put_ir_rx(rx, false);
+               return -ENXIO;
+       }
+
+       tx = get_ir_tx(ir);
+
+       /*
+        * service the device as long as it is returning
+        * data and we have space
+        */
+       do {
+               if (kthread_should_stop()) {
+                       ret = -ENODATA;
+                       break;
+               }
+
+               /*
+                * Lock i2c bus for the duration.  RX/TX chips interfere so
+                * this is worth it
+                */
+               mutex_lock(&ir->ir_lock);
+
+               if (kthread_should_stop()) {
+                       mutex_unlock(&ir->ir_lock);
+                       ret = -ENODATA;
+                       break;
+               }
+
+               /*
+                * Send random "poll command" (?)  Windows driver does this
+                * and it is a good point to detect chip failure.
+                */
+               ret = i2c_master_send(rx->c, sendbuf, 1);
+               if (ret != 1) {
+                       zilog_error("i2c_master_send failed with %d\n", ret);
+                       if (failures >= 3) {
+                               mutex_unlock(&ir->ir_lock);
+                               zilog_error("unable to read from the IR chip "
+                                           "after 3 resets, giving up\n");
+                               break;
+                       }
+
+                       /* Looks like the chip crashed, reset it */
+                       zilog_error("polling the IR receiver chip failed, "
+                                   "trying reset\n");
+
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       if (kthread_should_stop()) {
+                               mutex_unlock(&ir->ir_lock);
+                               ret = -ENODATA;
+                               break;
+                       }
+                       schedule_timeout((100 * HZ + 999) / 1000);
+                       if (tx != NULL)
+                               tx->need_boot = 1;
+
+                       ++failures;
+                       mutex_unlock(&ir->ir_lock);
+                       ret = 0;
+                       continue;
+               }
+
+               if (kthread_should_stop()) {
+                       mutex_unlock(&ir->ir_lock);
+                       ret = -ENODATA;
+                       break;
+               }
+               ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf));
+               mutex_unlock(&ir->ir_lock);
+               if (ret != sizeof(keybuf)) {
+                       zilog_error("i2c_master_recv failed with %d -- "
+                                   "keeping last read buffer\n", ret);
+               } else {
+                       rx->b[0] = keybuf[3];
+                       rx->b[1] = keybuf[4];
+                       rx->b[2] = keybuf[5];
+                       dprintk("key (0x%02x/0x%02x)\n", rx->b[0], rx->b[1]);
+               }
+
+               /* key pressed ? */
+               if (rx->hdpvr_data_fmt) {
+                       if (got_data && (keybuf[0] == 0x80)) {
+                               ret = 0;
+                               break;
+                       } else if (got_data && (keybuf[0] == 0x00)) {
+                               ret = -ENODATA;
+                               break;
+                       }
+               } else if ((rx->b[0] & 0x80) == 0) {
+                       ret = got_data ? 0 : -ENODATA;
+                       break;
+               }
+
+               /* look what we have */
+               code = (((__u16)rx->b[0] & 0x7f) << 6) | (rx->b[1] >> 2);
+
+               codes[0] = (code >> 8) & 0xff;
+               codes[1] = code & 0xff;
+
+               /* return it */
+               lirc_buffer_write(rbuf, codes);
+               ++got_data;
+               ret = 0;
+       } while (!lirc_buffer_full(rbuf));
+
+       mutex_unlock(&rx->client_lock);
+       if (tx != NULL)
+               put_ir_tx(tx, false);
+       put_ir_rx(rx, false);
+       return ret;
+}
+
+/*
+ * Main function of the polling thread -- from lirc_dev.
+ * We don't fit the LIRC model at all anymore.  This is horrible, but
+ * basically we have a single RX/TX device with a nasty failure mode
+ * that needs to be accounted for across the pair.  lirc lets us provide
+ * fops, but prevents us from using the internal polling, etc. if we do
+ * so.  Hence the replication.  Might be neater to extend the LIRC model
+ * to account for this but I'd think it's a very special case of seriously
+ * messed up hardware.
+ */
+static int lirc_thread(void *arg)
+{
+       struct IR *ir = arg;
+       struct lirc_buffer *rbuf = ir->l.rbuf;
+
+       dprintk("poll thread started\n");
+
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               /* if device not opened, we can sleep half a second */
+               if (atomic_read(&ir->open_count) == 0) {
+                       schedule_timeout(HZ/2);
+                       continue;
+               }
+
+               /*
+                * This is ~113*2 + 24 + jitter (2*repeat gap + code length).
+                * We use this interval as the chip resets every time you poll
+                * it (bad!).  This is therefore just sufficient to catch all
+                * of the button presses.  It makes the remote much more
+                * responsive.  You can see the difference by running irw and
+                * holding down a button.  With 100ms, the old polling
+                * interval, you'll notice breaks in the repeat sequence
+                * corresponding to lost keypresses.
+                */
+               schedule_timeout((260 * HZ) / 1000);
+               if (kthread_should_stop())
+                       break;
+               if (!add_to_buf(ir))
+                       wake_up_interruptible(&rbuf->wait_poll);
+       }
+
+       dprintk("poll thread ended\n");
+       return 0;
+}
+
+static int set_use_inc(void *data)
+{
+       return 0;
+}
+
+static void set_use_dec(void *data)
+{
+       return;
+}
+
+/* safe read of a uint32 (always network byte order) */
+static int read_uint32(unsigned char **data,
+                                    unsigned char *endp, unsigned int *val)
+{
+       if (*data + 4 > endp)
+               return 0;
+       *val = ((*data)[0] << 24) | ((*data)[1] << 16) |
+              ((*data)[2] << 8) | (*data)[3];
+       *data += 4;
+       return 1;
+}
+
+/* safe read of a uint8 */
+static int read_uint8(unsigned char **data,
+                                   unsigned char *endp, unsigned char *val)
+{
+       if (*data + 1 > endp)
+               return 0;
+       *val = *((*data)++);
+       return 1;
+}
+
+/* safe skipping of N bytes */
+static int skip(unsigned char **data,
+                             unsigned char *endp, unsigned int distance)
+{
+       if (*data + distance > endp)
+               return 0;
+       *data += distance;
+       return 1;
+}
+
+/* decompress key data into the given buffer */
+static int get_key_data(unsigned char *buf,
+                            unsigned int codeset, unsigned int key)
+{
+       unsigned char *data, *endp, *diffs, *key_block;
+       unsigned char keys, ndiffs, id;
+       unsigned int base, lim, pos, i;
+
+       /* Binary search for the codeset */
+       for (base = 0, lim = tx_data->num_code_sets; lim; lim >>= 1) {
+               pos = base + (lim >> 1);
+               data = tx_data->code_sets[pos];
+
+               if (!read_uint32(&data, tx_data->endp, &i))
+                       goto corrupt;
+
+               if (i == codeset)
+                       break;
+               else if (codeset > i) {
+                       base = pos + 1;
+                       --lim;
+               }
+       }
+       /* Not found? */
+       if (!lim)
+               return -EPROTO;
+
+       /* Set end of data block */
+       endp = pos < tx_data->num_code_sets - 1 ?
+               tx_data->code_sets[pos + 1] : tx_data->endp;
+
+       /* Read the block header */
+       if (!read_uint8(&data, endp, &keys) ||
+           !read_uint8(&data, endp, &ndiffs) ||
+           ndiffs > TX_BLOCK_SIZE || keys == 0)
+               goto corrupt;
+
+       /* Save diffs & skip */
+       diffs = data;
+       if (!skip(&data, endp, ndiffs))
+               goto corrupt;
+
+       /* Read the id of the first key */
+       if (!read_uint8(&data, endp, &id))
+               goto corrupt;
+
+       /* Unpack the first key's data */
+       for (i = 0; i < TX_BLOCK_SIZE; ++i) {
+               if (tx_data->fixed[i] == -1) {
+                       if (!read_uint8(&data, endp, &buf[i]))
+                               goto corrupt;
+               } else {
+                       buf[i] = (unsigned char)tx_data->fixed[i];
+               }
+       }
+
+       /* Early out key found/not found */
+       if (key == id)
+               return 0;
+       if (keys == 1)
+               return -EPROTO;
+
+       /* Sanity check */
+       key_block = data;
+       if (!skip(&data, endp, (keys - 1) * (ndiffs + 1)))
+               goto corrupt;
+
+       /* Binary search for the key */
+       for (base = 0, lim = keys - 1; lim; lim >>= 1) {
+               /* Seek to block */
+               unsigned char *key_data;
+               pos = base + (lim >> 1);
+               key_data = key_block + (ndiffs + 1) * pos;
+
+               if (*key_data == key) {
+                       /* skip key id */
+                       ++key_data;
+
+                       /* found, so unpack the diffs */
+                       for (i = 0; i < ndiffs; ++i) {
+                               unsigned char val;
+                               if (!read_uint8(&key_data, endp, &val) ||
+                                   diffs[i] >= TX_BLOCK_SIZE)
+                                       goto corrupt;
+                               buf[diffs[i]] = val;
+                       }
+
+                       return 0;
+               } else if (key > *key_data) {
+                       base = pos + 1;
+                       --lim;
+               }
+       }
+       /* Key not found */
+       return -EPROTO;
+
+corrupt:
+       zilog_error("firmware is corrupt\n");
+       return -EFAULT;
+}
+
+/* send a block of data to the IR TX device */
+static int send_data_block(struct IR_tx *tx, unsigned char *data_block)
+{
+       int i, j, ret;
+       unsigned char buf[5];
+
+       for (i = 0; i < TX_BLOCK_SIZE;) {
+               int tosend = TX_BLOCK_SIZE - i;
+               if (tosend > 4)
+                       tosend = 4;
+               buf[0] = (unsigned char)(i + 1);
+               for (j = 0; j < tosend; ++j)
+                       buf[1 + j] = data_block[i + j];
+               dprintk("%02x %02x %02x %02x %02x",
+                       buf[0], buf[1], buf[2], buf[3], buf[4]);
+               ret = i2c_master_send(tx->c, buf, tosend + 1);
+               if (ret != tosend + 1) {
+                       zilog_error("i2c_master_send failed with %d\n", ret);
+                       return ret < 0 ? ret : -EFAULT;
+               }
+               i += tosend;
+       }
+       return 0;
+}
+
+/* send boot data to the IR TX device */
+static int send_boot_data(struct IR_tx *tx)
+{
+       int ret, i;
+       unsigned char buf[4];
+
+       /* send the boot block */
+       ret = send_data_block(tx, tx_data->boot_data);
+       if (ret != 0)
+               return ret;
+
+       /* Hit the go button to activate the new boot data */
+       buf[0] = 0x00;
+       buf[1] = 0x20;
+       ret = i2c_master_send(tx->c, buf, 2);
+       if (ret != 2) {
+               zilog_error("i2c_master_send failed with %d\n", ret);
+               return ret < 0 ? ret : -EFAULT;
+       }
+
+       /*
+        * Wait for zilog to settle after hitting go post boot block upload.
+        * Without this delay, the HD-PVR and HVR-1950 both return an -EIO
+        * upon attempting to get firmware revision, and tx probe thus fails.
+        */
+       for (i = 0; i < 10; i++) {
+               ret = i2c_master_send(tx->c, buf, 1);
+               if (ret == 1)
+                       break;
+               udelay(100);
+       }
+
+       if (ret != 1) {
+               zilog_error("i2c_master_send failed with %d\n", ret);
+               return ret < 0 ? ret : -EFAULT;
+       }
+
+       /* Here comes the firmware version... (hopefully) */
+       ret = i2c_master_recv(tx->c, buf, 4);
+       if (ret != 4) {
+               zilog_error("i2c_master_recv failed with %d\n", ret);
+               return 0;
+       }
+       if ((buf[0] != 0x80) && (buf[0] != 0xa0)) {
+               zilog_error("unexpected IR TX init response: %02x\n", buf[0]);
+               return 0;
+       }
+       zilog_notify("Zilog/Hauppauge IR blaster firmware version "
+                    "%d.%d.%d loaded\n", buf[1], buf[2], buf[3]);
+
+       return 0;
+}
+
+/* unload "firmware", lock held */
+static void fw_unload_locked(void)
+{
+       if (tx_data) {
+               if (tx_data->code_sets)
+                       vfree(tx_data->code_sets);
+
+               if (tx_data->datap)
+                       vfree(tx_data->datap);
+
+               vfree(tx_data);
+               tx_data = NULL;
+               dprintk("successfully unloaded IR blaster firmware\n");
+       }
+}
+
+/* unload "firmware" for the IR TX device */
+static void fw_unload(void)
+{
+       mutex_lock(&tx_data_lock);
+       fw_unload_locked();
+       mutex_unlock(&tx_data_lock);
+}
+
+/* load "firmware" for the IR TX device */
+static int fw_load(struct IR_tx *tx)
+{
+       int ret;
+       unsigned int i;
+       unsigned char *data, version, num_global_fixed;
+       const struct firmware *fw_entry;
+
+       /* Already loaded? */
+       mutex_lock(&tx_data_lock);
+       if (tx_data) {
+               ret = 0;
+               goto out;
+       }
+
+       /* Request codeset data file */
+       ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", tx->ir->l.dev);
+       if (ret != 0) {
+               zilog_error("firmware haup-ir-blaster.bin not available "
+                           "(%d)\n", ret);
+               ret = ret < 0 ? ret : -EFAULT;
+               goto out;
+       }
+       dprintk("firmware of size %zu loaded\n", fw_entry->size);
+
+       /* Parse the file */
+       tx_data = vmalloc(sizeof(*tx_data));
+       if (tx_data == NULL) {
+               zilog_error("out of memory\n");
+               release_firmware(fw_entry);
+               ret = -ENOMEM;
+               goto out;
+       }
+       tx_data->code_sets = NULL;
+
+       /* Copy the data so hotplug doesn't get confused and timeout */
+       tx_data->datap = vmalloc(fw_entry->size);
+       if (tx_data->datap == NULL) {
+               zilog_error("out of memory\n");
+               release_firmware(fw_entry);
+               vfree(tx_data);
+               ret = -ENOMEM;
+               goto out;
+       }
+       memcpy(tx_data->datap, fw_entry->data, fw_entry->size);
+       tx_data->endp = tx_data->datap + fw_entry->size;
+       release_firmware(fw_entry); fw_entry = NULL;
+
+       /* Check version */
+       data = tx_data->datap;
+       if (!read_uint8(&data, tx_data->endp, &version))
+               goto corrupt;
+       if (version != 1) {
+               zilog_error("unsupported code set file version (%u, expected"
+                           "1) -- please upgrade to a newer driver",
+                           version);
+               fw_unload_locked();
+               ret = -EFAULT;
+               goto out;
+       }
+
+       /* Save boot block for later */
+       tx_data->boot_data = data;
+       if (!skip(&data, tx_data->endp, TX_BLOCK_SIZE))
+               goto corrupt;
+
+       if (!read_uint32(&data, tx_data->endp,
+                             &tx_data->num_code_sets))
+               goto corrupt;
+
+       dprintk("%u IR blaster codesets loaded\n", tx_data->num_code_sets);
+
+       tx_data->code_sets = vmalloc(
+               tx_data->num_code_sets * sizeof(char *));
+       if (tx_data->code_sets == NULL) {
+               fw_unload_locked();
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0; i < TX_BLOCK_SIZE; ++i)
+               tx_data->fixed[i] = -1;
+
+       /* Read global fixed data template */
+       if (!read_uint8(&data, tx_data->endp, &num_global_fixed) ||
+           num_global_fixed > TX_BLOCK_SIZE)
+               goto corrupt;
+       for (i = 0; i < num_global_fixed; ++i) {
+               unsigned char pos, val;
+               if (!read_uint8(&data, tx_data->endp, &pos) ||
+                   !read_uint8(&data, tx_data->endp, &val) ||
+                   pos >= TX_BLOCK_SIZE)
+                       goto corrupt;
+               tx_data->fixed[pos] = (int)val;
+       }
+
+       /* Filch out the position of each code set */
+       for (i = 0; i < tx_data->num_code_sets; ++i) {
+               unsigned int id;
+               unsigned char keys;
+               unsigned char ndiffs;
+
+               /* Save the codeset position */
+               tx_data->code_sets[i] = data;
+
+               /* Read header */
+               if (!read_uint32(&data, tx_data->endp, &id) ||
+                   !read_uint8(&data, tx_data->endp, &keys) ||
+                   !read_uint8(&data, tx_data->endp, &ndiffs) ||
+                   ndiffs > TX_BLOCK_SIZE || keys == 0)
+                       goto corrupt;
+
+               /* skip diff positions */
+               if (!skip(&data, tx_data->endp, ndiffs))
+                       goto corrupt;
+
+               /*
+                * After the diffs we have the first key id + data -
+                * global fixed
+                */
+               if (!skip(&data, tx_data->endp,
+                              1 + TX_BLOCK_SIZE - num_global_fixed))
+                       goto corrupt;
+
+               /* Then we have keys-1 blocks of key id+diffs */
+               if (!skip(&data, tx_data->endp,
+                              (ndiffs + 1) * (keys - 1)))
+                       goto corrupt;
+       }
+       ret = 0;
+       goto out;
+
+corrupt:
+       zilog_error("firmware is corrupt\n");
+       fw_unload_locked();
+       ret = -EFAULT;
+
+out:
+       mutex_unlock(&tx_data_lock);
+       return ret;
+}
+
+/* copied from lirc_dev */
+static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
+{
+       struct IR *ir = filep->private_data;
+       struct IR_rx *rx;
+       struct lirc_buffer *rbuf = ir->l.rbuf;
+       int ret = 0, written = 0, retries = 0;
+       unsigned int m;
+       DECLARE_WAITQUEUE(wait, current);
+
+       dprintk("read called\n");
+       if (n % rbuf->chunk_size) {
+               dprintk("read result = -EINVAL\n");
+               return -EINVAL;
+       }
+
+       rx = get_ir_rx(ir);
+       if (rx == NULL)
+               return -ENXIO;
+
+       /*
+        * we add ourselves to the task queue before buffer check
+        * to avoid losing scan code (in case when queue is awaken somewhere
+        * between while condition checking and scheduling)
+        */
+       add_wait_queue(&rbuf->wait_poll, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       /*
+        * while we didn't provide 'length' bytes, device is opened in blocking
+        * mode and 'copy_to_user' is happy, wait for data.
+        */
+       while (written < n && ret == 0) {
+               if (lirc_buffer_empty(rbuf)) {
+                       /*
+                        * According to the read(2) man page, 'written' can be
+                        * returned as less than 'n', instead of blocking
+                        * again, returning -EWOULDBLOCK, or returning
+                        * -ERESTARTSYS
+                        */
+                       if (written)
+                               break;
+                       if (filep->f_flags & O_NONBLOCK) {
+                               ret = -EWOULDBLOCK;
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               ret = -ERESTARTSYS;
+                               break;
+                       }
+                       schedule();
+                       set_current_state(TASK_INTERRUPTIBLE);
+               } else {
+                       unsigned char buf[rbuf->chunk_size];
+                       m = lirc_buffer_read(rbuf, buf);
+                       if (m == rbuf->chunk_size) {
+                               ret = copy_to_user((void *)outbuf+written, buf,
+                                                  rbuf->chunk_size);
+                               written += rbuf->chunk_size;
+                       } else {
+                               retries++;
+                       }
+                       if (retries >= 5) {
+                               zilog_error("Buffer read failed!\n");
+                               ret = -EIO;
+                       }
+               }
+       }
+
+       remove_wait_queue(&rbuf->wait_poll, &wait);
+       put_ir_rx(rx, false);
+       set_current_state(TASK_RUNNING);
+
+       dprintk("read result = %d (%s)\n", ret, ret ? "Error" : "OK");
+
+       return ret ? ret : written;
+}
+
+/* send a keypress to the IR TX device */
+static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
+{
+       unsigned char data_block[TX_BLOCK_SIZE];
+       unsigned char buf[2];
+       int i, ret;
+
+       /* Get data for the codeset/key */
+       ret = get_key_data(data_block, code, key);
+
+       if (ret == -EPROTO) {
+               zilog_error("failed to get data for code %u, key %u -- check "
+                           "lircd.conf entries\n", code, key);
+               return ret;
+       } else if (ret != 0)
+               return ret;
+
+       /* Send the data block */
+       ret = send_data_block(tx, data_block);
+       if (ret != 0)
+               return ret;
+
+       /* Send data block length? */
+       buf[0] = 0x00;
+       buf[1] = 0x40;
+       ret = i2c_master_send(tx->c, buf, 2);
+       if (ret != 2) {
+               zilog_error("i2c_master_send failed with %d\n", ret);
+               return ret < 0 ? ret : -EFAULT;
+       }
+
+       /* Give the z8 a moment to process data block */
+       for (i = 0; i < 10; i++) {
+               ret = i2c_master_send(tx->c, buf, 1);
+               if (ret == 1)
+                       break;
+               udelay(100);
+       }
+
+       if (ret != 1) {
+               zilog_error("i2c_master_send failed with %d\n", ret);
+               return ret < 0 ? ret : -EFAULT;
+       }
+
+       /* Send finished download? */
+       ret = i2c_master_recv(tx->c, buf, 1);
+       if (ret != 1) {
+               zilog_error("i2c_master_recv failed with %d\n", ret);
+               return ret < 0 ? ret : -EFAULT;
+       }
+       if (buf[0] != 0xA0) {
+               zilog_error("unexpected IR TX response #1: %02x\n",
+                       buf[0]);
+               return -EFAULT;
+       }
+
+       /* Send prepare command? */
+       buf[0] = 0x00;
+       buf[1] = 0x80;
+       ret = i2c_master_send(tx->c, buf, 2);
+       if (ret != 2) {
+               zilog_error("i2c_master_send failed with %d\n", ret);
+               return ret < 0 ? ret : -EFAULT;
+       }
+
+       /*
+        * The sleep bits aren't necessary on the HD PVR, and in fact, the
+        * last i2c_master_recv always fails with a -5, so for now, we're
+        * going to skip this whole mess and say we're done on the HD PVR
+        */
+       if (!tx->post_tx_ready_poll) {
+               dprintk("sent code %u, key %u\n", code, key);
+               return 0;
+       }
+
+       /*
+        * This bit NAKs until the device is ready, so we retry it
+        * sleeping a bit each time.  This seems to be what the windows
+        * driver does, approximately.
+        * Try for up to 1s.
+        */
+       for (i = 0; i < 20; ++i) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout((50 * HZ + 999) / 1000);
+               ret = i2c_master_send(tx->c, buf, 1);
+               if (ret == 1)
+                       break;
+               dprintk("NAK expected: i2c_master_send "
+                       "failed with %d (try %d)\n", ret, i+1);
+       }
+       if (ret != 1) {
+               zilog_error("IR TX chip never got ready: last i2c_master_send "
+                           "failed with %d\n", ret);
+               return ret < 0 ? ret : -EFAULT;
+       }
+
+       /* Seems to be an 'ok' response */
+       i = i2c_master_recv(tx->c, buf, 1);
+       if (i != 1) {
+               zilog_error("i2c_master_recv failed with %d\n", ret);
+               return -EFAULT;
+       }
+       if (buf[0] != 0x80) {
+               zilog_error("unexpected IR TX response #2: %02x\n", buf[0]);
+               return -EFAULT;
+       }
+
+       /* Oh good, it worked */
+       dprintk("sent code %u, key %u\n", code, key);
+       return 0;
+}
+
+/*
+ * Write a code to the device.  We take in a 32-bit number (an int) and then
+ * decode this to a codeset/key index.  The key data is then decompressed and
+ * sent to the device.  We have a spin lock as per i2c documentation to prevent
+ * multiple concurrent sends which would probably cause the device to explode.
+ */
+static ssize_t write(struct file *filep, const char *buf, size_t n,
+                         loff_t *ppos)
+{
+       struct IR *ir = filep->private_data;
+       struct IR_tx *tx;
+       size_t i;
+       int failures = 0;
+
+       /* Validate user parameters */
+       if (n % sizeof(int))
+               return -EINVAL;
+
+       /* Get a struct IR_tx reference */
+       tx = get_ir_tx(ir);
+       if (tx == NULL)
+               return -ENXIO;
+
+       /* Ensure our tx->c i2c_client remains valid for the duration */
+       mutex_lock(&tx->client_lock);
+       if (tx->c == NULL) {
+               mutex_unlock(&tx->client_lock);
+               put_ir_tx(tx, false);
+               return -ENXIO;
+       }
+
+       /* Lock i2c bus for the duration */
+       mutex_lock(&ir->ir_lock);
+
+       /* Send each keypress */
+       for (i = 0; i < n;) {
+               int ret = 0;
+               int command;
+
+               if (copy_from_user(&command, buf + i, sizeof(command))) {
+                       mutex_unlock(&ir->ir_lock);
+                       mutex_unlock(&tx->client_lock);
+                       put_ir_tx(tx, false);
+                       return -EFAULT;
+               }
+
+               /* Send boot data first if required */
+               if (tx->need_boot == 1) {
+                       /* Make sure we have the 'firmware' loaded, first */
+                       ret = fw_load(tx);
+                       if (ret != 0) {
+                               mutex_unlock(&ir->ir_lock);
+                               mutex_unlock(&tx->client_lock);
+                               put_ir_tx(tx, false);
+                               if (ret != -ENOMEM)
+                                       ret = -EIO;
+                               return ret;
+                       }
+                       /* Prep the chip for transmitting codes */
+                       ret = send_boot_data(tx);
+                       if (ret == 0)
+                               tx->need_boot = 0;
+               }
+
+               /* Send the code */
+               if (ret == 0) {
+                       ret = send_code(tx, (unsigned)command >> 16,
+                                           (unsigned)command & 0xFFFF);
+                       if (ret == -EPROTO) {
+                               mutex_unlock(&ir->ir_lock);
+                               mutex_unlock(&tx->client_lock);
+                               put_ir_tx(tx, false);
+                               return ret;
+                       }
+               }
+
+               /*
+                * Hmm, a failure.  If we've had a few then give up, otherwise
+                * try a reset
+                */
+               if (ret != 0) {
+                       /* Looks like the chip crashed, reset it */
+                       zilog_error("sending to the IR transmitter chip "
+                                   "failed, trying reset\n");
+
+                       if (failures >= 3) {
+                               zilog_error("unable to send to the IR chip "
+                                           "after 3 resets, giving up\n");
+                               mutex_unlock(&ir->ir_lock);
+                               mutex_unlock(&tx->client_lock);
+                               put_ir_tx(tx, false);
+                               return ret;
+                       }
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout((100 * HZ + 999) / 1000);
+                       tx->need_boot = 1;
+                       ++failures;
+               } else
+                       i += sizeof(int);
+       }
+
+       /* Release i2c bus */
+       mutex_unlock(&ir->ir_lock);
+
+       mutex_unlock(&tx->client_lock);
+
+       /* Give back our struct IR_tx reference */
+       put_ir_tx(tx, false);
+
+       /* All looks good */
+       return n;
+}
+
+/* copied from lirc_dev */
+static unsigned int poll(struct file *filep, poll_table *wait)
+{
+       struct IR *ir = filep->private_data;
+       struct IR_rx *rx;
+       struct lirc_buffer *rbuf = ir->l.rbuf;
+       unsigned int ret;
+
+       dprintk("poll called\n");
+
+       rx = get_ir_rx(ir);
+       if (rx == NULL) {
+               /*
+                * Revisit this, if our poll function ever reports writeable
+                * status for Tx
+                */
+               dprintk("poll result = POLLERR\n");
+               return POLLERR;
+       }
+
+       /*
+        * Add our lirc_buffer's wait_queue to the poll_table. A wake up on
+        * that buffer's wait queue indicates we may have a new poll status.
+        */
+       poll_wait(filep, &rbuf->wait_poll, wait);
+
+       /* Indicate what ops could happen immediately without blocking */
+       ret = lirc_buffer_empty(rbuf) ? 0 : (POLLIN|POLLRDNORM);
+
+       dprintk("poll result = %s\n", ret ? "POLLIN|POLLRDNORM" : "none");
+       return ret;
+}
+
+static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+       struct IR *ir = filep->private_data;
+       int result;
+       unsigned long mode, features;
+
+       features = ir->l.features;
+
+       switch (cmd) {
+       case LIRC_GET_LENGTH:
+               result = put_user((unsigned long)13,
+                                 (unsigned long *)arg);
+               break;
+       case LIRC_GET_FEATURES:
+               result = put_user(features, (unsigned long *) arg);
+               break;
+       case LIRC_GET_REC_MODE:
+               if (!(features&LIRC_CAN_REC_MASK))
+                       return -ENOSYS;
+
+               result = put_user(LIRC_REC2MODE
+                                 (features&LIRC_CAN_REC_MASK),
+                                 (unsigned long *)arg);
+               break;
+       case LIRC_SET_REC_MODE:
+               if (!(features&LIRC_CAN_REC_MASK))
+                       return -ENOSYS;
+
+               result = get_user(mode, (unsigned long *)arg);
+               if (!result && !(LIRC_MODE2REC(mode) & features))
+                       result = -EINVAL;
+               break;
+       case LIRC_GET_SEND_MODE:
+               if (!(features&LIRC_CAN_SEND_MASK))
+                       return -ENOSYS;
+
+               result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg);
+               break;
+       case LIRC_SET_SEND_MODE:
+               if (!(features&LIRC_CAN_SEND_MASK))
+                       return -ENOSYS;
+
+               result = get_user(mode, (unsigned long *) arg);
+               if (!result && mode != LIRC_MODE_PULSE)
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return result;
+}
+
+static struct IR *get_ir_device_by_minor(unsigned int minor)
+{
+       struct IR *ir;
+       struct IR *ret = NULL;
+
+       mutex_lock(&ir_devices_lock);
+
+       if (!list_empty(&ir_devices_list)) {
+               list_for_each_entry(ir, &ir_devices_list, list) {
+                       if (ir->l.minor == minor) {
+                               ret = get_ir_device(ir, true);
+                               break;
+                       }
+               }
+       }
+
+       mutex_unlock(&ir_devices_lock);
+       return ret;
+}
+
+/*
+ * Open the IR device.  Get hold of our IR structure and
+ * stash it in private_data for the file
+ */
+static int open(struct inode *node, struct file *filep)
+{
+       struct IR *ir;
+       unsigned int minor = MINOR(node->i_rdev);
+
+       /* find our IR struct */
+       ir = get_ir_device_by_minor(minor);
+
+       if (ir == NULL)
+               return -ENODEV;
+
+       atomic_inc(&ir->open_count);
+
+       /* stash our IR struct */
+       filep->private_data = ir;
+
+       nonseekable_open(node, filep);
+       return 0;
+}
+
+/* Close the IR device */
+static int close(struct inode *node, struct file *filep)
+{
+       /* find our IR struct */
+       struct IR *ir = filep->private_data;
+       if (ir == NULL) {
+               zilog_error("close: no private_data attached to the file!\n");
+               return -ENODEV;
+       }
+
+       atomic_dec(&ir->open_count);
+
+       put_ir_device(ir, false);
+       return 0;
+}
+
+static int ir_remove(struct i2c_client *client);
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id);
+
+#define ID_FLAG_TX     0x01
+#define ID_FLAG_HDPVR  0x02
+
+static const struct i2c_device_id ir_transceiver_id[] = {
+       { "ir_tx_z8f0811_haup",  ID_FLAG_TX                 },
+       { "ir_rx_z8f0811_haup",  0                          },
+       { "ir_tx_z8f0811_hdpvr", ID_FLAG_HDPVR | ID_FLAG_TX },
+       { "ir_rx_z8f0811_hdpvr", ID_FLAG_HDPVR              },
+       { }
+};
+
+static struct i2c_driver driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "Zilog/Hauppauge i2c IR",
+       },
+       .probe          = ir_probe,
+       .remove         = ir_remove,
+       .id_table       = ir_transceiver_id,
+};
+
+static const struct file_operations lirc_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .read           = read,
+       .write          = write,
+       .poll           = poll,
+       .unlocked_ioctl = ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = ioctl,
+#endif
+       .open           = open,
+       .release        = close
+};
+
+static struct lirc_driver lirc_template = {
+       .name           = "lirc_zilog",
+       .minor          = -1,
+       .code_length    = 13,
+       .buffer_size    = BUFLEN / 2,
+       .sample_rate    = 0, /* tell lirc_dev to not start its own kthread */
+       .chunk_size     = 2,
+       .set_use_inc    = set_use_inc,
+       .set_use_dec    = set_use_dec,
+       .fops           = &lirc_fops,
+       .owner          = THIS_MODULE,
+};
+
+static int ir_remove(struct i2c_client *client)
+{
+       if (strncmp("ir_tx_z8", client->name, 8) == 0) {
+               struct IR_tx *tx = i2c_get_clientdata(client);
+               if (tx != NULL) {
+                       mutex_lock(&tx->client_lock);
+                       tx->c = NULL;
+                       mutex_unlock(&tx->client_lock);
+                       put_ir_tx(tx, false);
+               }
+       } else if (strncmp("ir_rx_z8", client->name, 8) == 0) {
+               struct IR_rx *rx = i2c_get_clientdata(client);
+               if (rx != NULL) {
+                       mutex_lock(&rx->client_lock);
+                       rx->c = NULL;
+                       mutex_unlock(&rx->client_lock);
+                       put_ir_rx(rx, false);
+               }
+       }
+       return 0;
+}
+
+
+/* ir_devices_lock must be held */
+static struct IR *get_ir_device_by_adapter(struct i2c_adapter *adapter)
+{
+       struct IR *ir;
+
+       if (list_empty(&ir_devices_list))
+               return NULL;
+
+       list_for_each_entry(ir, &ir_devices_list, list)
+               if (ir->adapter == adapter) {
+                       get_ir_device(ir, true);
+                       return ir;
+               }
+
+       return NULL;
+}
+
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct IR *ir;
+       struct IR_tx *tx;
+       struct IR_rx *rx;
+       struct i2c_adapter *adap = client->adapter;
+       int ret;
+       bool tx_probe = false;
+
+       dprintk("%s: %s on i2c-%d (%s), client addr=0x%02x\n",
+               __func__, id->name, adap->nr, adap->name, client->addr);
+
+       /*
+        * The IR receiver    is at i2c address 0x71.
+        * The IR transmitter is at i2c address 0x70.
+        */
+
+       if (id->driver_data & ID_FLAG_TX)
+               tx_probe = true;
+       else if (tx_only) /* module option */
+               return -ENXIO;
+
+       zilog_info("probing IR %s on %s (i2c-%d)\n",
+                  tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
+
+       mutex_lock(&ir_devices_lock);
+
+       /* Use a single struct IR instance for both the Rx and Tx functions */
+       ir = get_ir_device_by_adapter(adap);
+       if (ir == NULL) {
+               ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+               if (ir == NULL) {
+                       ret = -ENOMEM;
+                       goto out_no_ir;
+               }
+               kref_init(&ir->ref);
+
+               /* store for use in ir_probe() again, and open() later on */
+               INIT_LIST_HEAD(&ir->list);
+               list_add_tail(&ir->list, &ir_devices_list);
+
+               ir->adapter = adap;
+               mutex_init(&ir->ir_lock);
+               atomic_set(&ir->open_count, 0);
+               spin_lock_init(&ir->tx_ref_lock);
+               spin_lock_init(&ir->rx_ref_lock);
+
+               /* set lirc_dev stuff */
+               memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
+               /*
+                * FIXME this is a pointer reference to us, but no refcount.
+                *
+                * This OK for now, since lirc_dev currently won't touch this
+                * buffer as we provide our own lirc_fops.
+                *
+                * Currently our own lirc_fops rely on this ir->l.rbuf pointer
+                */
+               ir->l.rbuf = &ir->rbuf;
+               ir->l.dev  = &adap->dev;
+               ret = lirc_buffer_init(ir->l.rbuf,
+                                      ir->l.chunk_size, ir->l.buffer_size);
+               if (ret)
+                       goto out_put_ir;
+       }
+
+       if (tx_probe) {
+               /* Get the IR_rx instance for later, if already allocated */
+               rx = get_ir_rx(ir);
+
+               /* Set up a struct IR_tx instance */
+               tx = kzalloc(sizeof(struct IR_tx), GFP_KERNEL);
+               if (tx == NULL) {
+                       ret = -ENOMEM;
+                       goto out_put_xx;
+               }
+               kref_init(&tx->ref);
+               ir->tx = tx;
+
+               ir->l.features |= LIRC_CAN_SEND_PULSE;
+               mutex_init(&tx->client_lock);
+               tx->c = client;
+               tx->need_boot = 1;
+               tx->post_tx_ready_poll =
+                              (id->driver_data & ID_FLAG_HDPVR) ? false : true;
+
+               /* An ir ref goes to the struct IR_tx instance */
+               tx->ir = get_ir_device(ir, true);
+
+               /* A tx ref goes to the i2c_client */
+               i2c_set_clientdata(client, get_ir_tx(ir));
+
+               /*
+                * Load the 'firmware'.  We do this before registering with
+                * lirc_dev, so the first firmware load attempt does not happen
+                * after a open() or write() call on the device.
+                *
+                * Failure here is not deemed catastrophic, so the receiver will
+                * still be usable.  Firmware load will be retried in write(),
+                * if it is needed.
+                */
+               fw_load(tx);
+
+               /* Proceed only if the Rx client is also ready or not needed */
+               if (rx == NULL && !tx_only) {
+                       zilog_info("probe of IR Tx on %s (i2c-%d) done. Waiting"
+                                  " on IR Rx.\n", adap->name, adap->nr);
+                       goto out_ok;
+               }
+       } else {
+               /* Get the IR_tx instance for later, if already allocated */
+               tx = get_ir_tx(ir);
+
+               /* Set up a struct IR_rx instance */
+               rx = kzalloc(sizeof(struct IR_rx), GFP_KERNEL);
+               if (rx == NULL) {
+                       ret = -ENOMEM;
+                       goto out_put_xx;
+               }
+               kref_init(&rx->ref);
+               ir->rx = rx;
+
+               ir->l.features |= LIRC_CAN_REC_LIRCCODE;
+               mutex_init(&rx->client_lock);
+               rx->c = client;
+               rx->hdpvr_data_fmt =
+                              (id->driver_data & ID_FLAG_HDPVR) ? true : false;
+
+               /* An ir ref goes to the struct IR_rx instance */
+               rx->ir = get_ir_device(ir, true);
+
+               /* An rx ref goes to the i2c_client */
+               i2c_set_clientdata(client, get_ir_rx(ir));
+
+               /*
+                * Start the polling thread.
+                * It will only perform an empty loop around schedule_timeout()
+                * until we register with lirc_dev and the first user open()
+                */
+               /* An ir ref goes to the new rx polling kthread */
+               rx->task = kthread_run(lirc_thread, get_ir_device(ir, true),
+                                      "zilog-rx-i2c-%d", adap->nr);
+               if (IS_ERR(rx->task)) {
+                       ret = PTR_ERR(rx->task);
+                       zilog_error("%s: could not start IR Rx polling thread"
+                                   "\n", __func__);
+                       /* Failed kthread, so put back the ir ref */
+                       put_ir_device(ir, true);
+                       /* Failure exit, so put back rx ref from i2c_client */
+                       i2c_set_clientdata(client, NULL);
+                       put_ir_rx(rx, true);
+                       ir->l.features &= ~LIRC_CAN_REC_LIRCCODE;
+                       goto out_put_xx;
+               }
+
+               /* Proceed only if the Tx client is also ready */
+               if (tx == NULL) {
+                       zilog_info("probe of IR Rx on %s (i2c-%d) done. Waiting"
+                                  " on IR Tx.\n", adap->name, adap->nr);
+                       goto out_ok;
+               }
+       }
+
+       /* register with lirc */
+       ir->l.minor = minor; /* module option: user requested minor number */
+       ir->l.minor = lirc_register_driver(&ir->l);
+       if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) {
+               zilog_error("%s: \"minor\" must be between 0 and %d (%d)!\n",
+                           __func__, MAX_IRCTL_DEVICES-1, ir->l.minor);
+               ret = -EBADRQC;
+               goto out_put_xx;
+       }
+       zilog_info("IR unit on %s (i2c-%d) registered as lirc%d and ready\n",
+                  adap->name, adap->nr, ir->l.minor);
+
+out_ok:
+       if (rx != NULL)
+               put_ir_rx(rx, true);
+       if (tx != NULL)
+               put_ir_tx(tx, true);
+       put_ir_device(ir, true);
+       zilog_info("probe of IR %s on %s (i2c-%d) done\n",
+                  tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
+       mutex_unlock(&ir_devices_lock);
+       return 0;
+
+out_put_xx:
+       if (rx != NULL)
+               put_ir_rx(rx, true);
+       if (tx != NULL)
+               put_ir_tx(tx, true);
+out_put_ir:
+       put_ir_device(ir, true);
+out_no_ir:
+       zilog_error("%s: probing IR %s on %s (i2c-%d) failed with %d\n",
+                   __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr,
+                  ret);
+       mutex_unlock(&ir_devices_lock);
+       return ret;
+}
+
+static int __init zilog_init(void)
+{
+       int ret;
+
+       zilog_notify("Zilog/Hauppauge IR driver initializing\n");
+
+       mutex_init(&tx_data_lock);
+
+       request_module("firmware_class");
+
+       ret = i2c_add_driver(&driver);
+       if (ret)
+               zilog_error("initialization failed\n");
+       else
+               zilog_notify("initialization complete\n");
+
+       return ret;
+}
+
+static void __exit zilog_exit(void)
+{
+       i2c_del_driver(&driver);
+       /* if loaded */
+       fw_unload();
+       zilog_notify("Zilog/Hauppauge IR driver unloaded\n");
+}
+
+module_init(zilog_init);
+module_exit(zilog_exit);
+
+MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)");
+MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, "
+             "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver, "
+             "Andy Walls");
+MODULE_LICENSE("GPL");
+/* for compat with old name, which isn't all that accurate anymore */
+MODULE_ALIAS("lirc_pvr150");
+
+module_param(minor, int, 0444);
+MODULE_PARM_DESC(minor, "Preferred minor device number");
+
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
+
+module_param(tx_only, bool, 0644);
+MODULE_PARM_DESC(tx_only, "Only handle the IR transmit function");
diff --git a/drivers/staging/media/solo6x10/Kconfig b/drivers/staging/media/solo6x10/Kconfig
new file mode 100644 (file)
index 0000000..03dcac4
--- /dev/null
@@ -0,0 +1,8 @@
+config SOLO6X10
+       tristate "Softlogic 6x10 MPEG codec cards"
+       depends on PCI && VIDEO_DEV && SND && I2C
+       select VIDEOBUF_DMA_SG
+       select SND_PCM
+       ---help---
+         This driver supports the Softlogic based MPEG-4 and h.264 codec
+         codec cards.
diff --git a/drivers/staging/media/solo6x10/Makefile b/drivers/staging/media/solo6x10/Makefile
new file mode 100644 (file)
index 0000000..72816cf
--- /dev/null
@@ -0,0 +1,3 @@
+solo6x10-y := core.o i2c.o p2m.o v4l2.o tw28.o gpio.o disp.o enc.o v4l2-enc.o g723.o
+
+obj-$(CONFIG_SOLO6X10) := solo6x10.o
diff --git a/drivers/staging/media/solo6x10/TODO b/drivers/staging/media/solo6x10/TODO
new file mode 100644 (file)
index 0000000..7e6c4fa
--- /dev/null
@@ -0,0 +1,24 @@
+TODO (staging => main):
+
+       * Motion detection flags need to be moved to v4l2
+       * Some private CIDs need to be moved to v4l2
+
+TODO (general):
+
+       * encoder on/off controls
+       * mpeg cid bitrate mode (vbr/cbr)
+       * mpeg cid bitrate/bitrate-peak
+       * mpeg encode of user data
+       * mpeg decode of user data
+       * switch between 4 frames/irq to 1 when using mjpeg (and then back
+         when not)
+       * implement a CID control for motion areas/thresholds
+       * implement CID controls for mozaic areas
+       * allow for higher level of interval (for < 1 fps)
+       * sound:
+         - implement playback via external sound jack
+         - implement loopback of external sound jack with incoming audio?
+         - implement pause/resume
+
+Plase send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc Ben Collins
+<bcollins@bluecherry.net>
diff --git a/drivers/staging/media/solo6x10/core.c b/drivers/staging/media/solo6x10/core.c
new file mode 100644 (file)
index 0000000..f974f64
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include "solo6x10.h"
+#include "tw28.h"
+
+MODULE_DESCRIPTION("Softlogic 6x10 MP4/H.264 Encoder/Decoder V4L2/ALSA Driver");
+MODULE_AUTHOR("Ben Collins <bcollins@bluecherry.net>");
+MODULE_VERSION(SOLO6X10_VERSION);
+MODULE_LICENSE("GPL");
+
+void solo_irq_on(struct solo_dev *solo_dev, u32 mask)
+{
+       solo_dev->irq_mask |= mask;
+       solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask);
+}
+
+void solo_irq_off(struct solo_dev *solo_dev, u32 mask)
+{
+       solo_dev->irq_mask &= ~mask;
+       solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask);
+}
+
+/* XXX We should check the return value of the sub-device ISR's */
+static irqreturn_t solo_isr(int irq, void *data)
+{
+       struct solo_dev *solo_dev = data;
+       u32 status;
+       int i;
+
+       status = solo_reg_read(solo_dev, SOLO_IRQ_STAT);
+       if (!status)
+               return IRQ_NONE;
+
+       if (status & ~solo_dev->irq_mask) {
+               solo_reg_write(solo_dev, SOLO_IRQ_STAT,
+                              status & ~solo_dev->irq_mask);
+               status &= solo_dev->irq_mask;
+       }
+
+       if (status & SOLO_IRQ_PCI_ERR) {
+               u32 err = solo_reg_read(solo_dev, SOLO_PCI_ERR);
+               solo_p2m_error_isr(solo_dev, err);
+               solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_PCI_ERR);
+       }
+
+       for (i = 0; i < SOLO_NR_P2M; i++)
+               if (status & SOLO_IRQ_P2M(i))
+                       solo_p2m_isr(solo_dev, i);
+
+       if (status & SOLO_IRQ_IIC)
+               solo_i2c_isr(solo_dev);
+
+       if (status & SOLO_IRQ_VIDEO_IN)
+               solo_video_in_isr(solo_dev);
+
+       /* Call this first so enc gets detected flag set */
+       if (status & SOLO_IRQ_MOTION)
+               solo_motion_isr(solo_dev);
+
+       if (status & SOLO_IRQ_ENCODER)
+               solo_enc_v4l2_isr(solo_dev);
+
+       if (status & SOLO_IRQ_G723)
+               solo_g723_isr(solo_dev);
+
+       return IRQ_HANDLED;
+}
+
+static void free_solo_dev(struct solo_dev *solo_dev)
+{
+       struct pci_dev *pdev;
+
+       if (!solo_dev)
+               return;
+
+       pdev = solo_dev->pdev;
+
+       /* If we never initialized the PCI device, then nothing else
+        * below here needs cleanup */
+       if (!pdev) {
+               kfree(solo_dev);
+               return;
+       }
+
+       /* Bring down the sub-devices first */
+       solo_g723_exit(solo_dev);
+       solo_enc_v4l2_exit(solo_dev);
+       solo_enc_exit(solo_dev);
+       solo_v4l2_exit(solo_dev);
+       solo_disp_exit(solo_dev);
+       solo_gpio_exit(solo_dev);
+       solo_p2m_exit(solo_dev);
+       solo_i2c_exit(solo_dev);
+
+       /* Now cleanup the PCI device */
+       if (solo_dev->reg_base) {
+               solo_irq_off(solo_dev, ~0);
+               pci_iounmap(pdev, solo_dev->reg_base);
+               free_irq(pdev->irq, solo_dev);
+       }
+
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+
+       kfree(solo_dev);
+}
+
+static int __devinit solo_pci_probe(struct pci_dev *pdev,
+                                   const struct pci_device_id *id)
+{
+       struct solo_dev *solo_dev;
+       int ret;
+       int sdram;
+       u8 chip_id;
+       u32 reg;
+
+       solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL);
+       if (solo_dev == NULL)
+               return -ENOMEM;
+
+       solo_dev->pdev = pdev;
+       spin_lock_init(&solo_dev->reg_io_lock);
+       pci_set_drvdata(pdev, solo_dev);
+
+       ret = pci_enable_device(pdev);
+       if (ret)
+               goto fail_probe;
+
+       pci_set_master(pdev);
+
+       ret = pci_request_regions(pdev, SOLO6X10_NAME);
+       if (ret)
+               goto fail_probe;
+
+       solo_dev->reg_base = pci_ioremap_bar(pdev, 0);
+       if (solo_dev->reg_base == NULL) {
+               ret = -ENOMEM;
+               goto fail_probe;
+       }
+
+       chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) &
+                                       SOLO_CHIP_ID_MASK;
+       switch (chip_id) {
+       case 7:
+               solo_dev->nr_chans = 16;
+               solo_dev->nr_ext = 5;
+               break;
+       case 6:
+               solo_dev->nr_chans = 8;
+               solo_dev->nr_ext = 2;
+               break;
+       default:
+               dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, "
+                        "defaulting to 4 channels\n",
+                        chip_id);
+       case 5:
+               solo_dev->nr_chans = 4;
+               solo_dev->nr_ext = 1;
+       }
+
+       solo_dev->flags = id->driver_data;
+
+       /* Disable all interrupts to start */
+       solo_irq_off(solo_dev, ~0);
+
+       reg = SOLO_SYS_CFG_SDRAM64BIT;
+       /* Initial global settings */
+       if (!(solo_dev->flags & FLAGS_6110))
+               reg |= SOLO6010_SYS_CFG_INPUTDIV(25) |
+                       SOLO6010_SYS_CFG_FEEDBACKDIV((SOLO_CLOCK_MHZ * 2) - 2) |
+                       SOLO6010_SYS_CFG_OUTDIV(3);
+       solo_reg_write(solo_dev, SOLO_SYS_CFG, reg);
+
+        if (solo_dev->flags & FLAGS_6110) {
+                u32 sys_clock_MHz = SOLO_CLOCK_MHZ;
+                u32 pll_DIVQ;
+                u32 pll_DIVF;
+
+                if (sys_clock_MHz < 125) {
+                        pll_DIVQ = 3;
+                        pll_DIVF = (sys_clock_MHz * 4) / 3;
+                } else {
+                        pll_DIVQ = 2;
+                        pll_DIVF = (sys_clock_MHz * 2) / 3;
+                }
+
+                solo_reg_write(solo_dev, SOLO6110_PLL_CONFIG,
+                              SOLO6110_PLL_RANGE_5_10MHZ |
+                              SOLO6110_PLL_DIVR(9) |
+                              SOLO6110_PLL_DIVQ_EXP(pll_DIVQ) |
+                              SOLO6110_PLL_DIVF(pll_DIVF) | SOLO6110_PLL_FSEN);
+               mdelay(1);      // PLL Locking time (1ms)
+
+               solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 3 << 8); /* ? */
+        } else
+               solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 1 << 8); /* ? */
+
+       solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, SOLO_CLOCK_MHZ - 1);
+
+       /* PLL locking time of 1ms */
+       mdelay(1);
+
+       ret = request_irq(pdev->irq, solo_isr, IRQF_SHARED, SOLO6X10_NAME,
+                         solo_dev);
+       if (ret)
+               goto fail_probe;
+
+       /* Handle this from the start */
+       solo_irq_on(solo_dev, SOLO_IRQ_PCI_ERR);
+
+       ret = solo_i2c_init(solo_dev);
+       if (ret)
+               goto fail_probe;
+
+       /* Setup the DMA engine */
+       sdram = (solo_dev->nr_chans >= 8) ? 2 : 1;
+       solo_reg_write(solo_dev, SOLO_DMA_CTRL,
+                      SOLO_DMA_CTRL_REFRESH_CYCLE(1) |
+                      SOLO_DMA_CTRL_SDRAM_SIZE(sdram) |
+                      SOLO_DMA_CTRL_SDRAM_CLK_INVERT |
+                      SOLO_DMA_CTRL_READ_CLK_SELECT |
+                      SOLO_DMA_CTRL_LATENCY(1));
+
+       ret = solo_p2m_init(solo_dev);
+       if (ret)
+               goto fail_probe;
+
+       ret = solo_disp_init(solo_dev);
+       if (ret)
+               goto fail_probe;
+
+       ret = solo_gpio_init(solo_dev);
+       if (ret)
+               goto fail_probe;
+
+       ret = solo_tw28_init(solo_dev);
+       if (ret)
+               goto fail_probe;
+
+       ret = solo_v4l2_init(solo_dev);
+       if (ret)
+               goto fail_probe;
+
+       ret = solo_enc_init(solo_dev);
+       if (ret)
+               goto fail_probe;
+
+       ret = solo_enc_v4l2_init(solo_dev);
+       if (ret)
+               goto fail_probe;
+
+       ret = solo_g723_init(solo_dev);
+       if (ret)
+               goto fail_probe;
+
+       return 0;
+
+fail_probe:
+       free_solo_dev(solo_dev);
+       return ret;
+}
+
+static void __devexit solo_pci_remove(struct pci_dev *pdev)
+{
+       struct solo_dev *solo_dev = pci_get_drvdata(pdev);
+
+       free_solo_dev(solo_dev);
+}
+
+static struct pci_device_id solo_id_table[] = {
+       /* 6010 based cards */
+       {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010)},
+       {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6110),
+        .driver_data = FLAGS_6110},
+       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16)},
+       /* 6110 based cards */
+       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16)},
+       {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, solo_id_table);
+
+static struct pci_driver solo_pci_driver = {
+       .name = SOLO6X10_NAME,
+       .id_table = solo_id_table,
+       .probe = solo_pci_probe,
+       .remove = solo_pci_remove,
+};
+
+static int __init solo_module_init(void)
+{
+       return pci_register_driver(&solo_pci_driver);
+}
+
+static void __exit solo_module_exit(void)
+{
+       pci_unregister_driver(&solo_pci_driver);
+}
+
+module_init(solo_module_init);
+module_exit(solo_module_exit);
diff --git a/drivers/staging/media/solo6x10/disp.c b/drivers/staging/media/solo6x10/disp.c
new file mode 100644 (file)
index 0000000..884c0eb
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ioctl.h>
+#include "solo6x10.h"
+
+#define SOLO_VCLK_DELAY                        3
+#define SOLO_PROGRESSIVE_VSIZE         1024
+
+#define SOLO_MOT_THRESH_W              64
+#define SOLO_MOT_THRESH_H              64
+#define SOLO_MOT_THRESH_SIZE           8192
+#define SOLO_MOT_THRESH_REAL           (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H)
+#define SOLO_MOT_FLAG_SIZE             512
+#define SOLO_MOT_FLAG_AREA             (SOLO_MOT_FLAG_SIZE * 32)
+
+static unsigned video_type;
+module_param(video_type, uint, 0644);
+MODULE_PARM_DESC(video_type, "video_type (0 = NTSC/Default, 1 = PAL)");
+
+static void solo_vin_config(struct solo_dev *solo_dev)
+{
+       solo_dev->vin_hstart = 8;
+       solo_dev->vin_vstart = 2;
+
+       solo_reg_write(solo_dev, SOLO_SYS_VCLK,
+                      SOLO_VCLK_SELECT(2) |
+                      SOLO_VCLK_VIN1415_DELAY(SOLO_VCLK_DELAY) |
+                      SOLO_VCLK_VIN1213_DELAY(SOLO_VCLK_DELAY) |
+                      SOLO_VCLK_VIN1011_DELAY(SOLO_VCLK_DELAY) |
+                      SOLO_VCLK_VIN0809_DELAY(SOLO_VCLK_DELAY) |
+                      SOLO_VCLK_VIN0607_DELAY(SOLO_VCLK_DELAY) |
+                      SOLO_VCLK_VIN0405_DELAY(SOLO_VCLK_DELAY) |
+                      SOLO_VCLK_VIN0203_DELAY(SOLO_VCLK_DELAY) |
+                      SOLO_VCLK_VIN0001_DELAY(SOLO_VCLK_DELAY));
+
+       solo_reg_write(solo_dev, SOLO_VI_ACT_I_P,
+                      SOLO_VI_H_START(solo_dev->vin_hstart) |
+                      SOLO_VI_V_START(solo_dev->vin_vstart) |
+                      SOLO_VI_V_STOP(solo_dev->vin_vstart +
+                                     solo_dev->video_vsize));
+
+       solo_reg_write(solo_dev, SOLO_VI_ACT_I_S,
+                      SOLO_VI_H_START(solo_dev->vout_hstart) |
+                      SOLO_VI_V_START(solo_dev->vout_vstart) |
+                      SOLO_VI_V_STOP(solo_dev->vout_vstart +
+                                     solo_dev->video_vsize));
+
+       solo_reg_write(solo_dev, SOLO_VI_ACT_P,
+                      SOLO_VI_H_START(0) |
+                      SOLO_VI_V_START(1) |
+                      SOLO_VI_V_STOP(SOLO_PROGRESSIVE_VSIZE));
+
+       solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT,
+                      SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0));
+
+       solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0);
+       solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2);
+
+       if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
+               solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
+                              SOLO_VI_PB_USER_MODE);
+               solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
+                              SOLO_VI_PB_HSIZE(858) | SOLO_VI_PB_VSIZE(246));
+               solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
+                              SOLO_VI_PB_VSTART(4) |
+                              SOLO_VI_PB_VSTOP(4 + 240));
+       } else {
+               solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
+                              SOLO_VI_PB_USER_MODE | SOLO_VI_PB_PAL);
+               solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
+                              SOLO_VI_PB_HSIZE(864) | SOLO_VI_PB_VSIZE(294));
+               solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
+                              SOLO_VI_PB_VSTART(4) |
+                              SOLO_VI_PB_VSTOP(4 + 288));
+       }
+       solo_reg_write(solo_dev, SOLO_VI_PB_ACT_H, SOLO_VI_PB_HSTART(16) |
+                      SOLO_VI_PB_HSTOP(16 + 720));
+}
+
+static void solo_disp_config(struct solo_dev *solo_dev)
+{
+       solo_dev->vout_hstart = 6;
+       solo_dev->vout_vstart = 8;
+
+       solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR,
+                      (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88);
+       solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR,
+                      (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f);
+       solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR,
+                      (16 << 24) | (128 << 16) | (16 << 8) | 128);
+
+       solo_reg_write(solo_dev, SOLO_VO_FMT_ENC,
+                      solo_dev->video_type |
+                      SOLO_VO_USER_COLOR_SET_NAV |
+                      SOLO_VO_NA_COLOR_Y(0) |
+                      SOLO_VO_NA_COLOR_CB(0) |
+                      SOLO_VO_NA_COLOR_CR(0));
+
+       solo_reg_write(solo_dev, SOLO_VO_ACT_H,
+                      SOLO_VO_H_START(solo_dev->vout_hstart) |
+                      SOLO_VO_H_STOP(solo_dev->vout_hstart +
+                                     solo_dev->video_hsize));
+
+       solo_reg_write(solo_dev, SOLO_VO_ACT_V,
+                      SOLO_VO_V_START(solo_dev->vout_vstart) |
+                      SOLO_VO_V_STOP(solo_dev->vout_vstart +
+                                     solo_dev->video_vsize));
+
+       solo_reg_write(solo_dev, SOLO_VO_RANGE_HV,
+                      SOLO_VO_H_LEN(solo_dev->video_hsize) |
+                      SOLO_VO_V_LEN(solo_dev->video_vsize));
+
+       solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 5);
+
+       solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON |
+                      SOLO_VO_DISP_ERASE_COUNT(8) |
+                      SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR));
+
+       solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
+
+       /* Enable channels we support */
+       solo_reg_write(solo_dev, SOLO_VI_CH_ENA, (1 << solo_dev->nr_chans) - 1);
+
+       /* Disable the watchdog */
+       solo_reg_write(solo_dev, SOLO_WATCHDOG, 0);
+}
+
+static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off,
+                              u16 val, int reg_size)
+{
+       u16 buf[64];
+       int i;
+       int ret = 0;
+
+       for (i = 0; i < sizeof(buf) >> 1; i++)
+               buf[i] = val;
+
+       for (i = 0; i < reg_size; i += sizeof(buf))
+               ret |= solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_VIN, 1, buf,
+                                   SOLO_MOTION_EXT_ADDR(solo_dev) + off + i,
+                                   sizeof(buf));
+
+       return ret;
+}
+
+void solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val)
+{
+       if (ch > solo_dev->nr_chans)
+               return;
+
+       solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
+                           (ch * SOLO_MOT_THRESH_SIZE * 2),
+                           val, SOLO_MOT_THRESH_REAL);
+}
+
+/* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k
+ * threshold and working table for each channel. Atleast that's what the
+ * spec says. However, this code (take from rdk) has some mystery 8k
+ * block right after the flag area, before the first thresh table. */
+static void solo_motion_config(struct solo_dev *solo_dev)
+{
+       int i;
+
+       for (i = 0; i < solo_dev->nr_chans; i++) {
+               /* Clear motion flag area */
+               solo_dma_vin_region(solo_dev, i * SOLO_MOT_FLAG_SIZE, 0x0000,
+                                   SOLO_MOT_FLAG_SIZE);
+
+               /* Clear working cache table */
+               solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
+                                   SOLO_MOT_THRESH_SIZE +
+                                   (i * SOLO_MOT_THRESH_SIZE * 2),
+                                   0x0000, SOLO_MOT_THRESH_REAL);
+
+               /* Set default threshold table */
+               solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH);
+       }
+
+       /* Default motion settings */
+       solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) |
+                      (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
+       solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL,
+                      SOLO_VI_MOTION_FRAME_COUNT(3) |
+                      SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16)
+                      | /* SOLO_VI_MOTION_INTR_START_STOP | */
+                      SOLO_VI_MOTION_SAMPLE_COUNT(10));
+
+       solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
+       solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
+}
+
+int solo_disp_init(struct solo_dev *solo_dev)
+{
+       int i;
+
+       solo_dev->video_hsize = 704;
+       if (video_type == 0) {
+               solo_dev->video_type = SOLO_VO_FMT_TYPE_NTSC;
+               solo_dev->video_vsize = 240;
+               solo_dev->fps = 30;
+       } else {
+               solo_dev->video_type = SOLO_VO_FMT_TYPE_PAL;
+               solo_dev->video_vsize = 288;
+               solo_dev->fps = 25;
+       }
+
+       solo_vin_config(solo_dev);
+       solo_motion_config(solo_dev);
+       solo_disp_config(solo_dev);
+
+       for (i = 0; i < solo_dev->nr_chans; i++)
+               solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1);
+
+       return 0;
+}
+
+void solo_disp_exit(struct solo_dev *solo_dev)
+{
+       int i;
+
+       solo_irq_off(solo_dev, SOLO_IRQ_MOTION);
+
+       solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0);
+       solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
+       solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
+
+       for (i = 0; i < solo_dev->nr_chans; i++) {
+               solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(i), 0);
+               solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(i), 0);
+               solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 0);
+       }
+
+       /* Set default border */
+       for (i = 0; i < 5; i++)
+               solo_reg_write(solo_dev, SOLO_VO_BORDER_X(i), 0);
+
+       for (i = 0; i < 5; i++)
+               solo_reg_write(solo_dev, SOLO_VO_BORDER_Y(i), 0);
+
+       solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_MASK, 0);
+       solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_MASK, 0);
+
+       solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0);
+       solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0);
+       solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0);
+
+       solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0);
+       solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0);
+       solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0);
+}
diff --git a/drivers/staging/media/solo6x10/enc.c b/drivers/staging/media/solo6x10/enc.c
new file mode 100644 (file)
index 0000000..de50259
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "solo6x10.h"
+#include "osd-font.h"
+
+#define CAPTURE_MAX_BANDWIDTH          32      /* D1 4channel (D1 == 4) */
+#define OSG_BUFFER_SIZE                        1024
+
+#define VI_PROG_HSIZE                  (1280 - 16)
+#define VI_PROG_VSIZE                  (1024 - 16)
+
+static void solo_capture_config(struct solo_dev *solo_dev)
+{
+       int i, j;
+       unsigned long height;
+       unsigned long width;
+       unsigned char *buf;
+
+       solo_reg_write(solo_dev, SOLO_CAP_BASE,
+                      SOLO_CAP_MAX_PAGE(SOLO_CAP_EXT_MAX_PAGE *
+                                        solo_dev->nr_chans) |
+                      SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16));
+       solo_reg_write(solo_dev, SOLO_CAP_BTW,
+                      (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) |
+                      SOLO_CAP_MAX_BANDWIDTH(CAPTURE_MAX_BANDWIDTH));
+
+       /* Set scale 1, 9 dimension */
+       width = solo_dev->video_hsize;
+       height = solo_dev->video_vsize;
+       solo_reg_write(solo_dev, SOLO_DIM_SCALE1,
+                      SOLO_DIM_H_MB_NUM(width / 16) |
+                      SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+                      SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+       /* Set scale 2, 10 dimension */
+       width = solo_dev->video_hsize / 2;
+       height = solo_dev->video_vsize;
+       solo_reg_write(solo_dev, SOLO_DIM_SCALE2,
+                      SOLO_DIM_H_MB_NUM(width / 16) |
+                      SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+                      SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+       /* Set scale 3, 11 dimension */
+       width = solo_dev->video_hsize / 2;
+       height = solo_dev->video_vsize / 2;
+       solo_reg_write(solo_dev, SOLO_DIM_SCALE3,
+                      SOLO_DIM_H_MB_NUM(width / 16) |
+                      SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+                      SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+       /* Set scale 4, 12 dimension */
+       width = solo_dev->video_hsize / 3;
+       height = solo_dev->video_vsize / 3;
+       solo_reg_write(solo_dev, SOLO_DIM_SCALE4,
+                      SOLO_DIM_H_MB_NUM(width / 16) |
+                      SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+                      SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+       /* Set scale 5, 13 dimension */
+       width = solo_dev->video_hsize / 4;
+       height = solo_dev->video_vsize / 2;
+       solo_reg_write(solo_dev, SOLO_DIM_SCALE5,
+                      SOLO_DIM_H_MB_NUM(width / 16) |
+                      SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
+                      SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+       /* Progressive */
+       width = VI_PROG_HSIZE;
+       height = VI_PROG_VSIZE;
+       solo_reg_write(solo_dev, SOLO_DIM_PROG,
+                      SOLO_DIM_H_MB_NUM(width / 16) |
+                      SOLO_DIM_V_MB_NUM_FRAME(height / 16) |
+                      SOLO_DIM_V_MB_NUM_FIELD(height / 16));
+
+       /* Clear OSD */
+       solo_reg_write(solo_dev, SOLO_VE_OSD_CH, 0);
+       solo_reg_write(solo_dev, SOLO_VE_OSD_BASE, SOLO_EOSD_EXT_ADDR >> 16);
+       solo_reg_write(solo_dev, SOLO_VE_OSD_CLR,
+                      0xF0 << 16 | 0x80 << 8 | 0x80);
+       solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, 0);
+
+       /* Clear OSG buffer */
+       buf = kzalloc(OSG_BUFFER_SIZE, GFP_KERNEL);
+       if (!buf)
+               return;
+
+       for (i = 0; i < solo_dev->nr_chans; i++) {
+               for (j = 0; j < SOLO_EOSD_EXT_SIZE; j += OSG_BUFFER_SIZE) {
+                       solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_MP4E, 1, buf,
+                                    SOLO_EOSD_EXT_ADDR +
+                                    (i * SOLO_EOSD_EXT_SIZE) + j,
+                                    OSG_BUFFER_SIZE);
+               }
+       }
+       kfree(buf);
+}
+
+int solo_osd_print(struct solo_enc_dev *solo_enc)
+{
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+       char *str = solo_enc->osd_text;
+       u8 *buf;
+       u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH);
+       int len = strlen(str);
+       int i, j;
+       int x = 1, y = 1;
+
+       if (len == 0) {
+               reg &= ~(1 << solo_enc->ch);
+               solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
+               return 0;
+       }
+
+       buf = kzalloc(SOLO_EOSD_EXT_SIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       for (i = 0; i < len; i++) {
+               for (j = 0; j < 16; j++) {
+                       buf[(j*2) + (i%2) + ((x + (i/2)) * 32) + (y * 2048)] =
+                               (solo_osd_font[(str[i] * 4) + (j / 4)]
+                                       >> ((3 - (j % 4)) * 8)) & 0xff;
+               }
+       }
+
+       solo_p2m_dma(solo_dev, 0, 1, buf, SOLO_EOSD_EXT_ADDR +
+                    (solo_enc->ch * SOLO_EOSD_EXT_SIZE), SOLO_EOSD_EXT_SIZE);
+       reg |= (1 << solo_enc->ch);
+       solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
+
+       kfree(buf);
+
+       return 0;
+}
+
+static void solo_jpeg_config(struct solo_dev *solo_dev)
+{
+       u32 reg;
+       if (solo_dev->flags & FLAGS_6110)
+               reg = (4 << 24) | (3 << 16) | (2 << 8) | (1 << 0);
+       else
+               reg = (2 << 24) | (2 << 16) | (2 << 8) | (2 << 0);
+       solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, reg);
+       solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, 0);
+       solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, 0);
+       solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG,
+               (SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) |
+               ((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff));
+       solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff);
+       /* que limit, samp limit, pos limit */
+       solo_reg_write(solo_dev, 0x0688, (0 << 16) | (30 << 8) | 60);
+}
+
+static void solo_mp4e_config(struct solo_dev *solo_dev)
+{
+       int i;
+       u32 reg;
+
+       /* We can only use VE_INTR_CTRL(0) if we want to support mjpeg */
+       solo_reg_write(solo_dev, SOLO_VE_CFG0,
+                      SOLO_VE_INTR_CTRL(0) |
+                      SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) |
+                      SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16));
+
+       solo_reg_write(solo_dev, SOLO_VE_CFG1,
+                      SOLO_VE_INSERT_INDEX | SOLO_VE_MOTION_MODE(0));
+
+       solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0);
+       solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0);
+       solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0);
+       solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0);
+       solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0);
+
+       reg = SOLO_VE_LITTLE_ENDIAN | SOLO_COMP_ATTR_FCODE(1) |
+               SOLO_COMP_TIME_INC(0) | SOLO_COMP_TIME_WIDTH(15);
+       if (solo_dev->flags & FLAGS_6110)
+               reg |= SOLO_DCT_INTERVAL(10);
+       else
+               reg |= SOLO_DCT_INTERVAL(36 / 4);
+       solo_reg_write(solo_dev, SOLO_VE_ATTR, reg);
+
+       for (i = 0; i < solo_dev->nr_chans; i++)
+               solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i),
+                              (SOLO_EREF_EXT_ADDR(solo_dev) +
+                              (i * SOLO_EREF_EXT_SIZE)) >> 16);
+
+       if (solo_dev->flags & FLAGS_6110)
+               solo_reg_write(solo_dev, 0x0634, 0x00040008); /* ? */
+}
+
+int solo_enc_init(struct solo_dev *solo_dev)
+{
+       int i;
+
+       solo_capture_config(solo_dev);
+       solo_mp4e_config(solo_dev);
+       solo_jpeg_config(solo_dev);
+
+       for (i = 0; i < solo_dev->nr_chans; i++) {
+               solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
+               solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
+       }
+
+       solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
+
+       return 0;
+}
+
+void solo_enc_exit(struct solo_dev *solo_dev)
+{
+       int i;
+
+       solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
+
+       for (i = 0; i < solo_dev->nr_chans; i++) {
+               solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
+               solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
+       }
+}
diff --git a/drivers/staging/media/solo6x10/g723.c b/drivers/staging/media/solo6x10/g723.c
new file mode 100644 (file)
index 0000000..59274bf
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/mempool.h>
+#include <linux/poll.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/freezer.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/control.h>
+#include "solo6x10.h"
+#include "tw28.h"
+
+#define G723_INTR_ORDER                0
+#define G723_FDMA_PAGES                32
+#define G723_PERIOD_BYTES      48
+#define G723_PERIOD_BLOCK      1024
+#define G723_FRAMES_PER_PAGE   48
+
+/* Sets up channels 16-19 for decoding and 0-15 for encoding */
+#define OUTMODE_MASK           0x300
+
+#define SAMPLERATE             8000
+#define BITRATE                        25
+
+/* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page
+ * is broken down to 20 * 48 byte regions (one for each channel possible)
+ * with the rest of the page being dummy data. */
+#define MAX_BUFFER             (G723_PERIOD_BYTES * PERIODS_MAX)
+#define IRQ_PAGES              4 /* 0 - 4 */
+#define PERIODS_MIN            (1 << IRQ_PAGES)
+#define PERIODS_MAX            G723_FDMA_PAGES
+
+struct solo_snd_pcm {
+       int             on;
+       spinlock_t      lock;
+       struct solo_dev *solo_dev;
+       unsigned char   g723_buf[G723_PERIOD_BYTES];
+};
+
+static void solo_g723_config(struct solo_dev *solo_dev)
+{
+       int clk_div;
+
+       clk_div = SOLO_CLOCK_MHZ / (SAMPLERATE * (BITRATE * 2) * 2);
+
+       solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE,
+                      SOLO_AUDIO_BITRATE(BITRATE) |
+                      SOLO_AUDIO_CLK_DIV(clk_div));
+
+       solo_reg_write(solo_dev, SOLO_AUDIO_FDMA_INTR,
+                     SOLO_AUDIO_FDMA_INTERVAL(IRQ_PAGES) |
+                     SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER) |
+                     SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16));
+
+       solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL,
+                      SOLO_AUDIO_ENABLE | SOLO_AUDIO_I2S_MODE |
+                      SOLO_AUDIO_I2S_MULTI(3) | SOLO_AUDIO_MODE(OUTMODE_MASK));
+}
+
+void solo_g723_isr(struct solo_dev *solo_dev)
+{
+       struct snd_pcm_str *pstr =
+               &solo_dev->snd_pcm->streams[SNDRV_PCM_STREAM_CAPTURE];
+       struct snd_pcm_substream *ss;
+       struct solo_snd_pcm *solo_pcm;
+
+       solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_G723);
+
+       for (ss = pstr->substream; ss != NULL; ss = ss->next) {
+               if (snd_pcm_substream_chip(ss) == NULL)
+                       continue;
+
+               /* This means open() hasn't been called on this one */
+               if (snd_pcm_substream_chip(ss) == solo_dev)
+                       continue;
+
+               /* Haven't triggered a start yet */
+               solo_pcm = snd_pcm_substream_chip(ss);
+               if (!solo_pcm->on)
+                       continue;
+
+               snd_pcm_period_elapsed(ss);
+       }
+}
+
+static int snd_solo_hw_params(struct snd_pcm_substream *ss,
+                             struct snd_pcm_hw_params *hw_params)
+{
+       return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
+}
+
+static int snd_solo_hw_free(struct snd_pcm_substream *ss)
+{
+       return snd_pcm_lib_free_pages(ss);
+}
+
+static struct snd_pcm_hardware snd_solo_pcm_hw = {
+       .info                   = (SNDRV_PCM_INFO_MMAP |
+                                  SNDRV_PCM_INFO_INTERLEAVED |
+                                  SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                  SNDRV_PCM_INFO_MMAP_VALID),
+       .formats                = SNDRV_PCM_FMTBIT_U8,
+       .rates                  = SNDRV_PCM_RATE_8000,
+       .rate_min               = 8000,
+       .rate_max               = 8000,
+       .channels_min           = 1,
+       .channels_max           = 1,
+       .buffer_bytes_max       = MAX_BUFFER,
+       .period_bytes_min       = G723_PERIOD_BYTES,
+       .period_bytes_max       = G723_PERIOD_BYTES,
+       .periods_min            = PERIODS_MIN,
+       .periods_max            = PERIODS_MAX,
+};
+
+static int snd_solo_pcm_open(struct snd_pcm_substream *ss)
+{
+       struct solo_dev *solo_dev = snd_pcm_substream_chip(ss);
+       struct solo_snd_pcm *solo_pcm;
+
+       solo_pcm = kzalloc(sizeof(*solo_pcm), GFP_KERNEL);
+       if (solo_pcm == NULL)
+               return -ENOMEM;
+
+       spin_lock_init(&solo_pcm->lock);
+       solo_pcm->solo_dev = solo_dev;
+       ss->runtime->hw = snd_solo_pcm_hw;
+
+       snd_pcm_substream_chip(ss) = solo_pcm;
+
+       return 0;
+}
+
+static int snd_solo_pcm_close(struct snd_pcm_substream *ss)
+{
+       struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
+
+       snd_pcm_substream_chip(ss) = solo_pcm->solo_dev;
+       kfree(solo_pcm);
+
+       return 0;
+}
+
+static int snd_solo_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
+{
+       struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
+       struct solo_dev *solo_dev = solo_pcm->solo_dev;
+       int ret = 0;
+
+       spin_lock(&solo_pcm->lock);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               if (solo_pcm->on == 0) {
+                       /* If this is the first user, switch on interrupts */
+                       if (atomic_inc_return(&solo_dev->snd_users) == 1)
+                               solo_irq_on(solo_dev, SOLO_IRQ_G723);
+                       solo_pcm->on = 1;
+               }
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               if (solo_pcm->on) {
+                       /* If this was our last user, switch them off */
+                       if (atomic_dec_return(&solo_dev->snd_users) == 0)
+                               solo_irq_off(solo_dev, SOLO_IRQ_G723);
+                       solo_pcm->on = 0;
+               }
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       spin_unlock(&solo_pcm->lock);
+
+       return ret;
+}
+
+static int snd_solo_pcm_prepare(struct snd_pcm_substream *ss)
+{
+       return 0;
+}
+
+static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss)
+{
+       struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
+       struct solo_dev *solo_dev = solo_pcm->solo_dev;
+       snd_pcm_uframes_t idx = solo_reg_read(solo_dev, SOLO_AUDIO_STA) & 0x1f;
+
+       return idx * G723_FRAMES_PER_PAGE;
+}
+
+static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel,
+                            snd_pcm_uframes_t pos, void __user *dst,
+                            snd_pcm_uframes_t count)
+{
+       struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
+       struct solo_dev *solo_dev = solo_pcm->solo_dev;
+       int err, i;
+
+       for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) {
+               int page = (pos / G723_FRAMES_PER_PAGE) + i;
+
+               err = solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_G723E, 0,
+                                  solo_pcm->g723_buf,
+                                  SOLO_G723_EXT_ADDR(solo_dev) +
+                                  (page * G723_PERIOD_BLOCK) +
+                                  (ss->number * G723_PERIOD_BYTES),
+                                  G723_PERIOD_BYTES);
+               if (err)
+                       return err;
+
+               err = copy_to_user(dst + (i * G723_PERIOD_BYTES),
+                                  solo_pcm->g723_buf, G723_PERIOD_BYTES);
+
+               if (err)
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+static struct snd_pcm_ops snd_solo_pcm_ops = {
+       .open = snd_solo_pcm_open,
+       .close = snd_solo_pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_solo_hw_params,
+       .hw_free = snd_solo_hw_free,
+       .prepare = snd_solo_pcm_prepare,
+       .trigger = snd_solo_pcm_trigger,
+       .pointer = snd_solo_pcm_pointer,
+       .copy = snd_solo_pcm_copy,
+};
+
+static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 1;
+       info->value.integer.min = 0;
+       info->value.integer.max = 15;
+       info->value.integer.step = 1;
+
+       return 0;
+}
+
+static int snd_solo_capture_volume_get(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *value)
+{
+       struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol);
+       u8 ch = value->id.numid - 1;
+
+       value->value.integer.value[0] = tw28_get_audio_gain(solo_dev, ch);
+
+       return 0;
+}
+
+static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *value)
+{
+       struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol);
+       u8 ch = value->id.numid - 1;
+       u8 old_val;
+
+       old_val = tw28_get_audio_gain(solo_dev, ch);
+       if (old_val == value->value.integer.value[0])
+               return 0;
+
+       tw28_set_audio_gain(solo_dev, ch, value->value.integer.value[0]);
+
+       return 1;
+}
+
+static struct snd_kcontrol_new snd_solo_capture_volume = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Capture Volume",
+       .info = snd_solo_capture_volume_info,
+       .get = snd_solo_capture_volume_get,
+       .put = snd_solo_capture_volume_put,
+};
+
+static int solo_snd_pcm_init(struct solo_dev *solo_dev)
+{
+       struct snd_card *card = solo_dev->snd_card;
+       struct snd_pcm *pcm;
+       struct snd_pcm_substream *ss;
+       int ret;
+       int i;
+
+       ret = snd_pcm_new(card, card->driver, 0, 0, solo_dev->nr_chans,
+                         &pcm);
+       if (ret < 0)
+               return ret;
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                       &snd_solo_pcm_ops);
+
+       snd_pcm_chip(pcm) = solo_dev;
+       pcm->info_flags = 0;
+       strcpy(pcm->name, card->shortname);
+
+       for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+            ss; ss = ss->next, i++)
+               sprintf(ss->name, "Camera #%d Audio", i);
+
+       ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
+                                       SNDRV_DMA_TYPE_CONTINUOUS,
+                                       snd_dma_continuous_data(GFP_KERNEL),
+                                       MAX_BUFFER, MAX_BUFFER);
+       if (ret < 0)
+               return ret;
+
+       solo_dev->snd_pcm = pcm;
+
+       return 0;
+}
+
+int solo_g723_init(struct solo_dev *solo_dev)
+{
+       static struct snd_device_ops ops = { NULL };
+       struct snd_card *card;
+       struct snd_kcontrol_new kctl;
+       char name[32];
+       int ret;
+
+       atomic_set(&solo_dev->snd_users, 0);
+
+       /* Allows for easier mapping between video and audio */
+       sprintf(name, "Softlogic%d", solo_dev->vfd->num);
+
+       ret = snd_card_create(SNDRV_DEFAULT_IDX1, name, THIS_MODULE, 0,
+                             &solo_dev->snd_card);
+       if (ret < 0)
+               return ret;
+
+       card = solo_dev->snd_card;
+
+       strcpy(card->driver, SOLO6X10_NAME);
+       strcpy(card->shortname, "SOLO-6x10 Audio");
+       sprintf(card->longname, "%s on %s IRQ %d", card->shortname,
+               pci_name(solo_dev->pdev), solo_dev->pdev->irq);
+       snd_card_set_dev(card, &solo_dev->pdev->dev);
+
+       ret = snd_device_new(card, SNDRV_DEV_LOWLEVEL, solo_dev, &ops);
+       if (ret < 0)
+               goto snd_error;
+
+       /* Mixer controls */
+       strcpy(card->mixername, "SOLO-6x10");
+       kctl = snd_solo_capture_volume;
+       kctl.count = solo_dev->nr_chans;
+       ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev));
+       if (ret < 0)
+               return ret;
+
+       ret = solo_snd_pcm_init(solo_dev);
+       if (ret < 0)
+               goto snd_error;
+
+       ret = snd_card_register(card);
+       if (ret < 0)
+               goto snd_error;
+
+       solo_g723_config(solo_dev);
+
+       dev_info(&solo_dev->pdev->dev, "Alsa sound card as %s\n", name);
+
+       return 0;
+
+snd_error:
+       snd_card_free(card);
+       return ret;
+}
+
+void solo_g723_exit(struct solo_dev *solo_dev)
+{
+       solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, 0);
+       solo_irq_off(solo_dev, SOLO_IRQ_G723);
+
+       snd_card_free(solo_dev->snd_card);
+}
diff --git a/drivers/staging/media/solo6x10/gpio.c b/drivers/staging/media/solo6x10/gpio.c
new file mode 100644 (file)
index 0000000..0925e6f
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include "solo6x10.h"
+
+static void solo_gpio_mode(struct solo_dev *solo_dev,
+                          unsigned int port_mask, unsigned int mode)
+{
+       int port;
+       unsigned int ret;
+
+       ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0);
+
+       /* To set gpio */
+       for (port = 0; port < 16; port++) {
+               if (!((1 << port) & port_mask))
+                       continue;
+
+               ret &= (~(3 << (port << 1)));
+               ret |= ((mode & 3) << (port << 1));
+       }
+
+       solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_0, ret);
+
+       /* To set extended gpio - sensor */
+       ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1);
+
+       for (port = 0; port < 16; port++) {
+               if (!((1 << (port + 16)) & port_mask))
+                       continue;
+
+               if (!mode)
+                       ret &= ~(1 << port);
+               else
+                       ret |= 1 << port;
+       }
+
+       solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret);
+}
+
+static void solo_gpio_set(struct solo_dev *solo_dev, unsigned int value)
+{
+       solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
+                      solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) | value);
+}
+
+static void solo_gpio_clear(struct solo_dev *solo_dev, unsigned int value)
+{
+       solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
+                      solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) & ~value);
+}
+
+static void solo_gpio_config(struct solo_dev *solo_dev)
+{
+       /* Video reset */
+       solo_gpio_mode(solo_dev, 0x30, 1);
+       solo_gpio_clear(solo_dev, 0x30);
+       udelay(100);
+       solo_gpio_set(solo_dev, 0x30);
+       udelay(100);
+
+       /* Warning: Don't touch the next line unless you're sure of what
+        * you're doing: first four gpio [0-3] are used for video. */
+       solo_gpio_mode(solo_dev, 0x0f, 2);
+
+       /* We use bit 8-15 of SOLO_GPIO_CONFIG_0 for relay purposes */
+       solo_gpio_mode(solo_dev, 0xff00, 1);
+
+       /* Initially set relay status to 0 */
+       solo_gpio_clear(solo_dev, 0xff00);
+}
+
+int solo_gpio_init(struct solo_dev *solo_dev)
+{
+       solo_gpio_config(solo_dev);
+       return 0;
+}
+
+void solo_gpio_exit(struct solo_dev *solo_dev)
+{
+       solo_gpio_clear(solo_dev, 0x30);
+       solo_gpio_config(solo_dev);
+}
diff --git a/drivers/staging/media/solo6x10/i2c.c b/drivers/staging/media/solo6x10/i2c.c
new file mode 100644 (file)
index 0000000..ef95a50
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* XXX: The SOLO6x10 i2c does not have separate interrupts for each i2c
+ * channel. The bus can only handle one i2c event at a time. The below handles
+ * this all wrong. We should be using the status registers to see if the bus
+ * is in use, and have a global lock to check the status register. Also,
+ * the bulk of the work should be handled out-of-interrupt. The ugly loops
+ * that occur during interrupt scare me. The ISR should merely signal
+ * thread context, ACK the interrupt, and move on. -- BenC */
+
+#include <linux/kernel.h>
+#include "solo6x10.h"
+
+u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off)
+{
+       struct i2c_msg msgs[2];
+       u8 data;
+
+       msgs[0].flags = 0;
+       msgs[0].addr = addr;
+       msgs[0].len = 1;
+       msgs[0].buf = &off;
+
+       msgs[1].flags = I2C_M_RD;
+       msgs[1].addr = addr;
+       msgs[1].len = 1;
+       msgs[1].buf = &data;
+
+       i2c_transfer(&solo_dev->i2c_adap[id], msgs, 2);
+
+       return data;
+}
+
+void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr,
+                       u8 off, u8 data)
+{
+       struct i2c_msg msgs;
+       u8 buf[2];
+
+       buf[0] = off;
+       buf[1] = data;
+       msgs.flags = 0;
+       msgs.addr = addr;
+       msgs.len = 2;
+       msgs.buf = buf;
+
+       i2c_transfer(&solo_dev->i2c_adap[id], &msgs, 1);
+}
+
+static void solo_i2c_flush(struct solo_dev *solo_dev, int wr)
+{
+       u32 ctrl;
+
+       ctrl = SOLO_IIC_CH_SET(solo_dev->i2c_id);
+
+       if (solo_dev->i2c_state == IIC_STATE_START)
+               ctrl |= SOLO_IIC_START;
+
+       if (wr) {
+               ctrl |= SOLO_IIC_WRITE;
+       } else {
+               ctrl |= SOLO_IIC_READ;
+               if (!(solo_dev->i2c_msg->flags & I2C_M_NO_RD_ACK))
+                       ctrl |= SOLO_IIC_ACK_EN;
+       }
+
+       if (solo_dev->i2c_msg_ptr == solo_dev->i2c_msg->len)
+               ctrl |= SOLO_IIC_STOP;
+
+       solo_reg_write(solo_dev, SOLO_IIC_CTRL, ctrl);
+}
+
+static void solo_i2c_start(struct solo_dev *solo_dev)
+{
+       u32 addr = solo_dev->i2c_msg->addr << 1;
+
+       if (solo_dev->i2c_msg->flags & I2C_M_RD)
+               addr |= 1;
+
+       solo_dev->i2c_state = IIC_STATE_START;
+       solo_reg_write(solo_dev, SOLO_IIC_TXD, addr);
+       solo_i2c_flush(solo_dev, 1);
+}
+
+static void solo_i2c_stop(struct solo_dev *solo_dev)
+{
+       solo_irq_off(solo_dev, SOLO_IRQ_IIC);
+       solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
+       solo_dev->i2c_state = IIC_STATE_STOP;
+       wake_up(&solo_dev->i2c_wait);
+}
+
+static int solo_i2c_handle_read(struct solo_dev *solo_dev)
+{
+prepare_read:
+       if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
+               solo_i2c_flush(solo_dev, 0);
+               return 0;
+       }
+
+       solo_dev->i2c_msg_ptr = 0;
+       solo_dev->i2c_msg++;
+       solo_dev->i2c_msg_num--;
+
+       if (solo_dev->i2c_msg_num == 0) {
+               solo_i2c_stop(solo_dev);
+               return 0;
+       }
+
+       if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
+               solo_i2c_start(solo_dev);
+       } else {
+               if (solo_dev->i2c_msg->flags & I2C_M_RD)
+                       goto prepare_read;
+               else
+                       solo_i2c_stop(solo_dev);
+       }
+
+       return 0;
+}
+
+static int solo_i2c_handle_write(struct solo_dev *solo_dev)
+{
+retry_write:
+       if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
+               solo_reg_write(solo_dev, SOLO_IIC_TXD,
+                              solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr]);
+               solo_dev->i2c_msg_ptr++;
+               solo_i2c_flush(solo_dev, 1);
+               return 0;
+       }
+
+       solo_dev->i2c_msg_ptr = 0;
+       solo_dev->i2c_msg++;
+       solo_dev->i2c_msg_num--;
+
+       if (solo_dev->i2c_msg_num == 0) {
+               solo_i2c_stop(solo_dev);
+               return 0;
+       }
+
+       if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
+               solo_i2c_start(solo_dev);
+       } else {
+               if (solo_dev->i2c_msg->flags & I2C_M_RD)
+                       solo_i2c_stop(solo_dev);
+               else
+                       goto retry_write;
+       }
+
+       return 0;
+}
+
+int solo_i2c_isr(struct solo_dev *solo_dev)
+{
+       u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL);
+       int ret = -EINVAL;
+
+       solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_IIC);
+
+       if (status & (SOLO_IIC_STATE_TRNS & SOLO_IIC_STATE_SIG_ERR) ||
+           solo_dev->i2c_id < 0) {
+               solo_i2c_stop(solo_dev);
+               return -ENXIO;
+       }
+
+       switch (solo_dev->i2c_state) {
+       case IIC_STATE_START:
+               if (solo_dev->i2c_msg->flags & I2C_M_RD) {
+                       solo_dev->i2c_state = IIC_STATE_READ;
+                       ret = solo_i2c_handle_read(solo_dev);
+                       break;
+               }
+
+               solo_dev->i2c_state = IIC_STATE_WRITE;
+       case IIC_STATE_WRITE:
+               ret = solo_i2c_handle_write(solo_dev);
+               break;
+
+       case IIC_STATE_READ:
+               solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr] =
+                       solo_reg_read(solo_dev, SOLO_IIC_RXD);
+               solo_dev->i2c_msg_ptr++;
+
+               ret = solo_i2c_handle_read(solo_dev);
+               break;
+
+       default:
+               solo_i2c_stop(solo_dev);
+       }
+
+       return ret;
+}
+
+static int solo_i2c_master_xfer(struct i2c_adapter *adap,
+                               struct i2c_msg msgs[], int num)
+{
+       struct solo_dev *solo_dev = adap->algo_data;
+       unsigned long timeout;
+       int ret;
+       int i;
+       DEFINE_WAIT(wait);
+
+       for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
+               if (&solo_dev->i2c_adap[i] == adap)
+                       break;
+       }
+
+       if (i == SOLO_I2C_ADAPTERS)
+               return num; /* XXX Right return value for failure? */
+
+       mutex_lock(&solo_dev->i2c_mutex);
+       solo_dev->i2c_id = i;
+       solo_dev->i2c_msg = msgs;
+       solo_dev->i2c_msg_num = num;
+       solo_dev->i2c_msg_ptr = 0;
+
+       solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
+       solo_irq_on(solo_dev, SOLO_IRQ_IIC);
+       solo_i2c_start(solo_dev);
+
+       timeout = HZ / 2;
+
+       for (;;) {
+               prepare_to_wait(&solo_dev->i2c_wait, &wait, TASK_INTERRUPTIBLE);
+
+               if (solo_dev->i2c_state == IIC_STATE_STOP)
+                       break;
+
+               timeout = schedule_timeout(timeout);
+               if (!timeout)
+                       break;
+
+               if (signal_pending(current))
+                       break;
+       }
+
+       finish_wait(&solo_dev->i2c_wait, &wait);
+       ret = num - solo_dev->i2c_msg_num;
+       solo_dev->i2c_state = IIC_STATE_IDLE;
+       solo_dev->i2c_id = -1;
+
+       mutex_unlock(&solo_dev->i2c_mutex);
+
+       return ret;
+}
+
+static u32 solo_i2c_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm solo_i2c_algo = {
+       .master_xfer    = solo_i2c_master_xfer,
+       .functionality  = solo_i2c_functionality,
+};
+
+int solo_i2c_init(struct solo_dev *solo_dev)
+{
+       int i;
+       int ret;
+
+       solo_reg_write(solo_dev, SOLO_IIC_CFG,
+                      SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE);
+
+       solo_dev->i2c_id = -1;
+       solo_dev->i2c_state = IIC_STATE_IDLE;
+       init_waitqueue_head(&solo_dev->i2c_wait);
+       mutex_init(&solo_dev->i2c_mutex);
+
+       for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
+               struct i2c_adapter *adap = &solo_dev->i2c_adap[i];
+
+               snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d", SOLO6X10_NAME, i);
+               adap->algo = &solo_i2c_algo;
+               adap->algo_data = solo_dev;
+               adap->retries = 1;
+               adap->dev.parent = &solo_dev->pdev->dev;
+
+               ret = i2c_add_adapter(adap);
+               if (ret) {
+                       adap->algo_data = NULL;
+                       break;
+               }
+       }
+
+       if (ret) {
+               for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
+                       if (!solo_dev->i2c_adap[i].algo_data)
+                               break;
+                       i2c_del_adapter(&solo_dev->i2c_adap[i]);
+                       solo_dev->i2c_adap[i].algo_data = NULL;
+               }
+               return ret;
+       }
+
+       dev_info(&solo_dev->pdev->dev, "Enabled %d i2c adapters\n",
+                SOLO_I2C_ADAPTERS);
+
+       return 0;
+}
+
+void solo_i2c_exit(struct solo_dev *solo_dev)
+{
+       int i;
+
+       for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
+               if (!solo_dev->i2c_adap[i].algo_data)
+                       continue;
+               i2c_del_adapter(&solo_dev->i2c_adap[i]);
+               solo_dev->i2c_adap[i].algo_data = NULL;
+       }
+}
diff --git a/drivers/staging/media/solo6x10/jpeg.h b/drivers/staging/media/solo6x10/jpeg.h
new file mode 100644 (file)
index 0000000..50defec
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __SOLO6X10_JPEG_H
+#define __SOLO6X10_JPEG_H
+
+static unsigned char jpeg_header[] = {
+       0xff, 0xd8, 0xff, 0xfe, 0x00, 0x0d, 0x42, 0x6c,
+       0x75, 0x65, 0x63, 0x68, 0x65, 0x72, 0x72, 0x79,
+       0x20, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x20, 0x16,
+       0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, 0x1a, 0x1c,
+       0x24, 0x22, 0x20, 0x26, 0x30, 0x50, 0x34, 0x30,
+       0x2c, 0x2c, 0x30, 0x62, 0x46, 0x4a, 0x3a, 0x50,
+       0x74, 0x66, 0x7a, 0x78, 0x72, 0x66, 0x70, 0x6e,
+       0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, 0xae, 0x8a,
+       0x6e, 0x70, 0xa0, 0xda, 0xa2, 0xae, 0xbe, 0xc4,
+       0xce, 0xd0, 0xce, 0x7c, 0x9a, 0xe2, 0xf2, 0xe0,
+       0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, 0xff, 0xdb,
+       0x00, 0x43, 0x01, 0x22, 0x24, 0x24, 0x30, 0x2a,
+       0x30, 0x5e, 0x34, 0x34, 0x5e, 0xc6, 0x84, 0x70,
+       0x84, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+       0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+       0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+       0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+       0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+       0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+       0xc6, 0xc6, 0xc6, 0xff, 0xc4, 0x01, 0xa2, 0x00,
+       0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+       0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01,
+       0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
+       0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03,
+       0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41,
+       0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14,
+       0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1,
+       0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62,
+       0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
+       0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34,
+       0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
+       0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
+       0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
+       0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74,
+       0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84,
+       0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
+       0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2,
+       0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
+       0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+       0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
+       0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+       0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5,
+       0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
+       0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01,
+       0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+       0x08, 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01,
+       0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
+       0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02,
+       0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12,
+       0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32,
+       0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1,
+       0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72,
+       0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1,
+       0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29,
+       0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43,
+       0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53,
+       0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63,
+       0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73,
+       0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82,
+       0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
+       0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+       0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
+       0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+       0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
+       0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5,
+       0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4,
+       0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3,
+       0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff,
+       0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x02, 0xc0,
+       0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03,
+       0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01,
+       0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+};
+
+/* This is the byte marker for the start of SOF0: 0xffc0 marker */
+#define SOF0_START     575
+
+#endif /* __SOLO6X10_JPEG_H */
diff --git a/drivers/staging/media/solo6x10/offsets.h b/drivers/staging/media/solo6x10/offsets.h
new file mode 100644 (file)
index 0000000..3d7e569
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __SOLO6X10_OFFSETS_H
+#define __SOLO6X10_OFFSETS_H
+
+/* Offsets and sizes of the external address */
+#define SOLO_DISP_EXT_ADDR                     0x00000000
+#define SOLO_DISP_EXT_SIZE                     0x00480000
+
+#define SOLO_DEC2LIVE_EXT_ADDR (SOLO_DISP_EXT_ADDR + SOLO_DISP_EXT_SIZE)
+#define SOLO_DEC2LIVE_EXT_SIZE                 0x00240000
+
+#define SOLO_OSG_EXT_ADDR (SOLO_DEC2LIVE_EXT_ADDR + SOLO_DEC2LIVE_EXT_SIZE)
+#define SOLO_OSG_EXT_SIZE                      0x00120000
+
+#define SOLO_EOSD_EXT_ADDR (SOLO_OSG_EXT_ADDR + SOLO_OSG_EXT_SIZE)
+#define SOLO_EOSD_EXT_SIZE                     0x00010000
+
+#define SOLO_MOTION_EXT_ADDR(__solo) (SOLO_EOSD_EXT_ADDR +     \
+                                     (SOLO_EOSD_EXT_SIZE * __solo->nr_chans))
+#define SOLO_MOTION_EXT_SIZE                   0x00080000
+
+#define SOLO_G723_EXT_ADDR(__solo) \
+               (SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE)
+#define SOLO_G723_EXT_SIZE                     0x00010000
+
+#define SOLO_CAP_EXT_ADDR(__solo) \
+               (SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE)
+#define SOLO_CAP_EXT_MAX_PAGE                  (18 + 15)
+#define SOLO_CAP_EXT_SIZE                      (SOLO_CAP_EXT_MAX_PAGE * 65536)
+
+/* This +1 is very important -- Why?! -- BenC */
+#define SOLO_EREF_EXT_ADDR(__solo) \
+               (SOLO_CAP_EXT_ADDR(__solo) + \
+                (SOLO_CAP_EXT_SIZE * (__solo->nr_chans + 1)))
+#define SOLO_EREF_EXT_SIZE                     0x00140000
+
+#define SOLO_MP4E_EXT_ADDR(__solo) \
+               (SOLO_EREF_EXT_ADDR(__solo) + \
+                (SOLO_EREF_EXT_SIZE * __solo->nr_chans))
+#define SOLO_MP4E_EXT_SIZE(__solo)             (0x00080000 * __solo->nr_chans)
+
+#define SOLO_DREF_EXT_ADDR(__solo) \
+               (SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo))
+#define SOLO_DREF_EXT_SIZE                     0x00140000
+
+#define SOLO_MP4D_EXT_ADDR(__solo) \
+               (SOLO_DREF_EXT_ADDR(__solo) + \
+                (SOLO_DREF_EXT_SIZE * __solo->nr_chans))
+#define SOLO_MP4D_EXT_SIZE                     0x00080000
+
+#define SOLO_JPEG_EXT_ADDR(__solo) \
+               (SOLO_MP4D_EXT_ADDR(__solo) + \
+                (SOLO_MP4D_EXT_SIZE * __solo->nr_chans))
+#define SOLO_JPEG_EXT_SIZE(__solo)             (0x00080000 * __solo->nr_chans)
+
+#endif /* __SOLO6X10_OFFSETS_H */
diff --git a/drivers/staging/media/solo6x10/osd-font.h b/drivers/staging/media/solo6x10/osd-font.h
new file mode 100644 (file)
index 0000000..591e0e8
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __SOLO6X10_OSD_FONT_H
+#define __SOLO6X10_OSD_FONT_H
+
+static const unsigned int solo_osd_font[] = {
+       0x00000000, 0x0000c0c8, 0xccfefe0c, 0x08000000,
+       0x00000000, 0x10103838, 0x7c7cfefe, 0x00000000, /* 0 */
+       0x00000000, 0xfefe7c7c, 0x38381010, 0x10000000,
+       0x00000000, 0x7c82fefe, 0xfefefe7c, 0x00000000,
+       0x00000000, 0x00001038, 0x10000000, 0x00000000,
+       0x00000000, 0x0010387c, 0xfe7c3810, 0x00000000,
+       0x00000000, 0x00384444, 0x44380000, 0x00000000,
+       0x00000000, 0x38448282, 0x82443800, 0x00000000,
+       0x00000000, 0x007c7c7c, 0x7c7c0000, 0x00000000,
+       0x00000000, 0x6c6c6c6c, 0x6c6c6c6c, 0x00000000,
+       0x00000000, 0x061e7efe, 0xfe7e1e06, 0x00000000,
+       0x00000000, 0xc0f0fcfe, 0xfefcf0c0, 0x00000000,
+       0x00000000, 0xc6cedefe, 0xfedecec6, 0x00000000,
+       0x00000000, 0xc6e6f6fe, 0xfef6e6c6, 0x00000000,
+       0x00000000, 0x12367efe, 0xfe7e3612, 0x00000000,
+       0x00000000, 0x90d8fcfe, 0xfefcd890, 0x00000000,
+       0x00000038, 0x7cc692ba, 0x92c67c38, 0x00000000,
+       0x00000038, 0x7cc6aa92, 0xaac67c38, 0x00000000,
+       0x00000038, 0x7830107c, 0xbaa8680c, 0x00000000,
+       0x00000038, 0x3c18127c, 0xb8382c60, 0x00000000,
+       0x00000044, 0xaa6c8254, 0x38eec67c, 0x00000000,
+       0x00000082, 0x44288244, 0x38c6827c, 0x00000000,
+       0x00000038, 0x444444fe, 0xfeeec6fe, 0x00000000,
+       0x00000018, 0x78187818, 0x3c7e7e3c, 0x00000000,
+       0x00000000, 0x3854929a, 0x82443800, 0x00000000,
+       0x00000000, 0x00c0c8cc, 0xfefe0c08, 0x00000000,
+       0x0000e0a0, 0xe040e00e, 0x8a0ea40e, 0x00000000,
+       0x0000e0a0, 0xe040e00e, 0x0a8e440e, 0x00000000,
+       0x0000007c, 0x82829292, 0x929282fe, 0x00000000,
+       0x000000f8, 0xfc046494, 0x946404fc, 0x00000000,
+       0x0000003f, 0x7f404c52, 0x524c407f, 0x00000000,
+       0x0000007c, 0x82ba82ba, 0x82ba82fe, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x183c3c3c, 0x18180018, 0x18000000, /* 32   ! */
+       0x00000066, 0x66240000, 0x00000000, 0x00000000,
+       0x00000000, 0x6c6cfe6c, 0x6c6cfe6c, 0x6c000000, /* 34 " # */
+       0x00001010, 0x7cd6d616, 0x7cd0d6d6, 0x7c101000,
+       0x00000000, 0x0086c660, 0x30180cc6, 0xc2000000, /* 36 $ % */
+       0x00000000, 0x386c6c38, 0xdc766666, 0xdc000000,
+       0x0000000c, 0x0c0c0600, 0x00000000, 0x00000000, /* 38 & ' */
+       0x00000000, 0x30180c0c, 0x0c0c0c18, 0x30000000,
+       0x00000000, 0x0c183030, 0x30303018, 0x0c000000, /* 40 ( ) */
+       0x00000000, 0x0000663c, 0xff3c6600, 0x00000000,
+       0x00000000, 0x00001818, 0x7e181800, 0x00000000, /* 42 * + */
+       0x00000000, 0x00000000, 0x00000e0e, 0x0c060000,
+       0x00000000, 0x00000000, 0x7e000000, 0x00000000, /* 44 , - */
+       0x00000000, 0x00000000, 0x00000006, 0x06000000,
+       0x00000000, 0x80c06030, 0x180c0602, 0x00000000, /* 46 . / */
+       0x0000007c, 0xc6e6f6de, 0xcec6c67c, 0x00000000,
+       0x00000030, 0x383c3030, 0x303030fc, 0x00000000, /* 48 0 1 */
+       0x0000007c, 0xc6c06030, 0x180cc6fe, 0x00000000,
+       0x0000007c, 0xc6c0c07c, 0xc0c0c67c, 0x00000000, /* 50 2 3 */
+       0x00000060, 0x70786c66, 0xfe6060f0, 0x00000000,
+       0x000000fe, 0x0606067e, 0xc0c0c67c, 0x00000000, /* 52 4 5 */
+       0x00000038, 0x0c06067e, 0xc6c6c67c, 0x00000000,
+       0x000000fe, 0xc6c06030, 0x18181818, 0x00000000, /* 54 6 7 */
+       0x0000007c, 0xc6c6c67c, 0xc6c6c67c, 0x00000000,
+       0x0000007c, 0xc6c6c6fc, 0xc0c06038, 0x00000000, /* 56 8 9 */
+       0x00000000, 0x18180000, 0x00181800, 0x00000000,
+       0x00000000, 0x18180000, 0x0018180c, 0x00000000, /* 58 : ; */
+       0x00000060, 0x30180c06, 0x0c183060, 0x00000000,
+       0x00000000, 0x007e0000, 0x007e0000, 0x00000000,
+       0x00000006, 0x0c183060, 0x30180c06, 0x00000000,
+       0x0000007c, 0xc6c66030, 0x30003030, 0x00000000,
+       0x0000007c, 0xc6f6d6d6, 0x7606067c, 0x00000000,
+       0x00000010, 0x386cc6c6, 0xfec6c6c6, 0x00000000, /* 64 @ A */
+       0x0000007e, 0xc6c6c67e, 0xc6c6c67e, 0x00000000,
+       0x00000078, 0xcc060606, 0x0606cc78, 0x00000000, /* 66 */
+       0x0000003e, 0x66c6c6c6, 0xc6c6663e, 0x00000000,
+       0x000000fe, 0x0606063e, 0x060606fe, 0x00000000, /* 68 */
+       0x000000fe, 0x0606063e, 0x06060606, 0x00000000,
+       0x00000078, 0xcc060606, 0xf6c6ccb8, 0x00000000, /* 70 */
+       0x000000c6, 0xc6c6c6fe, 0xc6c6c6c6, 0x00000000,
+       0x0000003c, 0x18181818, 0x1818183c, 0x00000000, /* 72 */
+       0x00000060, 0x60606060, 0x6066663c, 0x00000000,
+       0x000000c6, 0xc666361e, 0x3666c6c6, 0x00000000, /* 74 */
+       0x00000006, 0x06060606, 0x060606fe, 0x00000000,
+       0x000000c6, 0xeefed6c6, 0xc6c6c6c6, 0x00000000, /* 76 */
+       0x000000c6, 0xcedefef6, 0xe6c6c6c6, 0x00000000,
+       0x00000038, 0x6cc6c6c6, 0xc6c66c38, 0x00000000, /* 78 */
+       0x0000007e, 0xc6c6c67e, 0x06060606, 0x00000000,
+       0x00000038, 0x6cc6c6c6, 0xc6d67c38, 0x60000000, /* 80 */
+       0x0000007e, 0xc6c6c67e, 0x66c6c6c6, 0x00000000,
+       0x0000007c, 0xc6c60c38, 0x60c6c67c, 0x00000000, /* 82 */
+       0x0000007e, 0x18181818, 0x18181818, 0x00000000,
+       0x000000c6, 0xc6c6c6c6, 0xc6c6c67c, 0x00000000, /* 84 */
+       0x000000c6, 0xc6c6c6c6, 0xc66c3810, 0x00000000,
+       0x000000c6, 0xc6c6c6c6, 0xd6d6fe6c, 0x00000000, /* 86 */
+       0x000000c6, 0xc6c66c38, 0x6cc6c6c6, 0x00000000,
+       0x00000066, 0x66666666, 0x3c181818, 0x00000000, /* 88 */
+       0x000000fe, 0xc0603018, 0x0c0606fe, 0x00000000,
+       0x0000003c, 0x0c0c0c0c, 0x0c0c0c3c, 0x00000000, /* 90 */
+       0x00000002, 0x060c1830, 0x60c08000, 0x00000000,
+       0x0000003c, 0x30303030, 0x3030303c, 0x00000000, /* 92 */
+       0x00001038, 0x6cc60000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00fe0000,
+       0x00001818, 0x30000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00003c60, 0x7c66667c, 0x00000000,
+       0x0000000c, 0x0c0c7ccc, 0xcccccc7c, 0x00000000,
+       0x00000000, 0x00007cc6, 0x0606c67c, 0x00000000,
+       0x00000060, 0x60607c66, 0x6666667c, 0x00000000,
+       0x00000000, 0x00007cc6, 0xfe06c67c, 0x00000000,
+       0x00000078, 0x0c0c0c3e, 0x0c0c0c0c, 0x00000000,
+       0x00000000, 0x00007c66, 0x6666667c, 0x60603e00,
+       0x0000000c, 0x0c0c7ccc, 0xcccccccc, 0x00000000,
+       0x00000030, 0x30003830, 0x30303078, 0x00000000,
+       0x00000030, 0x30003c30, 0x30303030, 0x30301f00,
+       0x0000000c, 0x0c0ccc6c, 0x3c6ccccc, 0x00000000,
+       0x00000030, 0x30303030, 0x30303030, 0x00000000,
+       0x00000000, 0x000066fe, 0xd6d6d6d6, 0x00000000,
+       0x00000000, 0x000078cc, 0xcccccccc, 0x00000000,
+       0x00000000, 0x00007cc6, 0xc6c6c67c, 0x00000000,
+       0x00000000, 0x00007ccc, 0xcccccc7c, 0x0c0c0c00,
+       0x00000000, 0x00007c66, 0x6666667c, 0x60606000,
+       0x00000000, 0x000076dc, 0x0c0c0c0c, 0x00000000,
+       0x00000000, 0x00007cc6, 0x1c70c67c, 0x00000000,
+       0x00000000, 0x1818fe18, 0x18181870, 0x00000000,
+       0x00000000, 0x00006666, 0x6666663c, 0x00000000,
+       0x00000000, 0x0000c6c6, 0xc66c3810, 0x00000000,
+       0x00000000, 0x0000c6d6, 0xd6d6fe6c, 0x00000000,
+       0x00000000, 0x0000c66c, 0x38386cc6, 0x00000000,
+       0x00000000, 0x00006666, 0x6666667c, 0x60603e00,
+       0x00000000, 0x0000fe60, 0x30180cfe, 0x00000000,
+       0x00000070, 0x1818180e, 0x18181870, 0x00000000,
+       0x00000018, 0x18181800, 0x18181818, 0x00000000,
+       0x0000000e, 0x18181870, 0x1818180e, 0x00000000,
+       0x000000dc, 0x76000000, 0x00000000, 0x00000000,
+       0x00000000, 0x0010386c, 0xc6c6fe00, 0x00000000
+};
+
+#endif /* __SOLO6X10_OSD_FONT_H */
diff --git a/drivers/staging/media/solo6x10/p2m.c b/drivers/staging/media/solo6x10/p2m.c
new file mode 100644 (file)
index 0000000..56210f0
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/scatterlist.h>
+#include "solo6x10.h"
+
+/* #define SOLO_TEST_P2M */
+
+int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr,
+                void *sys_addr, u32 ext_addr, u32 size)
+{
+       dma_addr_t dma_addr;
+       int ret;
+
+       WARN_ON(!size);
+       BUG_ON(id >= SOLO_NR_P2M);
+
+       if (!size)
+               return -EINVAL;
+
+       dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size,
+                                 wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+
+       ret = solo_p2m_dma_t(solo_dev, id, wr, dma_addr, ext_addr, size);
+
+       pci_unmap_single(solo_dev->pdev, dma_addr, size,
+                        wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+
+       return ret;
+}
+
+int solo_p2m_dma_t(struct solo_dev *solo_dev, u8 id, int wr,
+                  dma_addr_t dma_addr, u32 ext_addr, u32 size)
+{
+       struct p2m_desc *desc = kzalloc(sizeof(*desc) * 2, GFP_DMA);
+       int ret;
+
+       if (desc == NULL)
+               return -ENOMEM;
+
+       solo_p2m_push_desc(&desc[1], wr, dma_addr, ext_addr, size, 0, 0);
+       ret = solo_p2m_dma_desc(solo_dev, id, desc, 2);
+       kfree(desc);
+
+       return ret;
+}
+
+void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr,
+                       u32 ext_addr, u32 size, int repeat, u32 ext_size)
+{
+       desc->ta = cpu_to_le32(dma_addr);
+       desc->fa = cpu_to_le32(ext_addr);
+
+       desc->ext = cpu_to_le32(SOLO_P2M_COPY_SIZE(size >> 2));
+       desc->ctrl = cpu_to_le32(SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) |
+                                (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON);
+
+       /* Ext size only matters when we're repeating */
+       if (repeat) {
+               desc->ext |= cpu_to_le32(SOLO_P2M_EXT_INC(ext_size >> 2));
+               desc->ctrl |=  cpu_to_le32(SOLO_P2M_PCI_INC(size >> 2) |
+                                          SOLO_P2M_REPEAT(repeat));
+       }
+}
+
+int solo_p2m_dma_desc(struct solo_dev *solo_dev, u8 id,
+                     struct p2m_desc *desc, int desc_count)
+{
+       struct solo_p2m_dev *p2m_dev;
+       unsigned int timeout;
+       int ret = 0;
+       u32 config = 0;
+       dma_addr_t desc_dma = 0;
+
+       BUG_ON(id >= SOLO_NR_P2M);
+       BUG_ON(!desc_count || desc_count > SOLO_NR_P2M_DESC);
+
+       p2m_dev = &solo_dev->p2m_dev[id];
+
+       mutex_lock(&p2m_dev->mutex);
+
+       solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
+
+       INIT_COMPLETION(p2m_dev->completion);
+       p2m_dev->error = 0;
+
+       /* Enable the descriptors */
+       config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(id));
+       desc_dma = pci_map_single(solo_dev->pdev, desc,
+                                 desc_count * sizeof(*desc),
+                                 PCI_DMA_TODEVICE);
+       solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), desc_dma);
+       solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), desc_count - 1);
+       solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config |
+                      SOLO_P2M_DESC_MODE);
+
+       /* Should have all descriptors completed from one interrupt */
+       timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ);
+
+       solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
+
+       /* Reset back to non-descriptor mode */
+       solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config);
+       solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), 0);
+       solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), 0);
+       pci_unmap_single(solo_dev->pdev, desc_dma,
+                        desc_count * sizeof(*desc),
+                        PCI_DMA_TODEVICE);
+
+       if (p2m_dev->error)
+               ret = -EIO;
+       else if (timeout == 0)
+               ret = -EAGAIN;
+
+       mutex_unlock(&p2m_dev->mutex);
+
+       WARN_ON_ONCE(ret);
+
+       return ret;
+}
+
+int solo_p2m_dma_sg(struct solo_dev *solo_dev, u8 id,
+                   struct p2m_desc *pdesc, int wr,
+                   struct scatterlist *sg, u32 sg_off,
+                   u32 ext_addr, u32 size)
+{
+       int i;
+       int idx;
+
+       BUG_ON(id >= SOLO_NR_P2M);
+
+       if (WARN_ON_ONCE(!size))
+               return -EINVAL;
+
+       memset(pdesc, 0, sizeof(*pdesc));
+
+       /* Should rewrite this to handle > SOLO_NR_P2M_DESC transactions */
+       for (i = 0, idx = 1; idx < SOLO_NR_P2M_DESC && sg && size > 0;
+            i++, sg = sg_next(sg)) {
+               struct p2m_desc *desc = &pdesc[idx];
+               u32 sg_len = sg_dma_len(sg);
+               u32 len;
+
+               if (sg_off >= sg_len) {
+                       sg_off -= sg_len;
+                       continue;
+               }
+
+               sg_len -= sg_off;
+               len = min(sg_len, size);
+
+               solo_p2m_push_desc(desc, wr, sg_dma_address(sg) + sg_off,
+                                  ext_addr, len, 0, 0);
+
+               size -= len;
+               ext_addr += len;
+               idx++;
+
+               sg_off = 0;
+       }
+
+       WARN_ON_ONCE(size || i >= SOLO_NR_P2M_DESC);
+
+       return solo_p2m_dma_desc(solo_dev, id, pdesc, idx);
+}
+
+#ifdef SOLO_TEST_P2M
+
+#define P2M_TEST_CHAR          0xbe
+
+static unsigned long long p2m_test(struct solo_dev *solo_dev, u8 id,
+                                  u32 base, int size)
+{
+       u8 *wr_buf;
+       u8 *rd_buf;
+       int i;
+       unsigned long long err_cnt = 0;
+
+       wr_buf = kmalloc(size, GFP_KERNEL);
+       if (!wr_buf) {
+               printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n");
+               return size;
+       }
+
+       rd_buf = kmalloc(size, GFP_KERNEL);
+       if (!rd_buf) {
+               printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n");
+               kfree(wr_buf);
+               return size;
+       }
+
+       memset(wr_buf, P2M_TEST_CHAR, size);
+       memset(rd_buf, P2M_TEST_CHAR + 1, size);
+
+       solo_p2m_dma(solo_dev, id, 1, wr_buf, base, size);
+       solo_p2m_dma(solo_dev, id, 0, rd_buf, base, size);
+
+       for (i = 0; i < size; i++)
+               if (wr_buf[i] != rd_buf[i])
+                       err_cnt++;
+
+       kfree(wr_buf);
+       kfree(rd_buf);
+
+       return err_cnt;
+}
+
+#define TEST_CHUNK_SIZE                (8 * 1024)
+
+static void run_p2m_test(struct solo_dev *solo_dev)
+{
+       unsigned long long errs = 0;
+       u32 size = SOLO_JPEG_EXT_ADDR(solo_dev) + SOLO_JPEG_EXT_SIZE(solo_dev);
+       int i, d;
+
+       printk(KERN_WARNING "%s: Testing %u bytes of external ram\n",
+              SOLO6X10_NAME, size);
+
+       for (i = 0; i < size; i += TEST_CHUNK_SIZE)
+               for (d = 0; d < 4; d++)
+                       errs += p2m_test(solo_dev, d, i, TEST_CHUNK_SIZE);
+
+       printk(KERN_WARNING "%s: Found %llu errors during p2m test\n",
+              SOLO6X10_NAME, errs);
+
+       return;
+}
+#else
+#define run_p2m_test(__solo)   do {} while (0)
+#endif
+
+void solo_p2m_isr(struct solo_dev *solo_dev, int id)
+{
+       struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id];
+
+       solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id));
+
+       complete(&p2m_dev->completion);
+}
+
+void solo_p2m_error_isr(struct solo_dev *solo_dev, u32 status)
+{
+       struct solo_p2m_dev *p2m_dev;
+       int i;
+
+       if (!(status & SOLO_PCI_ERR_P2M))
+               return;
+
+       for (i = 0; i < SOLO_NR_P2M; i++) {
+               p2m_dev = &solo_dev->p2m_dev[i];
+               p2m_dev->error = 1;
+               solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
+               complete(&p2m_dev->completion);
+       }
+}
+
+void solo_p2m_exit(struct solo_dev *solo_dev)
+{
+       int i;
+
+       for (i = 0; i < SOLO_NR_P2M; i++)
+               solo_irq_off(solo_dev, SOLO_IRQ_P2M(i));
+}
+
+int solo_p2m_init(struct solo_dev *solo_dev)
+{
+       struct solo_p2m_dev *p2m_dev;
+       int i;
+
+       for (i = 0; i < SOLO_NR_P2M; i++) {
+               p2m_dev = &solo_dev->p2m_dev[i];
+
+               mutex_init(&p2m_dev->mutex);
+               init_completion(&p2m_dev->completion);
+
+               solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
+               solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i),
+                              SOLO_P2M_CSC_16BIT_565 |
+                              SOLO_P2M_DMA_INTERVAL(3) |
+                              SOLO_P2M_DESC_INTR_OPT |
+                              SOLO_P2M_PCI_MASTER_MODE);
+               solo_irq_on(solo_dev, SOLO_IRQ_P2M(i));
+       }
+
+       run_p2m_test(solo_dev);
+
+       return 0;
+}
diff --git a/drivers/staging/media/solo6x10/registers.h b/drivers/staging/media/solo6x10/registers.h
new file mode 100644 (file)
index 0000000..aca5444
--- /dev/null
@@ -0,0 +1,637 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __SOLO6X10_REGISTERS_H
+#define __SOLO6X10_REGISTERS_H
+
+#include "offsets.h"
+
+/* Global 6X10 system configuration */
+#define SOLO_SYS_CFG                           0x0000
+#define   SOLO6010_SYS_CFG_FOUT_EN             0x00000001 /* 6010 only */
+#define   SOLO6010_SYS_CFG_PLL_BYPASS          0x00000002 /* 6010 only */
+#define   SOLO6010_SYS_CFG_PLL_PWDN            0x00000004 /* 6010 only */
+#define   SOLO6010_SYS_CFG_OUTDIV(__n)         (((__n) & 0x003) << 3) /* 6010 only */
+#define   SOLO6010_SYS_CFG_FEEDBACKDIV(__n)    (((__n) & 0x1ff) << 5) /* 6010 only */
+#define   SOLO6010_SYS_CFG_INPUTDIV(__n)       (((__n) & 0x01f) << 14) /* 6010 only */
+#define   SOLO_SYS_CFG_CLOCK_DIV               0x00080000
+#define   SOLO_SYS_CFG_NCLK_DELAY(__n)         (((__n) & 0x003) << 24)
+#define   SOLO_SYS_CFG_PCLK_DELAY(__n)         (((__n) & 0x00f) << 26)
+#define   SOLO_SYS_CFG_SDRAM64BIT              0x40000000 /* 6110: must be set */
+#define   SOLO_SYS_CFG_RESET                   0x80000000
+
+#define        SOLO_DMA_CTRL                           0x0004
+#define          SOLO_DMA_CTRL_REFRESH_CYCLE(n)        ((n)<<8)
+/* 0=16/32MB, 1=32/64MB, 2=64/128MB, 3=128/256MB */
+#define          SOLO_DMA_CTRL_SDRAM_SIZE(n)           ((n)<<6)
+#define          SOLO_DMA_CTRL_SDRAM_CLK_INVERT        (1<<5)
+#define          SOLO_DMA_CTRL_STROBE_SELECT           (1<<4)
+#define          SOLO_DMA_CTRL_READ_DATA_SELECT        (1<<3)
+#define          SOLO_DMA_CTRL_READ_CLK_SELECT         (1<<2)
+#define          SOLO_DMA_CTRL_LATENCY(n)              ((n)<<0)
+#define        SOLO_DMA_CTRL1                          0x0008
+
+#define SOLO_SYS_VCLK                          0x000C
+#define          SOLO_VCLK_INVERT                      (1<<22)
+/* 0=sys_clk/4, 1=sys_clk/2, 2=clk_in/2 of system input */
+#define          SOLO_VCLK_SELECT(n)                   ((n)<<20)
+#define          SOLO_VCLK_VIN1415_DELAY(n)            ((n)<<14)
+#define          SOLO_VCLK_VIN1213_DELAY(n)            ((n)<<12)
+#define          SOLO_VCLK_VIN1011_DELAY(n)            ((n)<<10)
+#define          SOLO_VCLK_VIN0809_DELAY(n)            ((n)<<8)
+#define          SOLO_VCLK_VIN0607_DELAY(n)            ((n)<<6)
+#define          SOLO_VCLK_VIN0405_DELAY(n)            ((n)<<4)
+#define          SOLO_VCLK_VIN0203_DELAY(n)            ((n)<<2)
+#define          SOLO_VCLK_VIN0001_DELAY(n)            ((n)<<0)
+
+#define SOLO_IRQ_STAT                          0x0010
+#define SOLO_IRQ_ENABLE                                0x0014
+#define          SOLO_IRQ_P2M(n)                       (1<<((n)+17))
+#define          SOLO_IRQ_GPIO                         (1<<16)
+#define          SOLO_IRQ_VIDEO_LOSS                   (1<<15)
+#define          SOLO_IRQ_VIDEO_IN                     (1<<14)
+#define          SOLO_IRQ_MOTION                       (1<<13)
+#define          SOLO_IRQ_ATA_CMD                      (1<<12)
+#define          SOLO_IRQ_ATA_DIR                      (1<<11)
+#define          SOLO_IRQ_PCI_ERR                      (1<<10)
+#define          SOLO_IRQ_PS2_1                        (1<<9)
+#define          SOLO_IRQ_PS2_0                        (1<<8)
+#define          SOLO_IRQ_SPI                          (1<<7)
+#define          SOLO_IRQ_IIC                          (1<<6)
+#define          SOLO_IRQ_UART(n)                      (1<<((n) + 4))
+#define          SOLO_IRQ_G723                         (1<<3)
+#define          SOLO_IRQ_DECODER                      (1<<1)
+#define          SOLO_IRQ_ENCODER                      (1<<0)
+
+#define SOLO_CHIP_OPTION                       0x001C
+#define   SOLO_CHIP_ID_MASK                    0x00000007
+
+#define SOLO6110_PLL_CONFIG                    0x0020
+#define   SOLO6110_PLL_RANGE_BYPASS            (0 << 20)
+#define   SOLO6110_PLL_RANGE_5_10MHZ           (1 << 20)
+#define   SOLO6110_PLL_RANGE_8_16MHZ           (2 << 20)
+#define   SOLO6110_PLL_RANGE_13_26MHZ          (3 << 20)
+#define   SOLO6110_PLL_RANGE_21_42MHZ          (4 << 20)
+#define   SOLO6110_PLL_RANGE_34_68MHZ          (5 << 20)
+#define   SOLO6110_PLL_RANGE_54_108MHZ         (6 << 20)
+#define   SOLO6110_PLL_RANGE_88_200MHZ         (7 << 20)
+#define   SOLO6110_PLL_DIVR(x)                 (((x) - 1) << 15)
+#define   SOLO6110_PLL_DIVQ_EXP(x)             ((x) << 12)
+#define   SOLO6110_PLL_DIVF(x)                 (((x) - 1) << 4)
+#define   SOLO6110_PLL_RESET                   (1 << 3)
+#define   SOLO6110_PLL_BYPASS                  (1 << 2)
+#define   SOLO6110_PLL_FSEN                    (1 << 1)
+#define   SOLO6110_PLL_FB                      (1 << 0)
+
+#define SOLO_EEPROM_CTRL                       0x0060
+#define          SOLO_EEPROM_ACCESS_EN                 (1<<7)
+#define          SOLO_EEPROM_CS                        (1<<3)
+#define          SOLO_EEPROM_CLK                       (1<<2)
+#define          SOLO_EEPROM_DO                        (1<<1)
+#define          SOLO_EEPROM_DI                        (1<<0)
+#define          SOLO_EEPROM_ENABLE                    (EEPROM_ACCESS_EN | EEPROM_CS)
+
+#define SOLO_PCI_ERR                           0x0070
+#define   SOLO_PCI_ERR_FATAL                   0x00000001
+#define   SOLO_PCI_ERR_PARITY                  0x00000002
+#define   SOLO_PCI_ERR_TARGET                  0x00000004
+#define   SOLO_PCI_ERR_TIMEOUT                 0x00000008
+#define   SOLO_PCI_ERR_P2M                     0x00000010
+#define   SOLO_PCI_ERR_ATA                     0x00000020
+#define   SOLO_PCI_ERR_P2M_DESC                        0x00000040
+#define   SOLO_PCI_ERR_FSM0(__s)               (((__s) >> 16) & 0x0f)
+#define   SOLO_PCI_ERR_FSM1(__s)               (((__s) >> 20) & 0x0f)
+#define   SOLO_PCI_ERR_FSM2(__s)               (((__s) >> 24) & 0x1f)
+
+#define SOLO_P2M_BASE                          0x0080
+
+#define SOLO_P2M_CONFIG(n)                     (0x0080 + ((n)*0x20))
+#define          SOLO_P2M_DMA_INTERVAL(n)              ((n)<<6)/* N*32 clocks */
+#define          SOLO_P2M_CSC_BYTE_REORDER             (1<<5)  /* BGR -> RGB */
+/* 0:r=[14:10] g=[9:5] b=[4:0], 1:r=[15:11] g=[10:5] b=[4:0] */
+#define          SOLO_P2M_CSC_16BIT_565                (1<<4)
+#define          SOLO_P2M_UV_SWAP                      (1<<3)
+#define          SOLO_P2M_PCI_MASTER_MODE              (1<<2)
+#define          SOLO_P2M_DESC_INTR_OPT                (1<<1)  /* 1:Empty, 0:Each */
+#define          SOLO_P2M_DESC_MODE                    (1<<0)
+
+#define SOLO_P2M_DES_ADR(n)                    (0x0084 + ((n)*0x20))
+
+#define SOLO_P2M_DESC_ID(n)                    (0x0088 + ((n)*0x20))
+#define          SOLO_P2M_UPDATE_ID(n)                 ((n)<<0)
+
+#define SOLO_P2M_STATUS(n)                     (0x008C + ((n)*0x20))
+#define          SOLO_P2M_COMMAND_DONE                 (1<<8)
+#define          SOLO_P2M_CURRENT_ID(stat)             (0xff & (stat))
+
+#define SOLO_P2M_CONTROL(n)                    (0x0090 + ((n)*0x20))
+#define          SOLO_P2M_PCI_INC(n)                   ((n)<<20)
+#define          SOLO_P2M_REPEAT(n)                    ((n)<<10)
+/* 0:512, 1:256, 2:128, 3:64, 4:32, 5:128(2page) */
+#define          SOLO_P2M_BURST_SIZE(n)                ((n)<<7)
+#define            SOLO_P2M_BURST_512                  0
+#define            SOLO_P2M_BURST_256                  1
+#define            SOLO_P2M_BURST_128                  2
+#define            SOLO_P2M_BURST_64                   3
+#define            SOLO_P2M_BURST_32                   4
+#define          SOLO_P2M_CSC_16BIT                    (1<<6)  /* 0:24bit, 1:16bit */
+/* 0:Y[0]<-0(OFF), 1:Y[0]<-1(ON), 2:Y[0]<-G[0], 3:Y[0]<-Bit[15] */
+#define          SOLO_P2M_ALPHA_MODE(n)                ((n)<<4)
+#define          SOLO_P2M_CSC_ON                       (1<<3)
+#define          SOLO_P2M_INTERRUPT_REQ                (1<<2)
+#define          SOLO_P2M_WRITE                        (1<<1)
+#define          SOLO_P2M_TRANS_ON                     (1<<0)
+
+#define SOLO_P2M_EXT_CFG(n)                    (0x0094 + ((n)*0x20))
+#define          SOLO_P2M_EXT_INC(n)                   ((n)<<20)
+#define          SOLO_P2M_COPY_SIZE(n)                 ((n)<<0)
+
+#define SOLO_P2M_TAR_ADR(n)                    (0x0098 + ((n)*0x20))
+
+#define SOLO_P2M_EXT_ADR(n)                    (0x009C + ((n)*0x20))
+
+#define SOLO_P2M_BUFFER(i)                     (0x2000 + ((i)*4))
+
+#define SOLO_VI_CH_SWITCH_0                    0x0100
+#define SOLO_VI_CH_SWITCH_1                    0x0104
+#define SOLO_VI_CH_SWITCH_2                    0x0108
+
+#define        SOLO_VI_CH_ENA                          0x010C
+#define        SOLO_VI_CH_FORMAT                       0x0110
+#define          SOLO_VI_FD_SEL_MASK(n)                ((n)<<16)
+#define          SOLO_VI_PROG_MASK(n)                  ((n)<<0)
+
+#define SOLO_VI_FMT_CFG                                0x0114
+#define          SOLO_VI_FMT_CHECK_VCOUNT              (1<<31)
+#define          SOLO_VI_FMT_CHECK_HCOUNT              (1<<30)
+#define   SOLO_VI_FMT_TEST_SIGNAL              (1<<28)
+
+#define        SOLO_VI_PAGE_SW                         0x0118
+#define          SOLO_FI_INV_DISP_LIVE(n)              ((n)<<8)
+#define          SOLO_FI_INV_DISP_OUT(n)               ((n)<<7)
+#define          SOLO_DISP_SYNC_FI(n)                  ((n)<<6)
+#define          SOLO_PIP_PAGE_ADD(n)                  ((n)<<3)
+#define          SOLO_NORMAL_PAGE_ADD(n)               ((n)<<0)
+
+#define        SOLO_VI_ACT_I_P                         0x011C
+#define        SOLO_VI_ACT_I_S                         0x0120
+#define        SOLO_VI_ACT_P                           0x0124
+#define          SOLO_VI_FI_INVERT                     (1<<31)
+#define          SOLO_VI_H_START(n)                    ((n)<<21)
+#define          SOLO_VI_V_START(n)                    ((n)<<11)
+#define          SOLO_VI_V_STOP(n)                     ((n)<<0)
+
+#define SOLO_VI_STATUS0                                0x0128
+#define   SOLO_VI_STATUS0_PAGE(__n)            ((__n) & 0x07)
+#define SOLO_VI_STATUS1                                0x012C
+
+/* XXX: Might be better off in kernel level disp.h */
+#define DISP_PAGE(stat)                                ((stat) & 0x07)
+
+#define SOLO_VI_PB_CONFIG                      0x0130
+#define          SOLO_VI_PB_USER_MODE                  (1<<1)
+#define          SOLO_VI_PB_PAL                        (1<<0)
+#define SOLO_VI_PB_RANGE_HV                    0x0134
+#define          SOLO_VI_PB_HSIZE(h)                   ((h)<<12)
+#define          SOLO_VI_PB_VSIZE(v)                   ((v)<<0)
+#define SOLO_VI_PB_ACT_H                       0x0138
+#define          SOLO_VI_PB_HSTART(n)                  ((n)<<12)
+#define          SOLO_VI_PB_HSTOP(n)                   ((n)<<0)
+#define SOLO_VI_PB_ACT_V                       0x013C
+#define          SOLO_VI_PB_VSTART(n)                  ((n)<<12)
+#define          SOLO_VI_PB_VSTOP(n)                   ((n)<<0)
+
+#define        SOLO_VI_MOSAIC(ch)                      (0x0140 + ((ch)*4))
+#define          SOLO_VI_MOSAIC_SX(x)                  ((x)<<24)
+#define          SOLO_VI_MOSAIC_EX(x)                  ((x)<<16)
+#define          SOLO_VI_MOSAIC_SY(x)                  ((x)<<8)
+#define          SOLO_VI_MOSAIC_EY(x)                  ((x)<<0)
+
+#define        SOLO_VI_WIN_CTRL0(ch)                   (0x0180 + ((ch)*4))
+#define        SOLO_VI_WIN_CTRL1(ch)                   (0x01C0 + ((ch)*4))
+
+#define          SOLO_VI_WIN_CHANNEL(n)                ((n)<<28)
+
+#define          SOLO_VI_WIN_PIP(n)                    ((n)<<27)
+#define          SOLO_VI_WIN_SCALE(n)                  ((n)<<24)
+
+#define          SOLO_VI_WIN_SX(x)                     ((x)<<12)
+#define          SOLO_VI_WIN_EX(x)                     ((x)<<0)
+
+#define          SOLO_VI_WIN_SY(x)                     ((x)<<12)
+#define          SOLO_VI_WIN_EY(x)                     ((x)<<0)
+
+#define        SOLO_VI_WIN_ON(ch)                      (0x0200 + ((ch)*4))
+
+#define SOLO_VI_WIN_SW                         0x0240
+#define SOLO_VI_WIN_LIVE_AUTO_MUTE             0x0244
+
+#define        SOLO_VI_MOT_ADR                         0x0260
+#define          SOLO_VI_MOTION_EN(mask)               ((mask)<<16)
+#define        SOLO_VI_MOT_CTRL                        0x0264
+#define          SOLO_VI_MOTION_FRAME_COUNT(n)         ((n)<<24)
+#define          SOLO_VI_MOTION_SAMPLE_LENGTH(n)       ((n)<<16)
+#define          SOLO_VI_MOTION_INTR_START_STOP        (1<<15)
+#define          SOLO_VI_MOTION_FREEZE_DATA            (1<<14)
+#define          SOLO_VI_MOTION_SAMPLE_COUNT(n)        ((n)<<0)
+#define SOLO_VI_MOT_CLEAR                      0x0268
+#define SOLO_VI_MOT_STATUS                     0x026C
+#define          SOLO_VI_MOTION_CNT(n)                 ((n)<<0)
+#define SOLO_VI_MOTION_BORDER                  0x0270
+#define SOLO_VI_MOTION_BAR                     0x0274
+#define          SOLO_VI_MOTION_Y_SET                  (1<<29)
+#define          SOLO_VI_MOTION_Y_ADD                  (1<<28)
+#define          SOLO_VI_MOTION_CB_SET                 (1<<27)
+#define          SOLO_VI_MOTION_CB_ADD                 (1<<26)
+#define          SOLO_VI_MOTION_CR_SET                 (1<<25)
+#define          SOLO_VI_MOTION_CR_ADD                 (1<<24)
+#define          SOLO_VI_MOTION_Y_VALUE(v)             ((v)<<16)
+#define          SOLO_VI_MOTION_CB_VALUE(v)            ((v)<<8)
+#define          SOLO_VI_MOTION_CR_VALUE(v)            ((v)<<0)
+
+#define        SOLO_VO_FMT_ENC                         0x0300
+#define          SOLO_VO_SCAN_MODE_PROGRESSIVE         (1<<31)
+#define          SOLO_VO_FMT_TYPE_PAL                  (1<<30)
+#define   SOLO_VO_FMT_TYPE_NTSC                        0
+#define          SOLO_VO_USER_SET                      (1<<29)
+
+#define          SOLO_VO_FI_CHANGE                     (1<<20)
+#define          SOLO_VO_USER_COLOR_SET_VSYNC          (1<<19)
+#define          SOLO_VO_USER_COLOR_SET_HSYNC          (1<<18)
+#define          SOLO_VO_USER_COLOR_SET_NAV            (1<<17)
+#define          SOLO_VO_USER_COLOR_SET_NAH            (1<<16)
+#define          SOLO_VO_NA_COLOR_Y(Y)                 ((Y)<<8)
+#define          SOLO_VO_NA_COLOR_CB(CB)               (((CB)/16)<<4)
+#define          SOLO_VO_NA_COLOR_CR(CR)               (((CR)/16)<<0)
+
+#define        SOLO_VO_ACT_H                           0x0304
+#define          SOLO_VO_H_BLANK(n)                    ((n)<<22)
+#define          SOLO_VO_H_START(n)                    ((n)<<11)
+#define          SOLO_VO_H_STOP(n)                     ((n)<<0)
+
+#define        SOLO_VO_ACT_V                           0x0308
+#define          SOLO_VO_V_BLANK(n)                    ((n)<<22)
+#define          SOLO_VO_V_START(n)                    ((n)<<11)
+#define          SOLO_VO_V_STOP(n)                     ((n)<<0)
+
+#define        SOLO_VO_RANGE_HV                        0x030C
+#define          SOLO_VO_SYNC_INVERT                   (1<<24)
+#define          SOLO_VO_HSYNC_INVERT                  (1<<23)
+#define          SOLO_VO_VSYNC_INVERT                  (1<<22)
+#define          SOLO_VO_H_LEN(n)                      ((n)<<11)
+#define          SOLO_VO_V_LEN(n)                      ((n)<<0)
+
+#define        SOLO_VO_DISP_CTRL                       0x0310
+#define          SOLO_VO_DISP_ON                       (1<<31)
+#define          SOLO_VO_DISP_ERASE_COUNT(n)           ((n&0xf)<<24)
+#define          SOLO_VO_DISP_DOUBLE_SCAN              (1<<22)
+#define          SOLO_VO_DISP_SINGLE_PAGE              (1<<21)
+#define          SOLO_VO_DISP_BASE(n)                  (((n)>>16) & 0xffff)
+
+#define SOLO_VO_DISP_ERASE                     0x0314
+#define          SOLO_VO_DISP_ERASE_ON                 (1<<0)
+
+#define        SOLO_VO_ZOOM_CTRL                       0x0318
+#define          SOLO_VO_ZOOM_VER_ON                   (1<<24)
+#define          SOLO_VO_ZOOM_HOR_ON                   (1<<23)
+#define          SOLO_VO_ZOOM_V_COMP                   (1<<22)
+#define          SOLO_VO_ZOOM_SX(h)                    (((h)/2)<<11)
+#define          SOLO_VO_ZOOM_SY(v)                    (((v)/2)<<0)
+
+#define SOLO_VO_FREEZE_CTRL                    0x031C
+#define          SOLO_VO_FREEZE_ON                     (1<<1)
+#define          SOLO_VO_FREEZE_INTERPOLATION          (1<<0)
+
+#define        SOLO_VO_BKG_COLOR                       0x0320
+#define          SOLO_BG_Y(y)                          ((y)<<16)
+#define          SOLO_BG_U(u)                          ((u)<<8)
+#define          SOLO_BG_V(v)                          ((v)<<0)
+
+#define        SOLO_VO_DEINTERLACE                     0x0324
+#define          SOLO_VO_DEINTERLACE_THRESHOLD(n)      ((n)<<8)
+#define          SOLO_VO_DEINTERLACE_EDGE_VALUE(n)     ((n)<<0)
+
+#define SOLO_VO_BORDER_LINE_COLOR              0x0330
+#define SOLO_VO_BORDER_FILL_COLOR              0x0334
+#define SOLO_VO_BORDER_LINE_MASK               0x0338
+#define SOLO_VO_BORDER_FILL_MASK               0x033c
+
+#define SOLO_VO_BORDER_X(n)                    (0x0340+((n)*4))
+#define SOLO_VO_BORDER_Y(n)                    (0x0354+((n)*4))
+
+#define SOLO_VO_CELL_EXT_SET                   0x0368
+#define SOLO_VO_CELL_EXT_START                 0x036c
+#define SOLO_VO_CELL_EXT_STOP                  0x0370
+
+#define SOLO_VO_CELL_EXT_SET2                  0x0374
+#define SOLO_VO_CELL_EXT_START2                        0x0378
+#define SOLO_VO_CELL_EXT_STOP2                 0x037c
+
+#define SOLO_VO_RECTANGLE_CTRL(n)              (0x0368+((n)*12))
+#define SOLO_VO_RECTANGLE_START(n)             (0x036c+((n)*12))
+#define SOLO_VO_RECTANGLE_STOP(n)              (0x0370+((n)*12))
+
+#define SOLO_VO_CURSOR_POS                     (0x0380)
+#define SOLO_VO_CURSOR_CLR                     (0x0384)
+#define SOLO_VO_CURSOR_CLR2                    (0x0388)
+#define SOLO_VO_CURSOR_MASK(id)                        (0x0390+((id)*4))
+
+#define SOLO_VO_EXPANSION(id)                  (0x0250+((id)*4))
+
+#define        SOLO_OSG_CONFIG                         0x03E0
+#define          SOLO_VO_OSG_ON                        (1<<31)
+#define          SOLO_VO_OSG_COLOR_MUTE                (1<<28)
+#define          SOLO_VO_OSG_ALPHA_RATE(n)             ((n)<<22)
+#define          SOLO_VO_OSG_ALPHA_BG_RATE(n)          ((n)<<16)
+#define          SOLO_VO_OSG_BASE(offset)              (((offset)>>16)&0xffff)
+
+#define SOLO_OSG_ERASE                         0x03E4
+#define          SOLO_OSG_ERASE_ON                     (0x80)
+#define          SOLO_OSG_ERASE_OFF                    (0x00)
+
+#define SOLO_VO_OSG_BLINK                      0x03E8
+#define          SOLO_VO_OSG_BLINK_ON                  (1<<1)
+#define          SOLO_VO_OSG_BLINK_INTREVAL18          (1<<0)
+
+#define SOLO_CAP_BASE                          0x0400
+#define          SOLO_CAP_MAX_PAGE(n)                  ((n)<<16)
+#define          SOLO_CAP_BASE_ADDR(n)                 ((n)<<0)
+#define SOLO_CAP_BTW                           0x0404
+#define          SOLO_CAP_PROG_BANDWIDTH(n)            ((n)<<8)
+#define          SOLO_CAP_MAX_BANDWIDTH(n)             ((n)<<0)
+
+#define SOLO_DIM_SCALE1                                0x0408
+#define SOLO_DIM_SCALE2                                0x040C
+#define SOLO_DIM_SCALE3                                0x0410
+#define SOLO_DIM_SCALE4                                0x0414
+#define SOLO_DIM_SCALE5                                0x0418
+#define          SOLO_DIM_V_MB_NUM_FRAME(n)            ((n)<<16)
+#define          SOLO_DIM_V_MB_NUM_FIELD(n)            ((n)<<8)
+#define          SOLO_DIM_H_MB_NUM(n)                  ((n)<<0)
+
+#define SOLO_DIM_PROG                          0x041C
+#define SOLO_CAP_STATUS                                0x0420
+
+#define SOLO_CAP_CH_SCALE(ch)                  (0x0440+((ch)*4))
+#define SOLO_CAP_CH_COMP_ENA_E(ch)             (0x0480+((ch)*4))
+#define SOLO_CAP_CH_INTV(ch)                   (0x04C0+((ch)*4))
+#define SOLO_CAP_CH_INTV_E(ch)                 (0x0500+((ch)*4))
+
+
+#define SOLO_VE_CFG0                           0x0610
+#define          SOLO_VE_TWO_PAGE_MODE                 (1<<31)
+#define          SOLO_VE_INTR_CTRL(n)                  ((n)<<24)
+#define          SOLO_VE_BLOCK_SIZE(n)                 ((n)<<16)
+#define          SOLO_VE_BLOCK_BASE(n)                 ((n)<<0)
+
+#define SOLO_VE_CFG1                           0x0614
+#define   SOLO6110_VE_MPEG_SIZE_H(n)           ((n)<<28) /* 6110 only */
+#define          SOLO6010_VE_BYTE_ALIGN(n)             ((n)<<24) /* 6010 only */
+#define   SOLO6110_VE_JPEG_SIZE_H(n)           ((n)<<20) /* 6110 only */
+#define          SOLO_VE_INSERT_INDEX                  (1<<18)
+#define          SOLO_VE_MOTION_MODE(n)                ((n)<<16)
+#define          SOLO_VE_MOTION_BASE(n)                ((n)<<0)
+
+#define SOLO_VE_WMRK_POLY                      0x061C
+#define SOLO_VE_VMRK_INIT_KEY                  0x0620
+#define SOLO_VE_WMRK_STRL                      0x0624
+#define SOLO_VE_ENCRYP_POLY                    0x0628
+#define SOLO_VE_ENCRYP_INIT                    0x062C
+#define SOLO_VE_ATTR                           0x0630
+#define          SOLO_VE_LITTLE_ENDIAN                 (1<<31)
+#define          SOLO_COMP_ATTR_RN                     (1<<30)
+#define          SOLO_COMP_ATTR_FCODE(n)               ((n)<<27)
+#define          SOLO_COMP_TIME_INC(n)                 ((n)<<25)
+#define          SOLO_COMP_TIME_WIDTH(n)               ((n)<<21)
+#define          SOLO_DCT_INTERVAL(n)                  ((n)<<16)
+
+#define SOLO_VE_STATE(n)                       (0x0640+((n)*4))
+
+#define SOLO_VE_JPEG_QP_TBL                    0x0670
+#define SOLO_VE_JPEG_QP_CH_L                   0x0674
+#define SOLO_VE_JPEG_QP_CH_H                   0x0678
+#define SOLO_VE_JPEG_CFG                       0x067C
+#define SOLO_VE_JPEG_CTRL                      0x0680
+
+#define SOLO_VE_OSD_CH                         0x0690
+#define SOLO_VE_OSD_BASE                       0x0694
+#define SOLO_VE_OSD_CLR                                0x0698
+#define SOLO_VE_OSD_OPT                                0x069C
+
+#define SOLO_VE_CH_INTL(ch)                    (0x0700+((ch)*4))
+#define SOLO6010_VE_CH_MOT(ch)                 (0x0740+((ch)*4)) /* 6010 only */
+#define SOLO_VE_CH_QP(ch)                      (0x0780+((ch)*4))
+#define SOLO_VE_CH_QP_E(ch)                    (0x07C0+((ch)*4))
+#define SOLO_VE_CH_GOP(ch)                     (0x0800+((ch)*4))
+#define SOLO_VE_CH_GOP_E(ch)                   (0x0840+((ch)*4))
+#define SOLO_VE_CH_REF_BASE(ch)                        (0x0880+((ch)*4))
+#define SOLO_VE_CH_REF_BASE_E(ch)              (0x08C0+((ch)*4))
+
+#define SOLO_VE_MPEG4_QUE(n)                   (0x0A00+((n)*8))
+#define SOLO_VE_JPEG_QUE(n)                    (0x0A04+((n)*8))
+
+#define SOLO_VD_CFG0                           0x0900
+#define          SOLO6010_VD_CFG_NO_WRITE_NO_WINDOW    (1<<24) /* 6010 only */
+#define          SOLO_VD_CFG_BUSY_WIAT_CODE            (1<<23)
+#define          SOLO_VD_CFG_BUSY_WIAT_REF             (1<<22)
+#define          SOLO_VD_CFG_BUSY_WIAT_RES             (1<<21)
+#define          SOLO_VD_CFG_BUSY_WIAT_MS              (1<<20)
+#define          SOLO_VD_CFG_SINGLE_MODE               (1<<18)
+#define          SOLO_VD_CFG_SCAL_MANUAL               (1<<17)
+#define          SOLO_VD_CFG_USER_PAGE_CTRL            (1<<16)
+#define          SOLO_VD_CFG_LITTLE_ENDIAN             (1<<15)
+#define          SOLO_VD_CFG_START_FI                  (1<<14)
+#define          SOLO_VD_CFG_ERR_LOCK                  (1<<13)
+#define          SOLO_VD_CFG_ERR_INT_ENA               (1<<12)
+#define          SOLO_VD_CFG_TIME_WIDTH(n)             ((n)<<8)
+#define          SOLO_VD_CFG_DCT_INTERVAL(n)           ((n)<<0)
+
+#define SOLO_VD_CFG1                           0x0904
+
+#define        SOLO_VD_DEINTERLACE                     0x0908
+#define          SOLO_VD_DEINTERLACE_THRESHOLD(n)      ((n)<<8)
+#define          SOLO_VD_DEINTERLACE_EDGE_VALUE(n)     ((n)<<0)
+
+#define SOLO_VD_CODE_ADR                       0x090C
+
+#define SOLO_VD_CTRL                           0x0910
+#define          SOLO_VD_OPER_ON                       (1<<31)
+#define          SOLO_VD_MAX_ITEM(n)                   ((n)<<0)
+
+#define SOLO_VD_STATUS0                                0x0920
+#define          SOLO_VD_STATUS0_INTR_ACK              (1<<22)
+#define          SOLO_VD_STATUS0_INTR_EMPTY            (1<<21)
+#define          SOLO_VD_STATUS0_INTR_ERR              (1<<20)
+
+#define SOLO_VD_STATUS1                                0x0924
+
+#define SOLO_VD_IDX0                           0x0930
+#define          SOLO_VD_IDX_INTERLACE                 (1<<30)
+#define          SOLO_VD_IDX_CHANNEL(n)                ((n)<<24)
+#define          SOLO_VD_IDX_SIZE(n)                   ((n)<<0)
+
+#define SOLO_VD_IDX1                           0x0934
+#define          SOLO_VD_IDX_SRC_SCALE(n)              ((n)<<28)
+#define          SOLO_VD_IDX_WINDOW(n)                 ((n)<<24)
+#define          SOLO_VD_IDX_DEINTERLACE               (1<<16)
+#define          SOLO_VD_IDX_H_BLOCK(n)                ((n)<<8)
+#define          SOLO_VD_IDX_V_BLOCK(n)                ((n)<<0)
+
+#define SOLO_VD_IDX2                           0x0938
+#define          SOLO_VD_IDX_REF_BASE_SIDE             (1<<31)
+#define          SOLO_VD_IDX_REF_BASE(n)               (((n)>>16)&0xffff)
+
+#define SOLO_VD_IDX3                           0x093C
+#define          SOLO_VD_IDX_DISP_SCALE(n)             ((n)<<28)
+#define          SOLO_VD_IDX_INTERLACE_WR              (1<<27)
+#define          SOLO_VD_IDX_INTERPOL                  (1<<26)
+#define          SOLO_VD_IDX_HOR2X                     (1<<25)
+#define          SOLO_VD_IDX_OFFSET_X(n)               ((n)<<12)
+#define          SOLO_VD_IDX_OFFSET_Y(n)               ((n)<<0)
+
+#define SOLO_VD_IDX4                           0x0940
+#define          SOLO_VD_IDX_DEC_WR_PAGE(n)            ((n)<<8)
+#define          SOLO_VD_IDX_DISP_RD_PAGE(n)           ((n)<<0)
+
+#define SOLO_VD_WR_PAGE(n)                     (0x03F0 + ((n) * 4))
+
+
+#define SOLO_GPIO_CONFIG_0                     0x0B00
+#define SOLO_GPIO_CONFIG_1                     0x0B04
+#define SOLO_GPIO_DATA_OUT                     0x0B08
+#define SOLO_GPIO_DATA_IN                      0x0B0C
+#define SOLO_GPIO_INT_ACK_STA                  0x0B10
+#define SOLO_GPIO_INT_ENA                      0x0B14
+#define SOLO_GPIO_INT_CFG_0                    0x0B18
+#define SOLO_GPIO_INT_CFG_1                    0x0B1C
+
+
+#define SOLO_IIC_CFG                           0x0B20
+#define          SOLO_IIC_ENABLE                       (1<<8)
+#define          SOLO_IIC_PRESCALE(n)                  ((n)<<0)
+
+#define SOLO_IIC_CTRL                          0x0B24
+#define          SOLO_IIC_AUTO_CLEAR                   (1<<20)
+#define          SOLO_IIC_STATE_RX_ACK                 (1<<19)
+#define          SOLO_IIC_STATE_BUSY                   (1<<18)
+#define          SOLO_IIC_STATE_SIG_ERR                (1<<17)
+#define          SOLO_IIC_STATE_TRNS                   (1<<16)
+#define          SOLO_IIC_CH_SET(n)                    ((n)<<5)
+#define          SOLO_IIC_ACK_EN                       (1<<4)
+#define          SOLO_IIC_START                        (1<<3)
+#define          SOLO_IIC_STOP                         (1<<2)
+#define          SOLO_IIC_READ                         (1<<1)
+#define          SOLO_IIC_WRITE                        (1<<0)
+
+#define SOLO_IIC_TXD                           0x0B28
+#define SOLO_IIC_RXD                           0x0B2C
+
+/*
+ *     UART REGISTER
+ */
+#define SOLO_UART_CONTROL(n)                   (0x0BA0 + ((n)*0x20))
+#define          SOLO_UART_CLK_DIV(n)                  ((n)<<24)
+#define          SOLO_MODEM_CTRL_EN                    (1<<20)
+#define          SOLO_PARITY_ERROR_DROP                (1<<18)
+#define          SOLO_IRQ_ERR_EN                       (1<<17)
+#define          SOLO_IRQ_RX_EN                        (1<<16)
+#define          SOLO_IRQ_TX_EN                        (1<<15)
+#define          SOLO_RX_EN                            (1<<14)
+#define          SOLO_TX_EN                            (1<<13)
+#define          SOLO_UART_HALF_DUPLEX                 (1<<12)
+#define          SOLO_UART_LOOPBACK                    (1<<11)
+
+#define          SOLO_BAUDRATE_230400                  ((0<<9)|(0<<6))
+#define          SOLO_BAUDRATE_115200                  ((0<<9)|(1<<6))
+#define          SOLO_BAUDRATE_57600                   ((0<<9)|(2<<6))
+#define          SOLO_BAUDRATE_38400                   ((0<<9)|(3<<6))
+#define          SOLO_BAUDRATE_19200                   ((0<<9)|(4<<6))
+#define          SOLO_BAUDRATE_9600                    ((0<<9)|(5<<6))
+#define          SOLO_BAUDRATE_4800                    ((0<<9)|(6<<6))
+#define          SOLO_BAUDRATE_2400                    ((1<<9)|(6<<6))
+#define          SOLO_BAUDRATE_1200                    ((2<<9)|(6<<6))
+#define          SOLO_BAUDRATE_300                     ((3<<9)|(6<<6))
+
+#define          SOLO_UART_DATA_BIT_8                  (3<<4)
+#define          SOLO_UART_DATA_BIT_7                  (2<<4)
+#define          SOLO_UART_DATA_BIT_6                  (1<<4)
+#define          SOLO_UART_DATA_BIT_5                  (0<<4)
+
+#define          SOLO_UART_STOP_BIT_1                  (0<<2)
+#define          SOLO_UART_STOP_BIT_2                  (1<<2)
+
+#define          SOLO_UART_PARITY_NONE                 (0<<0)
+#define          SOLO_UART_PARITY_EVEN                 (2<<0)
+#define          SOLO_UART_PARITY_ODD                  (3<<0)
+
+#define SOLO_UART_STATUS(n)                    (0x0BA4 + ((n)*0x20))
+#define          SOLO_UART_CTS                         (1<<15)
+#define          SOLO_UART_RX_BUSY                     (1<<14)
+#define          SOLO_UART_OVERRUN                     (1<<13)
+#define          SOLO_UART_FRAME_ERR                   (1<<12)
+#define          SOLO_UART_PARITY_ERR                  (1<<11)
+#define          SOLO_UART_TX_BUSY                     (1<<5)
+
+#define          SOLO_UART_RX_BUFF_CNT(stat)           (((stat)>>6) & 0x1f)
+#define          SOLO_UART_RX_BUFF_SIZE                8
+#define          SOLO_UART_TX_BUFF_CNT(stat)           (((stat)>>0) & 0x1f)
+#define          SOLO_UART_TX_BUFF_SIZE                8
+
+#define SOLO_UART_TX_DATA(n)                   (0x0BA8 + ((n)*0x20))
+#define          SOLO_UART_TX_DATA_PUSH                (1<<8)
+#define SOLO_UART_RX_DATA(n)                   (0x0BAC + ((n)*0x20))
+#define          SOLO_UART_RX_DATA_POP                 (1<<8)
+
+#define SOLO_TIMER_CLOCK_NUM                   0x0be0
+#define SOLO_TIMER_WATCHDOG                    0x0be4
+#define SOLO_TIMER_USEC                                0x0be8
+#define SOLO_TIMER_SEC                         0x0bec
+
+#define SOLO_AUDIO_CONTROL                     0x0D00
+#define          SOLO_AUDIO_ENABLE                     (1<<31)
+#define          SOLO_AUDIO_MASTER_MODE                (1<<30)
+#define          SOLO_AUDIO_I2S_MODE                   (1<<29)
+#define          SOLO_AUDIO_I2S_LR_SWAP                (1<<27)
+#define          SOLO_AUDIO_I2S_8BIT                   (1<<26)
+#define          SOLO_AUDIO_I2S_MULTI(n)               ((n)<<24)
+#define          SOLO_AUDIO_MIX_9TO0                   (1<<23)
+#define          SOLO_AUDIO_DEC_9TO0_VOL(n)            ((n)<<20)
+#define          SOLO_AUDIO_MIX_19TO10                 (1<<19)
+#define          SOLO_AUDIO_DEC_19TO10_VOL(n)          ((n)<<16)
+#define          SOLO_AUDIO_MODE(n)                    ((n)<<0)
+#define SOLO_AUDIO_SAMPLE                      0x0D04
+#define          SOLO_AUDIO_EE_MODE_ON                 (1<<30)
+#define          SOLO_AUDIO_EE_ENC_CH(ch)              ((ch)<<25)
+#define          SOLO_AUDIO_BITRATE(n)                 ((n)<<16)
+#define          SOLO_AUDIO_CLK_DIV(n)                 ((n)<<0)
+#define SOLO_AUDIO_FDMA_INTR                   0x0D08
+#define          SOLO_AUDIO_FDMA_INTERVAL(n)           ((n)<<19)
+#define          SOLO_AUDIO_INTR_ORDER(n)              ((n)<<16)
+#define          SOLO_AUDIO_FDMA_BASE(n)               ((n)<<0)
+#define SOLO_AUDIO_EVOL_0                      0x0D0C
+#define SOLO_AUDIO_EVOL_1                      0x0D10
+#define          SOLO_AUDIO_EVOL(ch, value)            ((value)<<((ch)%10))
+#define SOLO_AUDIO_STA                         0x0D14
+
+
+#define SOLO_WATCHDOG                          0x0BE4
+#define WATCHDOG_STAT(status)                  (status<<8)
+#define WATCHDOG_TIME(sec)                     (sec&0xff)
+
+#endif /* __SOLO6X10_REGISTERS_H */
diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h
new file mode 100644 (file)
index 0000000..abee721
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __SOLO6X10_H
+#define __SOLO6X10_H
+
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/semaphore.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <linux/atomic.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf-core.h>
+#include "registers.h"
+
+#ifndef PCI_VENDOR_ID_SOFTLOGIC
+#define PCI_VENDOR_ID_SOFTLOGIC                0x9413
+#define PCI_DEVICE_ID_SOLO6010         0x6010
+#define PCI_DEVICE_ID_SOLO6110         0x6110
+#endif
+
+#ifndef PCI_VENDOR_ID_BLUECHERRY
+#define PCI_VENDOR_ID_BLUECHERRY       0x1BB3
+/* Neugent Softlogic 6010 based cards */
+#define PCI_DEVICE_ID_NEUSOLO_4                0x4304
+#define PCI_DEVICE_ID_NEUSOLO_9                0x4309
+#define PCI_DEVICE_ID_NEUSOLO_16       0x4310
+/* Bluecherry Softlogic 6010 based cards */
+#define PCI_DEVICE_ID_BC_SOLO_4                0x4E04
+#define PCI_DEVICE_ID_BC_SOLO_9                0x4E09
+#define PCI_DEVICE_ID_BC_SOLO_16       0x4E10
+/* Bluecherry Softlogic 6110 based cards */
+#define PCI_DEVICE_ID_BC_6110_4                0x5304
+#define PCI_DEVICE_ID_BC_6110_8                0x5308
+#define PCI_DEVICE_ID_BC_6110_16       0x5310
+#endif /* Bluecherry */
+
+#define SOLO6X10_NAME                  "solo6x10"
+
+#define SOLO_MAX_CHANNELS              16
+
+/* Make sure these two match */
+#define SOLO6X10_VERSION               "2.1.0"
+#define SOLO6X10_VER_MAJOR             2
+#define SOLO6X10_VER_MINOR             0
+#define SOLO6X10_VER_SUB               0
+#define SOLO6X10_VER_NUM \
+       KERNEL_VERSION(SOLO6X10_VER_MAJOR, SOLO6X10_VER_MINOR, SOLO6X10_VER_SUB)
+
+#define FLAGS_6110                     1
+
+/*
+ * The SOLO6x10 actually has 8 i2c channels, but we only use 2.
+ * 0 - Techwell chip(s)
+ * 1 - SAA7128
+ */
+#define SOLO_I2C_ADAPTERS              2
+#define SOLO_I2C_TW                    0
+#define SOLO_I2C_SAA                   1
+
+/* DMA Engine setup */
+#define SOLO_NR_P2M                    4
+#define SOLO_NR_P2M_DESC               256
+/* MPEG and JPEG share the same interrupt and locks so they must be together
+ * in the same dma channel. */
+#define SOLO_P2M_DMA_ID_MP4E           0
+#define SOLO_P2M_DMA_ID_JPEG           0
+#define SOLO_P2M_DMA_ID_MP4D           1
+#define SOLO_P2M_DMA_ID_G723D          1
+#define SOLO_P2M_DMA_ID_DISP           2
+#define SOLO_P2M_DMA_ID_OSG            2
+#define SOLO_P2M_DMA_ID_G723E          3
+#define SOLO_P2M_DMA_ID_VIN            3
+
+/* Encoder standard modes */
+#define SOLO_ENC_MODE_CIF              2
+#define SOLO_ENC_MODE_HD1              1
+#define SOLO_ENC_MODE_D1               9
+
+#define SOLO_DEFAULT_GOP               30
+#define SOLO_DEFAULT_QP                        3
+
+/* There is 8MB memory available for solo to buffer MPEG4 frames.
+ * This gives us 512 * 16kbyte queues. */
+#define SOLO_NR_RING_BUFS              512
+
+#define SOLO_CLOCK_MHZ                 108
+
+#ifndef V4L2_BUF_FLAG_MOTION_ON
+#define V4L2_BUF_FLAG_MOTION_ON                0x0400
+#define V4L2_BUF_FLAG_MOTION_DETECTED  0x0800
+#endif
+#ifndef V4L2_CID_MOTION_ENABLE
+#define PRIVATE_CIDS
+#define V4L2_CID_MOTION_ENABLE         (V4L2_CID_PRIVATE_BASE+0)
+#define V4L2_CID_MOTION_THRESHOLD      (V4L2_CID_PRIVATE_BASE+1)
+#define V4L2_CID_MOTION_TRACE          (V4L2_CID_PRIVATE_BASE+2)
+#endif
+
+enum SOLO_I2C_STATE {
+       IIC_STATE_IDLE,
+       IIC_STATE_START,
+       IIC_STATE_READ,
+       IIC_STATE_WRITE,
+       IIC_STATE_STOP
+};
+
+struct p2m_desc {
+       u32 ctrl;
+       u32 ext;
+       u32 ta;
+       u32 fa;
+};
+
+struct solo_p2m_dev {
+       struct mutex            mutex;
+       struct completion       completion;
+       int                     error;
+};
+
+#define OSD_TEXT_MAX           30
+
+enum solo_enc_types {
+       SOLO_ENC_TYPE_STD,
+       SOLO_ENC_TYPE_EXT,
+};
+
+struct solo_enc_dev {
+       struct solo_dev         *solo_dev;
+       /* V4L2 Items */
+       struct video_device     *vfd;
+       /* General accounting */
+       wait_queue_head_t       thread_wait;
+       spinlock_t              lock;
+       atomic_t                readers;
+       u8                      ch;
+       u8                      mode, gop, qp, interlaced, interval;
+       u8                      reset_gop;
+       u8                      bw_weight;
+       u8                      motion_detected;
+       u16                     motion_thresh;
+       u16                     width;
+       u16                     height;
+       char                    osd_text[OSD_TEXT_MAX + 1];
+};
+
+struct solo_enc_buf {
+       u8                      vop;
+       u8                      ch;
+       enum solo_enc_types     type;
+       u32                     off;
+       u32                     size;
+       u32                     jpeg_off;
+       u32                     jpeg_size;
+       struct timeval          ts;
+};
+
+/* The SOLO6x10 PCI Device */
+struct solo_dev {
+       /* General stuff */
+       struct pci_dev          *pdev;
+       u8 __iomem              *reg_base;
+       int                     nr_chans;
+       int                     nr_ext;
+       u32                     flags;
+       u32                     irq_mask;
+       u32                     motion_mask;
+       spinlock_t              reg_io_lock;
+
+       /* tw28xx accounting */
+       u8                      tw2865, tw2864, tw2815;
+       u8                      tw28_cnt;
+
+       /* i2c related items */
+       struct i2c_adapter      i2c_adap[SOLO_I2C_ADAPTERS];
+       enum SOLO_I2C_STATE     i2c_state;
+       struct mutex            i2c_mutex;
+       int                     i2c_id;
+       wait_queue_head_t       i2c_wait;
+       struct i2c_msg          *i2c_msg;
+       unsigned int            i2c_msg_num;
+       unsigned int            i2c_msg_ptr;
+
+       /* P2M DMA Engine */
+       struct solo_p2m_dev     p2m_dev[SOLO_NR_P2M];
+
+       /* V4L2 Display items */
+       struct video_device     *vfd;
+       unsigned int            erasing;
+       unsigned int            frame_blank;
+       u8                      cur_disp_ch;
+       wait_queue_head_t       disp_thread_wait;
+
+       /* V4L2 Encoder items */
+       struct solo_enc_dev     *v4l2_enc[SOLO_MAX_CHANNELS];
+       u16                     enc_bw_remain;
+       /* IDX into hw mp4 encoder */
+       u8                      enc_idx;
+       /* Our software ring of enc buf references */
+       u16                     enc_wr_idx;
+       struct solo_enc_buf     enc_buf[SOLO_NR_RING_BUFS];
+
+       /* Current video settings */
+       u32                     video_type;
+       u16                     video_hsize, video_vsize;
+       u16                     vout_hstart, vout_vstart;
+       u16                     vin_hstart, vin_vstart;
+       u8                      fps;
+
+       /* Audio components */
+       struct snd_card         *snd_card;
+       struct snd_pcm          *snd_pcm;
+       atomic_t                snd_users;
+       int                     g723_hw_idx;
+};
+
+static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg)
+{
+       unsigned long flags;
+       u32 ret;
+       u16 val;
+
+       spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
+
+       ret = readl(solo_dev->reg_base + reg);
+       rmb();
+       pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
+       rmb();
+
+       spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
+
+       return ret;
+}
+
+static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, u32 data)
+{
+       unsigned long flags;
+       u16 val;
+
+       spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
+
+       writel(data, solo_dev->reg_base + reg);
+       wmb();
+       pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
+       rmb();
+
+       spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
+}
+
+void solo_irq_on(struct solo_dev *solo_dev, u32 mask);
+void solo_irq_off(struct solo_dev *solo_dev, u32 mask);
+
+/* Init/exit routeines for subsystems */
+int solo_disp_init(struct solo_dev *solo_dev);
+void solo_disp_exit(struct solo_dev *solo_dev);
+
+int solo_gpio_init(struct solo_dev *solo_dev);
+void solo_gpio_exit(struct solo_dev *solo_dev);
+
+int solo_i2c_init(struct solo_dev *solo_dev);
+void solo_i2c_exit(struct solo_dev *solo_dev);
+
+int solo_p2m_init(struct solo_dev *solo_dev);
+void solo_p2m_exit(struct solo_dev *solo_dev);
+
+int solo_v4l2_init(struct solo_dev *solo_dev);
+void solo_v4l2_exit(struct solo_dev *solo_dev);
+
+int solo_enc_init(struct solo_dev *solo_dev);
+void solo_enc_exit(struct solo_dev *solo_dev);
+
+int solo_enc_v4l2_init(struct solo_dev *solo_dev);
+void solo_enc_v4l2_exit(struct solo_dev *solo_dev);
+
+int solo_g723_init(struct solo_dev *solo_dev);
+void solo_g723_exit(struct solo_dev *solo_dev);
+
+/* ISR's */
+int solo_i2c_isr(struct solo_dev *solo_dev);
+void solo_p2m_isr(struct solo_dev *solo_dev, int id);
+void solo_p2m_error_isr(struct solo_dev *solo_dev, u32 status);
+void solo_enc_v4l2_isr(struct solo_dev *solo_dev);
+void solo_g723_isr(struct solo_dev *solo_dev);
+void solo_motion_isr(struct solo_dev *solo_dev);
+void solo_video_in_isr(struct solo_dev *solo_dev);
+
+/* i2c read/write */
+u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off);
+void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off,
+                       u8 data);
+
+/* P2M DMA */
+int solo_p2m_dma_t(struct solo_dev *solo_dev, u8 id, int wr,
+                  dma_addr_t dma_addr, u32 ext_addr, u32 size);
+int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr,
+                void *sys_addr, u32 ext_addr, u32 size);
+int solo_p2m_dma_sg(struct solo_dev *solo_dev, u8 id,
+                   struct p2m_desc *pdesc, int wr,
+                   struct scatterlist *sglist, u32 sg_off,
+                   u32 ext_addr, u32 size);
+void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr,
+                       u32 ext_addr, u32 size, int repeat, u32 ext_size);
+int solo_p2m_dma_desc(struct solo_dev *solo_dev, u8 id,
+                     struct p2m_desc *desc, int desc_count);
+
+/* Set the threshold for motion detection */
+void solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val);
+#define SOLO_DEF_MOT_THRESH            0x0300
+
+/* Write text on OSD */
+int solo_osd_print(struct solo_enc_dev *solo_enc);
+
+#endif /* __SOLO6X10_H */
diff --git a/drivers/staging/media/solo6x10/tw28.c b/drivers/staging/media/solo6x10/tw28.c
new file mode 100644 (file)
index 0000000..db56b42
--- /dev/null
@@ -0,0 +1,821 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include "solo6x10.h"
+#include "tw28.h"
+
+/* XXX: Some of these values are masked into an 8-bit regs, and shifted
+ * around for other 8-bit regs. What are the magic bits in these values? */
+#define DEFAULT_HDELAY_NTSC            (32 - 4)
+#define DEFAULT_HACTIVE_NTSC           (720 + 16)
+#define DEFAULT_VDELAY_NTSC            (7 - 2)
+#define DEFAULT_VACTIVE_NTSC           (240 + 4)
+
+#define DEFAULT_HDELAY_PAL             (32 + 4)
+#define DEFAULT_HACTIVE_PAL            (864-DEFAULT_HDELAY_PAL)
+#define DEFAULT_VDELAY_PAL             (6)
+#define DEFAULT_VACTIVE_PAL            (312-DEFAULT_VDELAY_PAL)
+
+static u8 tbl_tw2864_template[] = {
+       0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
+       0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+       0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
+       0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+       0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
+       0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+       0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
+       0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
+       0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
+       0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
+       0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */
+       0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01,
+       0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */
+       0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
+       0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
+       0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
+       0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */
+       0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
+       0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
+       0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
+       0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
+       0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
+};
+
+static u8 tbl_tw2865_ntsc_template[] = {
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
+       0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
+       0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
+       0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+       0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
+       0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+       0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, /* 0x40 */
+       0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
+       0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
+       0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
+       0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
+       0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
+       0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
+       0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
+       0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, /* 0xa0 */
+       0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
+       0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
+       0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8,
+       0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
+       0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
+       0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
+       0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
+       0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
+       0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
+       0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
+       0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
+};
+
+static u8 tbl_tw2865_pal_template[] = {
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */
+       0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */
+       0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */
+       0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */
+       0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+       0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, /* 0x40 */
+       0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
+       0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
+       0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
+       0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
+       0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
+       0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
+       0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
+       0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, /* 0xa0 */
+       0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
+       0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
+       0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8,
+       0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
+       0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
+       0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
+       0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
+       0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
+       0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
+       0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, /* 0xf0 */
+       0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
+};
+
+#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
+
+static u8 tw_readbyte(struct solo_dev *solo_dev, int chip_id, u8 tw6x_off,
+                     u8 tw_off)
+{
+       if (is_tw286x(solo_dev, chip_id))
+               return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+                                        TW_CHIP_OFFSET_ADDR(chip_id),
+                                        tw6x_off);
+       else
+               return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+                                        TW_CHIP_OFFSET_ADDR(chip_id),
+                                        tw_off);
+}
+
+static void tw_writebyte(struct solo_dev *solo_dev, int chip_id,
+                        u8 tw6x_off, u8 tw_off, u8 val)
+{
+       if (is_tw286x(solo_dev, chip_id))
+               solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+                                  TW_CHIP_OFFSET_ADDR(chip_id),
+                                  tw6x_off, val);
+       else
+               solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+                                  TW_CHIP_OFFSET_ADDR(chip_id),
+                                  tw_off, val);
+}
+
+static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off,
+                               u8 val)
+{
+       int i;
+
+       for (i = 0; i < 5; i++) {
+               u8 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, addr, off);
+               if (rval == val)
+                       return;
+
+               solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, addr, off, val);
+               msleep_interruptible(1);
+       }
+
+/*     printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n",
+               addr, off, val); */
+}
+
+static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr)
+{
+       u8 tbl_tw2865_common[256];
+       int i;
+
+       if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL)
+               memcpy(tbl_tw2865_common, tbl_tw2865_pal_template,
+                      sizeof(tbl_tw2865_common));
+       else
+               memcpy(tbl_tw2865_common, tbl_tw2865_ntsc_template,
+                      sizeof(tbl_tw2865_common));
+
+       /* ALINK Mode */
+       if (solo_dev->nr_chans == 4) {
+               tbl_tw2865_common[0xd2] = 0x01;
+               tbl_tw2865_common[0xcf] = 0x00;
+       } else if (solo_dev->nr_chans == 8) {
+               tbl_tw2865_common[0xd2] = 0x02;
+               if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+                       tbl_tw2865_common[0xcf] = 0x80;
+       } else if (solo_dev->nr_chans == 16) {
+               tbl_tw2865_common[0xd2] = 0x03;
+               if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+                       tbl_tw2865_common[0xcf] = 0x83;
+               else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
+                       tbl_tw2865_common[0xcf] = 0x83;
+               else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
+                       tbl_tw2865_common[0xcf] = 0x80;
+       }
+
+       for (i = 0; i < 0xff; i++) {
+               /* Skip read only registers */
+               if (i >= 0xb8 && i <= 0xc1)
+                       continue;
+               if ((i & ~0x30) == 0x00 ||
+                   (i & ~0x30) == 0x0c ||
+                   (i & ~0x30) == 0x0d)
+                       continue;
+               if (i >= 0xc4 && i <= 0xc7)
+                       continue;
+               if (i == 0xfd)
+                       continue;
+
+               tw_write_and_verify(solo_dev, dev_addr, i,
+                                   tbl_tw2865_common[i]);
+       }
+
+       return 0;
+}
+
+static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr)
+{
+       u8 tbl_tw2864_common[sizeof(tbl_tw2864_template)];
+       int i;
+
+       memcpy(tbl_tw2864_common, tbl_tw2864_template,
+              sizeof(tbl_tw2864_common));
+
+       if (solo_dev->tw2865 == 0) {
+               /* IRQ Mode */
+               if (solo_dev->nr_chans == 4) {
+                       tbl_tw2864_common[0xd2] = 0x01;
+                       tbl_tw2864_common[0xcf] = 0x00;
+               } else if (solo_dev->nr_chans == 8) {
+                       tbl_tw2864_common[0xd2] = 0x02;
+                       if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
+                               tbl_tw2864_common[0xcf] = 0x43;
+                       else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+                               tbl_tw2864_common[0xcf] = 0x40;
+               } else if (solo_dev->nr_chans == 16) {
+                       tbl_tw2864_common[0xd2] = 0x03;
+                       if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
+                               tbl_tw2864_common[0xcf] = 0x43;
+                       else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+                               tbl_tw2864_common[0xcf] = 0x43;
+                       else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
+                               tbl_tw2864_common[0xcf] = 0x43;
+                       else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
+                               tbl_tw2864_common[0xcf] = 0x40;
+               }
+       } else {
+               /* ALINK Mode. Assumes that the first tw28xx is a
+                * 2865 and these are in cascade. */
+               for (i = 0; i <= 4; i++)
+                       tbl_tw2864_common[0x08 | i << 4] = 0x12;
+
+               if (solo_dev->nr_chans == 8) {
+                       tbl_tw2864_common[0xd2] = 0x02;
+                       if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+                               tbl_tw2864_common[0xcf] = 0x80;
+               } else if (solo_dev->nr_chans == 16) {
+                       tbl_tw2864_common[0xd2] = 0x03;
+                       if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+                               tbl_tw2864_common[0xcf] = 0x83;
+                       else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
+                               tbl_tw2864_common[0xcf] = 0x83;
+                       else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
+                               tbl_tw2864_common[0xcf] = 0x80;
+               }
+       }
+
+       /* NTSC or PAL */
+       if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) {
+               for (i = 0; i < 4; i++) {
+                       tbl_tw2864_common[0x07 | (i << 4)] |= 0x10;
+                       tbl_tw2864_common[0x08 | (i << 4)] |= 0x06;
+                       tbl_tw2864_common[0x0a | (i << 4)] |= 0x08;
+                       tbl_tw2864_common[0x0b | (i << 4)] |= 0x13;
+                       tbl_tw2864_common[0x0e | (i << 4)] |= 0x01;
+               }
+               tbl_tw2864_common[0x9d] = 0x90;
+               tbl_tw2864_common[0xf3] = 0x00;
+               tbl_tw2864_common[0xf4] = 0xa0;
+       }
+
+       for (i = 0; i < 0xff; i++) {
+               /* Skip read only registers */
+               if (i >= 0xb8 && i <= 0xc1)
+                       continue;
+               if ((i & ~0x30) == 0x00 ||
+                   (i & ~0x30) == 0x0c ||
+                   (i & ~0x30) == 0x0d)
+                       continue;
+               if (i == 0x74 || i == 0x77 || i == 0x78 ||
+                   i == 0x79 || i == 0x7a)
+                       continue;
+               if (i == 0xfd)
+                       continue;
+
+               tw_write_and_verify(solo_dev, dev_addr, i,
+                                   tbl_tw2864_common[i]);
+       }
+
+       return 0;
+}
+
+static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr)
+{
+       u8 tbl_ntsc_tw2815_common[] = {
+               0x00, 0xc8, 0x20, 0xd0, 0x06, 0xf0, 0x08, 0x80,
+               0x80, 0x80, 0x80, 0x02, 0x06, 0x00, 0x11,
+       };
+
+       u8 tbl_pal_tw2815_common[] = {
+               0x00, 0x88, 0x20, 0xd0, 0x05, 0x20, 0x28, 0x80,
+               0x80, 0x80, 0x80, 0x82, 0x06, 0x00, 0x11,
+       };
+
+       u8 tbl_tw2815_sfr[] = {
+               0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, /* 0x00 */
+               0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00,
+               0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, /* 0x10 */
+               0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00,
+               0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, /* 0x20 */
+               0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88,
+               0x88, 0x11, 0x00, 0x88, 0x88, 0x00,             /* 0x30 */
+       };
+       u8 *tbl_tw2815_common;
+       int i;
+       int ch;
+
+       tbl_ntsc_tw2815_common[0x06] = 0;
+
+       /* Horizontal Delay Control */
+       tbl_ntsc_tw2815_common[0x02] = DEFAULT_HDELAY_NTSC & 0xff;
+       tbl_ntsc_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_NTSC >> 8);
+
+       /* Horizontal Active Control */
+       tbl_ntsc_tw2815_common[0x03] = DEFAULT_HACTIVE_NTSC & 0xff;
+       tbl_ntsc_tw2815_common[0x06] |=
+               ((0x03 & (DEFAULT_HACTIVE_NTSC >> 8)) << 2);
+
+       /* Vertical Delay Control */
+       tbl_ntsc_tw2815_common[0x04] = DEFAULT_VDELAY_NTSC & 0xff;
+       tbl_ntsc_tw2815_common[0x06] |=
+               ((0x01 & (DEFAULT_VDELAY_NTSC >> 8)) << 4);
+
+       /* Vertical Active Control */
+       tbl_ntsc_tw2815_common[0x05] = DEFAULT_VACTIVE_NTSC & 0xff;
+       tbl_ntsc_tw2815_common[0x06] |=
+               ((0x01 & (DEFAULT_VACTIVE_NTSC >> 8)) << 5);
+
+       tbl_pal_tw2815_common[0x06] = 0;
+
+       /* Horizontal Delay Control */
+       tbl_pal_tw2815_common[0x02] = DEFAULT_HDELAY_PAL & 0xff;
+       tbl_pal_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_PAL >> 8);
+
+       /* Horizontal Active Control */
+       tbl_pal_tw2815_common[0x03] = DEFAULT_HACTIVE_PAL & 0xff;
+       tbl_pal_tw2815_common[0x06] |=
+               ((0x03 & (DEFAULT_HACTIVE_PAL >> 8)) << 2);
+
+       /* Vertical Delay Control */
+       tbl_pal_tw2815_common[0x04] = DEFAULT_VDELAY_PAL & 0xff;
+       tbl_pal_tw2815_common[0x06] |=
+               ((0x01 & (DEFAULT_VDELAY_PAL >> 8)) << 4);
+
+       /* Vertical Active Control */
+       tbl_pal_tw2815_common[0x05] = DEFAULT_VACTIVE_PAL & 0xff;
+       tbl_pal_tw2815_common[0x06] |=
+               ((0x01 & (DEFAULT_VACTIVE_PAL >> 8)) << 5);
+
+       tbl_tw2815_common =
+           (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) ?
+            tbl_ntsc_tw2815_common : tbl_pal_tw2815_common;
+
+       /* Dual ITU-R BT.656 format */
+       tbl_tw2815_common[0x0d] |= 0x04;
+
+       /* Audio configuration */
+       tbl_tw2815_sfr[0x62 - 0x40] &= ~(3 << 6);
+
+       if (solo_dev->nr_chans == 4) {
+               tbl_tw2815_sfr[0x63 - 0x40] |= 1;
+               tbl_tw2815_sfr[0x62 - 0x40] |= 3 << 6;
+       } else if (solo_dev->nr_chans == 8) {
+               tbl_tw2815_sfr[0x63 - 0x40] |= 2;
+               if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
+                       tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
+               else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+                       tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
+       } else if (solo_dev->nr_chans == 16) {
+               tbl_tw2815_sfr[0x63 - 0x40] |= 3;
+               if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
+                       tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
+               else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+                       tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
+               else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
+                       tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
+               else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
+                       tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
+       }
+
+       /* Output mode of R_ADATM pin (0 mixing, 1 record) */
+       /* tbl_tw2815_sfr[0x63 - 0x40] |= 0 << 2; */
+
+       /* 8KHz, used to be 16KHz, but changed for remote client compat */
+       tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 2;
+       tbl_tw2815_sfr[0x6c - 0x40] |= 0 << 2;
+
+       /* Playback of right channel */
+       tbl_tw2815_sfr[0x6c - 0x40] |= 1 << 5;
+
+       /* Reserved value (XXX ??) */
+       tbl_tw2815_sfr[0x5c - 0x40] |= 1 << 5;
+
+       /* Analog output gain and mix ratio playback on full */
+       tbl_tw2815_sfr[0x70 - 0x40] |= 0xff;
+       /* Select playback audio and mute all except */
+       tbl_tw2815_sfr[0x71 - 0x40] |= 0x10;
+       tbl_tw2815_sfr[0x6d - 0x40] |= 0x0f;
+
+       /* End of audio configuration */
+
+       for (ch = 0; ch < 4; ch++) {
+               tbl_tw2815_common[0x0d] &= ~3;
+               switch (ch) {
+               case 0:
+                       tbl_tw2815_common[0x0d] |= 0x21;
+                       break;
+               case 1:
+                       tbl_tw2815_common[0x0d] |= 0x20;
+                       break;
+               case 2:
+                       tbl_tw2815_common[0x0d] |= 0x23;
+                       break;
+               case 3:
+                       tbl_tw2815_common[0x0d] |= 0x22;
+                       break;
+               }
+
+               for (i = 0; i < 0x0f; i++) {
+                       if (i == 0x00)
+                               continue;       /* read-only */
+                       solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+                                          dev_addr, (ch * 0x10) + i,
+                                          tbl_tw2815_common[i]);
+               }
+       }
+
+       for (i = 0x40; i < 0x76; i++) {
+               /* Skip read-only and nop registers */
+               if (i == 0x40 || i == 0x59 || i == 0x5a ||
+                   i == 0x5d || i == 0x5e || i == 0x5f)
+                       continue;
+
+               solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, dev_addr, i,
+                                      tbl_tw2815_sfr[i - 0x40]);
+       }
+
+       return 0;
+}
+
+#define FIRST_ACTIVE_LINE      0x0008
+#define LAST_ACTIVE_LINE       0x0102
+
+static void saa7128_setup(struct solo_dev *solo_dev)
+{
+       int i;
+       unsigned char regs[128] = {
+               0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x1C, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
+               0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f, 0x00, 0x00,
+               0x1c, 0x33, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00,
+               0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
+               0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
+               0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
+               0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e,
+               0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77,
+               0x41, 0x88, 0x41, 0x12, 0xed, 0x10, 0x10, 0x00,
+               0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
+               0x00, 0x00, 0x08, 0xff, 0x80, 0x00, 0xff, 0xff,
+       };
+
+       regs[0x7A] = FIRST_ACTIVE_LINE & 0xff;
+       regs[0x7B] = LAST_ACTIVE_LINE & 0xff;
+       regs[0x7C] = ((1 << 7) |
+                       (((LAST_ACTIVE_LINE >> 8) & 1) << 6) |
+                       (((FIRST_ACTIVE_LINE >> 8) & 1) << 4));
+
+       /* PAL: XXX: We could do a second set of regs to avoid this */
+       if (solo_dev->video_type != SOLO_VO_FMT_TYPE_NTSC) {
+               regs[0x28] = 0xE1;
+
+               regs[0x5A] = 0x0F;
+               regs[0x61] = 0x02;
+               regs[0x62] = 0x35;
+               regs[0x63] = 0xCB;
+               regs[0x64] = 0x8A;
+               regs[0x65] = 0x09;
+               regs[0x66] = 0x2A;
+
+               regs[0x6C] = 0xf1;
+               regs[0x6E] = 0x20;
+
+               regs[0x7A] = 0x06 + 12;
+               regs[0x7b] = 0x24 + 12;
+               regs[0x7c] |= 1 << 6;
+       }
+
+       /* First 0x25 bytes are read-only? */
+       for (i = 0x26; i < 128; i++) {
+               if (i == 0x60 || i == 0x7D)
+                       continue;
+               solo_i2c_writebyte(solo_dev, SOLO_I2C_SAA, 0x46, i, regs[i]);
+       }
+
+       return;
+}
+
+int solo_tw28_init(struct solo_dev *solo_dev)
+{
+       int i;
+       u8 value;
+
+       /* Detect techwell chip type */
+       for (i = 0; i < TW_NUM_CHIP; i++) {
+               value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+                                         TW_CHIP_OFFSET_ADDR(i), 0xFF);
+
+               switch (value >> 3) {
+               case 0x18:
+                       solo_dev->tw2865 |= 1 << i;
+                       solo_dev->tw28_cnt++;
+                       break;
+               case 0x0c:
+                       solo_dev->tw2864 |= 1 << i;
+                       solo_dev->tw28_cnt++;
+                       break;
+               default:
+                       value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+                                                 TW_CHIP_OFFSET_ADDR(i), 0x59);
+                       if ((value >> 3) == 0x04) {
+                               solo_dev->tw2815 |= 1 << i;
+                               solo_dev->tw28_cnt++;
+                       }
+               }
+       }
+
+       if (!solo_dev->tw28_cnt)
+               return -EINVAL;
+
+       saa7128_setup(solo_dev);
+
+       for (i = 0; i < solo_dev->tw28_cnt; i++) {
+               if ((solo_dev->tw2865 & (1 << i)))
+                       tw2865_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
+               else if ((solo_dev->tw2864 & (1 << i)))
+                       tw2864_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
+               else
+                       tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
+       }
+
+       dev_info(&solo_dev->pdev->dev, "Initialized %d tw28xx chip%s:",
+                solo_dev->tw28_cnt, solo_dev->tw28_cnt == 1 ? "" : "s");
+
+       if (solo_dev->tw2865)
+               printk(" tw2865[%d]", hweight32(solo_dev->tw2865));
+       if (solo_dev->tw2864)
+               printk(" tw2864[%d]", hweight32(solo_dev->tw2864));
+       if (solo_dev->tw2815)
+               printk(" tw2815[%d]", hweight32(solo_dev->tw2815));
+       printk("\n");
+
+       return 0;
+}
+
+/*
+ * We accessed the video status signal in the Techwell chip through
+ * iic/i2c because the video status reported by register REG_VI_STATUS1
+ * (address 0x012C) of the SOLO6010 chip doesn't give the correct video
+ * status signal values.
+ */
+int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch)
+{
+       u8 val, chip_num;
+
+       /* Get the right chip and on-chip channel */
+       chip_num = ch / 4;
+       ch %= 4;
+
+       val = tw_readbyte(solo_dev, chip_num, TW286X_AV_STAT_ADDR,
+                         TW_AV_STAT_ADDR) & 0x0f;
+
+       return val & (1 << ch) ? 1 : 0;
+}
+
+#if 0
+/* Status of audio from up to 4 techwell chips are combined into 1 variable.
+ * See techwell datasheet for details. */
+u16 tw28_get_audio_status(struct solo_dev *solo_dev)
+{
+       u8 val;
+       u16 status = 0;
+       int i;
+
+       for (i = 0; i < solo_dev->tw28_cnt; i++) {
+               val = (tw_readbyte(solo_dev, i, TW286X_AV_STAT_ADDR,
+                                  TW_AV_STAT_ADDR) & 0xf0) >> 4;
+               status |= val << (i * 4);
+       }
+
+       return status;
+}
+#endif
+
+int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val)
+{
+       char sval;
+       u8 chip_num;
+
+       /* Get the right chip and on-chip channel */
+       chip_num = ch / 4;
+       ch %= 4;
+
+       if (val > 255 || val < 0)
+               return -ERANGE;
+
+       switch (ctrl) {
+       case V4L2_CID_SHARPNESS:
+               /* Only 286x has sharpness */
+               if (val > 0x0f || val < 0)
+                       return -ERANGE;
+               if (is_tw286x(solo_dev, chip_num)) {
+                       u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+                                                TW_CHIP_OFFSET_ADDR(chip_num),
+                                                TW286x_SHARPNESS(chip_num));
+                       v &= 0xf0;
+                       v |= val;
+                       solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+                                          TW_CHIP_OFFSET_ADDR(chip_num),
+                                          TW286x_SHARPNESS(chip_num), v);
+               } else if (val != 0)
+                       return -ERANGE;
+               break;
+
+       case V4L2_CID_HUE:
+               if (is_tw286x(solo_dev, chip_num))
+                       sval = val - 128;
+               else
+                       sval = (char)val;
+               tw_writebyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
+                            TW_HUE_ADDR(ch), sval);
+
+               break;
+
+       case V4L2_CID_SATURATION:
+               if (is_tw286x(solo_dev, chip_num)) {
+                       solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
+                                          TW_CHIP_OFFSET_ADDR(chip_num),
+                                          TW286x_SATURATIONU_ADDR(ch), val);
+               }
+               tw_writebyte(solo_dev, chip_num, TW286x_SATURATIONV_ADDR(ch),
+                            TW_SATURATION_ADDR(ch), val);
+
+               break;
+
+       case V4L2_CID_CONTRAST:
+               tw_writebyte(solo_dev, chip_num, TW286x_CONTRAST_ADDR(ch),
+                            TW_CONTRAST_ADDR(ch), val);
+               break;
+
+       case V4L2_CID_BRIGHTNESS:
+               if (is_tw286x(solo_dev, chip_num))
+                       sval = val - 128;
+               else
+                       sval = (char)val;
+               tw_writebyte(solo_dev, chip_num, TW286x_BRIGHTNESS_ADDR(ch),
+                            TW_BRIGHTNESS_ADDR(ch), sval);
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
+                     s32 *val)
+{
+       u8 rval, chip_num;
+
+       /* Get the right chip and on-chip channel */
+       chip_num = ch / 4;
+       ch %= 4;
+
+       switch (ctrl) {
+       case V4L2_CID_SHARPNESS:
+               /* Only 286x has sharpness */
+               if (is_tw286x(solo_dev, chip_num)) {
+                       rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+                                                TW_CHIP_OFFSET_ADDR(chip_num),
+                                                TW286x_SHARPNESS(chip_num));
+                       *val = rval & 0x0f;
+               } else
+                       *val = 0;
+               break;
+       case V4L2_CID_HUE:
+               rval = tw_readbyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
+                                  TW_HUE_ADDR(ch));
+               if (is_tw286x(solo_dev, chip_num))
+                       *val = (s32)((char)rval) + 128;
+               else
+                       *val = rval;
+               break;
+       case V4L2_CID_SATURATION:
+               *val = tw_readbyte(solo_dev, chip_num,
+                                  TW286x_SATURATIONU_ADDR(ch),
+                                  TW_SATURATION_ADDR(ch));
+               break;
+       case V4L2_CID_CONTRAST:
+               *val = tw_readbyte(solo_dev, chip_num,
+                                  TW286x_CONTRAST_ADDR(ch),
+                                  TW_CONTRAST_ADDR(ch));
+               break;
+       case V4L2_CID_BRIGHTNESS:
+               rval = tw_readbyte(solo_dev, chip_num,
+                                  TW286x_BRIGHTNESS_ADDR(ch),
+                                  TW_BRIGHTNESS_ADDR(ch));
+               if (is_tw286x(solo_dev, chip_num))
+                       *val = (s32)((char)rval) + 128;
+               else
+                       *val = rval;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+#if 0
+/*
+ * For audio output volume, the output channel is only 1. In this case we
+ * don't need to offset TW_CHIP_OFFSET_ADDR. The TW_CHIP_OFFSET_ADDR used
+ * is the base address of the techwell chip.
+ */
+void tw2815_Set_AudioOutVol(struct solo_dev *solo_dev, unsigned int u_val)
+{
+       unsigned int val;
+       unsigned int chip_num;
+
+       chip_num = (solo_dev->nr_chans - 1) / 4;
+
+       val = tw_readbyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
+                         TW_AUDIO_OUTPUT_VOL_ADDR);
+
+       u_val = (val & 0x0f) | (u_val << 4);
+
+       tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
+                    TW_AUDIO_OUTPUT_VOL_ADDR, u_val);
+}
+#endif
+
+u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch)
+{
+       u8 val;
+       u8 chip_num;
+
+       /* Get the right chip and on-chip channel */
+       chip_num = ch / 4;
+       ch %= 4;
+
+       val = tw_readbyte(solo_dev, chip_num,
+                         TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
+                         TW_AUDIO_INPUT_GAIN_ADDR(ch));
+
+       return (ch % 2) ? (val >> 4) : (val & 0x0f);
+}
+
+void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val)
+{
+       u8 old_val;
+       u8 chip_num;
+
+       /* Get the right chip and on-chip channel */
+       chip_num = ch / 4;
+       ch %= 4;
+
+       old_val = tw_readbyte(solo_dev, chip_num,
+                             TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
+                             TW_AUDIO_INPUT_GAIN_ADDR(ch));
+
+       val = (old_val & ((ch % 2) ? 0x0f : 0xf0)) |
+               ((ch % 2) ? (val << 4) : val);
+
+       tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
+                    TW_AUDIO_INPUT_GAIN_ADDR(ch), val);
+}
diff --git a/drivers/staging/media/solo6x10/tw28.h b/drivers/staging/media/solo6x10/tw28.h
new file mode 100644 (file)
index 0000000..a44a03a
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __SOLO6X10_TW28_H
+#define __SOLO6X10_TW28_H
+
+#include "solo6x10.h"
+
+#define TW_NUM_CHIP                            4
+#define TW_BASE_ADDR                           0x28
+#define TW_CHIP_OFFSET_ADDR(n)                 (TW_BASE_ADDR + (n))
+
+/* tw2815 */
+#define TW_AV_STAT_ADDR                                0x5a
+#define TW_HUE_ADDR(n)                         (0x07 | ((n) << 4))
+#define TW_SATURATION_ADDR(n)                  (0x08 | ((n) << 4))
+#define TW_CONTRAST_ADDR(n)                    (0x09 | ((n) << 4))
+#define TW_BRIGHTNESS_ADDR(n)                  (0x0a | ((n) << 4))
+#define TW_AUDIO_OUTPUT_VOL_ADDR               0x70
+#define TW_AUDIO_INPUT_GAIN_ADDR(n)            (0x60 + ((n > 1) ? 1 : 0))
+
+/* tw286x */
+#define TW286X_AV_STAT_ADDR                    0xfd
+#define TW286x_HUE_ADDR(n)                     (0x06 | ((n) << 4))
+#define TW286x_SATURATIONU_ADDR(n)             (0x04 | ((n) << 4))
+#define TW286x_SATURATIONV_ADDR(n)             (0x05 | ((n) << 4))
+#define TW286x_CONTRAST_ADDR(n)                        (0x02 | ((n) << 4))
+#define TW286x_BRIGHTNESS_ADDR(n)              (0x01 | ((n) << 4))
+#define TW286x_SHARPNESS(n)                    (0x03 | ((n) << 4))
+#define TW286x_AUDIO_OUTPUT_VOL_ADDR           0xdf
+#define TW286x_AUDIO_INPUT_GAIN_ADDR(n)                (0xD0 + ((n > 1) ? 1 : 0))
+
+int solo_tw28_init(struct solo_dev *solo_dev);
+
+int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val);
+int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val);
+
+u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch);
+void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val);
+int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch);
+
+#if 0
+unsigned int tw2815_get_audio_status(struct SOLO *solo);
+void tw2815_Set_AudioOutVol(struct SOLO *solo, unsigned int u_val);
+#endif
+
+#endif /* __SOLO6X10_TW28_H */
diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c
new file mode 100644 (file)
index 0000000..bee7280
--- /dev/null
@@ -0,0 +1,1825 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/videobuf-dma-sg.h>
+#include "solo6x10.h"
+#include "tw28.h"
+#include "jpeg.h"
+
+#define MIN_VID_BUFFERS                4
+#define FRAME_BUF_SIZE         (128 * 1024)
+#define MP4_QS                 16
+
+static int solo_enc_thread(void *data);
+
+extern unsigned video_nr;
+
+struct solo_enc_fh {
+       struct                  solo_enc_dev *enc;
+       u32                     fmt;
+       u16                     rd_idx;
+       u8                      enc_on;
+       enum solo_enc_types     type;
+       struct videobuf_queue   vidq;
+       struct list_head        vidq_active;
+       struct task_struct      *kthread;
+       struct p2m_desc         desc[SOLO_NR_P2M_DESC];
+};
+
+static const u32 solo_user_ctrls[] = {
+       V4L2_CID_BRIGHTNESS,
+       V4L2_CID_CONTRAST,
+       V4L2_CID_SATURATION,
+       V4L2_CID_HUE,
+       V4L2_CID_SHARPNESS,
+       0
+};
+
+static const u32 solo_mpeg_ctrls[] = {
+       V4L2_CID_MPEG_VIDEO_ENCODING,
+       V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+       0
+};
+
+static const u32 solo_private_ctrls[] = {
+       V4L2_CID_MOTION_ENABLE,
+       V4L2_CID_MOTION_THRESHOLD,
+       0
+};
+
+static const u32 solo_fmtx_ctrls[] = {
+       V4L2_CID_RDS_TX_RADIO_TEXT,
+       0
+};
+
+static const u32 *solo_ctrl_classes[] = {
+       solo_user_ctrls,
+       solo_mpeg_ctrls,
+       solo_fmtx_ctrls,
+       solo_private_ctrls,
+       NULL
+};
+
+static int solo_is_motion_on(struct solo_enc_dev *solo_enc)
+{
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+       u8 ch = solo_enc->ch;
+
+       if (solo_dev->motion_mask & (1 << ch))
+               return 1;
+       return 0;
+}
+
+static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on)
+{
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+       u8 ch = solo_enc->ch;
+
+       spin_lock(&solo_enc->lock);
+
+       if (on)
+               solo_dev->motion_mask |= (1 << ch);
+       else
+               solo_dev->motion_mask &= ~(1 << ch);
+
+       /* Do this regardless of if we are turning on or off */
+       solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR,
+                      1 << solo_enc->ch);
+       solo_enc->motion_detected = 0;
+
+       solo_reg_write(solo_dev, SOLO_VI_MOT_ADR,
+                      SOLO_VI_MOTION_EN(solo_dev->motion_mask) |
+                      (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
+
+       if (solo_dev->motion_mask)
+               solo_irq_on(solo_dev, SOLO_IRQ_MOTION);
+       else
+               solo_irq_off(solo_dev, SOLO_IRQ_MOTION);
+
+       spin_unlock(&solo_enc->lock);
+}
+
+/* Should be called with solo_enc->lock held */
+static void solo_update_mode(struct solo_enc_dev *solo_enc)
+{
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+       assert_spin_locked(&solo_enc->lock);
+
+       solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0;
+       solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1);
+
+       switch (solo_enc->mode) {
+       case SOLO_ENC_MODE_CIF:
+               solo_enc->width = solo_dev->video_hsize >> 1;
+               solo_enc->height = solo_dev->video_vsize;
+               break;
+       case SOLO_ENC_MODE_D1:
+               solo_enc->width = solo_dev->video_hsize;
+               solo_enc->height = solo_dev->video_vsize << 1;
+               solo_enc->bw_weight <<= 2;
+               break;
+       default:
+               WARN(1, "mode is unknown\n");
+       }
+}
+
+/* Should be called with solo_enc->lock held */
+static int solo_enc_on(struct solo_enc_fh *fh)
+{
+       struct solo_enc_dev *solo_enc = fh->enc;
+       u8 ch = solo_enc->ch;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+       u8 interval;
+
+       assert_spin_locked(&solo_enc->lock);
+
+       if (fh->enc_on)
+               return 0;
+
+       solo_update_mode(solo_enc);
+
+       /* Make sure to bw check on first reader */
+       if (!atomic_read(&solo_enc->readers)) {
+               if (solo_enc->bw_weight > solo_dev->enc_bw_remain)
+                       return -EBUSY;
+               else
+                       solo_dev->enc_bw_remain -= solo_enc->bw_weight;
+       }
+
+       fh->enc_on = 1;
+       fh->rd_idx = solo_enc->solo_dev->enc_wr_idx;
+
+       if (fh->type == SOLO_ENC_TYPE_EXT)
+               solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1);
+
+       if (atomic_inc_return(&solo_enc->readers) > 1)
+               return 0;
+
+       /* Disable all encoding for this channel */
+       solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0);
+
+       /* Common for both std and ext encoding */
+       solo_reg_write(solo_dev, SOLO_VE_CH_INTL(ch),
+                      solo_enc->interlaced ? 1 : 0);
+
+       if (solo_enc->interlaced)
+               interval = solo_enc->interval - 1;
+       else
+               interval = solo_enc->interval;
+
+       /* Standard encoding only */
+       solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), solo_enc->gop);
+       solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp);
+       solo_reg_write(solo_dev, SOLO_CAP_CH_INTV(ch), interval);
+
+       /* Extended encoding only */
+       solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(ch), solo_enc->gop);
+       solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp);
+       solo_reg_write(solo_dev, SOLO_CAP_CH_INTV_E(ch), interval);
+
+       /* Enables the standard encoder */
+       solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode);
+
+       /* Settle down Beavis... */
+       mdelay(10);
+
+       return 0;
+}
+
+static void solo_enc_off(struct solo_enc_fh *fh)
+{
+       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+       if (!fh->enc_on)
+               return;
+
+       if (fh->kthread) {
+               kthread_stop(fh->kthread);
+               fh->kthread = NULL;
+       }
+
+       solo_dev->enc_bw_remain += solo_enc->bw_weight;
+       fh->enc_on = 0;
+
+       if (atomic_dec_return(&solo_enc->readers) > 0)
+               return;
+
+       solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0);
+       solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0);
+}
+
+static int solo_start_fh_thread(struct solo_enc_fh *fh)
+{
+       struct solo_enc_dev *solo_enc = fh->enc;
+
+       fh->kthread = kthread_run(solo_enc_thread, fh, SOLO6X10_NAME "_enc");
+
+       /* Oops, we had a problem */
+       if (IS_ERR(fh->kthread)) {
+               spin_lock(&solo_enc->lock);
+               solo_enc_off(fh);
+               spin_unlock(&solo_enc->lock);
+
+               return PTR_ERR(fh->kthread);
+       }
+
+       return 0;
+}
+
+static void enc_reset_gop(struct solo_dev *solo_dev, u8 ch)
+{
+       BUG_ON(ch >= solo_dev->nr_chans);
+       solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), 1);
+       solo_dev->v4l2_enc[ch]->reset_gop = 1;
+}
+
+static int enc_gop_reset(struct solo_dev *solo_dev, u8 ch, u8 vop)
+{
+       BUG_ON(ch >= solo_dev->nr_chans);
+       if (!solo_dev->v4l2_enc[ch]->reset_gop)
+               return 0;
+       if (vop)
+               return 1;
+       solo_dev->v4l2_enc[ch]->reset_gop = 0;
+       solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch),
+                      solo_dev->v4l2_enc[ch]->gop);
+       return 0;
+}
+
+static void enc_write_sg(struct scatterlist *sglist, void *buf, int size)
+{
+       struct scatterlist *sg;
+       u8 *src = buf;
+
+       for (sg = sglist; sg && size > 0; sg = sg_next(sg)) {
+               u8 *p = sg_virt(sg);
+               size_t len = sg_dma_len(sg);
+               int i;
+
+               for (i = 0; i < len && size; i++)
+                       p[i] = *(src++);
+       }
+}
+
+static int enc_get_mpeg_dma_sg(struct solo_dev *solo_dev,
+                              struct p2m_desc *desc,
+                              struct scatterlist *sglist, int skip,
+                              unsigned int off, unsigned int size)
+{
+       int ret;
+
+       if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
+               return -EINVAL;
+
+       if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) {
+               return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E,
+                                      desc, 0, sglist, skip,
+                                      SOLO_MP4E_EXT_ADDR(solo_dev) + off, size);
+       }
+
+       /* Buffer wrap */
+       ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0,
+                             sglist, skip, SOLO_MP4E_EXT_ADDR(solo_dev) + off,
+                             SOLO_MP4E_EXT_SIZE(solo_dev) - off);
+
+       ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0,
+                              sglist, skip + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
+                              SOLO_MP4E_EXT_ADDR(solo_dev),
+                              size + off - SOLO_MP4E_EXT_SIZE(solo_dev));
+
+       return ret;
+}
+
+static int enc_get_mpeg_dma_t(struct solo_dev *solo_dev,
+                             dma_addr_t buf, unsigned int off,
+                             unsigned int size)
+{
+       int ret;
+
+       if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
+               return -EINVAL;
+
+       if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) {
+               return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf,
+                                     SOLO_MP4E_EXT_ADDR(solo_dev) + off, size);
+       }
+
+       /* Buffer wrap */
+       ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf,
+                            SOLO_MP4E_EXT_ADDR(solo_dev) + off,
+                            SOLO_MP4E_EXT_SIZE(solo_dev) - off);
+
+       ret |= solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0,
+                             buf + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
+                             SOLO_MP4E_EXT_ADDR(solo_dev),
+                             size + off - SOLO_MP4E_EXT_SIZE(solo_dev));
+
+       return ret;
+}
+
+static int enc_get_mpeg_dma(struct solo_dev *solo_dev, void *buf,
+                           unsigned int off, unsigned int size)
+{
+       int ret;
+
+       dma_addr_t dma_addr = pci_map_single(solo_dev->pdev, buf, size,
+                                            PCI_DMA_FROMDEVICE);
+       ret = enc_get_mpeg_dma_t(solo_dev, dma_addr, off, size);
+       pci_unmap_single(solo_dev->pdev, dma_addr, size, PCI_DMA_FROMDEVICE);
+
+       return ret;
+}
+
+static int enc_get_jpeg_dma_sg(struct solo_dev *solo_dev,
+                              struct p2m_desc *desc,
+                              struct scatterlist *sglist, int skip,
+                              unsigned int off, unsigned int size)
+{
+       int ret;
+
+       if (off > SOLO_JPEG_EXT_SIZE(solo_dev))
+               return -EINVAL;
+
+       if (off + size <= SOLO_JPEG_EXT_SIZE(solo_dev)) {
+               return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG,
+                                      desc, 0, sglist, skip,
+                                      SOLO_JPEG_EXT_ADDR(solo_dev) + off, size);
+       }
+
+       /* Buffer wrap */
+       ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0,
+                             sglist, skip, SOLO_JPEG_EXT_ADDR(solo_dev) + off,
+                             SOLO_JPEG_EXT_SIZE(solo_dev) - off);
+
+       ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0,
+                              sglist, skip + SOLO_JPEG_EXT_SIZE(solo_dev) - off,
+                              SOLO_JPEG_EXT_ADDR(solo_dev),
+                              size + off - SOLO_JPEG_EXT_SIZE(solo_dev));
+
+       return ret;
+}
+
+/* Returns true of __chk is within the first __range bytes of __off */
+#define OFF_IN_RANGE(__off, __range, __chk) \
+       ((__off <= __chk) && ((__off + __range) >= __chk))
+
+static void solo_jpeg_header(struct solo_enc_dev *solo_enc,
+                            struct videobuf_dmabuf *vbuf)
+{
+       struct scatterlist *sg;
+       void *src = jpeg_header;
+       size_t copied = 0;
+       size_t to_copy = sizeof(jpeg_header);
+
+       for (sg = vbuf->sglist; sg && copied < to_copy; sg = sg_next(sg)) {
+               size_t this_copy = min(sg_dma_len(sg),
+                                      (unsigned int)(to_copy - copied));
+               u8 *p = sg_virt(sg);
+
+               memcpy(p, src + copied, this_copy);
+
+               if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 5))
+                       p[(SOF0_START + 5) - copied] =
+                               0xff & (solo_enc->height >> 8);
+               if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 6))
+                       p[(SOF0_START + 6) - copied] = 0xff & solo_enc->height;
+               if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 7))
+                       p[(SOF0_START + 7) - copied] =
+                               0xff & (solo_enc->width >> 8);
+               if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 8))
+                       p[(SOF0_START + 8) - copied] = 0xff & solo_enc->width;
+
+               copied += this_copy;
+       }
+}
+
+static int solo_fill_jpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
+                         struct videobuf_buffer *vb,
+                         struct videobuf_dmabuf *vbuf)
+{
+       struct solo_dev *solo_dev = fh->enc->solo_dev;
+       int size = enc_buf->jpeg_size;
+
+       /* Copy the header first (direct write) */
+       solo_jpeg_header(fh->enc, vbuf);
+
+       vb->size = size + sizeof(jpeg_header);
+
+       /* Grab the jpeg frame */
+       return enc_get_jpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist,
+                                  sizeof(jpeg_header),
+                                  enc_buf->jpeg_off, size);
+}
+
+static inline int vop_interlaced(__le32 *vh)
+{
+       return (__le32_to_cpu(vh[0]) >> 30) & 1;
+}
+
+static inline u32 vop_size(__le32 *vh)
+{
+       return __le32_to_cpu(vh[0]) & 0xFFFFF;
+}
+
+static inline u8 vop_hsize(__le32 *vh)
+{
+       return (__le32_to_cpu(vh[1]) >> 8) & 0xFF;
+}
+
+static inline u8 vop_vsize(__le32 *vh)
+{
+       return __le32_to_cpu(vh[1]) & 0xFF;
+}
+
+/* must be called with *bits % 8 = 0 */
+static void write_bytes(u8 **out, unsigned *bits, const u8 *src, unsigned count)
+{
+       memcpy(*out, src, count);
+       *out += count;
+       *bits += count * 8;
+}
+
+static void write_bits(u8 **out, unsigned *bits, u32 value, unsigned count)
+{
+
+       value <<= 32 - count; // shift to the right
+
+       while (count--) {
+               **out <<= 1;
+               **out |= !!(value & (1 << 31)); /* MSB */
+               value <<= 1;
+               if (++(*bits) % 8 == 0)
+                       (*out)++;
+       }
+}
+
+static void write_ue(u8 **out, unsigned *bits, unsigned value) /* H.264 only */
+{
+       uint32_t max = 0, cnt = 0;
+
+       while (value > max) {
+               max = (max + 2) * 2 - 2;
+               cnt++;
+       }
+       write_bits(out, bits, 1, cnt + 1);
+       write_bits(out, bits, ~(max - value), cnt);
+}
+
+static void write_se(u8 **out, unsigned *bits, int value) /* H.264 only */
+{
+       if (value <= 0)
+               write_ue(out, bits, -value * 2);
+       else
+               write_ue(out, bits, value * 2 - 1);
+}
+
+static void write_mpeg4_end(u8 **out, unsigned *bits)
+{
+       write_bits(out, bits, 0, 1);
+       /* align on 32-bit boundary */
+       if (*bits % 32)
+               write_bits(out, bits, 0xFFFFFFFF, 32 - *bits % 32);
+}
+
+static void write_h264_end(u8 **out, unsigned *bits, int align)
+{
+       write_bits(out, bits, 1, 1);
+       while ((*bits) % 8)
+               write_bits(out, bits, 0, 1);
+       if (align)
+               while ((*bits) % 32)
+                       write_bits(out, bits, 0, 1);
+}
+
+static void mpeg4_write_vol(u8 **out, struct solo_dev *solo_dev,
+                           __le32 *vh, unsigned fps, unsigned interval)
+{
+       static const u8 hdr[] = {
+               0, 0, 1, 0x00 /* video_object_start_code */,
+               0, 0, 1, 0x20 /* video_object_layer_start_code */
+       };
+       unsigned bits = 0;
+       unsigned width = vop_hsize(vh) << 4;
+       unsigned height = vop_vsize(vh) << 4;
+       unsigned interlaced = vop_interlaced(vh);
+
+       write_bytes(out, &bits, hdr, sizeof(hdr));
+       write_bits(out, &bits,    0,  1); /* random_accessible_vol */
+       write_bits(out, &bits, 0x04,  8); /* video_object_type_indication: main */
+       write_bits(out, &bits,    1,  1); /* is_object_layer_identifier */
+       write_bits(out, &bits,    2,  4); /* video_object_layer_verid: table V2-39 */
+       write_bits(out, &bits,    0,  3); /* video_object_layer_priority */
+       if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
+               write_bits(out, &bits,  3,  4); /* aspect_ratio_info, assuming 4:3 */
+       else
+               write_bits(out, &bits,  2,  4);
+       write_bits(out, &bits,    1,  1); /* vol_control_parameters */
+       write_bits(out, &bits,    1,  2); /* chroma_format: 4:2:0 */
+       write_bits(out, &bits,    1,  1); /* low_delay */
+       write_bits(out, &bits,    0,  1); /* vbv_parameters */
+       write_bits(out, &bits,    0,  2); /* video_object_layer_shape: rectangular */
+       write_bits(out, &bits,    1,  1); /* marker_bit */
+       write_bits(out, &bits,  fps, 16); /* vop_time_increment_resolution */
+       write_bits(out, &bits,    1,  1); /* marker_bit */
+       write_bits(out, &bits,    1,  1); /* fixed_vop_rate */
+       write_bits(out, &bits, interval, 15); /* fixed_vop_time_increment */
+       write_bits(out, &bits,    1,  1); /* marker_bit */
+       write_bits(out, &bits, width, 13); /* video_object_layer_width */
+       write_bits(out, &bits,    1,  1); /* marker_bit */
+       write_bits(out, &bits, height, 13); /* video_object_layer_height */
+       write_bits(out, &bits,    1,  1); /* marker_bit */
+       write_bits(out, &bits, interlaced, 1); /* interlaced */
+       write_bits(out, &bits,    1,  1); /* obmc_disable */
+       write_bits(out, &bits,    0,  2); /* sprite_enable */
+       write_bits(out, &bits,    0,  1); /* not_8_bit */
+       write_bits(out, &bits,    1,  0); /* quant_type */
+       write_bits(out, &bits,    0,  1); /* load_intra_quant_mat */
+       write_bits(out, &bits,    0,  1); /* load_nonintra_quant_mat */
+       write_bits(out, &bits,    0,  1); /* quarter_sample */
+       write_bits(out, &bits,    1,  1); /* complexity_estimation_disable */
+       write_bits(out, &bits,    1,  1); /* resync_marker_disable */
+       write_bits(out, &bits,    0,  1); /* data_partitioned */
+       write_bits(out, &bits,    0,  1); /* newpred_enable */
+       write_bits(out, &bits,    0,  1); /* reduced_resolution_vop_enable */
+       write_bits(out, &bits,    0,  1); /* scalability */
+       write_mpeg4_end(out, &bits);
+}
+
+static void h264_write_vol(u8 **out, struct solo_dev *solo_dev, __le32 *vh)
+{
+       static const u8 sps[] = {
+               0, 0, 0, 1 /* start code */, 0x67, 66 /* profile_idc */,
+               0 /* constraints */, 30 /* level_idc */
+       };
+       static const u8 pps[] = {
+               0, 0, 0, 1 /* start code */, 0x68
+       };
+
+       unsigned bits = 0;
+       unsigned mbs_w = vop_hsize(vh);
+       unsigned mbs_h = vop_vsize(vh);
+
+       write_bytes(out, &bits, sps, sizeof(sps));
+       write_ue(out, &bits,   0);      /* seq_parameter_set_id */
+       write_ue(out, &bits,   5);      /* log2_max_frame_num_minus4 */
+       write_ue(out, &bits,   0);      /* pic_order_cnt_type */
+       write_ue(out, &bits,   6);      /* log2_max_pic_order_cnt_lsb_minus4 */
+       write_ue(out, &bits,   1);      /* max_num_ref_frames */
+       write_bits(out, &bits, 0, 1);   /* gaps_in_frame_num_value_allowed_flag */
+       write_ue(out, &bits, mbs_w - 1);        /* pic_width_in_mbs_minus1 */
+       write_ue(out, &bits, mbs_h - 1);        /* pic_height_in_map_units_minus1 */
+       write_bits(out, &bits, 1, 1);   /* frame_mbs_only_flag */
+       write_bits(out, &bits, 1, 1);   /* direct_8x8_frame_field_flag */
+       write_bits(out, &bits, 0, 1);   /* frame_cropping_flag */
+       write_bits(out, &bits, 0, 1);   /* vui_parameters_present_flag */
+       write_h264_end(out, &bits, 0);
+
+       write_bytes(out, &bits, pps, sizeof(pps));
+       write_ue(out, &bits,   0);      /* pic_parameter_set_id */
+       write_ue(out, &bits,   0);      /* seq_parameter_set_id */
+       write_bits(out, &bits, 0, 1);   /* entropy_coding_mode_flag */
+       write_bits(out, &bits, 0, 1);   /* bottom_field_pic_order_in_frame_present_flag */
+       write_ue(out, &bits,   0);      /* num_slice_groups_minus1 */
+       write_ue(out, &bits,   0);      /* num_ref_idx_l0_default_active_minus1 */
+       write_ue(out, &bits,   0);      /* num_ref_idx_l1_default_active_minus1 */
+       write_bits(out, &bits, 0, 1);   /* weighted_pred_flag */
+       write_bits(out, &bits, 0, 2);   /* weighted_bipred_idc */
+       write_se(out, &bits,   0);      /* pic_init_qp_minus26 */
+       write_se(out, &bits,   0);      /* pic_init_qs_minus26 */
+       write_se(out, &bits,   2);      /* chroma_qp_index_offset */
+       write_bits(out, &bits, 0, 1);   /* deblocking_filter_control_present_flag */
+       write_bits(out, &bits, 1, 1);   /* constrained_intra_pred_flag */
+       write_bits(out, &bits, 0, 1);   /* redundant_pic_cnt_present_flag */
+       write_h264_end(out, &bits, 1);
+}
+
+static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
+                         struct videobuf_buffer *vb,
+                         struct videobuf_dmabuf *vbuf)
+{
+       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+#define VH_WORDS 16
+#define MAX_VOL_HEADER_LENGTH 64
+
+       __le32 vh[VH_WORDS];
+       int ret;
+       int frame_size, frame_off;
+       int skip = 0;
+
+       if (WARN_ON_ONCE(enc_buf->size <= sizeof(vh)))
+               return -EINVAL;
+
+       /* First get the hardware vop header (not real mpeg) */
+       ret = enc_get_mpeg_dma(solo_dev, vh, enc_buf->off, sizeof(vh));
+       if (WARN_ON_ONCE(ret))
+               return ret;
+
+       if (WARN_ON_ONCE(vop_size(vh) > enc_buf->size))
+               return -EINVAL;
+
+       vb->width = vop_hsize(vh) << 4;
+       vb->height = vop_vsize(vh) << 4;
+       vb->size = vop_size(vh);
+
+       /* If this is a key frame, add extra m4v header */
+       if (!enc_buf->vop) {
+               u8 header[MAX_VOL_HEADER_LENGTH], *out = header;
+
+               if (solo_dev->flags & FLAGS_6110)
+                       h264_write_vol(&out, solo_dev, vh);
+               else
+                       mpeg4_write_vol(&out, solo_dev, vh,
+                                       solo_dev->fps * 1000,
+                                       solo_enc->interval * 1000);
+               skip = out - header;
+               enc_write_sg(vbuf->sglist, header, skip);
+               /* Adjust the dma buffer past this header */
+               vb->size += skip;
+       }
+
+       /* Now get the actual mpeg payload */
+       frame_off = (enc_buf->off + sizeof(vh)) % SOLO_MP4E_EXT_SIZE(solo_dev);
+       frame_size = enc_buf->size - sizeof(vh);
+
+       ret = enc_get_mpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist,
+                                 skip, frame_off, frame_size);
+       WARN_ON_ONCE(ret);
+
+       return ret;
+}
+
+static void solo_enc_fillbuf(struct solo_enc_fh *fh,
+                           struct videobuf_buffer *vb)
+{
+       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+       struct solo_enc_buf *enc_buf = NULL;
+       struct videobuf_dmabuf *vbuf;
+       int ret;
+       int error = 1;
+       u16 idx = fh->rd_idx;
+
+       while (idx != solo_dev->enc_wr_idx) {
+               struct solo_enc_buf *ebuf = &solo_dev->enc_buf[idx];
+
+               idx = (idx + 1) % SOLO_NR_RING_BUFS;
+
+               if (ebuf->ch != solo_enc->ch)
+                       continue;
+
+               if (fh->fmt == V4L2_PIX_FMT_MPEG) {
+                       if (fh->type == ebuf->type) {
+                               enc_buf = ebuf;
+                               break;
+                       }
+               } else {
+                       /* For mjpeg, keep reading to the newest frame */
+                       enc_buf = ebuf;
+               }
+       }
+
+       fh->rd_idx = idx;
+
+       if (WARN_ON_ONCE(!enc_buf))
+               goto buf_err;
+
+       if ((fh->fmt == V4L2_PIX_FMT_MPEG &&
+            vb->bsize < enc_buf->size) ||
+           (fh->fmt == V4L2_PIX_FMT_MJPEG &&
+            vb->bsize < (enc_buf->jpeg_size + sizeof(jpeg_header)))) {
+               WARN_ON_ONCE(1);
+               goto buf_err;
+       }
+
+       vbuf = videobuf_to_dma(vb);
+       if (WARN_ON_ONCE(!vbuf))
+               goto buf_err;
+
+       if (fh->fmt == V4L2_PIX_FMT_MPEG)
+               ret = solo_fill_mpeg(fh, enc_buf, vb, vbuf);
+       else
+               ret = solo_fill_jpeg(fh, enc_buf, vb, vbuf);
+
+       if (!ret)
+               error = 0;
+
+buf_err:
+       if (error) {
+               vb->state = VIDEOBUF_ERROR;
+       } else {
+               vb->field_count++;
+               vb->ts = enc_buf->ts;
+               vb->state = VIDEOBUF_DONE;
+       }
+
+       wake_up(&vb->done);
+
+       return;
+}
+
+static void solo_enc_thread_try(struct solo_enc_fh *fh)
+{
+       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+       struct videobuf_buffer *vb;
+
+       for (;;) {
+               spin_lock(&solo_enc->lock);
+
+               if (fh->rd_idx == solo_dev->enc_wr_idx)
+                       break;
+
+               if (list_empty(&fh->vidq_active))
+                       break;
+
+               vb = list_first_entry(&fh->vidq_active,
+                                     struct videobuf_buffer, queue);
+
+               if (!waitqueue_active(&vb->done))
+                       break;
+
+               list_del(&vb->queue);
+
+               spin_unlock(&solo_enc->lock);
+
+               solo_enc_fillbuf(fh, vb);
+       }
+
+       assert_spin_locked(&solo_enc->lock);
+       spin_unlock(&solo_enc->lock);
+}
+
+static int solo_enc_thread(void *data)
+{
+       struct solo_enc_fh *fh = data;
+       struct solo_enc_dev *solo_enc = fh->enc;
+       DECLARE_WAITQUEUE(wait, current);
+
+       set_freezable();
+       add_wait_queue(&solo_enc->thread_wait, &wait);
+
+       for (;;) {
+               long timeout = schedule_timeout_interruptible(HZ);
+               if (timeout == -ERESTARTSYS || kthread_should_stop())
+                       break;
+               solo_enc_thread_try(fh);
+               try_to_freeze();
+       }
+
+       remove_wait_queue(&solo_enc->thread_wait, &wait);
+
+       return 0;
+}
+
+void solo_motion_isr(struct solo_dev *solo_dev)
+{
+       u32 status;
+       int i;
+
+       solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_MOTION);
+
+       status = solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS);
+
+       for (i = 0; i < solo_dev->nr_chans; i++) {
+               struct solo_enc_dev *solo_enc = solo_dev->v4l2_enc[i];
+
+               BUG_ON(solo_enc == NULL);
+
+               if (solo_enc->motion_detected)
+                       continue;
+               if (!(status & (1 << i)))
+                       continue;
+
+               solo_enc->motion_detected = 1;
+       }
+}
+
+void solo_enc_v4l2_isr(struct solo_dev *solo_dev)
+{
+       struct solo_enc_buf *enc_buf;
+       u32 mpeg_current, mpeg_next, mpeg_size;
+       u32 jpeg_current, jpeg_next, jpeg_size;
+       u32 reg_mpeg_size;
+       u8 cur_q, vop_type;
+       u8 ch;
+       enum solo_enc_types enc_type;
+
+       solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_ENCODER);
+
+       cur_q = ((solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xF) + 1) % MP4_QS;
+
+       reg_mpeg_size = ((solo_reg_read(solo_dev, SOLO_VE_STATE(0)) & 0xFFFFF) + 64 + 8) & ~7;
+
+       while (solo_dev->enc_idx != cur_q) {
+               mpeg_current = solo_reg_read(solo_dev,
+                                       SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
+               jpeg_current = solo_reg_read(solo_dev,
+                                       SOLO_VE_JPEG_QUE(solo_dev->enc_idx));
+               solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS;
+               mpeg_next = solo_reg_read(solo_dev,
+                                       SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
+               jpeg_next = solo_reg_read(solo_dev,
+                                       SOLO_VE_JPEG_QUE(solo_dev->enc_idx));
+
+               ch = (mpeg_current >> 24) & 0x1f;
+               if (ch >= SOLO_MAX_CHANNELS) {
+                       ch -= SOLO_MAX_CHANNELS;
+                       enc_type = SOLO_ENC_TYPE_EXT;
+               } else
+                       enc_type = SOLO_ENC_TYPE_STD;
+
+               vop_type = (mpeg_current >> 29) & 3;
+
+               mpeg_current &= 0x00ffffff;
+               mpeg_next    &= 0x00ffffff;
+               jpeg_current &= 0x00ffffff;
+               jpeg_next    &= 0x00ffffff;
+
+               mpeg_size = (SOLO_MP4E_EXT_SIZE(solo_dev) +
+                            mpeg_next - mpeg_current) %
+                           SOLO_MP4E_EXT_SIZE(solo_dev);
+
+               jpeg_size = (SOLO_JPEG_EXT_SIZE(solo_dev) +
+                            jpeg_next - jpeg_current) %
+                           SOLO_JPEG_EXT_SIZE(solo_dev);
+
+               /* XXX I think this means we had a ring overflow? */
+               if (mpeg_current > mpeg_next && mpeg_size != reg_mpeg_size) {
+                       enc_reset_gop(solo_dev, ch);
+                       continue;
+               }
+
+               /* When resetting the GOP, skip frames until I-frame */
+               if (enc_gop_reset(solo_dev, ch, vop_type))
+                       continue;
+
+               enc_buf = &solo_dev->enc_buf[solo_dev->enc_wr_idx];
+
+               enc_buf->vop = vop_type;
+               enc_buf->ch = ch;
+               enc_buf->off = mpeg_current;
+               enc_buf->size = mpeg_size;
+               enc_buf->jpeg_off = jpeg_current;
+               enc_buf->jpeg_size = jpeg_size;
+               enc_buf->type = enc_type;
+
+               do_gettimeofday(&enc_buf->ts);
+
+               solo_dev->enc_wr_idx = (solo_dev->enc_wr_idx + 1) %
+                                       SOLO_NR_RING_BUFS;
+
+               wake_up_interruptible(&solo_dev->v4l2_enc[ch]->thread_wait);
+       }
+
+       return;
+}
+
+static int solo_enc_buf_setup(struct videobuf_queue *vq, unsigned int *count,
+                             unsigned int *size)
+{
+       *size = FRAME_BUF_SIZE;
+
+       if (*count < MIN_VID_BUFFERS)
+               *count = MIN_VID_BUFFERS;
+
+       return 0;
+}
+
+static int solo_enc_buf_prepare(struct videobuf_queue *vq,
+                               struct videobuf_buffer *vb,
+                               enum v4l2_field field)
+{
+       struct solo_enc_fh *fh = vq->priv_data;
+       struct solo_enc_dev *solo_enc = fh->enc;
+
+       vb->size = FRAME_BUF_SIZE;
+       if (vb->baddr != 0 && vb->bsize < vb->size)
+               return -EINVAL;
+
+       /* These properties only change when queue is idle */
+       vb->width = solo_enc->width;
+       vb->height = solo_enc->height;
+       vb->field  = field;
+
+       if (vb->state == VIDEOBUF_NEEDS_INIT) {
+               int rc = videobuf_iolock(vq, vb, NULL);
+               if (rc < 0) {
+                       struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+                       videobuf_dma_unmap(vq->dev, dma);
+                       videobuf_dma_free(dma);
+                       vb->state = VIDEOBUF_NEEDS_INIT;
+                       return rc;
+               }
+       }
+       vb->state = VIDEOBUF_PREPARED;
+
+       return 0;
+}
+
+static void solo_enc_buf_queue(struct videobuf_queue *vq,
+                              struct videobuf_buffer *vb)
+{
+       struct solo_enc_fh *fh = vq->priv_data;
+
+       vb->state = VIDEOBUF_QUEUED;
+       list_add_tail(&vb->queue, &fh->vidq_active);
+       wake_up_interruptible(&fh->enc->thread_wait);
+}
+
+static void solo_enc_buf_release(struct videobuf_queue *vq,
+                                struct videobuf_buffer *vb)
+{
+       struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+       videobuf_dma_unmap(vq->dev, dma);
+       videobuf_dma_free(dma);
+       vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops solo_enc_video_qops = {
+       .buf_setup      = solo_enc_buf_setup,
+       .buf_prepare    = solo_enc_buf_prepare,
+       .buf_queue      = solo_enc_buf_queue,
+       .buf_release    = solo_enc_buf_release,
+};
+
+static unsigned int solo_enc_poll(struct file *file,
+                                 struct poll_table_struct *wait)
+{
+       struct solo_enc_fh *fh = file->private_data;
+
+       return videobuf_poll_stream(file, &fh->vidq, wait);
+}
+
+static int solo_enc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct solo_enc_fh *fh = file->private_data;
+
+       return videobuf_mmap_mapper(&fh->vidq, vma);
+}
+
+static int solo_enc_open(struct file *file)
+{
+       struct solo_enc_dev *solo_enc = video_drvdata(file);
+       struct solo_enc_fh *fh;
+
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (fh == NULL)
+               return -ENOMEM;
+
+       fh->enc = solo_enc;
+       file->private_data = fh;
+       INIT_LIST_HEAD(&fh->vidq_active);
+       fh->fmt = V4L2_PIX_FMT_MPEG;
+       fh->type = SOLO_ENC_TYPE_STD;
+
+       videobuf_queue_sg_init(&fh->vidq, &solo_enc_video_qops,
+                              &solo_enc->solo_dev->pdev->dev,
+                              &solo_enc->lock,
+                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                              V4L2_FIELD_INTERLACED,
+                              sizeof(struct videobuf_buffer), fh, NULL);
+
+       return 0;
+}
+
+static ssize_t solo_enc_read(struct file *file, char __user *data,
+                            size_t count, loff_t *ppos)
+{
+       struct solo_enc_fh *fh = file->private_data;
+       struct solo_enc_dev *solo_enc = fh->enc;
+
+       /* Make sure the encoder is on */
+       if (!fh->enc_on) {
+               int ret;
+
+               spin_lock(&solo_enc->lock);
+               ret = solo_enc_on(fh);
+               spin_unlock(&solo_enc->lock);
+               if (ret)
+                       return ret;
+
+               ret = solo_start_fh_thread(fh);
+               if (ret)
+                       return ret;
+       }
+
+       return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
+                                   file->f_flags & O_NONBLOCK);
+}
+
+static int solo_enc_release(struct file *file)
+{
+       struct solo_enc_fh *fh = file->private_data;
+       struct solo_enc_dev *solo_enc = fh->enc;
+
+       videobuf_stop(&fh->vidq);
+       videobuf_mmap_free(&fh->vidq);
+
+       spin_lock(&solo_enc->lock);
+       solo_enc_off(fh);
+       spin_unlock(&solo_enc->lock);
+
+       kfree(fh);
+
+       return 0;
+}
+
+static int solo_enc_querycap(struct file *file, void  *priv,
+                            struct v4l2_capability *cap)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+       strcpy(cap->driver, SOLO6X10_NAME);
+       snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
+                solo_enc->ch);
+       snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
+                pci_name(solo_dev->pdev));
+       cap->version = SOLO6X10_VER_NUM;
+       cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
+                               V4L2_CAP_READWRITE |
+                               V4L2_CAP_STREAMING;
+       return 0;
+}
+
+static int solo_enc_enum_input(struct file *file, void *priv,
+                              struct v4l2_input *input)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+       if (input->index)
+               return -EINVAL;
+
+       snprintf(input->name, sizeof(input->name), "Encoder %d",
+                solo_enc->ch + 1);
+       input->type = V4L2_INPUT_TYPE_CAMERA;
+
+       if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
+               input->std = V4L2_STD_NTSC_M;
+       else
+               input->std = V4L2_STD_PAL_B;
+
+       if (!tw28_get_video_status(solo_dev, solo_enc->ch))
+               input->status = V4L2_IN_ST_NO_SIGNAL;
+
+       return 0;
+}
+
+static int solo_enc_set_input(struct file *file, void *priv, unsigned int index)
+{
+       if (index)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int solo_enc_get_input(struct file *file, void *priv,
+                             unsigned int *index)
+{
+       *index = 0;
+
+       return 0;
+}
+
+static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
+                                struct v4l2_fmtdesc *f)
+{
+       switch (f->index) {
+       case 0:
+               f->pixelformat = V4L2_PIX_FMT_MPEG;
+               strcpy(f->description, "MPEG-4 AVC");
+               break;
+       case 1:
+               f->pixelformat = V4L2_PIX_FMT_MJPEG;
+               strcpy(f->description, "MJPEG");
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       f->flags = V4L2_FMT_FLAG_COMPRESSED;
+
+       return 0;
+}
+
+static int solo_enc_try_fmt_cap(struct file *file, void *priv,
+                           struct v4l2_format *f)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+
+       if (pix->pixelformat != V4L2_PIX_FMT_MPEG &&
+           pix->pixelformat != V4L2_PIX_FMT_MJPEG)
+               return -EINVAL;
+
+       /* We cannot change width/height in mid read */
+       if (atomic_read(&solo_enc->readers) > 0) {
+               if (pix->width != solo_enc->width ||
+                   pix->height != solo_enc->height)
+                       return -EBUSY;
+       }
+
+       if (pix->width < solo_dev->video_hsize ||
+           pix->height < solo_dev->video_vsize << 1) {
+               /* Default to CIF 1/2 size */
+               pix->width = solo_dev->video_hsize >> 1;
+               pix->height = solo_dev->video_vsize;
+       } else {
+               /* Full frame */
+               pix->width = solo_dev->video_hsize;
+               pix->height = solo_dev->video_vsize << 1;
+       }
+
+       if (pix->field == V4L2_FIELD_ANY)
+               pix->field = V4L2_FIELD_INTERLACED;
+       else if (pix->field != V4L2_FIELD_INTERLACED)
+               pix->field = V4L2_FIELD_INTERLACED;
+
+       /* Just set these */
+       pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+       pix->sizeimage = FRAME_BUF_SIZE;
+
+       return 0;
+}
+
+static int solo_enc_set_fmt_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       int ret;
+
+       spin_lock(&solo_enc->lock);
+
+       ret = solo_enc_try_fmt_cap(file, priv, f);
+       if (ret) {
+               spin_unlock(&solo_enc->lock);
+               return ret;
+       }
+
+       if (pix->width == solo_dev->video_hsize)
+               solo_enc->mode = SOLO_ENC_MODE_D1;
+       else
+               solo_enc->mode = SOLO_ENC_MODE_CIF;
+
+       /* This does not change the encoder at all */
+       fh->fmt = pix->pixelformat;
+
+       if (pix->priv)
+               fh->type = SOLO_ENC_TYPE_EXT;
+       ret = solo_enc_on(fh);
+
+       spin_unlock(&solo_enc->lock);
+
+       if (ret)
+               return ret;
+
+       return solo_start_fh_thread(fh);
+}
+
+static int solo_enc_get_fmt_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = fh->enc;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+
+       pix->width = solo_enc->width;
+       pix->height = solo_enc->height;
+       pix->pixelformat = fh->fmt;
+       pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
+                    V4L2_FIELD_NONE;
+       pix->sizeimage = FRAME_BUF_SIZE;
+       pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+       return 0;
+}
+
+static int solo_enc_reqbufs(struct file *file, void *priv,
+                           struct v4l2_requestbuffers *req)
+{
+       struct solo_enc_fh *fh = priv;
+
+       return videobuf_reqbufs(&fh->vidq, req);
+}
+
+static int solo_enc_querybuf(struct file *file, void *priv,
+                            struct v4l2_buffer *buf)
+{
+       struct solo_enc_fh *fh = priv;
+
+       return videobuf_querybuf(&fh->vidq, buf);
+}
+
+static int solo_enc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct solo_enc_fh *fh = priv;
+
+       return videobuf_qbuf(&fh->vidq, buf);
+}
+
+static int solo_enc_dqbuf(struct file *file, void *priv,
+                         struct v4l2_buffer *buf)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = fh->enc;
+       int ret;
+
+       /* Make sure the encoder is on */
+       if (!fh->enc_on) {
+               spin_lock(&solo_enc->lock);
+               ret = solo_enc_on(fh);
+               spin_unlock(&solo_enc->lock);
+               if (ret)
+                       return ret;
+
+               ret = solo_start_fh_thread(fh);
+               if (ret)
+                       return ret;
+       }
+
+       ret = videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
+       if (ret)
+               return ret;
+
+       /* Signal motion detection */
+       if (solo_is_motion_on(solo_enc)) {
+               buf->flags |= V4L2_BUF_FLAG_MOTION_ON;
+               if (solo_enc->motion_detected) {
+                       buf->flags |= V4L2_BUF_FLAG_MOTION_DETECTED;
+                       solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR,
+                                      1 << solo_enc->ch);
+                       solo_enc->motion_detected = 0;
+               }
+       }
+
+       /* Check for key frame on mpeg data */
+       if (fh->fmt == V4L2_PIX_FMT_MPEG) {
+               struct videobuf_dmabuf *vbuf =
+                               videobuf_to_dma(fh->vidq.bufs[buf->index]);
+
+               if (vbuf) {
+                       u8 *p = sg_virt(vbuf->sglist);
+                       if (p[3] == 0x00)
+                               buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
+                       else
+                               buf->flags |= V4L2_BUF_FLAG_PFRAME;
+               }
+       }
+
+       return 0;
+}
+
+static int solo_enc_streamon(struct file *file, void *priv,
+                            enum v4l2_buf_type i)
+{
+       struct solo_enc_fh *fh = priv;
+
+       if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       return videobuf_streamon(&fh->vidq);
+}
+
+static int solo_enc_streamoff(struct file *file, void *priv,
+                             enum v4l2_buf_type i)
+{
+       struct solo_enc_fh *fh = priv;
+
+       if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       return videobuf_streamoff(&fh->vidq);
+}
+
+static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id *i)
+{
+       return 0;
+}
+
+static int solo_enum_framesizes(struct file *file, void *priv,
+                               struct v4l2_frmsizeenum *fsize)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_dev *solo_dev = fh->enc->solo_dev;
+
+       if (fsize->pixel_format != V4L2_PIX_FMT_MPEG)
+               return -EINVAL;
+
+       switch (fsize->index) {
+       case 0:
+               fsize->discrete.width = solo_dev->video_hsize >> 1;
+               fsize->discrete.height = solo_dev->video_vsize;
+               break;
+       case 1:
+               fsize->discrete.width = solo_dev->video_hsize;
+               fsize->discrete.height = solo_dev->video_vsize << 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+
+       return 0;
+}
+
+static int solo_enum_frameintervals(struct file *file, void *priv,
+                                   struct v4l2_frmivalenum *fintv)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_dev *solo_dev = fh->enc->solo_dev;
+
+       if (fintv->pixel_format != V4L2_PIX_FMT_MPEG || fintv->index)
+               return -EINVAL;
+
+       fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
+
+       fintv->stepwise.min.numerator = solo_dev->fps;
+       fintv->stepwise.min.denominator = 1;
+
+       fintv->stepwise.max.numerator = solo_dev->fps;
+       fintv->stepwise.max.denominator = 15;
+
+       fintv->stepwise.step.numerator = 1;
+       fintv->stepwise.step.denominator = 1;
+
+       return 0;
+}
+
+static int solo_g_parm(struct file *file, void *priv,
+                      struct v4l2_streamparm *sp)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+       struct v4l2_captureparm *cp = &sp->parm.capture;
+
+       cp->capability = V4L2_CAP_TIMEPERFRAME;
+       cp->timeperframe.numerator = solo_enc->interval;
+       cp->timeperframe.denominator = solo_dev->fps;
+       cp->capturemode = 0;
+       /* XXX: Shouldn't we be able to get/set this from videobuf? */
+       cp->readbuffers = 2;
+
+       return 0;
+}
+
+static int solo_s_parm(struct file *file, void *priv,
+                      struct v4l2_streamparm *sp)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+       struct v4l2_captureparm *cp = &sp->parm.capture;
+
+       spin_lock(&solo_enc->lock);
+
+       if (atomic_read(&solo_enc->readers) > 0) {
+               spin_unlock(&solo_enc->lock);
+               return -EBUSY;
+       }
+
+       if ((cp->timeperframe.numerator == 0) ||
+           (cp->timeperframe.denominator == 0)) {
+               /* reset framerate */
+               cp->timeperframe.numerator = 1;
+               cp->timeperframe.denominator = solo_dev->fps;
+       }
+
+       if (cp->timeperframe.denominator != solo_dev->fps)
+               cp->timeperframe.denominator = solo_dev->fps;
+
+       if (cp->timeperframe.numerator > 15)
+               cp->timeperframe.numerator = 15;
+
+       solo_enc->interval = cp->timeperframe.numerator;
+
+       cp->capability = V4L2_CAP_TIMEPERFRAME;
+
+       solo_enc->gop = max(solo_dev->fps / solo_enc->interval, 1);
+       solo_update_mode(solo_enc);
+
+       spin_unlock(&solo_enc->lock);
+
+       return 0;
+}
+
+static int solo_queryctrl(struct file *file, void *priv,
+                         struct v4l2_queryctrl *qc)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+       qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
+       if (!qc->id)
+               return -EINVAL;
+
+       switch (qc->id) {
+       case V4L2_CID_BRIGHTNESS:
+       case V4L2_CID_CONTRAST:
+       case V4L2_CID_SATURATION:
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill(qc, 0x00, 0xff, 1, 0x80);
+       case V4L2_CID_SHARPNESS:
+               return v4l2_ctrl_query_fill(qc, 0x00, 0x0f, 1, 0x00);
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               return v4l2_ctrl_query_fill(
+                       qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+                       V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
+                       V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               return v4l2_ctrl_query_fill(qc, 1, 255, 1, solo_dev->fps);
+#ifdef PRIVATE_CIDS
+       case V4L2_CID_MOTION_THRESHOLD:
+               qc->flags |= V4L2_CTRL_FLAG_SLIDER;
+               qc->type = V4L2_CTRL_TYPE_INTEGER;
+               qc->minimum = 0;
+               qc->maximum = 0xffff;
+               qc->step = 1;
+               qc->default_value = SOLO_DEF_MOT_THRESH;
+               strlcpy(qc->name, "Motion Detection Threshold",
+                       sizeof(qc->name));
+               return 0;
+       case V4L2_CID_MOTION_ENABLE:
+               qc->type = V4L2_CTRL_TYPE_BOOLEAN;
+               qc->minimum = 0;
+               qc->maximum = qc->step = 1;
+               qc->default_value = 0;
+               strlcpy(qc->name, "Motion Detection Enable", sizeof(qc->name));
+               return 0;
+#else
+       case V4L2_CID_MOTION_THRESHOLD:
+               return v4l2_ctrl_query_fill(qc, 0, 0xffff, 1,
+                                           SOLO_DEF_MOT_THRESH);
+       case V4L2_CID_MOTION_ENABLE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+#endif
+       case V4L2_CID_RDS_TX_RADIO_TEXT:
+               qc->type = V4L2_CTRL_TYPE_STRING;
+               qc->minimum = 0;
+               qc->maximum = OSD_TEXT_MAX;
+               qc->step = 1;
+               qc->default_value = 0;
+               strlcpy(qc->name, "OSD Text", sizeof(qc->name));
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int solo_querymenu(struct file *file, void *priv,
+                         struct v4l2_querymenu *qmenu)
+{
+       struct v4l2_queryctrl qctrl;
+       int err;
+
+       qctrl.id = qmenu->id;
+       err = solo_queryctrl(file, priv, &qctrl);
+       if (err)
+               return err;
+
+       return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
+}
+
+static int solo_g_ctrl(struct file *file, void *priv,
+                      struct v4l2_control *ctrl)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+       case V4L2_CID_CONTRAST:
+       case V4L2_CID_SATURATION:
+       case V4L2_CID_HUE:
+       case V4L2_CID_SHARPNESS:
+               return tw28_get_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
+                                        &ctrl->value);
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               ctrl->value = solo_enc->gop;
+               break;
+       case V4L2_CID_MOTION_THRESHOLD:
+               ctrl->value = solo_enc->motion_thresh;
+               break;
+       case V4L2_CID_MOTION_ENABLE:
+               ctrl->value = solo_is_motion_on(solo_enc);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int solo_s_ctrl(struct file *file, void *priv,
+                      struct v4l2_control *ctrl)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = fh->enc;
+       struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+       case V4L2_CID_CONTRAST:
+       case V4L2_CID_SATURATION:
+       case V4L2_CID_HUE:
+       case V4L2_CID_SHARPNESS:
+               return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
+                                        ctrl->value);
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               if (ctrl->value != V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC)
+                       return -ERANGE;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               if (ctrl->value < 1 || ctrl->value > 255)
+                       return -ERANGE;
+               solo_enc->gop = ctrl->value;
+               solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch),
+                              solo_enc->gop);
+               solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch),
+                              solo_enc->gop);
+               break;
+       case V4L2_CID_MOTION_THRESHOLD:
+               /* TODO accept value on lower 16-bits and use high
+                * 16-bits to assign the value to a specific block */
+               if (ctrl->value < 0 || ctrl->value > 0xffff)
+                       return -ERANGE;
+               solo_enc->motion_thresh = ctrl->value;
+               solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->value);
+               break;
+       case V4L2_CID_MOTION_ENABLE:
+               solo_motion_toggle(solo_enc, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int solo_s_ext_ctrls(struct file *file, void *priv,
+                           struct v4l2_ext_controls *ctrls)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = fh->enc;
+       int i;
+
+       for (i = 0; i < ctrls->count; i++) {
+               struct v4l2_ext_control *ctrl = (ctrls->controls + i);
+               int err;
+
+               switch (ctrl->id) {
+               case V4L2_CID_RDS_TX_RADIO_TEXT:
+                       if (ctrl->size - 1 > OSD_TEXT_MAX)
+                               err = -ERANGE;
+                       else {
+                               err = copy_from_user(solo_enc->osd_text,
+                                                    ctrl->string,
+                                                    OSD_TEXT_MAX);
+                               solo_enc->osd_text[OSD_TEXT_MAX] = '\0';
+                               if (!err)
+                                       err = solo_osd_print(solo_enc);
+                       }
+                       break;
+               default:
+                       err = -EINVAL;
+               }
+
+               if (err < 0) {
+                       ctrls->error_idx = i;
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static int solo_g_ext_ctrls(struct file *file, void *priv,
+                           struct v4l2_ext_controls *ctrls)
+{
+       struct solo_enc_fh *fh = priv;
+       struct solo_enc_dev *solo_enc = fh->enc;
+       int i;
+
+       for (i = 0; i < ctrls->count; i++) {
+               struct v4l2_ext_control *ctrl = (ctrls->controls + i);
+               int err;
+
+               switch (ctrl->id) {
+               case V4L2_CID_RDS_TX_RADIO_TEXT:
+                       if (ctrl->size < OSD_TEXT_MAX) {
+                               ctrl->size = OSD_TEXT_MAX;
+                               err = -ENOSPC;
+                       } else {
+                               err = copy_to_user(ctrl->string,
+                                                  solo_enc->osd_text,
+                                                  OSD_TEXT_MAX);
+                       }
+                       break;
+               default:
+                       err = -EINVAL;
+               }
+
+               if (err < 0) {
+                       ctrls->error_idx = i;
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static const struct v4l2_file_operations solo_enc_fops = {
+       .owner                  = THIS_MODULE,
+       .open                   = solo_enc_open,
+       .release                = solo_enc_release,
+       .read                   = solo_enc_read,
+       .poll                   = solo_enc_poll,
+       .mmap                   = solo_enc_mmap,
+       .ioctl                  = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
+       .vidioc_querycap                = solo_enc_querycap,
+       .vidioc_s_std                   = solo_enc_s_std,
+       /* Input callbacks */
+       .vidioc_enum_input              = solo_enc_enum_input,
+       .vidioc_s_input                 = solo_enc_set_input,
+       .vidioc_g_input                 = solo_enc_get_input,
+       /* Video capture format callbacks */
+       .vidioc_enum_fmt_vid_cap        = solo_enc_enum_fmt_cap,
+       .vidioc_try_fmt_vid_cap         = solo_enc_try_fmt_cap,
+       .vidioc_s_fmt_vid_cap           = solo_enc_set_fmt_cap,
+       .vidioc_g_fmt_vid_cap           = solo_enc_get_fmt_cap,
+       /* Streaming I/O */
+       .vidioc_reqbufs                 = solo_enc_reqbufs,
+       .vidioc_querybuf                = solo_enc_querybuf,
+       .vidioc_qbuf                    = solo_enc_qbuf,
+       .vidioc_dqbuf                   = solo_enc_dqbuf,
+       .vidioc_streamon                = solo_enc_streamon,
+       .vidioc_streamoff               = solo_enc_streamoff,
+       /* Frame size and interval */
+       .vidioc_enum_framesizes         = solo_enum_framesizes,
+       .vidioc_enum_frameintervals     = solo_enum_frameintervals,
+       /* Video capture parameters */
+       .vidioc_s_parm                  = solo_s_parm,
+       .vidioc_g_parm                  = solo_g_parm,
+       /* Controls */
+       .vidioc_queryctrl               = solo_queryctrl,
+       .vidioc_querymenu               = solo_querymenu,
+       .vidioc_g_ctrl                  = solo_g_ctrl,
+       .vidioc_s_ctrl                  = solo_s_ctrl,
+       .vidioc_g_ext_ctrls             = solo_g_ext_ctrls,
+       .vidioc_s_ext_ctrls             = solo_s_ext_ctrls,
+};
+
+static struct video_device solo_enc_template = {
+       .name                   = SOLO6X10_NAME,
+       .fops                   = &solo_enc_fops,
+       .ioctl_ops              = &solo_enc_ioctl_ops,
+       .minor                  = -1,
+       .release                = video_device_release,
+
+       .tvnorms                = V4L2_STD_NTSC_M | V4L2_STD_PAL_B,
+       .current_norm           = V4L2_STD_NTSC_M,
+};
+
+static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, u8 ch)
+{
+       struct solo_enc_dev *solo_enc;
+       int ret;
+
+       solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
+       if (!solo_enc)
+               return ERR_PTR(-ENOMEM);
+
+       solo_enc->vfd = video_device_alloc();
+       if (!solo_enc->vfd) {
+               kfree(solo_enc);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       solo_enc->solo_dev = solo_dev;
+       solo_enc->ch = ch;
+
+       *solo_enc->vfd = solo_enc_template;
+       solo_enc->vfd->parent = &solo_dev->pdev->dev;
+       ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER,
+                                   video_nr);
+       if (ret < 0) {
+               video_device_release(solo_enc->vfd);
+               kfree(solo_enc);
+               return ERR_PTR(ret);
+       }
+
+       video_set_drvdata(solo_enc->vfd, solo_enc);
+
+       snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
+                "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num,
+                solo_enc->vfd->num);
+
+       if (video_nr != -1)
+               video_nr++;
+
+       spin_lock_init(&solo_enc->lock);
+       init_waitqueue_head(&solo_enc->thread_wait);
+       atomic_set(&solo_enc->readers, 0);
+
+       solo_enc->qp = SOLO_DEFAULT_QP;
+       solo_enc->gop = solo_dev->fps;
+       solo_enc->interval = 1;
+       solo_enc->mode = SOLO_ENC_MODE_CIF;
+       solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
+
+       spin_lock(&solo_enc->lock);
+       solo_update_mode(solo_enc);
+       spin_unlock(&solo_enc->lock);
+
+       return solo_enc;
+}
+
+static void solo_enc_free(struct solo_enc_dev *solo_enc)
+{
+       if (solo_enc == NULL)
+               return;
+
+       video_unregister_device(solo_enc->vfd);
+       kfree(solo_enc);
+}
+
+int solo_enc_v4l2_init(struct solo_dev *solo_dev)
+{
+       int i;
+
+       for (i = 0; i < solo_dev->nr_chans; i++) {
+               solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i);
+               if (IS_ERR(solo_dev->v4l2_enc[i]))
+                       break;
+       }
+
+       if (i != solo_dev->nr_chans) {
+               int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
+               while (i--)
+                       solo_enc_free(solo_dev->v4l2_enc[i]);
+               return ret;
+       }
+
+       /* D1@MAX-FPS * 4 */
+       solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4;
+
+       dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n",
+                solo_dev->v4l2_enc[0]->vfd->num,
+                solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
+
+       return 0;
+}
+
+void solo_enc_v4l2_exit(struct solo_dev *solo_dev)
+{
+       int i;
+
+       solo_irq_off(solo_dev, SOLO_IRQ_MOTION);
+
+       for (i = 0; i < solo_dev->nr_chans; i++)
+               solo_enc_free(solo_dev->v4l2_enc[i]);
+}
diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c
new file mode 100644 (file)
index 0000000..571c3a3
--- /dev/null
@@ -0,0 +1,964 @@
+/*
+ * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
+ * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/videobuf-dma-sg.h>
+#include "solo6x10.h"
+#include "tw28.h"
+
+#define SOLO_HW_BPL            2048
+#define SOLO_DISP_PIX_FIELD    V4L2_FIELD_INTERLACED
+
+/* Image size is two fields, SOLO_HW_BPL is one horizontal line */
+#define solo_vlines(__solo)    (__solo->video_vsize * 2)
+#define solo_image_size(__solo) (solo_bytesperline(__solo) * \
+                                solo_vlines(__solo))
+#define solo_bytesperline(__solo) (__solo->video_hsize * 2)
+
+#define MIN_VID_BUFFERS                4
+
+/* Simple file handle */
+struct solo_filehandle {
+       struct solo_dev         *solo_dev;
+       struct videobuf_queue   vidq;
+       struct task_struct      *kthread;
+       spinlock_t              slock;
+       int                     old_write;
+       struct list_head        vidq_active;
+       struct p2m_desc         desc[SOLO_NR_P2M_DESC];
+       int                     desc_idx;
+};
+
+unsigned video_nr = -1;
+module_param(video_nr, uint, 0644);
+MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)");
+
+static void erase_on(struct solo_dev *solo_dev)
+{
+       solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
+       solo_dev->erasing = 1;
+       solo_dev->frame_blank = 0;
+}
+
+static int erase_off(struct solo_dev *solo_dev)
+{
+       if (!solo_dev->erasing)
+               return 0;
+
+       /* First time around, assert erase off */
+       if (!solo_dev->frame_blank)
+               solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0);
+       /* Keep the erasing flag on for 8 frames minimum */
+       if (solo_dev->frame_blank++ >= 8)
+               solo_dev->erasing = 0;
+
+       return 1;
+}
+
+void solo_video_in_isr(struct solo_dev *solo_dev)
+{
+       solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_VIDEO_IN);
+       wake_up_interruptible(&solo_dev->disp_thread_wait);
+}
+
+static void solo_win_setup(struct solo_dev *solo_dev, u8 ch,
+                          int sx, int sy, int ex, int ey, int scale)
+{
+       if (ch >= solo_dev->nr_chans)
+               return;
+
+       /* Here, we just keep window/channel the same */
+       solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch),
+                      SOLO_VI_WIN_CHANNEL(ch) |
+                      SOLO_VI_WIN_SX(sx) |
+                      SOLO_VI_WIN_EX(ex) |
+                      SOLO_VI_WIN_SCALE(scale));
+
+       solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
+                      SOLO_VI_WIN_SY(sy) |
+                      SOLO_VI_WIN_EY(ey));
+}
+
+static int solo_v4l2_ch_ext_4up(struct solo_dev *solo_dev, u8 idx, int on)
+{
+       u8 ch = idx * 4;
+
+       if (ch >= solo_dev->nr_chans)
+               return -EINVAL;
+
+       if (!on) {
+               u8 i;
+               for (i = ch; i < ch + 4; i++)
+                       solo_win_setup(solo_dev, i, solo_dev->video_hsize,
+                                      solo_vlines(solo_dev),
+                                      solo_dev->video_hsize,
+                                      solo_vlines(solo_dev), 0);
+               return 0;
+       }
+
+       /* Row 1 */
+       solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2,
+                      solo_vlines(solo_dev) / 2, 3);
+       solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0,
+                      solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3);
+       /* Row 2 */
+       solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2,
+                      solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3);
+       solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2,
+                      solo_vlines(solo_dev) / 2, solo_dev->video_hsize,
+                      solo_vlines(solo_dev), 3);
+
+       return 0;
+}
+
+static int solo_v4l2_ch_ext_16up(struct solo_dev *solo_dev, int on)
+{
+       int sy, ysize, hsize, i;
+
+       if (!on) {
+               for (i = 0; i < 16; i++)
+                       solo_win_setup(solo_dev, i, solo_dev->video_hsize,
+                                      solo_vlines(solo_dev),
+                                      solo_dev->video_hsize,
+                                      solo_vlines(solo_dev), 0);
+               return 0;
+       }
+
+       ysize = solo_vlines(solo_dev) / 4;
+       hsize = solo_dev->video_hsize / 4;
+
+       for (sy = 0, i = 0; i < 4; i++, sy += ysize) {
+               solo_win_setup(solo_dev, i * 4, 0, sy, hsize,
+                              sy + ysize, 5);
+               solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy,
+                              hsize * 2, sy + ysize, 5);
+               solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy,
+                              hsize * 3, sy + ysize, 5);
+               solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy,
+                              solo_dev->video_hsize, sy + ysize, 5);
+       }
+
+       return 0;
+}
+
+static int solo_v4l2_ch(struct solo_dev *solo_dev, u8 ch, int on)
+{
+       u8 ext_ch;
+
+       if (ch < solo_dev->nr_chans) {
+               solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize,
+                              on ? 0 : solo_vlines(solo_dev),
+                              solo_dev->video_hsize, solo_vlines(solo_dev),
+                              on ? 1 : 0);
+               return 0;
+       }
+
+       if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
+               return -EINVAL;
+
+       ext_ch = ch - solo_dev->nr_chans;
+
+       /* 4up's first */
+       if (ext_ch < 4)
+               return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on);
+
+       /* Remaining case is 16up for 16-port */
+       return solo_v4l2_ch_ext_16up(solo_dev, on);
+}
+
+static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch)
+{
+       if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
+               return -EINVAL;
+
+       erase_on(solo_dev);
+
+       solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0);
+       solo_v4l2_ch(solo_dev, ch, 1);
+
+       solo_dev->cur_disp_ch = ch;
+
+       return 0;
+}
+
+static void disp_reset_desc(struct solo_filehandle *fh)
+{
+       /* We use desc mode, which ignores desc 0 */
+       memset(fh->desc, 0, sizeof(*fh->desc));
+       fh->desc_idx = 1;
+}
+
+static int disp_flush_descs(struct solo_filehandle *fh)
+{
+       int ret;
+
+       if (!fh->desc_idx)
+               return 0;
+
+       ret = solo_p2m_dma_desc(fh->solo_dev, SOLO_P2M_DMA_ID_DISP,
+                               fh->desc, fh->desc_idx);
+       disp_reset_desc(fh);
+
+       return ret;
+}
+
+static int disp_push_desc(struct solo_filehandle *fh, dma_addr_t dma_addr,
+                     u32 ext_addr, int size, int repeat, int ext_size)
+{
+       if (fh->desc_idx >= SOLO_NR_P2M_DESC) {
+               int ret = disp_flush_descs(fh);
+               if (ret)
+                       return ret;
+       }
+
+       solo_p2m_push_desc(&fh->desc[fh->desc_idx], 0, dma_addr, ext_addr,
+                          size, repeat, ext_size);
+       fh->desc_idx++;
+
+       return 0;
+}
+
+static void solo_fillbuf(struct solo_filehandle *fh,
+                        struct videobuf_buffer *vb)
+{
+       struct solo_dev *solo_dev = fh->solo_dev;
+       struct videobuf_dmabuf *vbuf;
+       unsigned int fdma_addr;
+       int error = 1;
+       int i;
+       struct scatterlist *sg;
+       dma_addr_t sg_dma;
+       int sg_size_left;
+
+       vbuf = videobuf_to_dma(vb);
+       if (!vbuf)
+               goto finish_buf;
+
+       if (erase_off(solo_dev)) {
+               int i;
+
+               /* Just blit to the entire sg list, ignoring size */
+               for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) {
+                       void *p = sg_virt(sg);
+                       size_t len = sg_dma_len(sg);
+
+                       for (i = 0; i < len; i += 2) {
+                               ((u8 *)p)[i] = 0x80;
+                               ((u8 *)p)[i + 1] = 0x00;
+                       }
+               }
+
+               error = 0;
+               goto finish_buf;
+       }
+
+       disp_reset_desc(fh);
+       sg = vbuf->sglist;
+       sg_dma = sg_dma_address(sg);
+       sg_size_left = sg_dma_len(sg);
+
+       fdma_addr = SOLO_DISP_EXT_ADDR + (fh->old_write *
+                       (SOLO_HW_BPL * solo_vlines(solo_dev)));
+
+       for (i = 0; i < solo_vlines(solo_dev); i++) {
+               int line_len = solo_bytesperline(solo_dev);
+               int lines;
+
+               if (!sg_size_left) {
+                       sg = sg_next(sg);
+                       if (sg == NULL)
+                               goto finish_buf;
+                       sg_dma = sg_dma_address(sg);
+                       sg_size_left = sg_dma_len(sg);
+               }
+
+               /* No room for an entire line, so chunk it up */
+               if (sg_size_left < line_len) {
+                       int this_addr = fdma_addr;
+
+                       while (line_len > 0) {
+                               int this_write;
+
+                               if (!sg_size_left) {
+                                       sg = sg_next(sg);
+                                       if (sg == NULL)
+                                               goto finish_buf;
+                                       sg_dma = sg_dma_address(sg);
+                                       sg_size_left = sg_dma_len(sg);
+                               }
+
+                               this_write = min(sg_size_left, line_len);
+
+                               if (disp_push_desc(fh, sg_dma, this_addr,
+                                                  this_write, 0, 0))
+                                       goto finish_buf;
+
+                               line_len -= this_write;
+                               sg_size_left -= this_write;
+                               sg_dma += this_write;
+                               this_addr += this_write;
+                       }
+
+                       fdma_addr += SOLO_HW_BPL;
+                       continue;
+               }
+
+               /* Shove as many lines into a repeating descriptor as possible */
+               lines = min(sg_size_left / line_len,
+                           solo_vlines(solo_dev) - i);
+
+               if (disp_push_desc(fh, sg_dma, fdma_addr, line_len,
+                                  lines - 1, SOLO_HW_BPL))
+                       goto finish_buf;
+
+               i += lines - 1;
+               fdma_addr += SOLO_HW_BPL * lines;
+               sg_dma += lines * line_len;
+               sg_size_left -= lines * line_len;
+       }
+
+       error = disp_flush_descs(fh);
+
+finish_buf:
+       if (error) {
+               vb->state = VIDEOBUF_ERROR;
+       } else {
+               vb->size = solo_vlines(solo_dev) * solo_bytesperline(solo_dev);
+               vb->state = VIDEOBUF_DONE;
+               vb->field_count++;
+               do_gettimeofday(&vb->ts);
+       }
+
+       wake_up(&vb->done);
+
+       return;
+}
+
+static void solo_thread_try(struct solo_filehandle *fh)
+{
+       struct videobuf_buffer *vb;
+       unsigned int cur_write;
+
+       for (;;) {
+               spin_lock(&fh->slock);
+
+               if (list_empty(&fh->vidq_active))
+                       break;
+
+               vb = list_first_entry(&fh->vidq_active, struct videobuf_buffer,
+                                     queue);
+
+               if (!waitqueue_active(&vb->done))
+                       break;
+
+               cur_write = SOLO_VI_STATUS0_PAGE(solo_reg_read(fh->solo_dev,
+                                                SOLO_VI_STATUS0));
+               if (cur_write == fh->old_write)
+                       break;
+
+               fh->old_write = cur_write;
+               list_del(&vb->queue);
+
+               spin_unlock(&fh->slock);
+
+               solo_fillbuf(fh, vb);
+       }
+
+       assert_spin_locked(&fh->slock);
+       spin_unlock(&fh->slock);
+}
+
+static int solo_thread(void *data)
+{
+       struct solo_filehandle *fh = data;
+       struct solo_dev *solo_dev = fh->solo_dev;
+       DECLARE_WAITQUEUE(wait, current);
+
+       set_freezable();
+       add_wait_queue(&solo_dev->disp_thread_wait, &wait);
+
+       for (;;) {
+               long timeout = schedule_timeout_interruptible(HZ);
+               if (timeout == -ERESTARTSYS || kthread_should_stop())
+                       break;
+               solo_thread_try(fh);
+               try_to_freeze();
+       }
+
+       remove_wait_queue(&solo_dev->disp_thread_wait, &wait);
+
+       return 0;
+}
+
+static int solo_start_thread(struct solo_filehandle *fh)
+{
+       fh->kthread = kthread_run(solo_thread, fh, SOLO6X10_NAME "_disp");
+
+       if (IS_ERR(fh->kthread))
+               return PTR_ERR(fh->kthread);
+
+       return 0;
+}
+
+static void solo_stop_thread(struct solo_filehandle *fh)
+{
+       if (fh->kthread) {
+               kthread_stop(fh->kthread);
+               fh->kthread = NULL;
+       }
+}
+
+static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count,
+                         unsigned int *size)
+{
+       struct solo_filehandle *fh = vq->priv_data;
+       struct solo_dev *solo_dev  = fh->solo_dev;
+
+       *size = solo_image_size(solo_dev);
+
+       if (*count < MIN_VID_BUFFERS)
+               *count = MIN_VID_BUFFERS;
+
+       return 0;
+}
+
+static int solo_buf_prepare(struct videobuf_queue *vq,
+                           struct videobuf_buffer *vb, enum v4l2_field field)
+{
+       struct solo_filehandle *fh  = vq->priv_data;
+       struct solo_dev *solo_dev = fh->solo_dev;
+
+       vb->size = solo_image_size(solo_dev);
+       if (vb->baddr != 0 && vb->bsize < vb->size)
+               return -EINVAL;
+
+       /* XXX: These properties only change when queue is idle */
+       vb->width  = solo_dev->video_hsize;
+       vb->height = solo_vlines(solo_dev);
+       vb->bytesperline = solo_bytesperline(solo_dev);
+       vb->field  = field;
+
+       if (vb->state == VIDEOBUF_NEEDS_INIT) {
+               int rc = videobuf_iolock(vq, vb, NULL);
+               if (rc < 0) {
+                       struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+                       videobuf_dma_unmap(vq->dev, dma);
+                       videobuf_dma_free(dma);
+                       vb->state = VIDEOBUF_NEEDS_INIT;
+                       return rc;
+               }
+       }
+       vb->state = VIDEOBUF_PREPARED;
+
+       return 0;
+}
+
+static void solo_buf_queue(struct videobuf_queue *vq,
+                          struct videobuf_buffer *vb)
+{
+       struct solo_filehandle *fh = vq->priv_data;
+       struct solo_dev *solo_dev = fh->solo_dev;
+
+       vb->state = VIDEOBUF_QUEUED;
+       list_add_tail(&vb->queue, &fh->vidq_active);
+       wake_up_interruptible(&solo_dev->disp_thread_wait);
+}
+
+static void solo_buf_release(struct videobuf_queue *vq,
+                            struct videobuf_buffer *vb)
+{
+       struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+       videobuf_dma_unmap(vq->dev, dma);
+       videobuf_dma_free(dma);
+       vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops solo_video_qops = {
+       .buf_setup      = solo_buf_setup,
+       .buf_prepare    = solo_buf_prepare,
+       .buf_queue      = solo_buf_queue,
+       .buf_release    = solo_buf_release,
+};
+
+static unsigned int solo_v4l2_poll(struct file *file,
+                                  struct poll_table_struct *wait)
+{
+       struct solo_filehandle *fh = file->private_data;
+
+       return videobuf_poll_stream(file, &fh->vidq, wait);
+}
+
+static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct solo_filehandle *fh = file->private_data;
+
+       return videobuf_mmap_mapper(&fh->vidq, vma);
+}
+
+static int solo_v4l2_open(struct file *file)
+{
+       struct solo_dev *solo_dev = video_drvdata(file);
+       struct solo_filehandle *fh;
+       int ret;
+
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (fh == NULL)
+               return -ENOMEM;
+
+       spin_lock_init(&fh->slock);
+       INIT_LIST_HEAD(&fh->vidq_active);
+       fh->solo_dev = solo_dev;
+       file->private_data = fh;
+
+       ret = solo_start_thread(fh);
+       if (ret) {
+               kfree(fh);
+               return ret;
+       }
+
+       videobuf_queue_sg_init(&fh->vidq, &solo_video_qops,
+                              &solo_dev->pdev->dev, &fh->slock,
+                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                              SOLO_DISP_PIX_FIELD,
+                              sizeof(struct videobuf_buffer), fh, NULL);
+
+       return 0;
+}
+
+static ssize_t solo_v4l2_read(struct file *file, char __user *data,
+                             size_t count, loff_t *ppos)
+{
+       struct solo_filehandle *fh = file->private_data;
+
+       return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
+                                   file->f_flags & O_NONBLOCK);
+}
+
+static int solo_v4l2_release(struct file *file)
+{
+       struct solo_filehandle *fh = file->private_data;
+
+       videobuf_stop(&fh->vidq);
+       videobuf_mmap_free(&fh->vidq);
+       solo_stop_thread(fh);
+       kfree(fh);
+
+       return 0;
+}
+
+static int solo_querycap(struct file *file, void  *priv,
+                        struct v4l2_capability *cap)
+{
+       struct solo_filehandle  *fh  = priv;
+       struct solo_dev *solo_dev = fh->solo_dev;
+
+       strcpy(cap->driver, SOLO6X10_NAME);
+       strcpy(cap->card, "Softlogic 6x10");
+       snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
+                pci_name(solo_dev->pdev));
+       cap->version = SOLO6X10_VER_NUM;
+       cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
+                               V4L2_CAP_READWRITE |
+                               V4L2_CAP_STREAMING;
+       return 0;
+}
+
+static int solo_enum_ext_input(struct solo_dev *solo_dev,
+                              struct v4l2_input *input)
+{
+       static const char *dispnames_1[] = { "4UP" };
+       static const char *dispnames_2[] = { "4UP-1", "4UP-2" };
+       static const char *dispnames_5[] = {
+               "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP"
+       };
+       const char **dispnames;
+
+       if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext))
+               return -EINVAL;
+
+       if (solo_dev->nr_ext == 5)
+               dispnames = dispnames_5;
+       else if (solo_dev->nr_ext == 2)
+               dispnames = dispnames_2;
+       else
+               dispnames = dispnames_1;
+
+       snprintf(input->name, sizeof(input->name), "Multi %s",
+                dispnames[input->index - solo_dev->nr_chans]);
+
+       return 0;
+}
+
+static int solo_enum_input(struct file *file, void *priv,
+                          struct v4l2_input *input)
+{
+       struct solo_filehandle *fh  = priv;
+       struct solo_dev *solo_dev = fh->solo_dev;
+
+       if (input->index >= solo_dev->nr_chans) {
+               int ret = solo_enum_ext_input(solo_dev, input);
+               if (ret < 0)
+                       return ret;
+       } else {
+               snprintf(input->name, sizeof(input->name), "Camera %d",
+                        input->index + 1);
+
+               /* We can only check this for normal inputs */
+               if (!tw28_get_video_status(solo_dev, input->index))
+                       input->status = V4L2_IN_ST_NO_SIGNAL;
+       }
+
+       input->type = V4L2_INPUT_TYPE_CAMERA;
+
+       if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
+               input->std = V4L2_STD_NTSC_M;
+       else
+               input->std = V4L2_STD_PAL_B;
+
+       return 0;
+}
+
+static int solo_set_input(struct file *file, void *priv, unsigned int index)
+{
+       struct solo_filehandle *fh = priv;
+
+       return solo_v4l2_set_ch(fh->solo_dev, index);
+}
+
+static int solo_get_input(struct file *file, void *priv, unsigned int *index)
+{
+       struct solo_filehandle *fh = priv;
+
+       *index = fh->solo_dev->cur_disp_ch;
+
+       return 0;
+}
+
+static int solo_enum_fmt_cap(struct file *file, void *priv,
+                            struct v4l2_fmtdesc *f)
+{
+       if (f->index)
+               return -EINVAL;
+
+       f->pixelformat = V4L2_PIX_FMT_UYVY;
+       strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
+
+       return 0;
+}
+
+static int solo_try_fmt_cap(struct file *file, void *priv,
+                           struct v4l2_format *f)
+{
+       struct solo_filehandle *fh = priv;
+       struct solo_dev *solo_dev = fh->solo_dev;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       int image_size = solo_image_size(solo_dev);
+
+       /* Check supported sizes */
+       if (pix->width != solo_dev->video_hsize)
+               pix->width = solo_dev->video_hsize;
+       if (pix->height != solo_vlines(solo_dev))
+               pix->height = solo_vlines(solo_dev);
+       if (pix->sizeimage != image_size)
+               pix->sizeimage = image_size;
+
+       /* Check formats */
+       if (pix->field == V4L2_FIELD_ANY)
+               pix->field = SOLO_DISP_PIX_FIELD;
+
+       if (pix->pixelformat != V4L2_PIX_FMT_UYVY ||
+           pix->field       != SOLO_DISP_PIX_FIELD ||
+           pix->colorspace  != V4L2_COLORSPACE_SMPTE170M)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int solo_set_fmt_cap(struct file *file, void *priv,
+                           struct v4l2_format *f)
+{
+       struct solo_filehandle *fh = priv;
+
+       if (videobuf_queue_is_busy(&fh->vidq))
+               return -EBUSY;
+
+       /* For right now, if it doesn't match our running config,
+        * then fail */
+       return solo_try_fmt_cap(file, priv, f);
+}
+
+static int solo_get_fmt_cap(struct file *file, void *priv,
+                           struct v4l2_format *f)
+{
+       struct solo_filehandle *fh = priv;
+       struct solo_dev *solo_dev = fh->solo_dev;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+
+       pix->width = solo_dev->video_hsize;
+       pix->height = solo_vlines(solo_dev);
+       pix->pixelformat = V4L2_PIX_FMT_UYVY;
+       pix->field = SOLO_DISP_PIX_FIELD;
+       pix->sizeimage = solo_image_size(solo_dev);
+       pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+       pix->bytesperline = solo_bytesperline(solo_dev);
+
+       return 0;
+}
+
+static int solo_reqbufs(struct file *file, void *priv,
+                       struct v4l2_requestbuffers *req)
+{
+       struct solo_filehandle *fh = priv;
+
+       return videobuf_reqbufs(&fh->vidq, req);
+}
+
+static int solo_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct solo_filehandle *fh = priv;
+
+       return videobuf_querybuf(&fh->vidq, buf);
+}
+
+static int solo_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct solo_filehandle *fh = priv;
+
+       return videobuf_qbuf(&fh->vidq, buf);
+}
+
+static int solo_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct solo_filehandle *fh = priv;
+
+       return videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
+}
+
+static int solo_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct solo_filehandle *fh = priv;
+
+       if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       return videobuf_streamon(&fh->vidq);
+}
+
+static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct solo_filehandle *fh = priv;
+
+       if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       return videobuf_streamoff(&fh->vidq);
+}
+
+static int solo_s_std(struct file *file, void *priv, v4l2_std_id *i)
+{
+       return 0;
+}
+
+static const u32 solo_motion_ctrls[] = {
+       V4L2_CID_MOTION_TRACE,
+       0
+};
+
+static const u32 *solo_ctrl_classes[] = {
+       solo_motion_ctrls,
+       NULL
+};
+
+static int solo_disp_queryctrl(struct file *file, void *priv,
+                              struct v4l2_queryctrl *qc)
+{
+       qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
+       if (!qc->id)
+               return -EINVAL;
+
+       switch (qc->id) {
+#ifdef PRIVATE_CIDS
+       case V4L2_CID_MOTION_TRACE:
+               qc->type = V4L2_CTRL_TYPE_BOOLEAN;
+               qc->minimum = 0;
+               qc->maximum = qc->step = 1;
+               qc->default_value = 0;
+               strlcpy(qc->name, "Motion Detection Trace", sizeof(qc->name));
+               return 0;
+#else
+       case V4L2_CID_MOTION_TRACE:
+               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+#endif
+       }
+       return -EINVAL;
+}
+
+static int solo_disp_g_ctrl(struct file *file, void *priv,
+                           struct v4l2_control *ctrl)
+{
+       struct solo_filehandle *fh = priv;
+       struct solo_dev *solo_dev = fh->solo_dev;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MOTION_TRACE:
+               ctrl->value = solo_reg_read(solo_dev, SOLO_VI_MOTION_BAR)
+                       ? 1 : 0;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int solo_disp_s_ctrl(struct file *file, void *priv,
+                           struct v4l2_control *ctrl)
+{
+       struct solo_filehandle *fh = priv;
+       struct solo_dev *solo_dev = fh->solo_dev;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MOTION_TRACE:
+               if (ctrl->value) {
+                       solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER,
+                                       SOLO_VI_MOTION_Y_ADD |
+                                       SOLO_VI_MOTION_Y_VALUE(0x20) |
+                                       SOLO_VI_MOTION_CB_VALUE(0x10) |
+                                       SOLO_VI_MOTION_CR_VALUE(0x10));
+                       solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR,
+                                       SOLO_VI_MOTION_CR_ADD |
+                                       SOLO_VI_MOTION_Y_VALUE(0x10) |
+                                       SOLO_VI_MOTION_CB_VALUE(0x80) |
+                                       SOLO_VI_MOTION_CR_VALUE(0x10));
+               } else {
+                       solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
+                       solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
+               }
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static const struct v4l2_file_operations solo_v4l2_fops = {
+       .owner                  = THIS_MODULE,
+       .open                   = solo_v4l2_open,
+       .release                = solo_v4l2_release,
+       .read                   = solo_v4l2_read,
+       .poll                   = solo_v4l2_poll,
+       .mmap                   = solo_v4l2_mmap,
+       .ioctl                  = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
+       .vidioc_querycap                = solo_querycap,
+       .vidioc_s_std                   = solo_s_std,
+       /* Input callbacks */
+       .vidioc_enum_input              = solo_enum_input,
+       .vidioc_s_input                 = solo_set_input,
+       .vidioc_g_input                 = solo_get_input,
+       /* Video capture format callbacks */
+       .vidioc_enum_fmt_vid_cap        = solo_enum_fmt_cap,
+       .vidioc_try_fmt_vid_cap         = solo_try_fmt_cap,
+       .vidioc_s_fmt_vid_cap           = solo_set_fmt_cap,
+       .vidioc_g_fmt_vid_cap           = solo_get_fmt_cap,
+       /* Streaming I/O */
+       .vidioc_reqbufs                 = solo_reqbufs,
+       .vidioc_querybuf                = solo_querybuf,
+       .vidioc_qbuf                    = solo_qbuf,
+       .vidioc_dqbuf                   = solo_dqbuf,
+       .vidioc_streamon                = solo_streamon,
+       .vidioc_streamoff               = solo_streamoff,
+       /* Controls */
+       .vidioc_queryctrl               = solo_disp_queryctrl,
+       .vidioc_g_ctrl                  = solo_disp_g_ctrl,
+       .vidioc_s_ctrl                  = solo_disp_s_ctrl,
+};
+
+static struct video_device solo_v4l2_template = {
+       .name                   = SOLO6X10_NAME,
+       .fops                   = &solo_v4l2_fops,
+       .ioctl_ops              = &solo_v4l2_ioctl_ops,
+       .minor                  = -1,
+       .release                = video_device_release,
+
+       .tvnorms                = V4L2_STD_NTSC_M | V4L2_STD_PAL_B,
+       .current_norm           = V4L2_STD_NTSC_M,
+};
+
+int solo_v4l2_init(struct solo_dev *solo_dev)
+{
+       int ret;
+       int i;
+
+       init_waitqueue_head(&solo_dev->disp_thread_wait);
+
+       solo_dev->vfd = video_device_alloc();
+       if (!solo_dev->vfd)
+               return -ENOMEM;
+
+       *solo_dev->vfd = solo_v4l2_template;
+       solo_dev->vfd->parent = &solo_dev->pdev->dev;
+
+       ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, video_nr);
+       if (ret < 0) {
+               video_device_release(solo_dev->vfd);
+               solo_dev->vfd = NULL;
+               return ret;
+       }
+
+       video_set_drvdata(solo_dev->vfd, solo_dev);
+
+       snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
+                SOLO6X10_NAME, solo_dev->vfd->num);
+
+       if (video_nr != -1)
+               video_nr++;
+
+       dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with "
+                "%d inputs (%d extended)\n", solo_dev->vfd->num,
+                solo_dev->nr_chans, solo_dev->nr_ext);
+
+       /* Cycle all the channels and clear */
+       for (i = 0; i < solo_dev->nr_chans; i++) {
+               solo_v4l2_set_ch(solo_dev, i);
+               while (erase_off(solo_dev))
+                       ;/* Do nothing */
+       }
+
+       /* Set the default display channel */
+       solo_v4l2_set_ch(solo_dev, 0);
+       while (erase_off(solo_dev))
+               ;/* Do nothing */
+
+       solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
+
+       return 0;
+}
+
+void solo_v4l2_exit(struct solo_dev *solo_dev)
+{
+       solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
+       if (solo_dev->vfd) {
+               video_unregister_device(solo_dev->vfd);
+               solo_dev->vfd = NULL;
+       }
+}
diff --git a/drivers/staging/solo6x10/Kconfig b/drivers/staging/solo6x10/Kconfig
deleted file mode 100644 (file)
index 03dcac4..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-config SOLO6X10
-       tristate "Softlogic 6x10 MPEG codec cards"
-       depends on PCI && VIDEO_DEV && SND && I2C
-       select VIDEOBUF_DMA_SG
-       select SND_PCM
-       ---help---
-         This driver supports the Softlogic based MPEG-4 and h.264 codec
-         codec cards.
diff --git a/drivers/staging/solo6x10/Makefile b/drivers/staging/solo6x10/Makefile
deleted file mode 100644 (file)
index 72816cf..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-solo6x10-y := core.o i2c.o p2m.o v4l2.o tw28.o gpio.o disp.o enc.o v4l2-enc.o g723.o
-
-obj-$(CONFIG_SOLO6X10) := solo6x10.o
diff --git a/drivers/staging/solo6x10/TODO b/drivers/staging/solo6x10/TODO
deleted file mode 100644 (file)
index 7e6c4fa..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-TODO (staging => main):
-
-       * Motion detection flags need to be moved to v4l2
-       * Some private CIDs need to be moved to v4l2
-
-TODO (general):
-
-       * encoder on/off controls
-       * mpeg cid bitrate mode (vbr/cbr)
-       * mpeg cid bitrate/bitrate-peak
-       * mpeg encode of user data
-       * mpeg decode of user data
-       * switch between 4 frames/irq to 1 when using mjpeg (and then back
-         when not)
-       * implement a CID control for motion areas/thresholds
-       * implement CID controls for mozaic areas
-       * allow for higher level of interval (for < 1 fps)
-       * sound:
-         - implement playback via external sound jack
-         - implement loopback of external sound jack with incoming audio?
-         - implement pause/resume
-
-Plase send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc Ben Collins
-<bcollins@bluecherry.net>
diff --git a/drivers/staging/solo6x10/core.c b/drivers/staging/solo6x10/core.c
deleted file mode 100644 (file)
index f974f64..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include "solo6x10.h"
-#include "tw28.h"
-
-MODULE_DESCRIPTION("Softlogic 6x10 MP4/H.264 Encoder/Decoder V4L2/ALSA Driver");
-MODULE_AUTHOR("Ben Collins <bcollins@bluecherry.net>");
-MODULE_VERSION(SOLO6X10_VERSION);
-MODULE_LICENSE("GPL");
-
-void solo_irq_on(struct solo_dev *solo_dev, u32 mask)
-{
-       solo_dev->irq_mask |= mask;
-       solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask);
-}
-
-void solo_irq_off(struct solo_dev *solo_dev, u32 mask)
-{
-       solo_dev->irq_mask &= ~mask;
-       solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask);
-}
-
-/* XXX We should check the return value of the sub-device ISR's */
-static irqreturn_t solo_isr(int irq, void *data)
-{
-       struct solo_dev *solo_dev = data;
-       u32 status;
-       int i;
-
-       status = solo_reg_read(solo_dev, SOLO_IRQ_STAT);
-       if (!status)
-               return IRQ_NONE;
-
-       if (status & ~solo_dev->irq_mask) {
-               solo_reg_write(solo_dev, SOLO_IRQ_STAT,
-                              status & ~solo_dev->irq_mask);
-               status &= solo_dev->irq_mask;
-       }
-
-       if (status & SOLO_IRQ_PCI_ERR) {
-               u32 err = solo_reg_read(solo_dev, SOLO_PCI_ERR);
-               solo_p2m_error_isr(solo_dev, err);
-               solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_PCI_ERR);
-       }
-
-       for (i = 0; i < SOLO_NR_P2M; i++)
-               if (status & SOLO_IRQ_P2M(i))
-                       solo_p2m_isr(solo_dev, i);
-
-       if (status & SOLO_IRQ_IIC)
-               solo_i2c_isr(solo_dev);
-
-       if (status & SOLO_IRQ_VIDEO_IN)
-               solo_video_in_isr(solo_dev);
-
-       /* Call this first so enc gets detected flag set */
-       if (status & SOLO_IRQ_MOTION)
-               solo_motion_isr(solo_dev);
-
-       if (status & SOLO_IRQ_ENCODER)
-               solo_enc_v4l2_isr(solo_dev);
-
-       if (status & SOLO_IRQ_G723)
-               solo_g723_isr(solo_dev);
-
-       return IRQ_HANDLED;
-}
-
-static void free_solo_dev(struct solo_dev *solo_dev)
-{
-       struct pci_dev *pdev;
-
-       if (!solo_dev)
-               return;
-
-       pdev = solo_dev->pdev;
-
-       /* If we never initialized the PCI device, then nothing else
-        * below here needs cleanup */
-       if (!pdev) {
-               kfree(solo_dev);
-               return;
-       }
-
-       /* Bring down the sub-devices first */
-       solo_g723_exit(solo_dev);
-       solo_enc_v4l2_exit(solo_dev);
-       solo_enc_exit(solo_dev);
-       solo_v4l2_exit(solo_dev);
-       solo_disp_exit(solo_dev);
-       solo_gpio_exit(solo_dev);
-       solo_p2m_exit(solo_dev);
-       solo_i2c_exit(solo_dev);
-
-       /* Now cleanup the PCI device */
-       if (solo_dev->reg_base) {
-               solo_irq_off(solo_dev, ~0);
-               pci_iounmap(pdev, solo_dev->reg_base);
-               free_irq(pdev->irq, solo_dev);
-       }
-
-       pci_release_regions(pdev);
-       pci_disable_device(pdev);
-       pci_set_drvdata(pdev, NULL);
-
-       kfree(solo_dev);
-}
-
-static int __devinit solo_pci_probe(struct pci_dev *pdev,
-                                   const struct pci_device_id *id)
-{
-       struct solo_dev *solo_dev;
-       int ret;
-       int sdram;
-       u8 chip_id;
-       u32 reg;
-
-       solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL);
-       if (solo_dev == NULL)
-               return -ENOMEM;
-
-       solo_dev->pdev = pdev;
-       spin_lock_init(&solo_dev->reg_io_lock);
-       pci_set_drvdata(pdev, solo_dev);
-
-       ret = pci_enable_device(pdev);
-       if (ret)
-               goto fail_probe;
-
-       pci_set_master(pdev);
-
-       ret = pci_request_regions(pdev, SOLO6X10_NAME);
-       if (ret)
-               goto fail_probe;
-
-       solo_dev->reg_base = pci_ioremap_bar(pdev, 0);
-       if (solo_dev->reg_base == NULL) {
-               ret = -ENOMEM;
-               goto fail_probe;
-       }
-
-       chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) &
-                                       SOLO_CHIP_ID_MASK;
-       switch (chip_id) {
-       case 7:
-               solo_dev->nr_chans = 16;
-               solo_dev->nr_ext = 5;
-               break;
-       case 6:
-               solo_dev->nr_chans = 8;
-               solo_dev->nr_ext = 2;
-               break;
-       default:
-               dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, "
-                        "defaulting to 4 channels\n",
-                        chip_id);
-       case 5:
-               solo_dev->nr_chans = 4;
-               solo_dev->nr_ext = 1;
-       }
-
-       solo_dev->flags = id->driver_data;
-
-       /* Disable all interrupts to start */
-       solo_irq_off(solo_dev, ~0);
-
-       reg = SOLO_SYS_CFG_SDRAM64BIT;
-       /* Initial global settings */
-       if (!(solo_dev->flags & FLAGS_6110))
-               reg |= SOLO6010_SYS_CFG_INPUTDIV(25) |
-                       SOLO6010_SYS_CFG_FEEDBACKDIV((SOLO_CLOCK_MHZ * 2) - 2) |
-                       SOLO6010_SYS_CFG_OUTDIV(3);
-       solo_reg_write(solo_dev, SOLO_SYS_CFG, reg);
-
-        if (solo_dev->flags & FLAGS_6110) {
-                u32 sys_clock_MHz = SOLO_CLOCK_MHZ;
-                u32 pll_DIVQ;
-                u32 pll_DIVF;
-
-                if (sys_clock_MHz < 125) {
-                        pll_DIVQ = 3;
-                        pll_DIVF = (sys_clock_MHz * 4) / 3;
-                } else {
-                        pll_DIVQ = 2;
-                        pll_DIVF = (sys_clock_MHz * 2) / 3;
-                }
-
-                solo_reg_write(solo_dev, SOLO6110_PLL_CONFIG,
-                              SOLO6110_PLL_RANGE_5_10MHZ |
-                              SOLO6110_PLL_DIVR(9) |
-                              SOLO6110_PLL_DIVQ_EXP(pll_DIVQ) |
-                              SOLO6110_PLL_DIVF(pll_DIVF) | SOLO6110_PLL_FSEN);
-               mdelay(1);      // PLL Locking time (1ms)
-
-               solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 3 << 8); /* ? */
-        } else
-               solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 1 << 8); /* ? */
-
-       solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, SOLO_CLOCK_MHZ - 1);
-
-       /* PLL locking time of 1ms */
-       mdelay(1);
-
-       ret = request_irq(pdev->irq, solo_isr, IRQF_SHARED, SOLO6X10_NAME,
-                         solo_dev);
-       if (ret)
-               goto fail_probe;
-
-       /* Handle this from the start */
-       solo_irq_on(solo_dev, SOLO_IRQ_PCI_ERR);
-
-       ret = solo_i2c_init(solo_dev);
-       if (ret)
-               goto fail_probe;
-
-       /* Setup the DMA engine */
-       sdram = (solo_dev->nr_chans >= 8) ? 2 : 1;
-       solo_reg_write(solo_dev, SOLO_DMA_CTRL,
-                      SOLO_DMA_CTRL_REFRESH_CYCLE(1) |
-                      SOLO_DMA_CTRL_SDRAM_SIZE(sdram) |
-                      SOLO_DMA_CTRL_SDRAM_CLK_INVERT |
-                      SOLO_DMA_CTRL_READ_CLK_SELECT |
-                      SOLO_DMA_CTRL_LATENCY(1));
-
-       ret = solo_p2m_init(solo_dev);
-       if (ret)
-               goto fail_probe;
-
-       ret = solo_disp_init(solo_dev);
-       if (ret)
-               goto fail_probe;
-
-       ret = solo_gpio_init(solo_dev);
-       if (ret)
-               goto fail_probe;
-
-       ret = solo_tw28_init(solo_dev);
-       if (ret)
-               goto fail_probe;
-
-       ret = solo_v4l2_init(solo_dev);
-       if (ret)
-               goto fail_probe;
-
-       ret = solo_enc_init(solo_dev);
-       if (ret)
-               goto fail_probe;
-
-       ret = solo_enc_v4l2_init(solo_dev);
-       if (ret)
-               goto fail_probe;
-
-       ret = solo_g723_init(solo_dev);
-       if (ret)
-               goto fail_probe;
-
-       return 0;
-
-fail_probe:
-       free_solo_dev(solo_dev);
-       return ret;
-}
-
-static void __devexit solo_pci_remove(struct pci_dev *pdev)
-{
-       struct solo_dev *solo_dev = pci_get_drvdata(pdev);
-
-       free_solo_dev(solo_dev);
-}
-
-static struct pci_device_id solo_id_table[] = {
-       /* 6010 based cards */
-       {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010)},
-       {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6110),
-        .driver_data = FLAGS_6110},
-       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16)},
-       /* 6110 based cards */
-       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8)},
-       {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16)},
-       {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, solo_id_table);
-
-static struct pci_driver solo_pci_driver = {
-       .name = SOLO6X10_NAME,
-       .id_table = solo_id_table,
-       .probe = solo_pci_probe,
-       .remove = solo_pci_remove,
-};
-
-static int __init solo_module_init(void)
-{
-       return pci_register_driver(&solo_pci_driver);
-}
-
-static void __exit solo_module_exit(void)
-{
-       pci_unregister_driver(&solo_pci_driver);
-}
-
-module_init(solo_module_init);
-module_exit(solo_module_exit);
diff --git a/drivers/staging/solo6x10/disp.c b/drivers/staging/solo6x10/disp.c
deleted file mode 100644 (file)
index 884c0eb..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-ioctl.h>
-#include "solo6x10.h"
-
-#define SOLO_VCLK_DELAY                        3
-#define SOLO_PROGRESSIVE_VSIZE         1024
-
-#define SOLO_MOT_THRESH_W              64
-#define SOLO_MOT_THRESH_H              64
-#define SOLO_MOT_THRESH_SIZE           8192
-#define SOLO_MOT_THRESH_REAL           (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H)
-#define SOLO_MOT_FLAG_SIZE             512
-#define SOLO_MOT_FLAG_AREA             (SOLO_MOT_FLAG_SIZE * 32)
-
-static unsigned video_type;
-module_param(video_type, uint, 0644);
-MODULE_PARM_DESC(video_type, "video_type (0 = NTSC/Default, 1 = PAL)");
-
-static void solo_vin_config(struct solo_dev *solo_dev)
-{
-       solo_dev->vin_hstart = 8;
-       solo_dev->vin_vstart = 2;
-
-       solo_reg_write(solo_dev, SOLO_SYS_VCLK,
-                      SOLO_VCLK_SELECT(2) |
-                      SOLO_VCLK_VIN1415_DELAY(SOLO_VCLK_DELAY) |
-                      SOLO_VCLK_VIN1213_DELAY(SOLO_VCLK_DELAY) |
-                      SOLO_VCLK_VIN1011_DELAY(SOLO_VCLK_DELAY) |
-                      SOLO_VCLK_VIN0809_DELAY(SOLO_VCLK_DELAY) |
-                      SOLO_VCLK_VIN0607_DELAY(SOLO_VCLK_DELAY) |
-                      SOLO_VCLK_VIN0405_DELAY(SOLO_VCLK_DELAY) |
-                      SOLO_VCLK_VIN0203_DELAY(SOLO_VCLK_DELAY) |
-                      SOLO_VCLK_VIN0001_DELAY(SOLO_VCLK_DELAY));
-
-       solo_reg_write(solo_dev, SOLO_VI_ACT_I_P,
-                      SOLO_VI_H_START(solo_dev->vin_hstart) |
-                      SOLO_VI_V_START(solo_dev->vin_vstart) |
-                      SOLO_VI_V_STOP(solo_dev->vin_vstart +
-                                     solo_dev->video_vsize));
-
-       solo_reg_write(solo_dev, SOLO_VI_ACT_I_S,
-                      SOLO_VI_H_START(solo_dev->vout_hstart) |
-                      SOLO_VI_V_START(solo_dev->vout_vstart) |
-                      SOLO_VI_V_STOP(solo_dev->vout_vstart +
-                                     solo_dev->video_vsize));
-
-       solo_reg_write(solo_dev, SOLO_VI_ACT_P,
-                      SOLO_VI_H_START(0) |
-                      SOLO_VI_V_START(1) |
-                      SOLO_VI_V_STOP(SOLO_PROGRESSIVE_VSIZE));
-
-       solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT,
-                      SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0));
-
-       solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0);
-       solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2);
-
-       if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
-               solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
-                              SOLO_VI_PB_USER_MODE);
-               solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
-                              SOLO_VI_PB_HSIZE(858) | SOLO_VI_PB_VSIZE(246));
-               solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
-                              SOLO_VI_PB_VSTART(4) |
-                              SOLO_VI_PB_VSTOP(4 + 240));
-       } else {
-               solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG,
-                              SOLO_VI_PB_USER_MODE | SOLO_VI_PB_PAL);
-               solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV,
-                              SOLO_VI_PB_HSIZE(864) | SOLO_VI_PB_VSIZE(294));
-               solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V,
-                              SOLO_VI_PB_VSTART(4) |
-                              SOLO_VI_PB_VSTOP(4 + 288));
-       }
-       solo_reg_write(solo_dev, SOLO_VI_PB_ACT_H, SOLO_VI_PB_HSTART(16) |
-                      SOLO_VI_PB_HSTOP(16 + 720));
-}
-
-static void solo_disp_config(struct solo_dev *solo_dev)
-{
-       solo_dev->vout_hstart = 6;
-       solo_dev->vout_vstart = 8;
-
-       solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR,
-                      (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88);
-       solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR,
-                      (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f);
-       solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR,
-                      (16 << 24) | (128 << 16) | (16 << 8) | 128);
-
-       solo_reg_write(solo_dev, SOLO_VO_FMT_ENC,
-                      solo_dev->video_type |
-                      SOLO_VO_USER_COLOR_SET_NAV |
-                      SOLO_VO_NA_COLOR_Y(0) |
-                      SOLO_VO_NA_COLOR_CB(0) |
-                      SOLO_VO_NA_COLOR_CR(0));
-
-       solo_reg_write(solo_dev, SOLO_VO_ACT_H,
-                      SOLO_VO_H_START(solo_dev->vout_hstart) |
-                      SOLO_VO_H_STOP(solo_dev->vout_hstart +
-                                     solo_dev->video_hsize));
-
-       solo_reg_write(solo_dev, SOLO_VO_ACT_V,
-                      SOLO_VO_V_START(solo_dev->vout_vstart) |
-                      SOLO_VO_V_STOP(solo_dev->vout_vstart +
-                                     solo_dev->video_vsize));
-
-       solo_reg_write(solo_dev, SOLO_VO_RANGE_HV,
-                      SOLO_VO_H_LEN(solo_dev->video_hsize) |
-                      SOLO_VO_V_LEN(solo_dev->video_vsize));
-
-       solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 5);
-
-       solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON |
-                      SOLO_VO_DISP_ERASE_COUNT(8) |
-                      SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR));
-
-       solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
-
-       /* Enable channels we support */
-       solo_reg_write(solo_dev, SOLO_VI_CH_ENA, (1 << solo_dev->nr_chans) - 1);
-
-       /* Disable the watchdog */
-       solo_reg_write(solo_dev, SOLO_WATCHDOG, 0);
-}
-
-static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off,
-                              u16 val, int reg_size)
-{
-       u16 buf[64];
-       int i;
-       int ret = 0;
-
-       for (i = 0; i < sizeof(buf) >> 1; i++)
-               buf[i] = val;
-
-       for (i = 0; i < reg_size; i += sizeof(buf))
-               ret |= solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_VIN, 1, buf,
-                                   SOLO_MOTION_EXT_ADDR(solo_dev) + off + i,
-                                   sizeof(buf));
-
-       return ret;
-}
-
-void solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val)
-{
-       if (ch > solo_dev->nr_chans)
-               return;
-
-       solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
-                           (ch * SOLO_MOT_THRESH_SIZE * 2),
-                           val, SOLO_MOT_THRESH_REAL);
-}
-
-/* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k
- * threshold and working table for each channel. Atleast that's what the
- * spec says. However, this code (take from rdk) has some mystery 8k
- * block right after the flag area, before the first thresh table. */
-static void solo_motion_config(struct solo_dev *solo_dev)
-{
-       int i;
-
-       for (i = 0; i < solo_dev->nr_chans; i++) {
-               /* Clear motion flag area */
-               solo_dma_vin_region(solo_dev, i * SOLO_MOT_FLAG_SIZE, 0x0000,
-                                   SOLO_MOT_FLAG_SIZE);
-
-               /* Clear working cache table */
-               solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
-                                   SOLO_MOT_THRESH_SIZE +
-                                   (i * SOLO_MOT_THRESH_SIZE * 2),
-                                   0x0000, SOLO_MOT_THRESH_REAL);
-
-               /* Set default threshold table */
-               solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH);
-       }
-
-       /* Default motion settings */
-       solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) |
-                      (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
-       solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL,
-                      SOLO_VI_MOTION_FRAME_COUNT(3) |
-                      SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16)
-                      | /* SOLO_VI_MOTION_INTR_START_STOP | */
-                      SOLO_VI_MOTION_SAMPLE_COUNT(10));
-
-       solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
-       solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
-}
-
-int solo_disp_init(struct solo_dev *solo_dev)
-{
-       int i;
-
-       solo_dev->video_hsize = 704;
-       if (video_type == 0) {
-               solo_dev->video_type = SOLO_VO_FMT_TYPE_NTSC;
-               solo_dev->video_vsize = 240;
-               solo_dev->fps = 30;
-       } else {
-               solo_dev->video_type = SOLO_VO_FMT_TYPE_PAL;
-               solo_dev->video_vsize = 288;
-               solo_dev->fps = 25;
-       }
-
-       solo_vin_config(solo_dev);
-       solo_motion_config(solo_dev);
-       solo_disp_config(solo_dev);
-
-       for (i = 0; i < solo_dev->nr_chans; i++)
-               solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1);
-
-       return 0;
-}
-
-void solo_disp_exit(struct solo_dev *solo_dev)
-{
-       int i;
-
-       solo_irq_off(solo_dev, SOLO_IRQ_MOTION);
-
-       solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0);
-       solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
-       solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
-
-       for (i = 0; i < solo_dev->nr_chans; i++) {
-               solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(i), 0);
-               solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(i), 0);
-               solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 0);
-       }
-
-       /* Set default border */
-       for (i = 0; i < 5; i++)
-               solo_reg_write(solo_dev, SOLO_VO_BORDER_X(i), 0);
-
-       for (i = 0; i < 5; i++)
-               solo_reg_write(solo_dev, SOLO_VO_BORDER_Y(i), 0);
-
-       solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_MASK, 0);
-       solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_MASK, 0);
-
-       solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0);
-       solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0);
-       solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0);
-
-       solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0);
-       solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0);
-       solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0);
-}
diff --git a/drivers/staging/solo6x10/enc.c b/drivers/staging/solo6x10/enc.c
deleted file mode 100644 (file)
index de50259..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include "solo6x10.h"
-#include "osd-font.h"
-
-#define CAPTURE_MAX_BANDWIDTH          32      /* D1 4channel (D1 == 4) */
-#define OSG_BUFFER_SIZE                        1024
-
-#define VI_PROG_HSIZE                  (1280 - 16)
-#define VI_PROG_VSIZE                  (1024 - 16)
-
-static void solo_capture_config(struct solo_dev *solo_dev)
-{
-       int i, j;
-       unsigned long height;
-       unsigned long width;
-       unsigned char *buf;
-
-       solo_reg_write(solo_dev, SOLO_CAP_BASE,
-                      SOLO_CAP_MAX_PAGE(SOLO_CAP_EXT_MAX_PAGE *
-                                        solo_dev->nr_chans) |
-                      SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16));
-       solo_reg_write(solo_dev, SOLO_CAP_BTW,
-                      (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) |
-                      SOLO_CAP_MAX_BANDWIDTH(CAPTURE_MAX_BANDWIDTH));
-
-       /* Set scale 1, 9 dimension */
-       width = solo_dev->video_hsize;
-       height = solo_dev->video_vsize;
-       solo_reg_write(solo_dev, SOLO_DIM_SCALE1,
-                      SOLO_DIM_H_MB_NUM(width / 16) |
-                      SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
-                      SOLO_DIM_V_MB_NUM_FIELD(height / 16));
-
-       /* Set scale 2, 10 dimension */
-       width = solo_dev->video_hsize / 2;
-       height = solo_dev->video_vsize;
-       solo_reg_write(solo_dev, SOLO_DIM_SCALE2,
-                      SOLO_DIM_H_MB_NUM(width / 16) |
-                      SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
-                      SOLO_DIM_V_MB_NUM_FIELD(height / 16));
-
-       /* Set scale 3, 11 dimension */
-       width = solo_dev->video_hsize / 2;
-       height = solo_dev->video_vsize / 2;
-       solo_reg_write(solo_dev, SOLO_DIM_SCALE3,
-                      SOLO_DIM_H_MB_NUM(width / 16) |
-                      SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
-                      SOLO_DIM_V_MB_NUM_FIELD(height / 16));
-
-       /* Set scale 4, 12 dimension */
-       width = solo_dev->video_hsize / 3;
-       height = solo_dev->video_vsize / 3;
-       solo_reg_write(solo_dev, SOLO_DIM_SCALE4,
-                      SOLO_DIM_H_MB_NUM(width / 16) |
-                      SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
-                      SOLO_DIM_V_MB_NUM_FIELD(height / 16));
-
-       /* Set scale 5, 13 dimension */
-       width = solo_dev->video_hsize / 4;
-       height = solo_dev->video_vsize / 2;
-       solo_reg_write(solo_dev, SOLO_DIM_SCALE5,
-                      SOLO_DIM_H_MB_NUM(width / 16) |
-                      SOLO_DIM_V_MB_NUM_FRAME(height / 8) |
-                      SOLO_DIM_V_MB_NUM_FIELD(height / 16));
-
-       /* Progressive */
-       width = VI_PROG_HSIZE;
-       height = VI_PROG_VSIZE;
-       solo_reg_write(solo_dev, SOLO_DIM_PROG,
-                      SOLO_DIM_H_MB_NUM(width / 16) |
-                      SOLO_DIM_V_MB_NUM_FRAME(height / 16) |
-                      SOLO_DIM_V_MB_NUM_FIELD(height / 16));
-
-       /* Clear OSD */
-       solo_reg_write(solo_dev, SOLO_VE_OSD_CH, 0);
-       solo_reg_write(solo_dev, SOLO_VE_OSD_BASE, SOLO_EOSD_EXT_ADDR >> 16);
-       solo_reg_write(solo_dev, SOLO_VE_OSD_CLR,
-                      0xF0 << 16 | 0x80 << 8 | 0x80);
-       solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, 0);
-
-       /* Clear OSG buffer */
-       buf = kzalloc(OSG_BUFFER_SIZE, GFP_KERNEL);
-       if (!buf)
-               return;
-
-       for (i = 0; i < solo_dev->nr_chans; i++) {
-               for (j = 0; j < SOLO_EOSD_EXT_SIZE; j += OSG_BUFFER_SIZE) {
-                       solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_MP4E, 1, buf,
-                                    SOLO_EOSD_EXT_ADDR +
-                                    (i * SOLO_EOSD_EXT_SIZE) + j,
-                                    OSG_BUFFER_SIZE);
-               }
-       }
-       kfree(buf);
-}
-
-int solo_osd_print(struct solo_enc_dev *solo_enc)
-{
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-       char *str = solo_enc->osd_text;
-       u8 *buf;
-       u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH);
-       int len = strlen(str);
-       int i, j;
-       int x = 1, y = 1;
-
-       if (len == 0) {
-               reg &= ~(1 << solo_enc->ch);
-               solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
-               return 0;
-       }
-
-       buf = kzalloc(SOLO_EOSD_EXT_SIZE, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       for (i = 0; i < len; i++) {
-               for (j = 0; j < 16; j++) {
-                       buf[(j*2) + (i%2) + ((x + (i/2)) * 32) + (y * 2048)] =
-                               (solo_osd_font[(str[i] * 4) + (j / 4)]
-                                       >> ((3 - (j % 4)) * 8)) & 0xff;
-               }
-       }
-
-       solo_p2m_dma(solo_dev, 0, 1, buf, SOLO_EOSD_EXT_ADDR +
-                    (solo_enc->ch * SOLO_EOSD_EXT_SIZE), SOLO_EOSD_EXT_SIZE);
-       reg |= (1 << solo_enc->ch);
-       solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
-
-       kfree(buf);
-
-       return 0;
-}
-
-static void solo_jpeg_config(struct solo_dev *solo_dev)
-{
-       u32 reg;
-       if (solo_dev->flags & FLAGS_6110)
-               reg = (4 << 24) | (3 << 16) | (2 << 8) | (1 << 0);
-       else
-               reg = (2 << 24) | (2 << 16) | (2 << 8) | (2 << 0);
-       solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, reg);
-       solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, 0);
-       solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, 0);
-       solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG,
-               (SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) |
-               ((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff));
-       solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff);
-       /* que limit, samp limit, pos limit */
-       solo_reg_write(solo_dev, 0x0688, (0 << 16) | (30 << 8) | 60);
-}
-
-static void solo_mp4e_config(struct solo_dev *solo_dev)
-{
-       int i;
-       u32 reg;
-
-       /* We can only use VE_INTR_CTRL(0) if we want to support mjpeg */
-       solo_reg_write(solo_dev, SOLO_VE_CFG0,
-                      SOLO_VE_INTR_CTRL(0) |
-                      SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) |
-                      SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16));
-
-       solo_reg_write(solo_dev, SOLO_VE_CFG1,
-                      SOLO_VE_INSERT_INDEX | SOLO_VE_MOTION_MODE(0));
-
-       solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0);
-       solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0);
-       solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0);
-       solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0);
-       solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0);
-
-       reg = SOLO_VE_LITTLE_ENDIAN | SOLO_COMP_ATTR_FCODE(1) |
-               SOLO_COMP_TIME_INC(0) | SOLO_COMP_TIME_WIDTH(15);
-       if (solo_dev->flags & FLAGS_6110)
-               reg |= SOLO_DCT_INTERVAL(10);
-       else
-               reg |= SOLO_DCT_INTERVAL(36 / 4);
-       solo_reg_write(solo_dev, SOLO_VE_ATTR, reg);
-
-       for (i = 0; i < solo_dev->nr_chans; i++)
-               solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i),
-                              (SOLO_EREF_EXT_ADDR(solo_dev) +
-                              (i * SOLO_EREF_EXT_SIZE)) >> 16);
-
-       if (solo_dev->flags & FLAGS_6110)
-               solo_reg_write(solo_dev, 0x0634, 0x00040008); /* ? */
-}
-
-int solo_enc_init(struct solo_dev *solo_dev)
-{
-       int i;
-
-       solo_capture_config(solo_dev);
-       solo_mp4e_config(solo_dev);
-       solo_jpeg_config(solo_dev);
-
-       for (i = 0; i < solo_dev->nr_chans; i++) {
-               solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
-               solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
-       }
-
-       solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
-
-       return 0;
-}
-
-void solo_enc_exit(struct solo_dev *solo_dev)
-{
-       int i;
-
-       solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
-
-       for (i = 0; i < solo_dev->nr_chans; i++) {
-               solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
-               solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
-       }
-}
diff --git a/drivers/staging/solo6x10/g723.c b/drivers/staging/solo6x10/g723.c
deleted file mode 100644 (file)
index 59274bf..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/mempool.h>
-#include <linux/poll.h>
-#include <linux/kthread.h>
-#include <linux/slab.h>
-#include <linux/freezer.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/control.h>
-#include "solo6x10.h"
-#include "tw28.h"
-
-#define G723_INTR_ORDER                0
-#define G723_FDMA_PAGES                32
-#define G723_PERIOD_BYTES      48
-#define G723_PERIOD_BLOCK      1024
-#define G723_FRAMES_PER_PAGE   48
-
-/* Sets up channels 16-19 for decoding and 0-15 for encoding */
-#define OUTMODE_MASK           0x300
-
-#define SAMPLERATE             8000
-#define BITRATE                        25
-
-/* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page
- * is broken down to 20 * 48 byte regions (one for each channel possible)
- * with the rest of the page being dummy data. */
-#define MAX_BUFFER             (G723_PERIOD_BYTES * PERIODS_MAX)
-#define IRQ_PAGES              4 /* 0 - 4 */
-#define PERIODS_MIN            (1 << IRQ_PAGES)
-#define PERIODS_MAX            G723_FDMA_PAGES
-
-struct solo_snd_pcm {
-       int             on;
-       spinlock_t      lock;
-       struct solo_dev *solo_dev;
-       unsigned char   g723_buf[G723_PERIOD_BYTES];
-};
-
-static void solo_g723_config(struct solo_dev *solo_dev)
-{
-       int clk_div;
-
-       clk_div = SOLO_CLOCK_MHZ / (SAMPLERATE * (BITRATE * 2) * 2);
-
-       solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE,
-                      SOLO_AUDIO_BITRATE(BITRATE) |
-                      SOLO_AUDIO_CLK_DIV(clk_div));
-
-       solo_reg_write(solo_dev, SOLO_AUDIO_FDMA_INTR,
-                     SOLO_AUDIO_FDMA_INTERVAL(IRQ_PAGES) |
-                     SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER) |
-                     SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16));
-
-       solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL,
-                      SOLO_AUDIO_ENABLE | SOLO_AUDIO_I2S_MODE |
-                      SOLO_AUDIO_I2S_MULTI(3) | SOLO_AUDIO_MODE(OUTMODE_MASK));
-}
-
-void solo_g723_isr(struct solo_dev *solo_dev)
-{
-       struct snd_pcm_str *pstr =
-               &solo_dev->snd_pcm->streams[SNDRV_PCM_STREAM_CAPTURE];
-       struct snd_pcm_substream *ss;
-       struct solo_snd_pcm *solo_pcm;
-
-       solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_G723);
-
-       for (ss = pstr->substream; ss != NULL; ss = ss->next) {
-               if (snd_pcm_substream_chip(ss) == NULL)
-                       continue;
-
-               /* This means open() hasn't been called on this one */
-               if (snd_pcm_substream_chip(ss) == solo_dev)
-                       continue;
-
-               /* Haven't triggered a start yet */
-               solo_pcm = snd_pcm_substream_chip(ss);
-               if (!solo_pcm->on)
-                       continue;
-
-               snd_pcm_period_elapsed(ss);
-       }
-}
-
-static int snd_solo_hw_params(struct snd_pcm_substream *ss,
-                             struct snd_pcm_hw_params *hw_params)
-{
-       return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
-}
-
-static int snd_solo_hw_free(struct snd_pcm_substream *ss)
-{
-       return snd_pcm_lib_free_pages(ss);
-}
-
-static struct snd_pcm_hardware snd_solo_pcm_hw = {
-       .info                   = (SNDRV_PCM_INFO_MMAP |
-                                  SNDRV_PCM_INFO_INTERLEAVED |
-                                  SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                  SNDRV_PCM_INFO_MMAP_VALID),
-       .formats                = SNDRV_PCM_FMTBIT_U8,
-       .rates                  = SNDRV_PCM_RATE_8000,
-       .rate_min               = 8000,
-       .rate_max               = 8000,
-       .channels_min           = 1,
-       .channels_max           = 1,
-       .buffer_bytes_max       = MAX_BUFFER,
-       .period_bytes_min       = G723_PERIOD_BYTES,
-       .period_bytes_max       = G723_PERIOD_BYTES,
-       .periods_min            = PERIODS_MIN,
-       .periods_max            = PERIODS_MAX,
-};
-
-static int snd_solo_pcm_open(struct snd_pcm_substream *ss)
-{
-       struct solo_dev *solo_dev = snd_pcm_substream_chip(ss);
-       struct solo_snd_pcm *solo_pcm;
-
-       solo_pcm = kzalloc(sizeof(*solo_pcm), GFP_KERNEL);
-       if (solo_pcm == NULL)
-               return -ENOMEM;
-
-       spin_lock_init(&solo_pcm->lock);
-       solo_pcm->solo_dev = solo_dev;
-       ss->runtime->hw = snd_solo_pcm_hw;
-
-       snd_pcm_substream_chip(ss) = solo_pcm;
-
-       return 0;
-}
-
-static int snd_solo_pcm_close(struct snd_pcm_substream *ss)
-{
-       struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
-
-       snd_pcm_substream_chip(ss) = solo_pcm->solo_dev;
-       kfree(solo_pcm);
-
-       return 0;
-}
-
-static int snd_solo_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
-{
-       struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
-       struct solo_dev *solo_dev = solo_pcm->solo_dev;
-       int ret = 0;
-
-       spin_lock(&solo_pcm->lock);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               if (solo_pcm->on == 0) {
-                       /* If this is the first user, switch on interrupts */
-                       if (atomic_inc_return(&solo_dev->snd_users) == 1)
-                               solo_irq_on(solo_dev, SOLO_IRQ_G723);
-                       solo_pcm->on = 1;
-               }
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-               if (solo_pcm->on) {
-                       /* If this was our last user, switch them off */
-                       if (atomic_dec_return(&solo_dev->snd_users) == 0)
-                               solo_irq_off(solo_dev, SOLO_IRQ_G723);
-                       solo_pcm->on = 0;
-               }
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       spin_unlock(&solo_pcm->lock);
-
-       return ret;
-}
-
-static int snd_solo_pcm_prepare(struct snd_pcm_substream *ss)
-{
-       return 0;
-}
-
-static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss)
-{
-       struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
-       struct solo_dev *solo_dev = solo_pcm->solo_dev;
-       snd_pcm_uframes_t idx = solo_reg_read(solo_dev, SOLO_AUDIO_STA) & 0x1f;
-
-       return idx * G723_FRAMES_PER_PAGE;
-}
-
-static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel,
-                            snd_pcm_uframes_t pos, void __user *dst,
-                            snd_pcm_uframes_t count)
-{
-       struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
-       struct solo_dev *solo_dev = solo_pcm->solo_dev;
-       int err, i;
-
-       for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) {
-               int page = (pos / G723_FRAMES_PER_PAGE) + i;
-
-               err = solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_G723E, 0,
-                                  solo_pcm->g723_buf,
-                                  SOLO_G723_EXT_ADDR(solo_dev) +
-                                  (page * G723_PERIOD_BLOCK) +
-                                  (ss->number * G723_PERIOD_BYTES),
-                                  G723_PERIOD_BYTES);
-               if (err)
-                       return err;
-
-               err = copy_to_user(dst + (i * G723_PERIOD_BYTES),
-                                  solo_pcm->g723_buf, G723_PERIOD_BYTES);
-
-               if (err)
-                       return -EFAULT;
-       }
-
-       return 0;
-}
-
-static struct snd_pcm_ops snd_solo_pcm_ops = {
-       .open = snd_solo_pcm_open,
-       .close = snd_solo_pcm_close,
-       .ioctl = snd_pcm_lib_ioctl,
-       .hw_params = snd_solo_hw_params,
-       .hw_free = snd_solo_hw_free,
-       .prepare = snd_solo_pcm_prepare,
-       .trigger = snd_solo_pcm_trigger,
-       .pointer = snd_solo_pcm_pointer,
-       .copy = snd_solo_pcm_copy,
-};
-
-static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol,
-                                       struct snd_ctl_elem_info *info)
-{
-       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       info->count = 1;
-       info->value.integer.min = 0;
-       info->value.integer.max = 15;
-       info->value.integer.step = 1;
-
-       return 0;
-}
-
-static int snd_solo_capture_volume_get(struct snd_kcontrol *kcontrol,
-                                      struct snd_ctl_elem_value *value)
-{
-       struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol);
-       u8 ch = value->id.numid - 1;
-
-       value->value.integer.value[0] = tw28_get_audio_gain(solo_dev, ch);
-
-       return 0;
-}
-
-static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol,
-                                      struct snd_ctl_elem_value *value)
-{
-       struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol);
-       u8 ch = value->id.numid - 1;
-       u8 old_val;
-
-       old_val = tw28_get_audio_gain(solo_dev, ch);
-       if (old_val == value->value.integer.value[0])
-               return 0;
-
-       tw28_set_audio_gain(solo_dev, ch, value->value.integer.value[0]);
-
-       return 1;
-}
-
-static struct snd_kcontrol_new snd_solo_capture_volume = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Capture Volume",
-       .info = snd_solo_capture_volume_info,
-       .get = snd_solo_capture_volume_get,
-       .put = snd_solo_capture_volume_put,
-};
-
-static int solo_snd_pcm_init(struct solo_dev *solo_dev)
-{
-       struct snd_card *card = solo_dev->snd_card;
-       struct snd_pcm *pcm;
-       struct snd_pcm_substream *ss;
-       int ret;
-       int i;
-
-       ret = snd_pcm_new(card, card->driver, 0, 0, solo_dev->nr_chans,
-                         &pcm);
-       if (ret < 0)
-               return ret;
-
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-                       &snd_solo_pcm_ops);
-
-       snd_pcm_chip(pcm) = solo_dev;
-       pcm->info_flags = 0;
-       strcpy(pcm->name, card->shortname);
-
-       for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
-            ss; ss = ss->next, i++)
-               sprintf(ss->name, "Camera #%d Audio", i);
-
-       ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
-                                       SNDRV_DMA_TYPE_CONTINUOUS,
-                                       snd_dma_continuous_data(GFP_KERNEL),
-                                       MAX_BUFFER, MAX_BUFFER);
-       if (ret < 0)
-               return ret;
-
-       solo_dev->snd_pcm = pcm;
-
-       return 0;
-}
-
-int solo_g723_init(struct solo_dev *solo_dev)
-{
-       static struct snd_device_ops ops = { NULL };
-       struct snd_card *card;
-       struct snd_kcontrol_new kctl;
-       char name[32];
-       int ret;
-
-       atomic_set(&solo_dev->snd_users, 0);
-
-       /* Allows for easier mapping between video and audio */
-       sprintf(name, "Softlogic%d", solo_dev->vfd->num);
-
-       ret = snd_card_create(SNDRV_DEFAULT_IDX1, name, THIS_MODULE, 0,
-                             &solo_dev->snd_card);
-       if (ret < 0)
-               return ret;
-
-       card = solo_dev->snd_card;
-
-       strcpy(card->driver, SOLO6X10_NAME);
-       strcpy(card->shortname, "SOLO-6x10 Audio");
-       sprintf(card->longname, "%s on %s IRQ %d", card->shortname,
-               pci_name(solo_dev->pdev), solo_dev->pdev->irq);
-       snd_card_set_dev(card, &solo_dev->pdev->dev);
-
-       ret = snd_device_new(card, SNDRV_DEV_LOWLEVEL, solo_dev, &ops);
-       if (ret < 0)
-               goto snd_error;
-
-       /* Mixer controls */
-       strcpy(card->mixername, "SOLO-6x10");
-       kctl = snd_solo_capture_volume;
-       kctl.count = solo_dev->nr_chans;
-       ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev));
-       if (ret < 0)
-               return ret;
-
-       ret = solo_snd_pcm_init(solo_dev);
-       if (ret < 0)
-               goto snd_error;
-
-       ret = snd_card_register(card);
-       if (ret < 0)
-               goto snd_error;
-
-       solo_g723_config(solo_dev);
-
-       dev_info(&solo_dev->pdev->dev, "Alsa sound card as %s\n", name);
-
-       return 0;
-
-snd_error:
-       snd_card_free(card);
-       return ret;
-}
-
-void solo_g723_exit(struct solo_dev *solo_dev)
-{
-       solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, 0);
-       solo_irq_off(solo_dev, SOLO_IRQ_G723);
-
-       snd_card_free(solo_dev->snd_card);
-}
diff --git a/drivers/staging/solo6x10/gpio.c b/drivers/staging/solo6x10/gpio.c
deleted file mode 100644 (file)
index 0925e6f..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <asm/uaccess.h>
-#include "solo6x10.h"
-
-static void solo_gpio_mode(struct solo_dev *solo_dev,
-                          unsigned int port_mask, unsigned int mode)
-{
-       int port;
-       unsigned int ret;
-
-       ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0);
-
-       /* To set gpio */
-       for (port = 0; port < 16; port++) {
-               if (!((1 << port) & port_mask))
-                       continue;
-
-               ret &= (~(3 << (port << 1)));
-               ret |= ((mode & 3) << (port << 1));
-       }
-
-       solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_0, ret);
-
-       /* To set extended gpio - sensor */
-       ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1);
-
-       for (port = 0; port < 16; port++) {
-               if (!((1 << (port + 16)) & port_mask))
-                       continue;
-
-               if (!mode)
-                       ret &= ~(1 << port);
-               else
-                       ret |= 1 << port;
-       }
-
-       solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret);
-}
-
-static void solo_gpio_set(struct solo_dev *solo_dev, unsigned int value)
-{
-       solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
-                      solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) | value);
-}
-
-static void solo_gpio_clear(struct solo_dev *solo_dev, unsigned int value)
-{
-       solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
-                      solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) & ~value);
-}
-
-static void solo_gpio_config(struct solo_dev *solo_dev)
-{
-       /* Video reset */
-       solo_gpio_mode(solo_dev, 0x30, 1);
-       solo_gpio_clear(solo_dev, 0x30);
-       udelay(100);
-       solo_gpio_set(solo_dev, 0x30);
-       udelay(100);
-
-       /* Warning: Don't touch the next line unless you're sure of what
-        * you're doing: first four gpio [0-3] are used for video. */
-       solo_gpio_mode(solo_dev, 0x0f, 2);
-
-       /* We use bit 8-15 of SOLO_GPIO_CONFIG_0 for relay purposes */
-       solo_gpio_mode(solo_dev, 0xff00, 1);
-
-       /* Initially set relay status to 0 */
-       solo_gpio_clear(solo_dev, 0xff00);
-}
-
-int solo_gpio_init(struct solo_dev *solo_dev)
-{
-       solo_gpio_config(solo_dev);
-       return 0;
-}
-
-void solo_gpio_exit(struct solo_dev *solo_dev)
-{
-       solo_gpio_clear(solo_dev, 0x30);
-       solo_gpio_config(solo_dev);
-}
diff --git a/drivers/staging/solo6x10/i2c.c b/drivers/staging/solo6x10/i2c.c
deleted file mode 100644 (file)
index ef95a50..0000000
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/* XXX: The SOLO6x10 i2c does not have separate interrupts for each i2c
- * channel. The bus can only handle one i2c event at a time. The below handles
- * this all wrong. We should be using the status registers to see if the bus
- * is in use, and have a global lock to check the status register. Also,
- * the bulk of the work should be handled out-of-interrupt. The ugly loops
- * that occur during interrupt scare me. The ISR should merely signal
- * thread context, ACK the interrupt, and move on. -- BenC */
-
-#include <linux/kernel.h>
-#include "solo6x10.h"
-
-u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off)
-{
-       struct i2c_msg msgs[2];
-       u8 data;
-
-       msgs[0].flags = 0;
-       msgs[0].addr = addr;
-       msgs[0].len = 1;
-       msgs[0].buf = &off;
-
-       msgs[1].flags = I2C_M_RD;
-       msgs[1].addr = addr;
-       msgs[1].len = 1;
-       msgs[1].buf = &data;
-
-       i2c_transfer(&solo_dev->i2c_adap[id], msgs, 2);
-
-       return data;
-}
-
-void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr,
-                       u8 off, u8 data)
-{
-       struct i2c_msg msgs;
-       u8 buf[2];
-
-       buf[0] = off;
-       buf[1] = data;
-       msgs.flags = 0;
-       msgs.addr = addr;
-       msgs.len = 2;
-       msgs.buf = buf;
-
-       i2c_transfer(&solo_dev->i2c_adap[id], &msgs, 1);
-}
-
-static void solo_i2c_flush(struct solo_dev *solo_dev, int wr)
-{
-       u32 ctrl;
-
-       ctrl = SOLO_IIC_CH_SET(solo_dev->i2c_id);
-
-       if (solo_dev->i2c_state == IIC_STATE_START)
-               ctrl |= SOLO_IIC_START;
-
-       if (wr) {
-               ctrl |= SOLO_IIC_WRITE;
-       } else {
-               ctrl |= SOLO_IIC_READ;
-               if (!(solo_dev->i2c_msg->flags & I2C_M_NO_RD_ACK))
-                       ctrl |= SOLO_IIC_ACK_EN;
-       }
-
-       if (solo_dev->i2c_msg_ptr == solo_dev->i2c_msg->len)
-               ctrl |= SOLO_IIC_STOP;
-
-       solo_reg_write(solo_dev, SOLO_IIC_CTRL, ctrl);
-}
-
-static void solo_i2c_start(struct solo_dev *solo_dev)
-{
-       u32 addr = solo_dev->i2c_msg->addr << 1;
-
-       if (solo_dev->i2c_msg->flags & I2C_M_RD)
-               addr |= 1;
-
-       solo_dev->i2c_state = IIC_STATE_START;
-       solo_reg_write(solo_dev, SOLO_IIC_TXD, addr);
-       solo_i2c_flush(solo_dev, 1);
-}
-
-static void solo_i2c_stop(struct solo_dev *solo_dev)
-{
-       solo_irq_off(solo_dev, SOLO_IRQ_IIC);
-       solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
-       solo_dev->i2c_state = IIC_STATE_STOP;
-       wake_up(&solo_dev->i2c_wait);
-}
-
-static int solo_i2c_handle_read(struct solo_dev *solo_dev)
-{
-prepare_read:
-       if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
-               solo_i2c_flush(solo_dev, 0);
-               return 0;
-       }
-
-       solo_dev->i2c_msg_ptr = 0;
-       solo_dev->i2c_msg++;
-       solo_dev->i2c_msg_num--;
-
-       if (solo_dev->i2c_msg_num == 0) {
-               solo_i2c_stop(solo_dev);
-               return 0;
-       }
-
-       if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
-               solo_i2c_start(solo_dev);
-       } else {
-               if (solo_dev->i2c_msg->flags & I2C_M_RD)
-                       goto prepare_read;
-               else
-                       solo_i2c_stop(solo_dev);
-       }
-
-       return 0;
-}
-
-static int solo_i2c_handle_write(struct solo_dev *solo_dev)
-{
-retry_write:
-       if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
-               solo_reg_write(solo_dev, SOLO_IIC_TXD,
-                              solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr]);
-               solo_dev->i2c_msg_ptr++;
-               solo_i2c_flush(solo_dev, 1);
-               return 0;
-       }
-
-       solo_dev->i2c_msg_ptr = 0;
-       solo_dev->i2c_msg++;
-       solo_dev->i2c_msg_num--;
-
-       if (solo_dev->i2c_msg_num == 0) {
-               solo_i2c_stop(solo_dev);
-               return 0;
-       }
-
-       if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
-               solo_i2c_start(solo_dev);
-       } else {
-               if (solo_dev->i2c_msg->flags & I2C_M_RD)
-                       solo_i2c_stop(solo_dev);
-               else
-                       goto retry_write;
-       }
-
-       return 0;
-}
-
-int solo_i2c_isr(struct solo_dev *solo_dev)
-{
-       u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL);
-       int ret = -EINVAL;
-
-       solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_IIC);
-
-       if (status & (SOLO_IIC_STATE_TRNS & SOLO_IIC_STATE_SIG_ERR) ||
-           solo_dev->i2c_id < 0) {
-               solo_i2c_stop(solo_dev);
-               return -ENXIO;
-       }
-
-       switch (solo_dev->i2c_state) {
-       case IIC_STATE_START:
-               if (solo_dev->i2c_msg->flags & I2C_M_RD) {
-                       solo_dev->i2c_state = IIC_STATE_READ;
-                       ret = solo_i2c_handle_read(solo_dev);
-                       break;
-               }
-
-               solo_dev->i2c_state = IIC_STATE_WRITE;
-       case IIC_STATE_WRITE:
-               ret = solo_i2c_handle_write(solo_dev);
-               break;
-
-       case IIC_STATE_READ:
-               solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr] =
-                       solo_reg_read(solo_dev, SOLO_IIC_RXD);
-               solo_dev->i2c_msg_ptr++;
-
-               ret = solo_i2c_handle_read(solo_dev);
-               break;
-
-       default:
-               solo_i2c_stop(solo_dev);
-       }
-
-       return ret;
-}
-
-static int solo_i2c_master_xfer(struct i2c_adapter *adap,
-                               struct i2c_msg msgs[], int num)
-{
-       struct solo_dev *solo_dev = adap->algo_data;
-       unsigned long timeout;
-       int ret;
-       int i;
-       DEFINE_WAIT(wait);
-
-       for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
-               if (&solo_dev->i2c_adap[i] == adap)
-                       break;
-       }
-
-       if (i == SOLO_I2C_ADAPTERS)
-               return num; /* XXX Right return value for failure? */
-
-       mutex_lock(&solo_dev->i2c_mutex);
-       solo_dev->i2c_id = i;
-       solo_dev->i2c_msg = msgs;
-       solo_dev->i2c_msg_num = num;
-       solo_dev->i2c_msg_ptr = 0;
-
-       solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
-       solo_irq_on(solo_dev, SOLO_IRQ_IIC);
-       solo_i2c_start(solo_dev);
-
-       timeout = HZ / 2;
-
-       for (;;) {
-               prepare_to_wait(&solo_dev->i2c_wait, &wait, TASK_INTERRUPTIBLE);
-
-               if (solo_dev->i2c_state == IIC_STATE_STOP)
-                       break;
-
-               timeout = schedule_timeout(timeout);
-               if (!timeout)
-                       break;
-
-               if (signal_pending(current))
-                       break;
-       }
-
-       finish_wait(&solo_dev->i2c_wait, &wait);
-       ret = num - solo_dev->i2c_msg_num;
-       solo_dev->i2c_state = IIC_STATE_IDLE;
-       solo_dev->i2c_id = -1;
-
-       mutex_unlock(&solo_dev->i2c_mutex);
-
-       return ret;
-}
-
-static u32 solo_i2c_functionality(struct i2c_adapter *adap)
-{
-       return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm solo_i2c_algo = {
-       .master_xfer    = solo_i2c_master_xfer,
-       .functionality  = solo_i2c_functionality,
-};
-
-int solo_i2c_init(struct solo_dev *solo_dev)
-{
-       int i;
-       int ret;
-
-       solo_reg_write(solo_dev, SOLO_IIC_CFG,
-                      SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE);
-
-       solo_dev->i2c_id = -1;
-       solo_dev->i2c_state = IIC_STATE_IDLE;
-       init_waitqueue_head(&solo_dev->i2c_wait);
-       mutex_init(&solo_dev->i2c_mutex);
-
-       for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
-               struct i2c_adapter *adap = &solo_dev->i2c_adap[i];
-
-               snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d", SOLO6X10_NAME, i);
-               adap->algo = &solo_i2c_algo;
-               adap->algo_data = solo_dev;
-               adap->retries = 1;
-               adap->dev.parent = &solo_dev->pdev->dev;
-
-               ret = i2c_add_adapter(adap);
-               if (ret) {
-                       adap->algo_data = NULL;
-                       break;
-               }
-       }
-
-       if (ret) {
-               for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
-                       if (!solo_dev->i2c_adap[i].algo_data)
-                               break;
-                       i2c_del_adapter(&solo_dev->i2c_adap[i]);
-                       solo_dev->i2c_adap[i].algo_data = NULL;
-               }
-               return ret;
-       }
-
-       dev_info(&solo_dev->pdev->dev, "Enabled %d i2c adapters\n",
-                SOLO_I2C_ADAPTERS);
-
-       return 0;
-}
-
-void solo_i2c_exit(struct solo_dev *solo_dev)
-{
-       int i;
-
-       for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
-               if (!solo_dev->i2c_adap[i].algo_data)
-                       continue;
-               i2c_del_adapter(&solo_dev->i2c_adap[i]);
-               solo_dev->i2c_adap[i].algo_data = NULL;
-       }
-}
diff --git a/drivers/staging/solo6x10/jpeg.h b/drivers/staging/solo6x10/jpeg.h
deleted file mode 100644 (file)
index 50defec..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __SOLO6X10_JPEG_H
-#define __SOLO6X10_JPEG_H
-
-static unsigned char jpeg_header[] = {
-       0xff, 0xd8, 0xff, 0xfe, 0x00, 0x0d, 0x42, 0x6c,
-       0x75, 0x65, 0x63, 0x68, 0x65, 0x72, 0x72, 0x79,
-       0x20, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x20, 0x16,
-       0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, 0x1a, 0x1c,
-       0x24, 0x22, 0x20, 0x26, 0x30, 0x50, 0x34, 0x30,
-       0x2c, 0x2c, 0x30, 0x62, 0x46, 0x4a, 0x3a, 0x50,
-       0x74, 0x66, 0x7a, 0x78, 0x72, 0x66, 0x70, 0x6e,
-       0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, 0xae, 0x8a,
-       0x6e, 0x70, 0xa0, 0xda, 0xa2, 0xae, 0xbe, 0xc4,
-       0xce, 0xd0, 0xce, 0x7c, 0x9a, 0xe2, 0xf2, 0xe0,
-       0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, 0xff, 0xdb,
-       0x00, 0x43, 0x01, 0x22, 0x24, 0x24, 0x30, 0x2a,
-       0x30, 0x5e, 0x34, 0x34, 0x5e, 0xc6, 0x84, 0x70,
-       0x84, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-       0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-       0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-       0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-       0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-       0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-       0xc6, 0xc6, 0xc6, 0xff, 0xc4, 0x01, 0xa2, 0x00,
-       0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
-       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-       0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01,
-       0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
-       0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03,
-       0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41,
-       0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14,
-       0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1,
-       0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62,
-       0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19,
-       0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34,
-       0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,
-       0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54,
-       0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
-       0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74,
-       0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84,
-       0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
-       0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2,
-       0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
-       0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
-       0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
-       0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
-       0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5,
-       0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
-       0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x01,
-       0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-       0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-       0x08, 0x09, 0x0a, 0x0b, 0x11, 0x00, 0x02, 0x01,
-       0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
-       0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02,
-       0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12,
-       0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32,
-       0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1,
-       0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72,
-       0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1,
-       0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29,
-       0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43,
-       0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53,
-       0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63,
-       0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73,
-       0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82,
-       0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
-       0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
-       0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
-       0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
-       0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
-       0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5,
-       0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4,
-       0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3,
-       0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff,
-       0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x02, 0xc0,
-       0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03,
-       0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01,
-       0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
-};
-
-/* This is the byte marker for the start of SOF0: 0xffc0 marker */
-#define SOF0_START     575
-
-#endif /* __SOLO6X10_JPEG_H */
diff --git a/drivers/staging/solo6x10/offsets.h b/drivers/staging/solo6x10/offsets.h
deleted file mode 100644 (file)
index 3d7e569..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __SOLO6X10_OFFSETS_H
-#define __SOLO6X10_OFFSETS_H
-
-/* Offsets and sizes of the external address */
-#define SOLO_DISP_EXT_ADDR                     0x00000000
-#define SOLO_DISP_EXT_SIZE                     0x00480000
-
-#define SOLO_DEC2LIVE_EXT_ADDR (SOLO_DISP_EXT_ADDR + SOLO_DISP_EXT_SIZE)
-#define SOLO_DEC2LIVE_EXT_SIZE                 0x00240000
-
-#define SOLO_OSG_EXT_ADDR (SOLO_DEC2LIVE_EXT_ADDR + SOLO_DEC2LIVE_EXT_SIZE)
-#define SOLO_OSG_EXT_SIZE                      0x00120000
-
-#define SOLO_EOSD_EXT_ADDR (SOLO_OSG_EXT_ADDR + SOLO_OSG_EXT_SIZE)
-#define SOLO_EOSD_EXT_SIZE                     0x00010000
-
-#define SOLO_MOTION_EXT_ADDR(__solo) (SOLO_EOSD_EXT_ADDR +     \
-                                     (SOLO_EOSD_EXT_SIZE * __solo->nr_chans))
-#define SOLO_MOTION_EXT_SIZE                   0x00080000
-
-#define SOLO_G723_EXT_ADDR(__solo) \
-               (SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE)
-#define SOLO_G723_EXT_SIZE                     0x00010000
-
-#define SOLO_CAP_EXT_ADDR(__solo) \
-               (SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE)
-#define SOLO_CAP_EXT_MAX_PAGE                  (18 + 15)
-#define SOLO_CAP_EXT_SIZE                      (SOLO_CAP_EXT_MAX_PAGE * 65536)
-
-/* This +1 is very important -- Why?! -- BenC */
-#define SOLO_EREF_EXT_ADDR(__solo) \
-               (SOLO_CAP_EXT_ADDR(__solo) + \
-                (SOLO_CAP_EXT_SIZE * (__solo->nr_chans + 1)))
-#define SOLO_EREF_EXT_SIZE                     0x00140000
-
-#define SOLO_MP4E_EXT_ADDR(__solo) \
-               (SOLO_EREF_EXT_ADDR(__solo) + \
-                (SOLO_EREF_EXT_SIZE * __solo->nr_chans))
-#define SOLO_MP4E_EXT_SIZE(__solo)             (0x00080000 * __solo->nr_chans)
-
-#define SOLO_DREF_EXT_ADDR(__solo) \
-               (SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo))
-#define SOLO_DREF_EXT_SIZE                     0x00140000
-
-#define SOLO_MP4D_EXT_ADDR(__solo) \
-               (SOLO_DREF_EXT_ADDR(__solo) + \
-                (SOLO_DREF_EXT_SIZE * __solo->nr_chans))
-#define SOLO_MP4D_EXT_SIZE                     0x00080000
-
-#define SOLO_JPEG_EXT_ADDR(__solo) \
-               (SOLO_MP4D_EXT_ADDR(__solo) + \
-                (SOLO_MP4D_EXT_SIZE * __solo->nr_chans))
-#define SOLO_JPEG_EXT_SIZE(__solo)             (0x00080000 * __solo->nr_chans)
-
-#endif /* __SOLO6X10_OFFSETS_H */
diff --git a/drivers/staging/solo6x10/osd-font.h b/drivers/staging/solo6x10/osd-font.h
deleted file mode 100644 (file)
index 591e0e8..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __SOLO6X10_OSD_FONT_H
-#define __SOLO6X10_OSD_FONT_H
-
-static const unsigned int solo_osd_font[] = {
-       0x00000000, 0x0000c0c8, 0xccfefe0c, 0x08000000,
-       0x00000000, 0x10103838, 0x7c7cfefe, 0x00000000, /* 0 */
-       0x00000000, 0xfefe7c7c, 0x38381010, 0x10000000,
-       0x00000000, 0x7c82fefe, 0xfefefe7c, 0x00000000,
-       0x00000000, 0x00001038, 0x10000000, 0x00000000,
-       0x00000000, 0x0010387c, 0xfe7c3810, 0x00000000,
-       0x00000000, 0x00384444, 0x44380000, 0x00000000,
-       0x00000000, 0x38448282, 0x82443800, 0x00000000,
-       0x00000000, 0x007c7c7c, 0x7c7c0000, 0x00000000,
-       0x00000000, 0x6c6c6c6c, 0x6c6c6c6c, 0x00000000,
-       0x00000000, 0x061e7efe, 0xfe7e1e06, 0x00000000,
-       0x00000000, 0xc0f0fcfe, 0xfefcf0c0, 0x00000000,
-       0x00000000, 0xc6cedefe, 0xfedecec6, 0x00000000,
-       0x00000000, 0xc6e6f6fe, 0xfef6e6c6, 0x00000000,
-       0x00000000, 0x12367efe, 0xfe7e3612, 0x00000000,
-       0x00000000, 0x90d8fcfe, 0xfefcd890, 0x00000000,
-       0x00000038, 0x7cc692ba, 0x92c67c38, 0x00000000,
-       0x00000038, 0x7cc6aa92, 0xaac67c38, 0x00000000,
-       0x00000038, 0x7830107c, 0xbaa8680c, 0x00000000,
-       0x00000038, 0x3c18127c, 0xb8382c60, 0x00000000,
-       0x00000044, 0xaa6c8254, 0x38eec67c, 0x00000000,
-       0x00000082, 0x44288244, 0x38c6827c, 0x00000000,
-       0x00000038, 0x444444fe, 0xfeeec6fe, 0x00000000,
-       0x00000018, 0x78187818, 0x3c7e7e3c, 0x00000000,
-       0x00000000, 0x3854929a, 0x82443800, 0x00000000,
-       0x00000000, 0x00c0c8cc, 0xfefe0c08, 0x00000000,
-       0x0000e0a0, 0xe040e00e, 0x8a0ea40e, 0x00000000,
-       0x0000e0a0, 0xe040e00e, 0x0a8e440e, 0x00000000,
-       0x0000007c, 0x82829292, 0x929282fe, 0x00000000,
-       0x000000f8, 0xfc046494, 0x946404fc, 0x00000000,
-       0x0000003f, 0x7f404c52, 0x524c407f, 0x00000000,
-       0x0000007c, 0x82ba82ba, 0x82ba82fe, 0x00000000,
-       0x00000000, 0x00000000, 0x00000000, 0x00000000,
-       0x00000000, 0x183c3c3c, 0x18180018, 0x18000000, /* 32   ! */
-       0x00000066, 0x66240000, 0x00000000, 0x00000000,
-       0x00000000, 0x6c6cfe6c, 0x6c6cfe6c, 0x6c000000, /* 34 " # */
-       0x00001010, 0x7cd6d616, 0x7cd0d6d6, 0x7c101000,
-       0x00000000, 0x0086c660, 0x30180cc6, 0xc2000000, /* 36 $ % */
-       0x00000000, 0x386c6c38, 0xdc766666, 0xdc000000,
-       0x0000000c, 0x0c0c0600, 0x00000000, 0x00000000, /* 38 & ' */
-       0x00000000, 0x30180c0c, 0x0c0c0c18, 0x30000000,
-       0x00000000, 0x0c183030, 0x30303018, 0x0c000000, /* 40 ( ) */
-       0x00000000, 0x0000663c, 0xff3c6600, 0x00000000,
-       0x00000000, 0x00001818, 0x7e181800, 0x00000000, /* 42 * + */
-       0x00000000, 0x00000000, 0x00000e0e, 0x0c060000,
-       0x00000000, 0x00000000, 0x7e000000, 0x00000000, /* 44 , - */
-       0x00000000, 0x00000000, 0x00000006, 0x06000000,
-       0x00000000, 0x80c06030, 0x180c0602, 0x00000000, /* 46 . / */
-       0x0000007c, 0xc6e6f6de, 0xcec6c67c, 0x00000000,
-       0x00000030, 0x383c3030, 0x303030fc, 0x00000000, /* 48 0 1 */
-       0x0000007c, 0xc6c06030, 0x180cc6fe, 0x00000000,
-       0x0000007c, 0xc6c0c07c, 0xc0c0c67c, 0x00000000, /* 50 2 3 */
-       0x00000060, 0x70786c66, 0xfe6060f0, 0x00000000,
-       0x000000fe, 0x0606067e, 0xc0c0c67c, 0x00000000, /* 52 4 5 */
-       0x00000038, 0x0c06067e, 0xc6c6c67c, 0x00000000,
-       0x000000fe, 0xc6c06030, 0x18181818, 0x00000000, /* 54 6 7 */
-       0x0000007c, 0xc6c6c67c, 0xc6c6c67c, 0x00000000,
-       0x0000007c, 0xc6c6c6fc, 0xc0c06038, 0x00000000, /* 56 8 9 */
-       0x00000000, 0x18180000, 0x00181800, 0x00000000,
-       0x00000000, 0x18180000, 0x0018180c, 0x00000000, /* 58 : ; */
-       0x00000060, 0x30180c06, 0x0c183060, 0x00000000,
-       0x00000000, 0x007e0000, 0x007e0000, 0x00000000,
-       0x00000006, 0x0c183060, 0x30180c06, 0x00000000,
-       0x0000007c, 0xc6c66030, 0x30003030, 0x00000000,
-       0x0000007c, 0xc6f6d6d6, 0x7606067c, 0x00000000,
-       0x00000010, 0x386cc6c6, 0xfec6c6c6, 0x00000000, /* 64 @ A */
-       0x0000007e, 0xc6c6c67e, 0xc6c6c67e, 0x00000000,
-       0x00000078, 0xcc060606, 0x0606cc78, 0x00000000, /* 66 */
-       0x0000003e, 0x66c6c6c6, 0xc6c6663e, 0x00000000,
-       0x000000fe, 0x0606063e, 0x060606fe, 0x00000000, /* 68 */
-       0x000000fe, 0x0606063e, 0x06060606, 0x00000000,
-       0x00000078, 0xcc060606, 0xf6c6ccb8, 0x00000000, /* 70 */
-       0x000000c6, 0xc6c6c6fe, 0xc6c6c6c6, 0x00000000,
-       0x0000003c, 0x18181818, 0x1818183c, 0x00000000, /* 72 */
-       0x00000060, 0x60606060, 0x6066663c, 0x00000000,
-       0x000000c6, 0xc666361e, 0x3666c6c6, 0x00000000, /* 74 */
-       0x00000006, 0x06060606, 0x060606fe, 0x00000000,
-       0x000000c6, 0xeefed6c6, 0xc6c6c6c6, 0x00000000, /* 76 */
-       0x000000c6, 0xcedefef6, 0xe6c6c6c6, 0x00000000,
-       0x00000038, 0x6cc6c6c6, 0xc6c66c38, 0x00000000, /* 78 */
-       0x0000007e, 0xc6c6c67e, 0x06060606, 0x00000000,
-       0x00000038, 0x6cc6c6c6, 0xc6d67c38, 0x60000000, /* 80 */
-       0x0000007e, 0xc6c6c67e, 0x66c6c6c6, 0x00000000,
-       0x0000007c, 0xc6c60c38, 0x60c6c67c, 0x00000000, /* 82 */
-       0x0000007e, 0x18181818, 0x18181818, 0x00000000,
-       0x000000c6, 0xc6c6c6c6, 0xc6c6c67c, 0x00000000, /* 84 */
-       0x000000c6, 0xc6c6c6c6, 0xc66c3810, 0x00000000,
-       0x000000c6, 0xc6c6c6c6, 0xd6d6fe6c, 0x00000000, /* 86 */
-       0x000000c6, 0xc6c66c38, 0x6cc6c6c6, 0x00000000,
-       0x00000066, 0x66666666, 0x3c181818, 0x00000000, /* 88 */
-       0x000000fe, 0xc0603018, 0x0c0606fe, 0x00000000,
-       0x0000003c, 0x0c0c0c0c, 0x0c0c0c3c, 0x00000000, /* 90 */
-       0x00000002, 0x060c1830, 0x60c08000, 0x00000000,
-       0x0000003c, 0x30303030, 0x3030303c, 0x00000000, /* 92 */
-       0x00001038, 0x6cc60000, 0x00000000, 0x00000000,
-       0x00000000, 0x00000000, 0x00000000, 0x00fe0000,
-       0x00001818, 0x30000000, 0x00000000, 0x00000000,
-       0x00000000, 0x00003c60, 0x7c66667c, 0x00000000,
-       0x0000000c, 0x0c0c7ccc, 0xcccccc7c, 0x00000000,
-       0x00000000, 0x00007cc6, 0x0606c67c, 0x00000000,
-       0x00000060, 0x60607c66, 0x6666667c, 0x00000000,
-       0x00000000, 0x00007cc6, 0xfe06c67c, 0x00000000,
-       0x00000078, 0x0c0c0c3e, 0x0c0c0c0c, 0x00000000,
-       0x00000000, 0x00007c66, 0x6666667c, 0x60603e00,
-       0x0000000c, 0x0c0c7ccc, 0xcccccccc, 0x00000000,
-       0x00000030, 0x30003830, 0x30303078, 0x00000000,
-       0x00000030, 0x30003c30, 0x30303030, 0x30301f00,
-       0x0000000c, 0x0c0ccc6c, 0x3c6ccccc, 0x00000000,
-       0x00000030, 0x30303030, 0x30303030, 0x00000000,
-       0x00000000, 0x000066fe, 0xd6d6d6d6, 0x00000000,
-       0x00000000, 0x000078cc, 0xcccccccc, 0x00000000,
-       0x00000000, 0x00007cc6, 0xc6c6c67c, 0x00000000,
-       0x00000000, 0x00007ccc, 0xcccccc7c, 0x0c0c0c00,
-       0x00000000, 0x00007c66, 0x6666667c, 0x60606000,
-       0x00000000, 0x000076dc, 0x0c0c0c0c, 0x00000000,
-       0x00000000, 0x00007cc6, 0x1c70c67c, 0x00000000,
-       0x00000000, 0x1818fe18, 0x18181870, 0x00000000,
-       0x00000000, 0x00006666, 0x6666663c, 0x00000000,
-       0x00000000, 0x0000c6c6, 0xc66c3810, 0x00000000,
-       0x00000000, 0x0000c6d6, 0xd6d6fe6c, 0x00000000,
-       0x00000000, 0x0000c66c, 0x38386cc6, 0x00000000,
-       0x00000000, 0x00006666, 0x6666667c, 0x60603e00,
-       0x00000000, 0x0000fe60, 0x30180cfe, 0x00000000,
-       0x00000070, 0x1818180e, 0x18181870, 0x00000000,
-       0x00000018, 0x18181800, 0x18181818, 0x00000000,
-       0x0000000e, 0x18181870, 0x1818180e, 0x00000000,
-       0x000000dc, 0x76000000, 0x00000000, 0x00000000,
-       0x00000000, 0x0010386c, 0xc6c6fe00, 0x00000000
-};
-
-#endif /* __SOLO6X10_OSD_FONT_H */
diff --git a/drivers/staging/solo6x10/p2m.c b/drivers/staging/solo6x10/p2m.c
deleted file mode 100644 (file)
index 56210f0..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/scatterlist.h>
-#include "solo6x10.h"
-
-/* #define SOLO_TEST_P2M */
-
-int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr,
-                void *sys_addr, u32 ext_addr, u32 size)
-{
-       dma_addr_t dma_addr;
-       int ret;
-
-       WARN_ON(!size);
-       BUG_ON(id >= SOLO_NR_P2M);
-
-       if (!size)
-               return -EINVAL;
-
-       dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size,
-                                 wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-
-       ret = solo_p2m_dma_t(solo_dev, id, wr, dma_addr, ext_addr, size);
-
-       pci_unmap_single(solo_dev->pdev, dma_addr, size,
-                        wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-
-       return ret;
-}
-
-int solo_p2m_dma_t(struct solo_dev *solo_dev, u8 id, int wr,
-                  dma_addr_t dma_addr, u32 ext_addr, u32 size)
-{
-       struct p2m_desc *desc = kzalloc(sizeof(*desc) * 2, GFP_DMA);
-       int ret;
-
-       if (desc == NULL)
-               return -ENOMEM;
-
-       solo_p2m_push_desc(&desc[1], wr, dma_addr, ext_addr, size, 0, 0);
-       ret = solo_p2m_dma_desc(solo_dev, id, desc, 2);
-       kfree(desc);
-
-       return ret;
-}
-
-void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr,
-                       u32 ext_addr, u32 size, int repeat, u32 ext_size)
-{
-       desc->ta = cpu_to_le32(dma_addr);
-       desc->fa = cpu_to_le32(ext_addr);
-
-       desc->ext = cpu_to_le32(SOLO_P2M_COPY_SIZE(size >> 2));
-       desc->ctrl = cpu_to_le32(SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) |
-                                (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON);
-
-       /* Ext size only matters when we're repeating */
-       if (repeat) {
-               desc->ext |= cpu_to_le32(SOLO_P2M_EXT_INC(ext_size >> 2));
-               desc->ctrl |=  cpu_to_le32(SOLO_P2M_PCI_INC(size >> 2) |
-                                          SOLO_P2M_REPEAT(repeat));
-       }
-}
-
-int solo_p2m_dma_desc(struct solo_dev *solo_dev, u8 id,
-                     struct p2m_desc *desc, int desc_count)
-{
-       struct solo_p2m_dev *p2m_dev;
-       unsigned int timeout;
-       int ret = 0;
-       u32 config = 0;
-       dma_addr_t desc_dma = 0;
-
-       BUG_ON(id >= SOLO_NR_P2M);
-       BUG_ON(!desc_count || desc_count > SOLO_NR_P2M_DESC);
-
-       p2m_dev = &solo_dev->p2m_dev[id];
-
-       mutex_lock(&p2m_dev->mutex);
-
-       solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
-
-       INIT_COMPLETION(p2m_dev->completion);
-       p2m_dev->error = 0;
-
-       /* Enable the descriptors */
-       config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(id));
-       desc_dma = pci_map_single(solo_dev->pdev, desc,
-                                 desc_count * sizeof(*desc),
-                                 PCI_DMA_TODEVICE);
-       solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), desc_dma);
-       solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), desc_count - 1);
-       solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config |
-                      SOLO_P2M_DESC_MODE);
-
-       /* Should have all descriptors completed from one interrupt */
-       timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ);
-
-       solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
-
-       /* Reset back to non-descriptor mode */
-       solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config);
-       solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), 0);
-       solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), 0);
-       pci_unmap_single(solo_dev->pdev, desc_dma,
-                        desc_count * sizeof(*desc),
-                        PCI_DMA_TODEVICE);
-
-       if (p2m_dev->error)
-               ret = -EIO;
-       else if (timeout == 0)
-               ret = -EAGAIN;
-
-       mutex_unlock(&p2m_dev->mutex);
-
-       WARN_ON_ONCE(ret);
-
-       return ret;
-}
-
-int solo_p2m_dma_sg(struct solo_dev *solo_dev, u8 id,
-                   struct p2m_desc *pdesc, int wr,
-                   struct scatterlist *sg, u32 sg_off,
-                   u32 ext_addr, u32 size)
-{
-       int i;
-       int idx;
-
-       BUG_ON(id >= SOLO_NR_P2M);
-
-       if (WARN_ON_ONCE(!size))
-               return -EINVAL;
-
-       memset(pdesc, 0, sizeof(*pdesc));
-
-       /* Should rewrite this to handle > SOLO_NR_P2M_DESC transactions */
-       for (i = 0, idx = 1; idx < SOLO_NR_P2M_DESC && sg && size > 0;
-            i++, sg = sg_next(sg)) {
-               struct p2m_desc *desc = &pdesc[idx];
-               u32 sg_len = sg_dma_len(sg);
-               u32 len;
-
-               if (sg_off >= sg_len) {
-                       sg_off -= sg_len;
-                       continue;
-               }
-
-               sg_len -= sg_off;
-               len = min(sg_len, size);
-
-               solo_p2m_push_desc(desc, wr, sg_dma_address(sg) + sg_off,
-                                  ext_addr, len, 0, 0);
-
-               size -= len;
-               ext_addr += len;
-               idx++;
-
-               sg_off = 0;
-       }
-
-       WARN_ON_ONCE(size || i >= SOLO_NR_P2M_DESC);
-
-       return solo_p2m_dma_desc(solo_dev, id, pdesc, idx);
-}
-
-#ifdef SOLO_TEST_P2M
-
-#define P2M_TEST_CHAR          0xbe
-
-static unsigned long long p2m_test(struct solo_dev *solo_dev, u8 id,
-                                  u32 base, int size)
-{
-       u8 *wr_buf;
-       u8 *rd_buf;
-       int i;
-       unsigned long long err_cnt = 0;
-
-       wr_buf = kmalloc(size, GFP_KERNEL);
-       if (!wr_buf) {
-               printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n");
-               return size;
-       }
-
-       rd_buf = kmalloc(size, GFP_KERNEL);
-       if (!rd_buf) {
-               printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n");
-               kfree(wr_buf);
-               return size;
-       }
-
-       memset(wr_buf, P2M_TEST_CHAR, size);
-       memset(rd_buf, P2M_TEST_CHAR + 1, size);
-
-       solo_p2m_dma(solo_dev, id, 1, wr_buf, base, size);
-       solo_p2m_dma(solo_dev, id, 0, rd_buf, base, size);
-
-       for (i = 0; i < size; i++)
-               if (wr_buf[i] != rd_buf[i])
-                       err_cnt++;
-
-       kfree(wr_buf);
-       kfree(rd_buf);
-
-       return err_cnt;
-}
-
-#define TEST_CHUNK_SIZE                (8 * 1024)
-
-static void run_p2m_test(struct solo_dev *solo_dev)
-{
-       unsigned long long errs = 0;
-       u32 size = SOLO_JPEG_EXT_ADDR(solo_dev) + SOLO_JPEG_EXT_SIZE(solo_dev);
-       int i, d;
-
-       printk(KERN_WARNING "%s: Testing %u bytes of external ram\n",
-              SOLO6X10_NAME, size);
-
-       for (i = 0; i < size; i += TEST_CHUNK_SIZE)
-               for (d = 0; d < 4; d++)
-                       errs += p2m_test(solo_dev, d, i, TEST_CHUNK_SIZE);
-
-       printk(KERN_WARNING "%s: Found %llu errors during p2m test\n",
-              SOLO6X10_NAME, errs);
-
-       return;
-}
-#else
-#define run_p2m_test(__solo)   do {} while (0)
-#endif
-
-void solo_p2m_isr(struct solo_dev *solo_dev, int id)
-{
-       struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id];
-
-       solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id));
-
-       complete(&p2m_dev->completion);
-}
-
-void solo_p2m_error_isr(struct solo_dev *solo_dev, u32 status)
-{
-       struct solo_p2m_dev *p2m_dev;
-       int i;
-
-       if (!(status & SOLO_PCI_ERR_P2M))
-               return;
-
-       for (i = 0; i < SOLO_NR_P2M; i++) {
-               p2m_dev = &solo_dev->p2m_dev[i];
-               p2m_dev->error = 1;
-               solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
-               complete(&p2m_dev->completion);
-       }
-}
-
-void solo_p2m_exit(struct solo_dev *solo_dev)
-{
-       int i;
-
-       for (i = 0; i < SOLO_NR_P2M; i++)
-               solo_irq_off(solo_dev, SOLO_IRQ_P2M(i));
-}
-
-int solo_p2m_init(struct solo_dev *solo_dev)
-{
-       struct solo_p2m_dev *p2m_dev;
-       int i;
-
-       for (i = 0; i < SOLO_NR_P2M; i++) {
-               p2m_dev = &solo_dev->p2m_dev[i];
-
-               mutex_init(&p2m_dev->mutex);
-               init_completion(&p2m_dev->completion);
-
-               solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
-               solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i),
-                              SOLO_P2M_CSC_16BIT_565 |
-                              SOLO_P2M_DMA_INTERVAL(3) |
-                              SOLO_P2M_DESC_INTR_OPT |
-                              SOLO_P2M_PCI_MASTER_MODE);
-               solo_irq_on(solo_dev, SOLO_IRQ_P2M(i));
-       }
-
-       run_p2m_test(solo_dev);
-
-       return 0;
-}
diff --git a/drivers/staging/solo6x10/registers.h b/drivers/staging/solo6x10/registers.h
deleted file mode 100644 (file)
index aca5444..0000000
+++ /dev/null
@@ -1,637 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __SOLO6X10_REGISTERS_H
-#define __SOLO6X10_REGISTERS_H
-
-#include "offsets.h"
-
-/* Global 6X10 system configuration */
-#define SOLO_SYS_CFG                           0x0000
-#define   SOLO6010_SYS_CFG_FOUT_EN             0x00000001 /* 6010 only */
-#define   SOLO6010_SYS_CFG_PLL_BYPASS          0x00000002 /* 6010 only */
-#define   SOLO6010_SYS_CFG_PLL_PWDN            0x00000004 /* 6010 only */
-#define   SOLO6010_SYS_CFG_OUTDIV(__n)         (((__n) & 0x003) << 3) /* 6010 only */
-#define   SOLO6010_SYS_CFG_FEEDBACKDIV(__n)    (((__n) & 0x1ff) << 5) /* 6010 only */
-#define   SOLO6010_SYS_CFG_INPUTDIV(__n)       (((__n) & 0x01f) << 14) /* 6010 only */
-#define   SOLO_SYS_CFG_CLOCK_DIV               0x00080000
-#define   SOLO_SYS_CFG_NCLK_DELAY(__n)         (((__n) & 0x003) << 24)
-#define   SOLO_SYS_CFG_PCLK_DELAY(__n)         (((__n) & 0x00f) << 26)
-#define   SOLO_SYS_CFG_SDRAM64BIT              0x40000000 /* 6110: must be set */
-#define   SOLO_SYS_CFG_RESET                   0x80000000
-
-#define        SOLO_DMA_CTRL                           0x0004
-#define          SOLO_DMA_CTRL_REFRESH_CYCLE(n)        ((n)<<8)
-/* 0=16/32MB, 1=32/64MB, 2=64/128MB, 3=128/256MB */
-#define          SOLO_DMA_CTRL_SDRAM_SIZE(n)           ((n)<<6)
-#define          SOLO_DMA_CTRL_SDRAM_CLK_INVERT        (1<<5)
-#define          SOLO_DMA_CTRL_STROBE_SELECT           (1<<4)
-#define          SOLO_DMA_CTRL_READ_DATA_SELECT        (1<<3)
-#define          SOLO_DMA_CTRL_READ_CLK_SELECT         (1<<2)
-#define          SOLO_DMA_CTRL_LATENCY(n)              ((n)<<0)
-#define        SOLO_DMA_CTRL1                          0x0008
-
-#define SOLO_SYS_VCLK                          0x000C
-#define          SOLO_VCLK_INVERT                      (1<<22)
-/* 0=sys_clk/4, 1=sys_clk/2, 2=clk_in/2 of system input */
-#define          SOLO_VCLK_SELECT(n)                   ((n)<<20)
-#define          SOLO_VCLK_VIN1415_DELAY(n)            ((n)<<14)
-#define          SOLO_VCLK_VIN1213_DELAY(n)            ((n)<<12)
-#define          SOLO_VCLK_VIN1011_DELAY(n)            ((n)<<10)
-#define          SOLO_VCLK_VIN0809_DELAY(n)            ((n)<<8)
-#define          SOLO_VCLK_VIN0607_DELAY(n)            ((n)<<6)
-#define          SOLO_VCLK_VIN0405_DELAY(n)            ((n)<<4)
-#define          SOLO_VCLK_VIN0203_DELAY(n)            ((n)<<2)
-#define          SOLO_VCLK_VIN0001_DELAY(n)            ((n)<<0)
-
-#define SOLO_IRQ_STAT                          0x0010
-#define SOLO_IRQ_ENABLE                                0x0014
-#define          SOLO_IRQ_P2M(n)                       (1<<((n)+17))
-#define          SOLO_IRQ_GPIO                         (1<<16)
-#define          SOLO_IRQ_VIDEO_LOSS                   (1<<15)
-#define          SOLO_IRQ_VIDEO_IN                     (1<<14)
-#define          SOLO_IRQ_MOTION                       (1<<13)
-#define          SOLO_IRQ_ATA_CMD                      (1<<12)
-#define          SOLO_IRQ_ATA_DIR                      (1<<11)
-#define          SOLO_IRQ_PCI_ERR                      (1<<10)
-#define          SOLO_IRQ_PS2_1                        (1<<9)
-#define          SOLO_IRQ_PS2_0                        (1<<8)
-#define          SOLO_IRQ_SPI                          (1<<7)
-#define          SOLO_IRQ_IIC                          (1<<6)
-#define          SOLO_IRQ_UART(n)                      (1<<((n) + 4))
-#define          SOLO_IRQ_G723                         (1<<3)
-#define          SOLO_IRQ_DECODER                      (1<<1)
-#define          SOLO_IRQ_ENCODER                      (1<<0)
-
-#define SOLO_CHIP_OPTION                       0x001C
-#define   SOLO_CHIP_ID_MASK                    0x00000007
-
-#define SOLO6110_PLL_CONFIG                    0x0020
-#define   SOLO6110_PLL_RANGE_BYPASS            (0 << 20)
-#define   SOLO6110_PLL_RANGE_5_10MHZ           (1 << 20)
-#define   SOLO6110_PLL_RANGE_8_16MHZ           (2 << 20)
-#define   SOLO6110_PLL_RANGE_13_26MHZ          (3 << 20)
-#define   SOLO6110_PLL_RANGE_21_42MHZ          (4 << 20)
-#define   SOLO6110_PLL_RANGE_34_68MHZ          (5 << 20)
-#define   SOLO6110_PLL_RANGE_54_108MHZ         (6 << 20)
-#define   SOLO6110_PLL_RANGE_88_200MHZ         (7 << 20)
-#define   SOLO6110_PLL_DIVR(x)                 (((x) - 1) << 15)
-#define   SOLO6110_PLL_DIVQ_EXP(x)             ((x) << 12)
-#define   SOLO6110_PLL_DIVF(x)                 (((x) - 1) << 4)
-#define   SOLO6110_PLL_RESET                   (1 << 3)
-#define   SOLO6110_PLL_BYPASS                  (1 << 2)
-#define   SOLO6110_PLL_FSEN                    (1 << 1)
-#define   SOLO6110_PLL_FB                      (1 << 0)
-
-#define SOLO_EEPROM_CTRL                       0x0060
-#define          SOLO_EEPROM_ACCESS_EN                 (1<<7)
-#define          SOLO_EEPROM_CS                        (1<<3)
-#define          SOLO_EEPROM_CLK                       (1<<2)
-#define          SOLO_EEPROM_DO                        (1<<1)
-#define          SOLO_EEPROM_DI                        (1<<0)
-#define          SOLO_EEPROM_ENABLE                    (EEPROM_ACCESS_EN | EEPROM_CS)
-
-#define SOLO_PCI_ERR                           0x0070
-#define   SOLO_PCI_ERR_FATAL                   0x00000001
-#define   SOLO_PCI_ERR_PARITY                  0x00000002
-#define   SOLO_PCI_ERR_TARGET                  0x00000004
-#define   SOLO_PCI_ERR_TIMEOUT                 0x00000008
-#define   SOLO_PCI_ERR_P2M                     0x00000010
-#define   SOLO_PCI_ERR_ATA                     0x00000020
-#define   SOLO_PCI_ERR_P2M_DESC                        0x00000040
-#define   SOLO_PCI_ERR_FSM0(__s)               (((__s) >> 16) & 0x0f)
-#define   SOLO_PCI_ERR_FSM1(__s)               (((__s) >> 20) & 0x0f)
-#define   SOLO_PCI_ERR_FSM2(__s)               (((__s) >> 24) & 0x1f)
-
-#define SOLO_P2M_BASE                          0x0080
-
-#define SOLO_P2M_CONFIG(n)                     (0x0080 + ((n)*0x20))
-#define          SOLO_P2M_DMA_INTERVAL(n)              ((n)<<6)/* N*32 clocks */
-#define          SOLO_P2M_CSC_BYTE_REORDER             (1<<5)  /* BGR -> RGB */
-/* 0:r=[14:10] g=[9:5] b=[4:0], 1:r=[15:11] g=[10:5] b=[4:0] */
-#define          SOLO_P2M_CSC_16BIT_565                (1<<4)
-#define          SOLO_P2M_UV_SWAP                      (1<<3)
-#define          SOLO_P2M_PCI_MASTER_MODE              (1<<2)
-#define          SOLO_P2M_DESC_INTR_OPT                (1<<1)  /* 1:Empty, 0:Each */
-#define          SOLO_P2M_DESC_MODE                    (1<<0)
-
-#define SOLO_P2M_DES_ADR(n)                    (0x0084 + ((n)*0x20))
-
-#define SOLO_P2M_DESC_ID(n)                    (0x0088 + ((n)*0x20))
-#define          SOLO_P2M_UPDATE_ID(n)                 ((n)<<0)
-
-#define SOLO_P2M_STATUS(n)                     (0x008C + ((n)*0x20))
-#define          SOLO_P2M_COMMAND_DONE                 (1<<8)
-#define          SOLO_P2M_CURRENT_ID(stat)             (0xff & (stat))
-
-#define SOLO_P2M_CONTROL(n)                    (0x0090 + ((n)*0x20))
-#define          SOLO_P2M_PCI_INC(n)                   ((n)<<20)
-#define          SOLO_P2M_REPEAT(n)                    ((n)<<10)
-/* 0:512, 1:256, 2:128, 3:64, 4:32, 5:128(2page) */
-#define          SOLO_P2M_BURST_SIZE(n)                ((n)<<7)
-#define            SOLO_P2M_BURST_512                  0
-#define            SOLO_P2M_BURST_256                  1
-#define            SOLO_P2M_BURST_128                  2
-#define            SOLO_P2M_BURST_64                   3
-#define            SOLO_P2M_BURST_32                   4
-#define          SOLO_P2M_CSC_16BIT                    (1<<6)  /* 0:24bit, 1:16bit */
-/* 0:Y[0]<-0(OFF), 1:Y[0]<-1(ON), 2:Y[0]<-G[0], 3:Y[0]<-Bit[15] */
-#define          SOLO_P2M_ALPHA_MODE(n)                ((n)<<4)
-#define          SOLO_P2M_CSC_ON                       (1<<3)
-#define          SOLO_P2M_INTERRUPT_REQ                (1<<2)
-#define          SOLO_P2M_WRITE                        (1<<1)
-#define          SOLO_P2M_TRANS_ON                     (1<<0)
-
-#define SOLO_P2M_EXT_CFG(n)                    (0x0094 + ((n)*0x20))
-#define          SOLO_P2M_EXT_INC(n)                   ((n)<<20)
-#define          SOLO_P2M_COPY_SIZE(n)                 ((n)<<0)
-
-#define SOLO_P2M_TAR_ADR(n)                    (0x0098 + ((n)*0x20))
-
-#define SOLO_P2M_EXT_ADR(n)                    (0x009C + ((n)*0x20))
-
-#define SOLO_P2M_BUFFER(i)                     (0x2000 + ((i)*4))
-
-#define SOLO_VI_CH_SWITCH_0                    0x0100
-#define SOLO_VI_CH_SWITCH_1                    0x0104
-#define SOLO_VI_CH_SWITCH_2                    0x0108
-
-#define        SOLO_VI_CH_ENA                          0x010C
-#define        SOLO_VI_CH_FORMAT                       0x0110
-#define          SOLO_VI_FD_SEL_MASK(n)                ((n)<<16)
-#define          SOLO_VI_PROG_MASK(n)                  ((n)<<0)
-
-#define SOLO_VI_FMT_CFG                                0x0114
-#define          SOLO_VI_FMT_CHECK_VCOUNT              (1<<31)
-#define          SOLO_VI_FMT_CHECK_HCOUNT              (1<<30)
-#define   SOLO_VI_FMT_TEST_SIGNAL              (1<<28)
-
-#define        SOLO_VI_PAGE_SW                         0x0118
-#define          SOLO_FI_INV_DISP_LIVE(n)              ((n)<<8)
-#define          SOLO_FI_INV_DISP_OUT(n)               ((n)<<7)
-#define          SOLO_DISP_SYNC_FI(n)                  ((n)<<6)
-#define          SOLO_PIP_PAGE_ADD(n)                  ((n)<<3)
-#define          SOLO_NORMAL_PAGE_ADD(n)               ((n)<<0)
-
-#define        SOLO_VI_ACT_I_P                         0x011C
-#define        SOLO_VI_ACT_I_S                         0x0120
-#define        SOLO_VI_ACT_P                           0x0124
-#define          SOLO_VI_FI_INVERT                     (1<<31)
-#define          SOLO_VI_H_START(n)                    ((n)<<21)
-#define          SOLO_VI_V_START(n)                    ((n)<<11)
-#define          SOLO_VI_V_STOP(n)                     ((n)<<0)
-
-#define SOLO_VI_STATUS0                                0x0128
-#define   SOLO_VI_STATUS0_PAGE(__n)            ((__n) & 0x07)
-#define SOLO_VI_STATUS1                                0x012C
-
-/* XXX: Might be better off in kernel level disp.h */
-#define DISP_PAGE(stat)                                ((stat) & 0x07)
-
-#define SOLO_VI_PB_CONFIG                      0x0130
-#define          SOLO_VI_PB_USER_MODE                  (1<<1)
-#define          SOLO_VI_PB_PAL                        (1<<0)
-#define SOLO_VI_PB_RANGE_HV                    0x0134
-#define          SOLO_VI_PB_HSIZE(h)                   ((h)<<12)
-#define          SOLO_VI_PB_VSIZE(v)                   ((v)<<0)
-#define SOLO_VI_PB_ACT_H                       0x0138
-#define          SOLO_VI_PB_HSTART(n)                  ((n)<<12)
-#define          SOLO_VI_PB_HSTOP(n)                   ((n)<<0)
-#define SOLO_VI_PB_ACT_V                       0x013C
-#define          SOLO_VI_PB_VSTART(n)                  ((n)<<12)
-#define          SOLO_VI_PB_VSTOP(n)                   ((n)<<0)
-
-#define        SOLO_VI_MOSAIC(ch)                      (0x0140 + ((ch)*4))
-#define          SOLO_VI_MOSAIC_SX(x)                  ((x)<<24)
-#define          SOLO_VI_MOSAIC_EX(x)                  ((x)<<16)
-#define          SOLO_VI_MOSAIC_SY(x)                  ((x)<<8)
-#define          SOLO_VI_MOSAIC_EY(x)                  ((x)<<0)
-
-#define        SOLO_VI_WIN_CTRL0(ch)                   (0x0180 + ((ch)*4))
-#define        SOLO_VI_WIN_CTRL1(ch)                   (0x01C0 + ((ch)*4))
-
-#define          SOLO_VI_WIN_CHANNEL(n)                ((n)<<28)
-
-#define          SOLO_VI_WIN_PIP(n)                    ((n)<<27)
-#define          SOLO_VI_WIN_SCALE(n)                  ((n)<<24)
-
-#define          SOLO_VI_WIN_SX(x)                     ((x)<<12)
-#define          SOLO_VI_WIN_EX(x)                     ((x)<<0)
-
-#define          SOLO_VI_WIN_SY(x)                     ((x)<<12)
-#define          SOLO_VI_WIN_EY(x)                     ((x)<<0)
-
-#define        SOLO_VI_WIN_ON(ch)                      (0x0200 + ((ch)*4))
-
-#define SOLO_VI_WIN_SW                         0x0240
-#define SOLO_VI_WIN_LIVE_AUTO_MUTE             0x0244
-
-#define        SOLO_VI_MOT_ADR                         0x0260
-#define          SOLO_VI_MOTION_EN(mask)               ((mask)<<16)
-#define        SOLO_VI_MOT_CTRL                        0x0264
-#define          SOLO_VI_MOTION_FRAME_COUNT(n)         ((n)<<24)
-#define          SOLO_VI_MOTION_SAMPLE_LENGTH(n)       ((n)<<16)
-#define          SOLO_VI_MOTION_INTR_START_STOP        (1<<15)
-#define          SOLO_VI_MOTION_FREEZE_DATA            (1<<14)
-#define          SOLO_VI_MOTION_SAMPLE_COUNT(n)        ((n)<<0)
-#define SOLO_VI_MOT_CLEAR                      0x0268
-#define SOLO_VI_MOT_STATUS                     0x026C
-#define          SOLO_VI_MOTION_CNT(n)                 ((n)<<0)
-#define SOLO_VI_MOTION_BORDER                  0x0270
-#define SOLO_VI_MOTION_BAR                     0x0274
-#define          SOLO_VI_MOTION_Y_SET                  (1<<29)
-#define          SOLO_VI_MOTION_Y_ADD                  (1<<28)
-#define          SOLO_VI_MOTION_CB_SET                 (1<<27)
-#define          SOLO_VI_MOTION_CB_ADD                 (1<<26)
-#define          SOLO_VI_MOTION_CR_SET                 (1<<25)
-#define          SOLO_VI_MOTION_CR_ADD                 (1<<24)
-#define          SOLO_VI_MOTION_Y_VALUE(v)             ((v)<<16)
-#define          SOLO_VI_MOTION_CB_VALUE(v)            ((v)<<8)
-#define          SOLO_VI_MOTION_CR_VALUE(v)            ((v)<<0)
-
-#define        SOLO_VO_FMT_ENC                         0x0300
-#define          SOLO_VO_SCAN_MODE_PROGRESSIVE         (1<<31)
-#define          SOLO_VO_FMT_TYPE_PAL                  (1<<30)
-#define   SOLO_VO_FMT_TYPE_NTSC                        0
-#define          SOLO_VO_USER_SET                      (1<<29)
-
-#define          SOLO_VO_FI_CHANGE                     (1<<20)
-#define          SOLO_VO_USER_COLOR_SET_VSYNC          (1<<19)
-#define          SOLO_VO_USER_COLOR_SET_HSYNC          (1<<18)
-#define          SOLO_VO_USER_COLOR_SET_NAV            (1<<17)
-#define          SOLO_VO_USER_COLOR_SET_NAH            (1<<16)
-#define          SOLO_VO_NA_COLOR_Y(Y)                 ((Y)<<8)
-#define          SOLO_VO_NA_COLOR_CB(CB)               (((CB)/16)<<4)
-#define          SOLO_VO_NA_COLOR_CR(CR)               (((CR)/16)<<0)
-
-#define        SOLO_VO_ACT_H                           0x0304
-#define          SOLO_VO_H_BLANK(n)                    ((n)<<22)
-#define          SOLO_VO_H_START(n)                    ((n)<<11)
-#define          SOLO_VO_H_STOP(n)                     ((n)<<0)
-
-#define        SOLO_VO_ACT_V                           0x0308
-#define          SOLO_VO_V_BLANK(n)                    ((n)<<22)
-#define          SOLO_VO_V_START(n)                    ((n)<<11)
-#define          SOLO_VO_V_STOP(n)                     ((n)<<0)
-
-#define        SOLO_VO_RANGE_HV                        0x030C
-#define          SOLO_VO_SYNC_INVERT                   (1<<24)
-#define          SOLO_VO_HSYNC_INVERT                  (1<<23)
-#define          SOLO_VO_VSYNC_INVERT                  (1<<22)
-#define          SOLO_VO_H_LEN(n)                      ((n)<<11)
-#define          SOLO_VO_V_LEN(n)                      ((n)<<0)
-
-#define        SOLO_VO_DISP_CTRL                       0x0310
-#define          SOLO_VO_DISP_ON                       (1<<31)
-#define          SOLO_VO_DISP_ERASE_COUNT(n)           ((n&0xf)<<24)
-#define          SOLO_VO_DISP_DOUBLE_SCAN              (1<<22)
-#define          SOLO_VO_DISP_SINGLE_PAGE              (1<<21)
-#define          SOLO_VO_DISP_BASE(n)                  (((n)>>16) & 0xffff)
-
-#define SOLO_VO_DISP_ERASE                     0x0314
-#define          SOLO_VO_DISP_ERASE_ON                 (1<<0)
-
-#define        SOLO_VO_ZOOM_CTRL                       0x0318
-#define          SOLO_VO_ZOOM_VER_ON                   (1<<24)
-#define          SOLO_VO_ZOOM_HOR_ON                   (1<<23)
-#define          SOLO_VO_ZOOM_V_COMP                   (1<<22)
-#define          SOLO_VO_ZOOM_SX(h)                    (((h)/2)<<11)
-#define          SOLO_VO_ZOOM_SY(v)                    (((v)/2)<<0)
-
-#define SOLO_VO_FREEZE_CTRL                    0x031C
-#define          SOLO_VO_FREEZE_ON                     (1<<1)
-#define          SOLO_VO_FREEZE_INTERPOLATION          (1<<0)
-
-#define        SOLO_VO_BKG_COLOR                       0x0320
-#define          SOLO_BG_Y(y)                          ((y)<<16)
-#define          SOLO_BG_U(u)                          ((u)<<8)
-#define          SOLO_BG_V(v)                          ((v)<<0)
-
-#define        SOLO_VO_DEINTERLACE                     0x0324
-#define          SOLO_VO_DEINTERLACE_THRESHOLD(n)      ((n)<<8)
-#define          SOLO_VO_DEINTERLACE_EDGE_VALUE(n)     ((n)<<0)
-
-#define SOLO_VO_BORDER_LINE_COLOR              0x0330
-#define SOLO_VO_BORDER_FILL_COLOR              0x0334
-#define SOLO_VO_BORDER_LINE_MASK               0x0338
-#define SOLO_VO_BORDER_FILL_MASK               0x033c
-
-#define SOLO_VO_BORDER_X(n)                    (0x0340+((n)*4))
-#define SOLO_VO_BORDER_Y(n)                    (0x0354+((n)*4))
-
-#define SOLO_VO_CELL_EXT_SET                   0x0368
-#define SOLO_VO_CELL_EXT_START                 0x036c
-#define SOLO_VO_CELL_EXT_STOP                  0x0370
-
-#define SOLO_VO_CELL_EXT_SET2                  0x0374
-#define SOLO_VO_CELL_EXT_START2                        0x0378
-#define SOLO_VO_CELL_EXT_STOP2                 0x037c
-
-#define SOLO_VO_RECTANGLE_CTRL(n)              (0x0368+((n)*12))
-#define SOLO_VO_RECTANGLE_START(n)             (0x036c+((n)*12))
-#define SOLO_VO_RECTANGLE_STOP(n)              (0x0370+((n)*12))
-
-#define SOLO_VO_CURSOR_POS                     (0x0380)
-#define SOLO_VO_CURSOR_CLR                     (0x0384)
-#define SOLO_VO_CURSOR_CLR2                    (0x0388)
-#define SOLO_VO_CURSOR_MASK(id)                        (0x0390+((id)*4))
-
-#define SOLO_VO_EXPANSION(id)                  (0x0250+((id)*4))
-
-#define        SOLO_OSG_CONFIG                         0x03E0
-#define          SOLO_VO_OSG_ON                        (1<<31)
-#define          SOLO_VO_OSG_COLOR_MUTE                (1<<28)
-#define          SOLO_VO_OSG_ALPHA_RATE(n)             ((n)<<22)
-#define          SOLO_VO_OSG_ALPHA_BG_RATE(n)          ((n)<<16)
-#define          SOLO_VO_OSG_BASE(offset)              (((offset)>>16)&0xffff)
-
-#define SOLO_OSG_ERASE                         0x03E4
-#define          SOLO_OSG_ERASE_ON                     (0x80)
-#define          SOLO_OSG_ERASE_OFF                    (0x00)
-
-#define SOLO_VO_OSG_BLINK                      0x03E8
-#define          SOLO_VO_OSG_BLINK_ON                  (1<<1)
-#define          SOLO_VO_OSG_BLINK_INTREVAL18          (1<<0)
-
-#define SOLO_CAP_BASE                          0x0400
-#define          SOLO_CAP_MAX_PAGE(n)                  ((n)<<16)
-#define          SOLO_CAP_BASE_ADDR(n)                 ((n)<<0)
-#define SOLO_CAP_BTW                           0x0404
-#define          SOLO_CAP_PROG_BANDWIDTH(n)            ((n)<<8)
-#define          SOLO_CAP_MAX_BANDWIDTH(n)             ((n)<<0)
-
-#define SOLO_DIM_SCALE1                                0x0408
-#define SOLO_DIM_SCALE2                                0x040C
-#define SOLO_DIM_SCALE3                                0x0410
-#define SOLO_DIM_SCALE4                                0x0414
-#define SOLO_DIM_SCALE5                                0x0418
-#define          SOLO_DIM_V_MB_NUM_FRAME(n)            ((n)<<16)
-#define          SOLO_DIM_V_MB_NUM_FIELD(n)            ((n)<<8)
-#define          SOLO_DIM_H_MB_NUM(n)                  ((n)<<0)
-
-#define SOLO_DIM_PROG                          0x041C
-#define SOLO_CAP_STATUS                                0x0420
-
-#define SOLO_CAP_CH_SCALE(ch)                  (0x0440+((ch)*4))
-#define SOLO_CAP_CH_COMP_ENA_E(ch)             (0x0480+((ch)*4))
-#define SOLO_CAP_CH_INTV(ch)                   (0x04C0+((ch)*4))
-#define SOLO_CAP_CH_INTV_E(ch)                 (0x0500+((ch)*4))
-
-
-#define SOLO_VE_CFG0                           0x0610
-#define          SOLO_VE_TWO_PAGE_MODE                 (1<<31)
-#define          SOLO_VE_INTR_CTRL(n)                  ((n)<<24)
-#define          SOLO_VE_BLOCK_SIZE(n)                 ((n)<<16)
-#define          SOLO_VE_BLOCK_BASE(n)                 ((n)<<0)
-
-#define SOLO_VE_CFG1                           0x0614
-#define   SOLO6110_VE_MPEG_SIZE_H(n)           ((n)<<28) /* 6110 only */
-#define          SOLO6010_VE_BYTE_ALIGN(n)             ((n)<<24) /* 6010 only */
-#define   SOLO6110_VE_JPEG_SIZE_H(n)           ((n)<<20) /* 6110 only */
-#define          SOLO_VE_INSERT_INDEX                  (1<<18)
-#define          SOLO_VE_MOTION_MODE(n)                ((n)<<16)
-#define          SOLO_VE_MOTION_BASE(n)                ((n)<<0)
-
-#define SOLO_VE_WMRK_POLY                      0x061C
-#define SOLO_VE_VMRK_INIT_KEY                  0x0620
-#define SOLO_VE_WMRK_STRL                      0x0624
-#define SOLO_VE_ENCRYP_POLY                    0x0628
-#define SOLO_VE_ENCRYP_INIT                    0x062C
-#define SOLO_VE_ATTR                           0x0630
-#define          SOLO_VE_LITTLE_ENDIAN                 (1<<31)
-#define          SOLO_COMP_ATTR_RN                     (1<<30)
-#define          SOLO_COMP_ATTR_FCODE(n)               ((n)<<27)
-#define          SOLO_COMP_TIME_INC(n)                 ((n)<<25)
-#define          SOLO_COMP_TIME_WIDTH(n)               ((n)<<21)
-#define          SOLO_DCT_INTERVAL(n)                  ((n)<<16)
-
-#define SOLO_VE_STATE(n)                       (0x0640+((n)*4))
-
-#define SOLO_VE_JPEG_QP_TBL                    0x0670
-#define SOLO_VE_JPEG_QP_CH_L                   0x0674
-#define SOLO_VE_JPEG_QP_CH_H                   0x0678
-#define SOLO_VE_JPEG_CFG                       0x067C
-#define SOLO_VE_JPEG_CTRL                      0x0680
-
-#define SOLO_VE_OSD_CH                         0x0690
-#define SOLO_VE_OSD_BASE                       0x0694
-#define SOLO_VE_OSD_CLR                                0x0698
-#define SOLO_VE_OSD_OPT                                0x069C
-
-#define SOLO_VE_CH_INTL(ch)                    (0x0700+((ch)*4))
-#define SOLO6010_VE_CH_MOT(ch)                 (0x0740+((ch)*4)) /* 6010 only */
-#define SOLO_VE_CH_QP(ch)                      (0x0780+((ch)*4))
-#define SOLO_VE_CH_QP_E(ch)                    (0x07C0+((ch)*4))
-#define SOLO_VE_CH_GOP(ch)                     (0x0800+((ch)*4))
-#define SOLO_VE_CH_GOP_E(ch)                   (0x0840+((ch)*4))
-#define SOLO_VE_CH_REF_BASE(ch)                        (0x0880+((ch)*4))
-#define SOLO_VE_CH_REF_BASE_E(ch)              (0x08C0+((ch)*4))
-
-#define SOLO_VE_MPEG4_QUE(n)                   (0x0A00+((n)*8))
-#define SOLO_VE_JPEG_QUE(n)                    (0x0A04+((n)*8))
-
-#define SOLO_VD_CFG0                           0x0900
-#define          SOLO6010_VD_CFG_NO_WRITE_NO_WINDOW    (1<<24) /* 6010 only */
-#define          SOLO_VD_CFG_BUSY_WIAT_CODE            (1<<23)
-#define          SOLO_VD_CFG_BUSY_WIAT_REF             (1<<22)
-#define          SOLO_VD_CFG_BUSY_WIAT_RES             (1<<21)
-#define          SOLO_VD_CFG_BUSY_WIAT_MS              (1<<20)
-#define          SOLO_VD_CFG_SINGLE_MODE               (1<<18)
-#define          SOLO_VD_CFG_SCAL_MANUAL               (1<<17)
-#define          SOLO_VD_CFG_USER_PAGE_CTRL            (1<<16)
-#define          SOLO_VD_CFG_LITTLE_ENDIAN             (1<<15)
-#define          SOLO_VD_CFG_START_FI                  (1<<14)
-#define          SOLO_VD_CFG_ERR_LOCK                  (1<<13)
-#define          SOLO_VD_CFG_ERR_INT_ENA               (1<<12)
-#define          SOLO_VD_CFG_TIME_WIDTH(n)             ((n)<<8)
-#define          SOLO_VD_CFG_DCT_INTERVAL(n)           ((n)<<0)
-
-#define SOLO_VD_CFG1                           0x0904
-
-#define        SOLO_VD_DEINTERLACE                     0x0908
-#define          SOLO_VD_DEINTERLACE_THRESHOLD(n)      ((n)<<8)
-#define          SOLO_VD_DEINTERLACE_EDGE_VALUE(n)     ((n)<<0)
-
-#define SOLO_VD_CODE_ADR                       0x090C
-
-#define SOLO_VD_CTRL                           0x0910
-#define          SOLO_VD_OPER_ON                       (1<<31)
-#define          SOLO_VD_MAX_ITEM(n)                   ((n)<<0)
-
-#define SOLO_VD_STATUS0                                0x0920
-#define          SOLO_VD_STATUS0_INTR_ACK              (1<<22)
-#define          SOLO_VD_STATUS0_INTR_EMPTY            (1<<21)
-#define          SOLO_VD_STATUS0_INTR_ERR              (1<<20)
-
-#define SOLO_VD_STATUS1                                0x0924
-
-#define SOLO_VD_IDX0                           0x0930
-#define          SOLO_VD_IDX_INTERLACE                 (1<<30)
-#define          SOLO_VD_IDX_CHANNEL(n)                ((n)<<24)
-#define          SOLO_VD_IDX_SIZE(n)                   ((n)<<0)
-
-#define SOLO_VD_IDX1                           0x0934
-#define          SOLO_VD_IDX_SRC_SCALE(n)              ((n)<<28)
-#define          SOLO_VD_IDX_WINDOW(n)                 ((n)<<24)
-#define          SOLO_VD_IDX_DEINTERLACE               (1<<16)
-#define          SOLO_VD_IDX_H_BLOCK(n)                ((n)<<8)
-#define          SOLO_VD_IDX_V_BLOCK(n)                ((n)<<0)
-
-#define SOLO_VD_IDX2                           0x0938
-#define          SOLO_VD_IDX_REF_BASE_SIDE             (1<<31)
-#define          SOLO_VD_IDX_REF_BASE(n)               (((n)>>16)&0xffff)
-
-#define SOLO_VD_IDX3                           0x093C
-#define          SOLO_VD_IDX_DISP_SCALE(n)             ((n)<<28)
-#define          SOLO_VD_IDX_INTERLACE_WR              (1<<27)
-#define          SOLO_VD_IDX_INTERPOL                  (1<<26)
-#define          SOLO_VD_IDX_HOR2X                     (1<<25)
-#define          SOLO_VD_IDX_OFFSET_X(n)               ((n)<<12)
-#define          SOLO_VD_IDX_OFFSET_Y(n)               ((n)<<0)
-
-#define SOLO_VD_IDX4                           0x0940
-#define          SOLO_VD_IDX_DEC_WR_PAGE(n)            ((n)<<8)
-#define          SOLO_VD_IDX_DISP_RD_PAGE(n)           ((n)<<0)
-
-#define SOLO_VD_WR_PAGE(n)                     (0x03F0 + ((n) * 4))
-
-
-#define SOLO_GPIO_CONFIG_0                     0x0B00
-#define SOLO_GPIO_CONFIG_1                     0x0B04
-#define SOLO_GPIO_DATA_OUT                     0x0B08
-#define SOLO_GPIO_DATA_IN                      0x0B0C
-#define SOLO_GPIO_INT_ACK_STA                  0x0B10
-#define SOLO_GPIO_INT_ENA                      0x0B14
-#define SOLO_GPIO_INT_CFG_0                    0x0B18
-#define SOLO_GPIO_INT_CFG_1                    0x0B1C
-
-
-#define SOLO_IIC_CFG                           0x0B20
-#define          SOLO_IIC_ENABLE                       (1<<8)
-#define          SOLO_IIC_PRESCALE(n)                  ((n)<<0)
-
-#define SOLO_IIC_CTRL                          0x0B24
-#define          SOLO_IIC_AUTO_CLEAR                   (1<<20)
-#define          SOLO_IIC_STATE_RX_ACK                 (1<<19)
-#define          SOLO_IIC_STATE_BUSY                   (1<<18)
-#define          SOLO_IIC_STATE_SIG_ERR                (1<<17)
-#define          SOLO_IIC_STATE_TRNS                   (1<<16)
-#define          SOLO_IIC_CH_SET(n)                    ((n)<<5)
-#define          SOLO_IIC_ACK_EN                       (1<<4)
-#define          SOLO_IIC_START                        (1<<3)
-#define          SOLO_IIC_STOP                         (1<<2)
-#define          SOLO_IIC_READ                         (1<<1)
-#define          SOLO_IIC_WRITE                        (1<<0)
-
-#define SOLO_IIC_TXD                           0x0B28
-#define SOLO_IIC_RXD                           0x0B2C
-
-/*
- *     UART REGISTER
- */
-#define SOLO_UART_CONTROL(n)                   (0x0BA0 + ((n)*0x20))
-#define          SOLO_UART_CLK_DIV(n)                  ((n)<<24)
-#define          SOLO_MODEM_CTRL_EN                    (1<<20)
-#define          SOLO_PARITY_ERROR_DROP                (1<<18)
-#define          SOLO_IRQ_ERR_EN                       (1<<17)
-#define          SOLO_IRQ_RX_EN                        (1<<16)
-#define          SOLO_IRQ_TX_EN                        (1<<15)
-#define          SOLO_RX_EN                            (1<<14)
-#define          SOLO_TX_EN                            (1<<13)
-#define          SOLO_UART_HALF_DUPLEX                 (1<<12)
-#define          SOLO_UART_LOOPBACK                    (1<<11)
-
-#define          SOLO_BAUDRATE_230400                  ((0<<9)|(0<<6))
-#define          SOLO_BAUDRATE_115200                  ((0<<9)|(1<<6))
-#define          SOLO_BAUDRATE_57600                   ((0<<9)|(2<<6))
-#define          SOLO_BAUDRATE_38400                   ((0<<9)|(3<<6))
-#define          SOLO_BAUDRATE_19200                   ((0<<9)|(4<<6))
-#define          SOLO_BAUDRATE_9600                    ((0<<9)|(5<<6))
-#define          SOLO_BAUDRATE_4800                    ((0<<9)|(6<<6))
-#define          SOLO_BAUDRATE_2400                    ((1<<9)|(6<<6))
-#define          SOLO_BAUDRATE_1200                    ((2<<9)|(6<<6))
-#define          SOLO_BAUDRATE_300                     ((3<<9)|(6<<6))
-
-#define          SOLO_UART_DATA_BIT_8                  (3<<4)
-#define          SOLO_UART_DATA_BIT_7                  (2<<4)
-#define          SOLO_UART_DATA_BIT_6                  (1<<4)
-#define          SOLO_UART_DATA_BIT_5                  (0<<4)
-
-#define          SOLO_UART_STOP_BIT_1                  (0<<2)
-#define          SOLO_UART_STOP_BIT_2                  (1<<2)
-
-#define          SOLO_UART_PARITY_NONE                 (0<<0)
-#define          SOLO_UART_PARITY_EVEN                 (2<<0)
-#define          SOLO_UART_PARITY_ODD                  (3<<0)
-
-#define SOLO_UART_STATUS(n)                    (0x0BA4 + ((n)*0x20))
-#define          SOLO_UART_CTS                         (1<<15)
-#define          SOLO_UART_RX_BUSY                     (1<<14)
-#define          SOLO_UART_OVERRUN                     (1<<13)
-#define          SOLO_UART_FRAME_ERR                   (1<<12)
-#define          SOLO_UART_PARITY_ERR                  (1<<11)
-#define          SOLO_UART_TX_BUSY                     (1<<5)
-
-#define          SOLO_UART_RX_BUFF_CNT(stat)           (((stat)>>6) & 0x1f)
-#define          SOLO_UART_RX_BUFF_SIZE                8
-#define          SOLO_UART_TX_BUFF_CNT(stat)           (((stat)>>0) & 0x1f)
-#define          SOLO_UART_TX_BUFF_SIZE                8
-
-#define SOLO_UART_TX_DATA(n)                   (0x0BA8 + ((n)*0x20))
-#define          SOLO_UART_TX_DATA_PUSH                (1<<8)
-#define SOLO_UART_RX_DATA(n)                   (0x0BAC + ((n)*0x20))
-#define          SOLO_UART_RX_DATA_POP                 (1<<8)
-
-#define SOLO_TIMER_CLOCK_NUM                   0x0be0
-#define SOLO_TIMER_WATCHDOG                    0x0be4
-#define SOLO_TIMER_USEC                                0x0be8
-#define SOLO_TIMER_SEC                         0x0bec
-
-#define SOLO_AUDIO_CONTROL                     0x0D00
-#define          SOLO_AUDIO_ENABLE                     (1<<31)
-#define          SOLO_AUDIO_MASTER_MODE                (1<<30)
-#define          SOLO_AUDIO_I2S_MODE                   (1<<29)
-#define          SOLO_AUDIO_I2S_LR_SWAP                (1<<27)
-#define          SOLO_AUDIO_I2S_8BIT                   (1<<26)
-#define          SOLO_AUDIO_I2S_MULTI(n)               ((n)<<24)
-#define          SOLO_AUDIO_MIX_9TO0                   (1<<23)
-#define          SOLO_AUDIO_DEC_9TO0_VOL(n)            ((n)<<20)
-#define          SOLO_AUDIO_MIX_19TO10                 (1<<19)
-#define          SOLO_AUDIO_DEC_19TO10_VOL(n)          ((n)<<16)
-#define          SOLO_AUDIO_MODE(n)                    ((n)<<0)
-#define SOLO_AUDIO_SAMPLE                      0x0D04
-#define          SOLO_AUDIO_EE_MODE_ON                 (1<<30)
-#define          SOLO_AUDIO_EE_ENC_CH(ch)              ((ch)<<25)
-#define          SOLO_AUDIO_BITRATE(n)                 ((n)<<16)
-#define          SOLO_AUDIO_CLK_DIV(n)                 ((n)<<0)
-#define SOLO_AUDIO_FDMA_INTR                   0x0D08
-#define          SOLO_AUDIO_FDMA_INTERVAL(n)           ((n)<<19)
-#define          SOLO_AUDIO_INTR_ORDER(n)              ((n)<<16)
-#define          SOLO_AUDIO_FDMA_BASE(n)               ((n)<<0)
-#define SOLO_AUDIO_EVOL_0                      0x0D0C
-#define SOLO_AUDIO_EVOL_1                      0x0D10
-#define          SOLO_AUDIO_EVOL(ch, value)            ((value)<<((ch)%10))
-#define SOLO_AUDIO_STA                         0x0D14
-
-
-#define SOLO_WATCHDOG                          0x0BE4
-#define WATCHDOG_STAT(status)                  (status<<8)
-#define WATCHDOG_TIME(sec)                     (sec&0xff)
-
-#endif /* __SOLO6X10_REGISTERS_H */
diff --git a/drivers/staging/solo6x10/solo6x10.h b/drivers/staging/solo6x10/solo6x10.h
deleted file mode 100644 (file)
index abee721..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __SOLO6X10_H
-#define __SOLO6X10_H
-
-#include <linux/version.h>
-#include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/semaphore.h>
-#include <linux/mutex.h>
-#include <linux/list.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include <linux/atomic.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-dev.h>
-#include <media/videobuf-core.h>
-#include "registers.h"
-
-#ifndef PCI_VENDOR_ID_SOFTLOGIC
-#define PCI_VENDOR_ID_SOFTLOGIC                0x9413
-#define PCI_DEVICE_ID_SOLO6010         0x6010
-#define PCI_DEVICE_ID_SOLO6110         0x6110
-#endif
-
-#ifndef PCI_VENDOR_ID_BLUECHERRY
-#define PCI_VENDOR_ID_BLUECHERRY       0x1BB3
-/* Neugent Softlogic 6010 based cards */
-#define PCI_DEVICE_ID_NEUSOLO_4                0x4304
-#define PCI_DEVICE_ID_NEUSOLO_9                0x4309
-#define PCI_DEVICE_ID_NEUSOLO_16       0x4310
-/* Bluecherry Softlogic 6010 based cards */
-#define PCI_DEVICE_ID_BC_SOLO_4                0x4E04
-#define PCI_DEVICE_ID_BC_SOLO_9                0x4E09
-#define PCI_DEVICE_ID_BC_SOLO_16       0x4E10
-/* Bluecherry Softlogic 6110 based cards */
-#define PCI_DEVICE_ID_BC_6110_4                0x5304
-#define PCI_DEVICE_ID_BC_6110_8                0x5308
-#define PCI_DEVICE_ID_BC_6110_16       0x5310
-#endif /* Bluecherry */
-
-#define SOLO6X10_NAME                  "solo6x10"
-
-#define SOLO_MAX_CHANNELS              16
-
-/* Make sure these two match */
-#define SOLO6X10_VERSION               "2.1.0"
-#define SOLO6X10_VER_MAJOR             2
-#define SOLO6X10_VER_MINOR             0
-#define SOLO6X10_VER_SUB               0
-#define SOLO6X10_VER_NUM \
-       KERNEL_VERSION(SOLO6X10_VER_MAJOR, SOLO6X10_VER_MINOR, SOLO6X10_VER_SUB)
-
-#define FLAGS_6110                     1
-
-/*
- * The SOLO6x10 actually has 8 i2c channels, but we only use 2.
- * 0 - Techwell chip(s)
- * 1 - SAA7128
- */
-#define SOLO_I2C_ADAPTERS              2
-#define SOLO_I2C_TW                    0
-#define SOLO_I2C_SAA                   1
-
-/* DMA Engine setup */
-#define SOLO_NR_P2M                    4
-#define SOLO_NR_P2M_DESC               256
-/* MPEG and JPEG share the same interrupt and locks so they must be together
- * in the same dma channel. */
-#define SOLO_P2M_DMA_ID_MP4E           0
-#define SOLO_P2M_DMA_ID_JPEG           0
-#define SOLO_P2M_DMA_ID_MP4D           1
-#define SOLO_P2M_DMA_ID_G723D          1
-#define SOLO_P2M_DMA_ID_DISP           2
-#define SOLO_P2M_DMA_ID_OSG            2
-#define SOLO_P2M_DMA_ID_G723E          3
-#define SOLO_P2M_DMA_ID_VIN            3
-
-/* Encoder standard modes */
-#define SOLO_ENC_MODE_CIF              2
-#define SOLO_ENC_MODE_HD1              1
-#define SOLO_ENC_MODE_D1               9
-
-#define SOLO_DEFAULT_GOP               30
-#define SOLO_DEFAULT_QP                        3
-
-/* There is 8MB memory available for solo to buffer MPEG4 frames.
- * This gives us 512 * 16kbyte queues. */
-#define SOLO_NR_RING_BUFS              512
-
-#define SOLO_CLOCK_MHZ                 108
-
-#ifndef V4L2_BUF_FLAG_MOTION_ON
-#define V4L2_BUF_FLAG_MOTION_ON                0x0400
-#define V4L2_BUF_FLAG_MOTION_DETECTED  0x0800
-#endif
-#ifndef V4L2_CID_MOTION_ENABLE
-#define PRIVATE_CIDS
-#define V4L2_CID_MOTION_ENABLE         (V4L2_CID_PRIVATE_BASE+0)
-#define V4L2_CID_MOTION_THRESHOLD      (V4L2_CID_PRIVATE_BASE+1)
-#define V4L2_CID_MOTION_TRACE          (V4L2_CID_PRIVATE_BASE+2)
-#endif
-
-enum SOLO_I2C_STATE {
-       IIC_STATE_IDLE,
-       IIC_STATE_START,
-       IIC_STATE_READ,
-       IIC_STATE_WRITE,
-       IIC_STATE_STOP
-};
-
-struct p2m_desc {
-       u32 ctrl;
-       u32 ext;
-       u32 ta;
-       u32 fa;
-};
-
-struct solo_p2m_dev {
-       struct mutex            mutex;
-       struct completion       completion;
-       int                     error;
-};
-
-#define OSD_TEXT_MAX           30
-
-enum solo_enc_types {
-       SOLO_ENC_TYPE_STD,
-       SOLO_ENC_TYPE_EXT,
-};
-
-struct solo_enc_dev {
-       struct solo_dev         *solo_dev;
-       /* V4L2 Items */
-       struct video_device     *vfd;
-       /* General accounting */
-       wait_queue_head_t       thread_wait;
-       spinlock_t              lock;
-       atomic_t                readers;
-       u8                      ch;
-       u8                      mode, gop, qp, interlaced, interval;
-       u8                      reset_gop;
-       u8                      bw_weight;
-       u8                      motion_detected;
-       u16                     motion_thresh;
-       u16                     width;
-       u16                     height;
-       char                    osd_text[OSD_TEXT_MAX + 1];
-};
-
-struct solo_enc_buf {
-       u8                      vop;
-       u8                      ch;
-       enum solo_enc_types     type;
-       u32                     off;
-       u32                     size;
-       u32                     jpeg_off;
-       u32                     jpeg_size;
-       struct timeval          ts;
-};
-
-/* The SOLO6x10 PCI Device */
-struct solo_dev {
-       /* General stuff */
-       struct pci_dev          *pdev;
-       u8 __iomem              *reg_base;
-       int                     nr_chans;
-       int                     nr_ext;
-       u32                     flags;
-       u32                     irq_mask;
-       u32                     motion_mask;
-       spinlock_t              reg_io_lock;
-
-       /* tw28xx accounting */
-       u8                      tw2865, tw2864, tw2815;
-       u8                      tw28_cnt;
-
-       /* i2c related items */
-       struct i2c_adapter      i2c_adap[SOLO_I2C_ADAPTERS];
-       enum SOLO_I2C_STATE     i2c_state;
-       struct mutex            i2c_mutex;
-       int                     i2c_id;
-       wait_queue_head_t       i2c_wait;
-       struct i2c_msg          *i2c_msg;
-       unsigned int            i2c_msg_num;
-       unsigned int            i2c_msg_ptr;
-
-       /* P2M DMA Engine */
-       struct solo_p2m_dev     p2m_dev[SOLO_NR_P2M];
-
-       /* V4L2 Display items */
-       struct video_device     *vfd;
-       unsigned int            erasing;
-       unsigned int            frame_blank;
-       u8                      cur_disp_ch;
-       wait_queue_head_t       disp_thread_wait;
-
-       /* V4L2 Encoder items */
-       struct solo_enc_dev     *v4l2_enc[SOLO_MAX_CHANNELS];
-       u16                     enc_bw_remain;
-       /* IDX into hw mp4 encoder */
-       u8                      enc_idx;
-       /* Our software ring of enc buf references */
-       u16                     enc_wr_idx;
-       struct solo_enc_buf     enc_buf[SOLO_NR_RING_BUFS];
-
-       /* Current video settings */
-       u32                     video_type;
-       u16                     video_hsize, video_vsize;
-       u16                     vout_hstart, vout_vstart;
-       u16                     vin_hstart, vin_vstart;
-       u8                      fps;
-
-       /* Audio components */
-       struct snd_card         *snd_card;
-       struct snd_pcm          *snd_pcm;
-       atomic_t                snd_users;
-       int                     g723_hw_idx;
-};
-
-static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg)
-{
-       unsigned long flags;
-       u32 ret;
-       u16 val;
-
-       spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
-
-       ret = readl(solo_dev->reg_base + reg);
-       rmb();
-       pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
-       rmb();
-
-       spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
-
-       return ret;
-}
-
-static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, u32 data)
-{
-       unsigned long flags;
-       u16 val;
-
-       spin_lock_irqsave(&solo_dev->reg_io_lock, flags);
-
-       writel(data, solo_dev->reg_base + reg);
-       wmb();
-       pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val);
-       rmb();
-
-       spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
-}
-
-void solo_irq_on(struct solo_dev *solo_dev, u32 mask);
-void solo_irq_off(struct solo_dev *solo_dev, u32 mask);
-
-/* Init/exit routeines for subsystems */
-int solo_disp_init(struct solo_dev *solo_dev);
-void solo_disp_exit(struct solo_dev *solo_dev);
-
-int solo_gpio_init(struct solo_dev *solo_dev);
-void solo_gpio_exit(struct solo_dev *solo_dev);
-
-int solo_i2c_init(struct solo_dev *solo_dev);
-void solo_i2c_exit(struct solo_dev *solo_dev);
-
-int solo_p2m_init(struct solo_dev *solo_dev);
-void solo_p2m_exit(struct solo_dev *solo_dev);
-
-int solo_v4l2_init(struct solo_dev *solo_dev);
-void solo_v4l2_exit(struct solo_dev *solo_dev);
-
-int solo_enc_init(struct solo_dev *solo_dev);
-void solo_enc_exit(struct solo_dev *solo_dev);
-
-int solo_enc_v4l2_init(struct solo_dev *solo_dev);
-void solo_enc_v4l2_exit(struct solo_dev *solo_dev);
-
-int solo_g723_init(struct solo_dev *solo_dev);
-void solo_g723_exit(struct solo_dev *solo_dev);
-
-/* ISR's */
-int solo_i2c_isr(struct solo_dev *solo_dev);
-void solo_p2m_isr(struct solo_dev *solo_dev, int id);
-void solo_p2m_error_isr(struct solo_dev *solo_dev, u32 status);
-void solo_enc_v4l2_isr(struct solo_dev *solo_dev);
-void solo_g723_isr(struct solo_dev *solo_dev);
-void solo_motion_isr(struct solo_dev *solo_dev);
-void solo_video_in_isr(struct solo_dev *solo_dev);
-
-/* i2c read/write */
-u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off);
-void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off,
-                       u8 data);
-
-/* P2M DMA */
-int solo_p2m_dma_t(struct solo_dev *solo_dev, u8 id, int wr,
-                  dma_addr_t dma_addr, u32 ext_addr, u32 size);
-int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr,
-                void *sys_addr, u32 ext_addr, u32 size);
-int solo_p2m_dma_sg(struct solo_dev *solo_dev, u8 id,
-                   struct p2m_desc *pdesc, int wr,
-                   struct scatterlist *sglist, u32 sg_off,
-                   u32 ext_addr, u32 size);
-void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr,
-                       u32 ext_addr, u32 size, int repeat, u32 ext_size);
-int solo_p2m_dma_desc(struct solo_dev *solo_dev, u8 id,
-                     struct p2m_desc *desc, int desc_count);
-
-/* Set the threshold for motion detection */
-void solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val);
-#define SOLO_DEF_MOT_THRESH            0x0300
-
-/* Write text on OSD */
-int solo_osd_print(struct solo_enc_dev *solo_enc);
-
-#endif /* __SOLO6X10_H */
diff --git a/drivers/staging/solo6x10/tw28.c b/drivers/staging/solo6x10/tw28.c
deleted file mode 100644 (file)
index db56b42..0000000
+++ /dev/null
@@ -1,821 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include "solo6x10.h"
-#include "tw28.h"
-
-/* XXX: Some of these values are masked into an 8-bit regs, and shifted
- * around for other 8-bit regs. What are the magic bits in these values? */
-#define DEFAULT_HDELAY_NTSC            (32 - 4)
-#define DEFAULT_HACTIVE_NTSC           (720 + 16)
-#define DEFAULT_VDELAY_NTSC            (7 - 2)
-#define DEFAULT_VACTIVE_NTSC           (240 + 4)
-
-#define DEFAULT_HDELAY_PAL             (32 + 4)
-#define DEFAULT_HACTIVE_PAL            (864-DEFAULT_HDELAY_PAL)
-#define DEFAULT_VDELAY_PAL             (6)
-#define DEFAULT_VACTIVE_PAL            (312-DEFAULT_VDELAY_PAL)
-
-static u8 tbl_tw2864_template[] = {
-       0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
-       0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-       0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
-       0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-       0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
-       0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-       0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
-       0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
-       0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
-       0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
-       0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */
-       0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01,
-       0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */
-       0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
-       0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
-       0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
-       0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */
-       0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
-       0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
-       0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
-       0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
-       0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
-};
-
-static u8 tbl_tw2865_ntsc_template[] = {
-       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
-       0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
-       0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
-       0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-       0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
-       0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-       0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, /* 0x40 */
-       0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
-       0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
-       0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
-       0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
-       0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
-       0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
-       0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
-       0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, /* 0xa0 */
-       0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
-       0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
-       0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8,
-       0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
-       0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
-       0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
-       0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
-       0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
-       0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
-       0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
-       0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
-};
-
-static u8 tbl_tw2865_pal_template[] = {
-       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */
-       0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
-       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */
-       0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
-       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */
-       0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
-       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */
-       0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
-       0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, /* 0x40 */
-       0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
-       0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
-       0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
-       0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
-       0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
-       0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
-       0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
-       0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, /* 0xa0 */
-       0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
-       0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
-       0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8,
-       0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
-       0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
-       0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
-       0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
-       0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
-       0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
-       0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, /* 0xf0 */
-       0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
-};
-
-#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
-
-static u8 tw_readbyte(struct solo_dev *solo_dev, int chip_id, u8 tw6x_off,
-                     u8 tw_off)
-{
-       if (is_tw286x(solo_dev, chip_id))
-               return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
-                                        TW_CHIP_OFFSET_ADDR(chip_id),
-                                        tw6x_off);
-       else
-               return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
-                                        TW_CHIP_OFFSET_ADDR(chip_id),
-                                        tw_off);
-}
-
-static void tw_writebyte(struct solo_dev *solo_dev, int chip_id,
-                        u8 tw6x_off, u8 tw_off, u8 val)
-{
-       if (is_tw286x(solo_dev, chip_id))
-               solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
-                                  TW_CHIP_OFFSET_ADDR(chip_id),
-                                  tw6x_off, val);
-       else
-               solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
-                                  TW_CHIP_OFFSET_ADDR(chip_id),
-                                  tw_off, val);
-}
-
-static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off,
-                               u8 val)
-{
-       int i;
-
-       for (i = 0; i < 5; i++) {
-               u8 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, addr, off);
-               if (rval == val)
-                       return;
-
-               solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, addr, off, val);
-               msleep_interruptible(1);
-       }
-
-/*     printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n",
-               addr, off, val); */
-}
-
-static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr)
-{
-       u8 tbl_tw2865_common[256];
-       int i;
-
-       if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL)
-               memcpy(tbl_tw2865_common, tbl_tw2865_pal_template,
-                      sizeof(tbl_tw2865_common));
-       else
-               memcpy(tbl_tw2865_common, tbl_tw2865_ntsc_template,
-                      sizeof(tbl_tw2865_common));
-
-       /* ALINK Mode */
-       if (solo_dev->nr_chans == 4) {
-               tbl_tw2865_common[0xd2] = 0x01;
-               tbl_tw2865_common[0xcf] = 0x00;
-       } else if (solo_dev->nr_chans == 8) {
-               tbl_tw2865_common[0xd2] = 0x02;
-               if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-                       tbl_tw2865_common[0xcf] = 0x80;
-       } else if (solo_dev->nr_chans == 16) {
-               tbl_tw2865_common[0xd2] = 0x03;
-               if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-                       tbl_tw2865_common[0xcf] = 0x83;
-               else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
-                       tbl_tw2865_common[0xcf] = 0x83;
-               else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
-                       tbl_tw2865_common[0xcf] = 0x80;
-       }
-
-       for (i = 0; i < 0xff; i++) {
-               /* Skip read only registers */
-               if (i >= 0xb8 && i <= 0xc1)
-                       continue;
-               if ((i & ~0x30) == 0x00 ||
-                   (i & ~0x30) == 0x0c ||
-                   (i & ~0x30) == 0x0d)
-                       continue;
-               if (i >= 0xc4 && i <= 0xc7)
-                       continue;
-               if (i == 0xfd)
-                       continue;
-
-               tw_write_and_verify(solo_dev, dev_addr, i,
-                                   tbl_tw2865_common[i]);
-       }
-
-       return 0;
-}
-
-static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr)
-{
-       u8 tbl_tw2864_common[sizeof(tbl_tw2864_template)];
-       int i;
-
-       memcpy(tbl_tw2864_common, tbl_tw2864_template,
-              sizeof(tbl_tw2864_common));
-
-       if (solo_dev->tw2865 == 0) {
-               /* IRQ Mode */
-               if (solo_dev->nr_chans == 4) {
-                       tbl_tw2864_common[0xd2] = 0x01;
-                       tbl_tw2864_common[0xcf] = 0x00;
-               } else if (solo_dev->nr_chans == 8) {
-                       tbl_tw2864_common[0xd2] = 0x02;
-                       if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
-                               tbl_tw2864_common[0xcf] = 0x43;
-                       else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-                               tbl_tw2864_common[0xcf] = 0x40;
-               } else if (solo_dev->nr_chans == 16) {
-                       tbl_tw2864_common[0xd2] = 0x03;
-                       if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
-                               tbl_tw2864_common[0xcf] = 0x43;
-                       else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-                               tbl_tw2864_common[0xcf] = 0x43;
-                       else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
-                               tbl_tw2864_common[0xcf] = 0x43;
-                       else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
-                               tbl_tw2864_common[0xcf] = 0x40;
-               }
-       } else {
-               /* ALINK Mode. Assumes that the first tw28xx is a
-                * 2865 and these are in cascade. */
-               for (i = 0; i <= 4; i++)
-                       tbl_tw2864_common[0x08 | i << 4] = 0x12;
-
-               if (solo_dev->nr_chans == 8) {
-                       tbl_tw2864_common[0xd2] = 0x02;
-                       if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-                               tbl_tw2864_common[0xcf] = 0x80;
-               } else if (solo_dev->nr_chans == 16) {
-                       tbl_tw2864_common[0xd2] = 0x03;
-                       if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-                               tbl_tw2864_common[0xcf] = 0x83;
-                       else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
-                               tbl_tw2864_common[0xcf] = 0x83;
-                       else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
-                               tbl_tw2864_common[0xcf] = 0x80;
-               }
-       }
-
-       /* NTSC or PAL */
-       if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) {
-               for (i = 0; i < 4; i++) {
-                       tbl_tw2864_common[0x07 | (i << 4)] |= 0x10;
-                       tbl_tw2864_common[0x08 | (i << 4)] |= 0x06;
-                       tbl_tw2864_common[0x0a | (i << 4)] |= 0x08;
-                       tbl_tw2864_common[0x0b | (i << 4)] |= 0x13;
-                       tbl_tw2864_common[0x0e | (i << 4)] |= 0x01;
-               }
-               tbl_tw2864_common[0x9d] = 0x90;
-               tbl_tw2864_common[0xf3] = 0x00;
-               tbl_tw2864_common[0xf4] = 0xa0;
-       }
-
-       for (i = 0; i < 0xff; i++) {
-               /* Skip read only registers */
-               if (i >= 0xb8 && i <= 0xc1)
-                       continue;
-               if ((i & ~0x30) == 0x00 ||
-                   (i & ~0x30) == 0x0c ||
-                   (i & ~0x30) == 0x0d)
-                       continue;
-               if (i == 0x74 || i == 0x77 || i == 0x78 ||
-                   i == 0x79 || i == 0x7a)
-                       continue;
-               if (i == 0xfd)
-                       continue;
-
-               tw_write_and_verify(solo_dev, dev_addr, i,
-                                   tbl_tw2864_common[i]);
-       }
-
-       return 0;
-}
-
-static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr)
-{
-       u8 tbl_ntsc_tw2815_common[] = {
-               0x00, 0xc8, 0x20, 0xd0, 0x06, 0xf0, 0x08, 0x80,
-               0x80, 0x80, 0x80, 0x02, 0x06, 0x00, 0x11,
-       };
-
-       u8 tbl_pal_tw2815_common[] = {
-               0x00, 0x88, 0x20, 0xd0, 0x05, 0x20, 0x28, 0x80,
-               0x80, 0x80, 0x80, 0x82, 0x06, 0x00, 0x11,
-       };
-
-       u8 tbl_tw2815_sfr[] = {
-               0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, /* 0x00 */
-               0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00,
-               0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, /* 0x10 */
-               0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00,
-               0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, /* 0x20 */
-               0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88,
-               0x88, 0x11, 0x00, 0x88, 0x88, 0x00,             /* 0x30 */
-       };
-       u8 *tbl_tw2815_common;
-       int i;
-       int ch;
-
-       tbl_ntsc_tw2815_common[0x06] = 0;
-
-       /* Horizontal Delay Control */
-       tbl_ntsc_tw2815_common[0x02] = DEFAULT_HDELAY_NTSC & 0xff;
-       tbl_ntsc_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_NTSC >> 8);
-
-       /* Horizontal Active Control */
-       tbl_ntsc_tw2815_common[0x03] = DEFAULT_HACTIVE_NTSC & 0xff;
-       tbl_ntsc_tw2815_common[0x06] |=
-               ((0x03 & (DEFAULT_HACTIVE_NTSC >> 8)) << 2);
-
-       /* Vertical Delay Control */
-       tbl_ntsc_tw2815_common[0x04] = DEFAULT_VDELAY_NTSC & 0xff;
-       tbl_ntsc_tw2815_common[0x06] |=
-               ((0x01 & (DEFAULT_VDELAY_NTSC >> 8)) << 4);
-
-       /* Vertical Active Control */
-       tbl_ntsc_tw2815_common[0x05] = DEFAULT_VACTIVE_NTSC & 0xff;
-       tbl_ntsc_tw2815_common[0x06] |=
-               ((0x01 & (DEFAULT_VACTIVE_NTSC >> 8)) << 5);
-
-       tbl_pal_tw2815_common[0x06] = 0;
-
-       /* Horizontal Delay Control */
-       tbl_pal_tw2815_common[0x02] = DEFAULT_HDELAY_PAL & 0xff;
-       tbl_pal_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_PAL >> 8);
-
-       /* Horizontal Active Control */
-       tbl_pal_tw2815_common[0x03] = DEFAULT_HACTIVE_PAL & 0xff;
-       tbl_pal_tw2815_common[0x06] |=
-               ((0x03 & (DEFAULT_HACTIVE_PAL >> 8)) << 2);
-
-       /* Vertical Delay Control */
-       tbl_pal_tw2815_common[0x04] = DEFAULT_VDELAY_PAL & 0xff;
-       tbl_pal_tw2815_common[0x06] |=
-               ((0x01 & (DEFAULT_VDELAY_PAL >> 8)) << 4);
-
-       /* Vertical Active Control */
-       tbl_pal_tw2815_common[0x05] = DEFAULT_VACTIVE_PAL & 0xff;
-       tbl_pal_tw2815_common[0x06] |=
-               ((0x01 & (DEFAULT_VACTIVE_PAL >> 8)) << 5);
-
-       tbl_tw2815_common =
-           (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) ?
-            tbl_ntsc_tw2815_common : tbl_pal_tw2815_common;
-
-       /* Dual ITU-R BT.656 format */
-       tbl_tw2815_common[0x0d] |= 0x04;
-
-       /* Audio configuration */
-       tbl_tw2815_sfr[0x62 - 0x40] &= ~(3 << 6);
-
-       if (solo_dev->nr_chans == 4) {
-               tbl_tw2815_sfr[0x63 - 0x40] |= 1;
-               tbl_tw2815_sfr[0x62 - 0x40] |= 3 << 6;
-       } else if (solo_dev->nr_chans == 8) {
-               tbl_tw2815_sfr[0x63 - 0x40] |= 2;
-               if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
-                       tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
-               else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-                       tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
-       } else if (solo_dev->nr_chans == 16) {
-               tbl_tw2815_sfr[0x63 - 0x40] |= 3;
-               if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
-                       tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
-               else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
-                       tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
-               else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
-                       tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
-               else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
-                       tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
-       }
-
-       /* Output mode of R_ADATM pin (0 mixing, 1 record) */
-       /* tbl_tw2815_sfr[0x63 - 0x40] |= 0 << 2; */
-
-       /* 8KHz, used to be 16KHz, but changed for remote client compat */
-       tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 2;
-       tbl_tw2815_sfr[0x6c - 0x40] |= 0 << 2;
-
-       /* Playback of right channel */
-       tbl_tw2815_sfr[0x6c - 0x40] |= 1 << 5;
-
-       /* Reserved value (XXX ??) */
-       tbl_tw2815_sfr[0x5c - 0x40] |= 1 << 5;
-
-       /* Analog output gain and mix ratio playback on full */
-       tbl_tw2815_sfr[0x70 - 0x40] |= 0xff;
-       /* Select playback audio and mute all except */
-       tbl_tw2815_sfr[0x71 - 0x40] |= 0x10;
-       tbl_tw2815_sfr[0x6d - 0x40] |= 0x0f;
-
-       /* End of audio configuration */
-
-       for (ch = 0; ch < 4; ch++) {
-               tbl_tw2815_common[0x0d] &= ~3;
-               switch (ch) {
-               case 0:
-                       tbl_tw2815_common[0x0d] |= 0x21;
-                       break;
-               case 1:
-                       tbl_tw2815_common[0x0d] |= 0x20;
-                       break;
-               case 2:
-                       tbl_tw2815_common[0x0d] |= 0x23;
-                       break;
-               case 3:
-                       tbl_tw2815_common[0x0d] |= 0x22;
-                       break;
-               }
-
-               for (i = 0; i < 0x0f; i++) {
-                       if (i == 0x00)
-                               continue;       /* read-only */
-                       solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
-                                          dev_addr, (ch * 0x10) + i,
-                                          tbl_tw2815_common[i]);
-               }
-       }
-
-       for (i = 0x40; i < 0x76; i++) {
-               /* Skip read-only and nop registers */
-               if (i == 0x40 || i == 0x59 || i == 0x5a ||
-                   i == 0x5d || i == 0x5e || i == 0x5f)
-                       continue;
-
-               solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, dev_addr, i,
-                                      tbl_tw2815_sfr[i - 0x40]);
-       }
-
-       return 0;
-}
-
-#define FIRST_ACTIVE_LINE      0x0008
-#define LAST_ACTIVE_LINE       0x0102
-
-static void saa7128_setup(struct solo_dev *solo_dev)
-{
-       int i;
-       unsigned char regs[128] = {
-               0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
-               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x1C, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
-               0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f, 0x00, 0x00,
-               0x1c, 0x33, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00,
-               0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
-               0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
-               0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
-               0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e,
-               0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77,
-               0x41, 0x88, 0x41, 0x12, 0xed, 0x10, 0x10, 0x00,
-               0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
-               0x00, 0x00, 0x08, 0xff, 0x80, 0x00, 0xff, 0xff,
-       };
-
-       regs[0x7A] = FIRST_ACTIVE_LINE & 0xff;
-       regs[0x7B] = LAST_ACTIVE_LINE & 0xff;
-       regs[0x7C] = ((1 << 7) |
-                       (((LAST_ACTIVE_LINE >> 8) & 1) << 6) |
-                       (((FIRST_ACTIVE_LINE >> 8) & 1) << 4));
-
-       /* PAL: XXX: We could do a second set of regs to avoid this */
-       if (solo_dev->video_type != SOLO_VO_FMT_TYPE_NTSC) {
-               regs[0x28] = 0xE1;
-
-               regs[0x5A] = 0x0F;
-               regs[0x61] = 0x02;
-               regs[0x62] = 0x35;
-               regs[0x63] = 0xCB;
-               regs[0x64] = 0x8A;
-               regs[0x65] = 0x09;
-               regs[0x66] = 0x2A;
-
-               regs[0x6C] = 0xf1;
-               regs[0x6E] = 0x20;
-
-               regs[0x7A] = 0x06 + 12;
-               regs[0x7b] = 0x24 + 12;
-               regs[0x7c] |= 1 << 6;
-       }
-
-       /* First 0x25 bytes are read-only? */
-       for (i = 0x26; i < 128; i++) {
-               if (i == 0x60 || i == 0x7D)
-                       continue;
-               solo_i2c_writebyte(solo_dev, SOLO_I2C_SAA, 0x46, i, regs[i]);
-       }
-
-       return;
-}
-
-int solo_tw28_init(struct solo_dev *solo_dev)
-{
-       int i;
-       u8 value;
-
-       /* Detect techwell chip type */
-       for (i = 0; i < TW_NUM_CHIP; i++) {
-               value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
-                                         TW_CHIP_OFFSET_ADDR(i), 0xFF);
-
-               switch (value >> 3) {
-               case 0x18:
-                       solo_dev->tw2865 |= 1 << i;
-                       solo_dev->tw28_cnt++;
-                       break;
-               case 0x0c:
-                       solo_dev->tw2864 |= 1 << i;
-                       solo_dev->tw28_cnt++;
-                       break;
-               default:
-                       value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
-                                                 TW_CHIP_OFFSET_ADDR(i), 0x59);
-                       if ((value >> 3) == 0x04) {
-                               solo_dev->tw2815 |= 1 << i;
-                               solo_dev->tw28_cnt++;
-                       }
-               }
-       }
-
-       if (!solo_dev->tw28_cnt)
-               return -EINVAL;
-
-       saa7128_setup(solo_dev);
-
-       for (i = 0; i < solo_dev->tw28_cnt; i++) {
-               if ((solo_dev->tw2865 & (1 << i)))
-                       tw2865_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
-               else if ((solo_dev->tw2864 & (1 << i)))
-                       tw2864_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
-               else
-                       tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
-       }
-
-       dev_info(&solo_dev->pdev->dev, "Initialized %d tw28xx chip%s:",
-                solo_dev->tw28_cnt, solo_dev->tw28_cnt == 1 ? "" : "s");
-
-       if (solo_dev->tw2865)
-               printk(" tw2865[%d]", hweight32(solo_dev->tw2865));
-       if (solo_dev->tw2864)
-               printk(" tw2864[%d]", hweight32(solo_dev->tw2864));
-       if (solo_dev->tw2815)
-               printk(" tw2815[%d]", hweight32(solo_dev->tw2815));
-       printk("\n");
-
-       return 0;
-}
-
-/*
- * We accessed the video status signal in the Techwell chip through
- * iic/i2c because the video status reported by register REG_VI_STATUS1
- * (address 0x012C) of the SOLO6010 chip doesn't give the correct video
- * status signal values.
- */
-int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch)
-{
-       u8 val, chip_num;
-
-       /* Get the right chip and on-chip channel */
-       chip_num = ch / 4;
-       ch %= 4;
-
-       val = tw_readbyte(solo_dev, chip_num, TW286X_AV_STAT_ADDR,
-                         TW_AV_STAT_ADDR) & 0x0f;
-
-       return val & (1 << ch) ? 1 : 0;
-}
-
-#if 0
-/* Status of audio from up to 4 techwell chips are combined into 1 variable.
- * See techwell datasheet for details. */
-u16 tw28_get_audio_status(struct solo_dev *solo_dev)
-{
-       u8 val;
-       u16 status = 0;
-       int i;
-
-       for (i = 0; i < solo_dev->tw28_cnt; i++) {
-               val = (tw_readbyte(solo_dev, i, TW286X_AV_STAT_ADDR,
-                                  TW_AV_STAT_ADDR) & 0xf0) >> 4;
-               status |= val << (i * 4);
-       }
-
-       return status;
-}
-#endif
-
-int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val)
-{
-       char sval;
-       u8 chip_num;
-
-       /* Get the right chip and on-chip channel */
-       chip_num = ch / 4;
-       ch %= 4;
-
-       if (val > 255 || val < 0)
-               return -ERANGE;
-
-       switch (ctrl) {
-       case V4L2_CID_SHARPNESS:
-               /* Only 286x has sharpness */
-               if (val > 0x0f || val < 0)
-                       return -ERANGE;
-               if (is_tw286x(solo_dev, chip_num)) {
-                       u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
-                                                TW_CHIP_OFFSET_ADDR(chip_num),
-                                                TW286x_SHARPNESS(chip_num));
-                       v &= 0xf0;
-                       v |= val;
-                       solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
-                                          TW_CHIP_OFFSET_ADDR(chip_num),
-                                          TW286x_SHARPNESS(chip_num), v);
-               } else if (val != 0)
-                       return -ERANGE;
-               break;
-
-       case V4L2_CID_HUE:
-               if (is_tw286x(solo_dev, chip_num))
-                       sval = val - 128;
-               else
-                       sval = (char)val;
-               tw_writebyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
-                            TW_HUE_ADDR(ch), sval);
-
-               break;
-
-       case V4L2_CID_SATURATION:
-               if (is_tw286x(solo_dev, chip_num)) {
-                       solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
-                                          TW_CHIP_OFFSET_ADDR(chip_num),
-                                          TW286x_SATURATIONU_ADDR(ch), val);
-               }
-               tw_writebyte(solo_dev, chip_num, TW286x_SATURATIONV_ADDR(ch),
-                            TW_SATURATION_ADDR(ch), val);
-
-               break;
-
-       case V4L2_CID_CONTRAST:
-               tw_writebyte(solo_dev, chip_num, TW286x_CONTRAST_ADDR(ch),
-                            TW_CONTRAST_ADDR(ch), val);
-               break;
-
-       case V4L2_CID_BRIGHTNESS:
-               if (is_tw286x(solo_dev, chip_num))
-                       sval = val - 128;
-               else
-                       sval = (char)val;
-               tw_writebyte(solo_dev, chip_num, TW286x_BRIGHTNESS_ADDR(ch),
-                            TW_BRIGHTNESS_ADDR(ch), sval);
-
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
-                     s32 *val)
-{
-       u8 rval, chip_num;
-
-       /* Get the right chip and on-chip channel */
-       chip_num = ch / 4;
-       ch %= 4;
-
-       switch (ctrl) {
-       case V4L2_CID_SHARPNESS:
-               /* Only 286x has sharpness */
-               if (is_tw286x(solo_dev, chip_num)) {
-                       rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
-                                                TW_CHIP_OFFSET_ADDR(chip_num),
-                                                TW286x_SHARPNESS(chip_num));
-                       *val = rval & 0x0f;
-               } else
-                       *val = 0;
-               break;
-       case V4L2_CID_HUE:
-               rval = tw_readbyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
-                                  TW_HUE_ADDR(ch));
-               if (is_tw286x(solo_dev, chip_num))
-                       *val = (s32)((char)rval) + 128;
-               else
-                       *val = rval;
-               break;
-       case V4L2_CID_SATURATION:
-               *val = tw_readbyte(solo_dev, chip_num,
-                                  TW286x_SATURATIONU_ADDR(ch),
-                                  TW_SATURATION_ADDR(ch));
-               break;
-       case V4L2_CID_CONTRAST:
-               *val = tw_readbyte(solo_dev, chip_num,
-                                  TW286x_CONTRAST_ADDR(ch),
-                                  TW_CONTRAST_ADDR(ch));
-               break;
-       case V4L2_CID_BRIGHTNESS:
-               rval = tw_readbyte(solo_dev, chip_num,
-                                  TW286x_BRIGHTNESS_ADDR(ch),
-                                  TW_BRIGHTNESS_ADDR(ch));
-               if (is_tw286x(solo_dev, chip_num))
-                       *val = (s32)((char)rval) + 128;
-               else
-                       *val = rval;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-#if 0
-/*
- * For audio output volume, the output channel is only 1. In this case we
- * don't need to offset TW_CHIP_OFFSET_ADDR. The TW_CHIP_OFFSET_ADDR used
- * is the base address of the techwell chip.
- */
-void tw2815_Set_AudioOutVol(struct solo_dev *solo_dev, unsigned int u_val)
-{
-       unsigned int val;
-       unsigned int chip_num;
-
-       chip_num = (solo_dev->nr_chans - 1) / 4;
-
-       val = tw_readbyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
-                         TW_AUDIO_OUTPUT_VOL_ADDR);
-
-       u_val = (val & 0x0f) | (u_val << 4);
-
-       tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
-                    TW_AUDIO_OUTPUT_VOL_ADDR, u_val);
-}
-#endif
-
-u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch)
-{
-       u8 val;
-       u8 chip_num;
-
-       /* Get the right chip and on-chip channel */
-       chip_num = ch / 4;
-       ch %= 4;
-
-       val = tw_readbyte(solo_dev, chip_num,
-                         TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
-                         TW_AUDIO_INPUT_GAIN_ADDR(ch));
-
-       return (ch % 2) ? (val >> 4) : (val & 0x0f);
-}
-
-void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val)
-{
-       u8 old_val;
-       u8 chip_num;
-
-       /* Get the right chip and on-chip channel */
-       chip_num = ch / 4;
-       ch %= 4;
-
-       old_val = tw_readbyte(solo_dev, chip_num,
-                             TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
-                             TW_AUDIO_INPUT_GAIN_ADDR(ch));
-
-       val = (old_val & ((ch % 2) ? 0x0f : 0xf0)) |
-               ((ch % 2) ? (val << 4) : val);
-
-       tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
-                    TW_AUDIO_INPUT_GAIN_ADDR(ch), val);
-}
diff --git a/drivers/staging/solo6x10/tw28.h b/drivers/staging/solo6x10/tw28.h
deleted file mode 100644 (file)
index a44a03a..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __SOLO6X10_TW28_H
-#define __SOLO6X10_TW28_H
-
-#include "solo6x10.h"
-
-#define TW_NUM_CHIP                            4
-#define TW_BASE_ADDR                           0x28
-#define TW_CHIP_OFFSET_ADDR(n)                 (TW_BASE_ADDR + (n))
-
-/* tw2815 */
-#define TW_AV_STAT_ADDR                                0x5a
-#define TW_HUE_ADDR(n)                         (0x07 | ((n) << 4))
-#define TW_SATURATION_ADDR(n)                  (0x08 | ((n) << 4))
-#define TW_CONTRAST_ADDR(n)                    (0x09 | ((n) << 4))
-#define TW_BRIGHTNESS_ADDR(n)                  (0x0a | ((n) << 4))
-#define TW_AUDIO_OUTPUT_VOL_ADDR               0x70
-#define TW_AUDIO_INPUT_GAIN_ADDR(n)            (0x60 + ((n > 1) ? 1 : 0))
-
-/* tw286x */
-#define TW286X_AV_STAT_ADDR                    0xfd
-#define TW286x_HUE_ADDR(n)                     (0x06 | ((n) << 4))
-#define TW286x_SATURATIONU_ADDR(n)             (0x04 | ((n) << 4))
-#define TW286x_SATURATIONV_ADDR(n)             (0x05 | ((n) << 4))
-#define TW286x_CONTRAST_ADDR(n)                        (0x02 | ((n) << 4))
-#define TW286x_BRIGHTNESS_ADDR(n)              (0x01 | ((n) << 4))
-#define TW286x_SHARPNESS(n)                    (0x03 | ((n) << 4))
-#define TW286x_AUDIO_OUTPUT_VOL_ADDR           0xdf
-#define TW286x_AUDIO_INPUT_GAIN_ADDR(n)                (0xD0 + ((n > 1) ? 1 : 0))
-
-int solo_tw28_init(struct solo_dev *solo_dev);
-
-int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val);
-int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val);
-
-u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch);
-void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val);
-int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch);
-
-#if 0
-unsigned int tw2815_get_audio_status(struct SOLO *solo);
-void tw2815_Set_AudioOutVol(struct SOLO *solo, unsigned int u_val);
-#endif
-
-#endif /* __SOLO6X10_TW28_H */
diff --git a/drivers/staging/solo6x10/v4l2-enc.c b/drivers/staging/solo6x10/v4l2-enc.c
deleted file mode 100644 (file)
index bee7280..0000000
+++ /dev/null
@@ -1,1825 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-common.h>
-#include <media/videobuf-dma-sg.h>
-#include "solo6x10.h"
-#include "tw28.h"
-#include "jpeg.h"
-
-#define MIN_VID_BUFFERS                4
-#define FRAME_BUF_SIZE         (128 * 1024)
-#define MP4_QS                 16
-
-static int solo_enc_thread(void *data);
-
-extern unsigned video_nr;
-
-struct solo_enc_fh {
-       struct                  solo_enc_dev *enc;
-       u32                     fmt;
-       u16                     rd_idx;
-       u8                      enc_on;
-       enum solo_enc_types     type;
-       struct videobuf_queue   vidq;
-       struct list_head        vidq_active;
-       struct task_struct      *kthread;
-       struct p2m_desc         desc[SOLO_NR_P2M_DESC];
-};
-
-static const u32 solo_user_ctrls[] = {
-       V4L2_CID_BRIGHTNESS,
-       V4L2_CID_CONTRAST,
-       V4L2_CID_SATURATION,
-       V4L2_CID_HUE,
-       V4L2_CID_SHARPNESS,
-       0
-};
-
-static const u32 solo_mpeg_ctrls[] = {
-       V4L2_CID_MPEG_VIDEO_ENCODING,
-       V4L2_CID_MPEG_VIDEO_GOP_SIZE,
-       0
-};
-
-static const u32 solo_private_ctrls[] = {
-       V4L2_CID_MOTION_ENABLE,
-       V4L2_CID_MOTION_THRESHOLD,
-       0
-};
-
-static const u32 solo_fmtx_ctrls[] = {
-       V4L2_CID_RDS_TX_RADIO_TEXT,
-       0
-};
-
-static const u32 *solo_ctrl_classes[] = {
-       solo_user_ctrls,
-       solo_mpeg_ctrls,
-       solo_fmtx_ctrls,
-       solo_private_ctrls,
-       NULL
-};
-
-static int solo_is_motion_on(struct solo_enc_dev *solo_enc)
-{
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-       u8 ch = solo_enc->ch;
-
-       if (solo_dev->motion_mask & (1 << ch))
-               return 1;
-       return 0;
-}
-
-static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on)
-{
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-       u8 ch = solo_enc->ch;
-
-       spin_lock(&solo_enc->lock);
-
-       if (on)
-               solo_dev->motion_mask |= (1 << ch);
-       else
-               solo_dev->motion_mask &= ~(1 << ch);
-
-       /* Do this regardless of if we are turning on or off */
-       solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR,
-                      1 << solo_enc->ch);
-       solo_enc->motion_detected = 0;
-
-       solo_reg_write(solo_dev, SOLO_VI_MOT_ADR,
-                      SOLO_VI_MOTION_EN(solo_dev->motion_mask) |
-                      (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
-
-       if (solo_dev->motion_mask)
-               solo_irq_on(solo_dev, SOLO_IRQ_MOTION);
-       else
-               solo_irq_off(solo_dev, SOLO_IRQ_MOTION);
-
-       spin_unlock(&solo_enc->lock);
-}
-
-/* Should be called with solo_enc->lock held */
-static void solo_update_mode(struct solo_enc_dev *solo_enc)
-{
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-       assert_spin_locked(&solo_enc->lock);
-
-       solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0;
-       solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1);
-
-       switch (solo_enc->mode) {
-       case SOLO_ENC_MODE_CIF:
-               solo_enc->width = solo_dev->video_hsize >> 1;
-               solo_enc->height = solo_dev->video_vsize;
-               break;
-       case SOLO_ENC_MODE_D1:
-               solo_enc->width = solo_dev->video_hsize;
-               solo_enc->height = solo_dev->video_vsize << 1;
-               solo_enc->bw_weight <<= 2;
-               break;
-       default:
-               WARN(1, "mode is unknown\n");
-       }
-}
-
-/* Should be called with solo_enc->lock held */
-static int solo_enc_on(struct solo_enc_fh *fh)
-{
-       struct solo_enc_dev *solo_enc = fh->enc;
-       u8 ch = solo_enc->ch;
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-       u8 interval;
-
-       assert_spin_locked(&solo_enc->lock);
-
-       if (fh->enc_on)
-               return 0;
-
-       solo_update_mode(solo_enc);
-
-       /* Make sure to bw check on first reader */
-       if (!atomic_read(&solo_enc->readers)) {
-               if (solo_enc->bw_weight > solo_dev->enc_bw_remain)
-                       return -EBUSY;
-               else
-                       solo_dev->enc_bw_remain -= solo_enc->bw_weight;
-       }
-
-       fh->enc_on = 1;
-       fh->rd_idx = solo_enc->solo_dev->enc_wr_idx;
-
-       if (fh->type == SOLO_ENC_TYPE_EXT)
-               solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1);
-
-       if (atomic_inc_return(&solo_enc->readers) > 1)
-               return 0;
-
-       /* Disable all encoding for this channel */
-       solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0);
-
-       /* Common for both std and ext encoding */
-       solo_reg_write(solo_dev, SOLO_VE_CH_INTL(ch),
-                      solo_enc->interlaced ? 1 : 0);
-
-       if (solo_enc->interlaced)
-               interval = solo_enc->interval - 1;
-       else
-               interval = solo_enc->interval;
-
-       /* Standard encoding only */
-       solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), solo_enc->gop);
-       solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp);
-       solo_reg_write(solo_dev, SOLO_CAP_CH_INTV(ch), interval);
-
-       /* Extended encoding only */
-       solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(ch), solo_enc->gop);
-       solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp);
-       solo_reg_write(solo_dev, SOLO_CAP_CH_INTV_E(ch), interval);
-
-       /* Enables the standard encoder */
-       solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode);
-
-       /* Settle down Beavis... */
-       mdelay(10);
-
-       return 0;
-}
-
-static void solo_enc_off(struct solo_enc_fh *fh)
-{
-       struct solo_enc_dev *solo_enc = fh->enc;
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-       if (!fh->enc_on)
-               return;
-
-       if (fh->kthread) {
-               kthread_stop(fh->kthread);
-               fh->kthread = NULL;
-       }
-
-       solo_dev->enc_bw_remain += solo_enc->bw_weight;
-       fh->enc_on = 0;
-
-       if (atomic_dec_return(&solo_enc->readers) > 0)
-               return;
-
-       solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0);
-       solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0);
-}
-
-static int solo_start_fh_thread(struct solo_enc_fh *fh)
-{
-       struct solo_enc_dev *solo_enc = fh->enc;
-
-       fh->kthread = kthread_run(solo_enc_thread, fh, SOLO6X10_NAME "_enc");
-
-       /* Oops, we had a problem */
-       if (IS_ERR(fh->kthread)) {
-               spin_lock(&solo_enc->lock);
-               solo_enc_off(fh);
-               spin_unlock(&solo_enc->lock);
-
-               return PTR_ERR(fh->kthread);
-       }
-
-       return 0;
-}
-
-static void enc_reset_gop(struct solo_dev *solo_dev, u8 ch)
-{
-       BUG_ON(ch >= solo_dev->nr_chans);
-       solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), 1);
-       solo_dev->v4l2_enc[ch]->reset_gop = 1;
-}
-
-static int enc_gop_reset(struct solo_dev *solo_dev, u8 ch, u8 vop)
-{
-       BUG_ON(ch >= solo_dev->nr_chans);
-       if (!solo_dev->v4l2_enc[ch]->reset_gop)
-               return 0;
-       if (vop)
-               return 1;
-       solo_dev->v4l2_enc[ch]->reset_gop = 0;
-       solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch),
-                      solo_dev->v4l2_enc[ch]->gop);
-       return 0;
-}
-
-static void enc_write_sg(struct scatterlist *sglist, void *buf, int size)
-{
-       struct scatterlist *sg;
-       u8 *src = buf;
-
-       for (sg = sglist; sg && size > 0; sg = sg_next(sg)) {
-               u8 *p = sg_virt(sg);
-               size_t len = sg_dma_len(sg);
-               int i;
-
-               for (i = 0; i < len && size; i++)
-                       p[i] = *(src++);
-       }
-}
-
-static int enc_get_mpeg_dma_sg(struct solo_dev *solo_dev,
-                              struct p2m_desc *desc,
-                              struct scatterlist *sglist, int skip,
-                              unsigned int off, unsigned int size)
-{
-       int ret;
-
-       if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
-               return -EINVAL;
-
-       if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) {
-               return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E,
-                                      desc, 0, sglist, skip,
-                                      SOLO_MP4E_EXT_ADDR(solo_dev) + off, size);
-       }
-
-       /* Buffer wrap */
-       ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0,
-                             sglist, skip, SOLO_MP4E_EXT_ADDR(solo_dev) + off,
-                             SOLO_MP4E_EXT_SIZE(solo_dev) - off);
-
-       ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0,
-                              sglist, skip + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
-                              SOLO_MP4E_EXT_ADDR(solo_dev),
-                              size + off - SOLO_MP4E_EXT_SIZE(solo_dev));
-
-       return ret;
-}
-
-static int enc_get_mpeg_dma_t(struct solo_dev *solo_dev,
-                             dma_addr_t buf, unsigned int off,
-                             unsigned int size)
-{
-       int ret;
-
-       if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
-               return -EINVAL;
-
-       if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) {
-               return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf,
-                                     SOLO_MP4E_EXT_ADDR(solo_dev) + off, size);
-       }
-
-       /* Buffer wrap */
-       ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf,
-                            SOLO_MP4E_EXT_ADDR(solo_dev) + off,
-                            SOLO_MP4E_EXT_SIZE(solo_dev) - off);
-
-       ret |= solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0,
-                             buf + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
-                             SOLO_MP4E_EXT_ADDR(solo_dev),
-                             size + off - SOLO_MP4E_EXT_SIZE(solo_dev));
-
-       return ret;
-}
-
-static int enc_get_mpeg_dma(struct solo_dev *solo_dev, void *buf,
-                           unsigned int off, unsigned int size)
-{
-       int ret;
-
-       dma_addr_t dma_addr = pci_map_single(solo_dev->pdev, buf, size,
-                                            PCI_DMA_FROMDEVICE);
-       ret = enc_get_mpeg_dma_t(solo_dev, dma_addr, off, size);
-       pci_unmap_single(solo_dev->pdev, dma_addr, size, PCI_DMA_FROMDEVICE);
-
-       return ret;
-}
-
-static int enc_get_jpeg_dma_sg(struct solo_dev *solo_dev,
-                              struct p2m_desc *desc,
-                              struct scatterlist *sglist, int skip,
-                              unsigned int off, unsigned int size)
-{
-       int ret;
-
-       if (off > SOLO_JPEG_EXT_SIZE(solo_dev))
-               return -EINVAL;
-
-       if (off + size <= SOLO_JPEG_EXT_SIZE(solo_dev)) {
-               return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG,
-                                      desc, 0, sglist, skip,
-                                      SOLO_JPEG_EXT_ADDR(solo_dev) + off, size);
-       }
-
-       /* Buffer wrap */
-       ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0,
-                             sglist, skip, SOLO_JPEG_EXT_ADDR(solo_dev) + off,
-                             SOLO_JPEG_EXT_SIZE(solo_dev) - off);
-
-       ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0,
-                              sglist, skip + SOLO_JPEG_EXT_SIZE(solo_dev) - off,
-                              SOLO_JPEG_EXT_ADDR(solo_dev),
-                              size + off - SOLO_JPEG_EXT_SIZE(solo_dev));
-
-       return ret;
-}
-
-/* Returns true of __chk is within the first __range bytes of __off */
-#define OFF_IN_RANGE(__off, __range, __chk) \
-       ((__off <= __chk) && ((__off + __range) >= __chk))
-
-static void solo_jpeg_header(struct solo_enc_dev *solo_enc,
-                            struct videobuf_dmabuf *vbuf)
-{
-       struct scatterlist *sg;
-       void *src = jpeg_header;
-       size_t copied = 0;
-       size_t to_copy = sizeof(jpeg_header);
-
-       for (sg = vbuf->sglist; sg && copied < to_copy; sg = sg_next(sg)) {
-               size_t this_copy = min(sg_dma_len(sg),
-                                      (unsigned int)(to_copy - copied));
-               u8 *p = sg_virt(sg);
-
-               memcpy(p, src + copied, this_copy);
-
-               if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 5))
-                       p[(SOF0_START + 5) - copied] =
-                               0xff & (solo_enc->height >> 8);
-               if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 6))
-                       p[(SOF0_START + 6) - copied] = 0xff & solo_enc->height;
-               if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 7))
-                       p[(SOF0_START + 7) - copied] =
-                               0xff & (solo_enc->width >> 8);
-               if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 8))
-                       p[(SOF0_START + 8) - copied] = 0xff & solo_enc->width;
-
-               copied += this_copy;
-       }
-}
-
-static int solo_fill_jpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
-                         struct videobuf_buffer *vb,
-                         struct videobuf_dmabuf *vbuf)
-{
-       struct solo_dev *solo_dev = fh->enc->solo_dev;
-       int size = enc_buf->jpeg_size;
-
-       /* Copy the header first (direct write) */
-       solo_jpeg_header(fh->enc, vbuf);
-
-       vb->size = size + sizeof(jpeg_header);
-
-       /* Grab the jpeg frame */
-       return enc_get_jpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist,
-                                  sizeof(jpeg_header),
-                                  enc_buf->jpeg_off, size);
-}
-
-static inline int vop_interlaced(__le32 *vh)
-{
-       return (__le32_to_cpu(vh[0]) >> 30) & 1;
-}
-
-static inline u32 vop_size(__le32 *vh)
-{
-       return __le32_to_cpu(vh[0]) & 0xFFFFF;
-}
-
-static inline u8 vop_hsize(__le32 *vh)
-{
-       return (__le32_to_cpu(vh[1]) >> 8) & 0xFF;
-}
-
-static inline u8 vop_vsize(__le32 *vh)
-{
-       return __le32_to_cpu(vh[1]) & 0xFF;
-}
-
-/* must be called with *bits % 8 = 0 */
-static void write_bytes(u8 **out, unsigned *bits, const u8 *src, unsigned count)
-{
-       memcpy(*out, src, count);
-       *out += count;
-       *bits += count * 8;
-}
-
-static void write_bits(u8 **out, unsigned *bits, u32 value, unsigned count)
-{
-
-       value <<= 32 - count; // shift to the right
-
-       while (count--) {
-               **out <<= 1;
-               **out |= !!(value & (1 << 31)); /* MSB */
-               value <<= 1;
-               if (++(*bits) % 8 == 0)
-                       (*out)++;
-       }
-}
-
-static void write_ue(u8 **out, unsigned *bits, unsigned value) /* H.264 only */
-{
-       uint32_t max = 0, cnt = 0;
-
-       while (value > max) {
-               max = (max + 2) * 2 - 2;
-               cnt++;
-       }
-       write_bits(out, bits, 1, cnt + 1);
-       write_bits(out, bits, ~(max - value), cnt);
-}
-
-static void write_se(u8 **out, unsigned *bits, int value) /* H.264 only */
-{
-       if (value <= 0)
-               write_ue(out, bits, -value * 2);
-       else
-               write_ue(out, bits, value * 2 - 1);
-}
-
-static void write_mpeg4_end(u8 **out, unsigned *bits)
-{
-       write_bits(out, bits, 0, 1);
-       /* align on 32-bit boundary */
-       if (*bits % 32)
-               write_bits(out, bits, 0xFFFFFFFF, 32 - *bits % 32);
-}
-
-static void write_h264_end(u8 **out, unsigned *bits, int align)
-{
-       write_bits(out, bits, 1, 1);
-       while ((*bits) % 8)
-               write_bits(out, bits, 0, 1);
-       if (align)
-               while ((*bits) % 32)
-                       write_bits(out, bits, 0, 1);
-}
-
-static void mpeg4_write_vol(u8 **out, struct solo_dev *solo_dev,
-                           __le32 *vh, unsigned fps, unsigned interval)
-{
-       static const u8 hdr[] = {
-               0, 0, 1, 0x00 /* video_object_start_code */,
-               0, 0, 1, 0x20 /* video_object_layer_start_code */
-       };
-       unsigned bits = 0;
-       unsigned width = vop_hsize(vh) << 4;
-       unsigned height = vop_vsize(vh) << 4;
-       unsigned interlaced = vop_interlaced(vh);
-
-       write_bytes(out, &bits, hdr, sizeof(hdr));
-       write_bits(out, &bits,    0,  1); /* random_accessible_vol */
-       write_bits(out, &bits, 0x04,  8); /* video_object_type_indication: main */
-       write_bits(out, &bits,    1,  1); /* is_object_layer_identifier */
-       write_bits(out, &bits,    2,  4); /* video_object_layer_verid: table V2-39 */
-       write_bits(out, &bits,    0,  3); /* video_object_layer_priority */
-       if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
-               write_bits(out, &bits,  3,  4); /* aspect_ratio_info, assuming 4:3 */
-       else
-               write_bits(out, &bits,  2,  4);
-       write_bits(out, &bits,    1,  1); /* vol_control_parameters */
-       write_bits(out, &bits,    1,  2); /* chroma_format: 4:2:0 */
-       write_bits(out, &bits,    1,  1); /* low_delay */
-       write_bits(out, &bits,    0,  1); /* vbv_parameters */
-       write_bits(out, &bits,    0,  2); /* video_object_layer_shape: rectangular */
-       write_bits(out, &bits,    1,  1); /* marker_bit */
-       write_bits(out, &bits,  fps, 16); /* vop_time_increment_resolution */
-       write_bits(out, &bits,    1,  1); /* marker_bit */
-       write_bits(out, &bits,    1,  1); /* fixed_vop_rate */
-       write_bits(out, &bits, interval, 15); /* fixed_vop_time_increment */
-       write_bits(out, &bits,    1,  1); /* marker_bit */
-       write_bits(out, &bits, width, 13); /* video_object_layer_width */
-       write_bits(out, &bits,    1,  1); /* marker_bit */
-       write_bits(out, &bits, height, 13); /* video_object_layer_height */
-       write_bits(out, &bits,    1,  1); /* marker_bit */
-       write_bits(out, &bits, interlaced, 1); /* interlaced */
-       write_bits(out, &bits,    1,  1); /* obmc_disable */
-       write_bits(out, &bits,    0,  2); /* sprite_enable */
-       write_bits(out, &bits,    0,  1); /* not_8_bit */
-       write_bits(out, &bits,    1,  0); /* quant_type */
-       write_bits(out, &bits,    0,  1); /* load_intra_quant_mat */
-       write_bits(out, &bits,    0,  1); /* load_nonintra_quant_mat */
-       write_bits(out, &bits,    0,  1); /* quarter_sample */
-       write_bits(out, &bits,    1,  1); /* complexity_estimation_disable */
-       write_bits(out, &bits,    1,  1); /* resync_marker_disable */
-       write_bits(out, &bits,    0,  1); /* data_partitioned */
-       write_bits(out, &bits,    0,  1); /* newpred_enable */
-       write_bits(out, &bits,    0,  1); /* reduced_resolution_vop_enable */
-       write_bits(out, &bits,    0,  1); /* scalability */
-       write_mpeg4_end(out, &bits);
-}
-
-static void h264_write_vol(u8 **out, struct solo_dev *solo_dev, __le32 *vh)
-{
-       static const u8 sps[] = {
-               0, 0, 0, 1 /* start code */, 0x67, 66 /* profile_idc */,
-               0 /* constraints */, 30 /* level_idc */
-       };
-       static const u8 pps[] = {
-               0, 0, 0, 1 /* start code */, 0x68
-       };
-
-       unsigned bits = 0;
-       unsigned mbs_w = vop_hsize(vh);
-       unsigned mbs_h = vop_vsize(vh);
-
-       write_bytes(out, &bits, sps, sizeof(sps));
-       write_ue(out, &bits,   0);      /* seq_parameter_set_id */
-       write_ue(out, &bits,   5);      /* log2_max_frame_num_minus4 */
-       write_ue(out, &bits,   0);      /* pic_order_cnt_type */
-       write_ue(out, &bits,   6);      /* log2_max_pic_order_cnt_lsb_minus4 */
-       write_ue(out, &bits,   1);      /* max_num_ref_frames */
-       write_bits(out, &bits, 0, 1);   /* gaps_in_frame_num_value_allowed_flag */
-       write_ue(out, &bits, mbs_w - 1);        /* pic_width_in_mbs_minus1 */
-       write_ue(out, &bits, mbs_h - 1);        /* pic_height_in_map_units_minus1 */
-       write_bits(out, &bits, 1, 1);   /* frame_mbs_only_flag */
-       write_bits(out, &bits, 1, 1);   /* direct_8x8_frame_field_flag */
-       write_bits(out, &bits, 0, 1);   /* frame_cropping_flag */
-       write_bits(out, &bits, 0, 1);   /* vui_parameters_present_flag */
-       write_h264_end(out, &bits, 0);
-
-       write_bytes(out, &bits, pps, sizeof(pps));
-       write_ue(out, &bits,   0);      /* pic_parameter_set_id */
-       write_ue(out, &bits,   0);      /* seq_parameter_set_id */
-       write_bits(out, &bits, 0, 1);   /* entropy_coding_mode_flag */
-       write_bits(out, &bits, 0, 1);   /* bottom_field_pic_order_in_frame_present_flag */
-       write_ue(out, &bits,   0);      /* num_slice_groups_minus1 */
-       write_ue(out, &bits,   0);      /* num_ref_idx_l0_default_active_minus1 */
-       write_ue(out, &bits,   0);      /* num_ref_idx_l1_default_active_minus1 */
-       write_bits(out, &bits, 0, 1);   /* weighted_pred_flag */
-       write_bits(out, &bits, 0, 2);   /* weighted_bipred_idc */
-       write_se(out, &bits,   0);      /* pic_init_qp_minus26 */
-       write_se(out, &bits,   0);      /* pic_init_qs_minus26 */
-       write_se(out, &bits,   2);      /* chroma_qp_index_offset */
-       write_bits(out, &bits, 0, 1);   /* deblocking_filter_control_present_flag */
-       write_bits(out, &bits, 1, 1);   /* constrained_intra_pred_flag */
-       write_bits(out, &bits, 0, 1);   /* redundant_pic_cnt_present_flag */
-       write_h264_end(out, &bits, 1);
-}
-
-static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
-                         struct videobuf_buffer *vb,
-                         struct videobuf_dmabuf *vbuf)
-{
-       struct solo_enc_dev *solo_enc = fh->enc;
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-#define VH_WORDS 16
-#define MAX_VOL_HEADER_LENGTH 64
-
-       __le32 vh[VH_WORDS];
-       int ret;
-       int frame_size, frame_off;
-       int skip = 0;
-
-       if (WARN_ON_ONCE(enc_buf->size <= sizeof(vh)))
-               return -EINVAL;
-
-       /* First get the hardware vop header (not real mpeg) */
-       ret = enc_get_mpeg_dma(solo_dev, vh, enc_buf->off, sizeof(vh));
-       if (WARN_ON_ONCE(ret))
-               return ret;
-
-       if (WARN_ON_ONCE(vop_size(vh) > enc_buf->size))
-               return -EINVAL;
-
-       vb->width = vop_hsize(vh) << 4;
-       vb->height = vop_vsize(vh) << 4;
-       vb->size = vop_size(vh);
-
-       /* If this is a key frame, add extra m4v header */
-       if (!enc_buf->vop) {
-               u8 header[MAX_VOL_HEADER_LENGTH], *out = header;
-
-               if (solo_dev->flags & FLAGS_6110)
-                       h264_write_vol(&out, solo_dev, vh);
-               else
-                       mpeg4_write_vol(&out, solo_dev, vh,
-                                       solo_dev->fps * 1000,
-                                       solo_enc->interval * 1000);
-               skip = out - header;
-               enc_write_sg(vbuf->sglist, header, skip);
-               /* Adjust the dma buffer past this header */
-               vb->size += skip;
-       }
-
-       /* Now get the actual mpeg payload */
-       frame_off = (enc_buf->off + sizeof(vh)) % SOLO_MP4E_EXT_SIZE(solo_dev);
-       frame_size = enc_buf->size - sizeof(vh);
-
-       ret = enc_get_mpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist,
-                                 skip, frame_off, frame_size);
-       WARN_ON_ONCE(ret);
-
-       return ret;
-}
-
-static void solo_enc_fillbuf(struct solo_enc_fh *fh,
-                           struct videobuf_buffer *vb)
-{
-       struct solo_enc_dev *solo_enc = fh->enc;
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-       struct solo_enc_buf *enc_buf = NULL;
-       struct videobuf_dmabuf *vbuf;
-       int ret;
-       int error = 1;
-       u16 idx = fh->rd_idx;
-
-       while (idx != solo_dev->enc_wr_idx) {
-               struct solo_enc_buf *ebuf = &solo_dev->enc_buf[idx];
-
-               idx = (idx + 1) % SOLO_NR_RING_BUFS;
-
-               if (ebuf->ch != solo_enc->ch)
-                       continue;
-
-               if (fh->fmt == V4L2_PIX_FMT_MPEG) {
-                       if (fh->type == ebuf->type) {
-                               enc_buf = ebuf;
-                               break;
-                       }
-               } else {
-                       /* For mjpeg, keep reading to the newest frame */
-                       enc_buf = ebuf;
-               }
-       }
-
-       fh->rd_idx = idx;
-
-       if (WARN_ON_ONCE(!enc_buf))
-               goto buf_err;
-
-       if ((fh->fmt == V4L2_PIX_FMT_MPEG &&
-            vb->bsize < enc_buf->size) ||
-           (fh->fmt == V4L2_PIX_FMT_MJPEG &&
-            vb->bsize < (enc_buf->jpeg_size + sizeof(jpeg_header)))) {
-               WARN_ON_ONCE(1);
-               goto buf_err;
-       }
-
-       vbuf = videobuf_to_dma(vb);
-       if (WARN_ON_ONCE(!vbuf))
-               goto buf_err;
-
-       if (fh->fmt == V4L2_PIX_FMT_MPEG)
-               ret = solo_fill_mpeg(fh, enc_buf, vb, vbuf);
-       else
-               ret = solo_fill_jpeg(fh, enc_buf, vb, vbuf);
-
-       if (!ret)
-               error = 0;
-
-buf_err:
-       if (error) {
-               vb->state = VIDEOBUF_ERROR;
-       } else {
-               vb->field_count++;
-               vb->ts = enc_buf->ts;
-               vb->state = VIDEOBUF_DONE;
-       }
-
-       wake_up(&vb->done);
-
-       return;
-}
-
-static void solo_enc_thread_try(struct solo_enc_fh *fh)
-{
-       struct solo_enc_dev *solo_enc = fh->enc;
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-       struct videobuf_buffer *vb;
-
-       for (;;) {
-               spin_lock(&solo_enc->lock);
-
-               if (fh->rd_idx == solo_dev->enc_wr_idx)
-                       break;
-
-               if (list_empty(&fh->vidq_active))
-                       break;
-
-               vb = list_first_entry(&fh->vidq_active,
-                                     struct videobuf_buffer, queue);
-
-               if (!waitqueue_active(&vb->done))
-                       break;
-
-               list_del(&vb->queue);
-
-               spin_unlock(&solo_enc->lock);
-
-               solo_enc_fillbuf(fh, vb);
-       }
-
-       assert_spin_locked(&solo_enc->lock);
-       spin_unlock(&solo_enc->lock);
-}
-
-static int solo_enc_thread(void *data)
-{
-       struct solo_enc_fh *fh = data;
-       struct solo_enc_dev *solo_enc = fh->enc;
-       DECLARE_WAITQUEUE(wait, current);
-
-       set_freezable();
-       add_wait_queue(&solo_enc->thread_wait, &wait);
-
-       for (;;) {
-               long timeout = schedule_timeout_interruptible(HZ);
-               if (timeout == -ERESTARTSYS || kthread_should_stop())
-                       break;
-               solo_enc_thread_try(fh);
-               try_to_freeze();
-       }
-
-       remove_wait_queue(&solo_enc->thread_wait, &wait);
-
-       return 0;
-}
-
-void solo_motion_isr(struct solo_dev *solo_dev)
-{
-       u32 status;
-       int i;
-
-       solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_MOTION);
-
-       status = solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS);
-
-       for (i = 0; i < solo_dev->nr_chans; i++) {
-               struct solo_enc_dev *solo_enc = solo_dev->v4l2_enc[i];
-
-               BUG_ON(solo_enc == NULL);
-
-               if (solo_enc->motion_detected)
-                       continue;
-               if (!(status & (1 << i)))
-                       continue;
-
-               solo_enc->motion_detected = 1;
-       }
-}
-
-void solo_enc_v4l2_isr(struct solo_dev *solo_dev)
-{
-       struct solo_enc_buf *enc_buf;
-       u32 mpeg_current, mpeg_next, mpeg_size;
-       u32 jpeg_current, jpeg_next, jpeg_size;
-       u32 reg_mpeg_size;
-       u8 cur_q, vop_type;
-       u8 ch;
-       enum solo_enc_types enc_type;
-
-       solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_ENCODER);
-
-       cur_q = ((solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xF) + 1) % MP4_QS;
-
-       reg_mpeg_size = ((solo_reg_read(solo_dev, SOLO_VE_STATE(0)) & 0xFFFFF) + 64 + 8) & ~7;
-
-       while (solo_dev->enc_idx != cur_q) {
-               mpeg_current = solo_reg_read(solo_dev,
-                                       SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
-               jpeg_current = solo_reg_read(solo_dev,
-                                       SOLO_VE_JPEG_QUE(solo_dev->enc_idx));
-               solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS;
-               mpeg_next = solo_reg_read(solo_dev,
-                                       SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
-               jpeg_next = solo_reg_read(solo_dev,
-                                       SOLO_VE_JPEG_QUE(solo_dev->enc_idx));
-
-               ch = (mpeg_current >> 24) & 0x1f;
-               if (ch >= SOLO_MAX_CHANNELS) {
-                       ch -= SOLO_MAX_CHANNELS;
-                       enc_type = SOLO_ENC_TYPE_EXT;
-               } else
-                       enc_type = SOLO_ENC_TYPE_STD;
-
-               vop_type = (mpeg_current >> 29) & 3;
-
-               mpeg_current &= 0x00ffffff;
-               mpeg_next    &= 0x00ffffff;
-               jpeg_current &= 0x00ffffff;
-               jpeg_next    &= 0x00ffffff;
-
-               mpeg_size = (SOLO_MP4E_EXT_SIZE(solo_dev) +
-                            mpeg_next - mpeg_current) %
-                           SOLO_MP4E_EXT_SIZE(solo_dev);
-
-               jpeg_size = (SOLO_JPEG_EXT_SIZE(solo_dev) +
-                            jpeg_next - jpeg_current) %
-                           SOLO_JPEG_EXT_SIZE(solo_dev);
-
-               /* XXX I think this means we had a ring overflow? */
-               if (mpeg_current > mpeg_next && mpeg_size != reg_mpeg_size) {
-                       enc_reset_gop(solo_dev, ch);
-                       continue;
-               }
-
-               /* When resetting the GOP, skip frames until I-frame */
-               if (enc_gop_reset(solo_dev, ch, vop_type))
-                       continue;
-
-               enc_buf = &solo_dev->enc_buf[solo_dev->enc_wr_idx];
-
-               enc_buf->vop = vop_type;
-               enc_buf->ch = ch;
-               enc_buf->off = mpeg_current;
-               enc_buf->size = mpeg_size;
-               enc_buf->jpeg_off = jpeg_current;
-               enc_buf->jpeg_size = jpeg_size;
-               enc_buf->type = enc_type;
-
-               do_gettimeofday(&enc_buf->ts);
-
-               solo_dev->enc_wr_idx = (solo_dev->enc_wr_idx + 1) %
-                                       SOLO_NR_RING_BUFS;
-
-               wake_up_interruptible(&solo_dev->v4l2_enc[ch]->thread_wait);
-       }
-
-       return;
-}
-
-static int solo_enc_buf_setup(struct videobuf_queue *vq, unsigned int *count,
-                             unsigned int *size)
-{
-       *size = FRAME_BUF_SIZE;
-
-       if (*count < MIN_VID_BUFFERS)
-               *count = MIN_VID_BUFFERS;
-
-       return 0;
-}
-
-static int solo_enc_buf_prepare(struct videobuf_queue *vq,
-                               struct videobuf_buffer *vb,
-                               enum v4l2_field field)
-{
-       struct solo_enc_fh *fh = vq->priv_data;
-       struct solo_enc_dev *solo_enc = fh->enc;
-
-       vb->size = FRAME_BUF_SIZE;
-       if (vb->baddr != 0 && vb->bsize < vb->size)
-               return -EINVAL;
-
-       /* These properties only change when queue is idle */
-       vb->width = solo_enc->width;
-       vb->height = solo_enc->height;
-       vb->field  = field;
-
-       if (vb->state == VIDEOBUF_NEEDS_INIT) {
-               int rc = videobuf_iolock(vq, vb, NULL);
-               if (rc < 0) {
-                       struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
-                       videobuf_dma_unmap(vq->dev, dma);
-                       videobuf_dma_free(dma);
-                       vb->state = VIDEOBUF_NEEDS_INIT;
-                       return rc;
-               }
-       }
-       vb->state = VIDEOBUF_PREPARED;
-
-       return 0;
-}
-
-static void solo_enc_buf_queue(struct videobuf_queue *vq,
-                              struct videobuf_buffer *vb)
-{
-       struct solo_enc_fh *fh = vq->priv_data;
-
-       vb->state = VIDEOBUF_QUEUED;
-       list_add_tail(&vb->queue, &fh->vidq_active);
-       wake_up_interruptible(&fh->enc->thread_wait);
-}
-
-static void solo_enc_buf_release(struct videobuf_queue *vq,
-                                struct videobuf_buffer *vb)
-{
-       struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
-
-       videobuf_dma_unmap(vq->dev, dma);
-       videobuf_dma_free(dma);
-       vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static struct videobuf_queue_ops solo_enc_video_qops = {
-       .buf_setup      = solo_enc_buf_setup,
-       .buf_prepare    = solo_enc_buf_prepare,
-       .buf_queue      = solo_enc_buf_queue,
-       .buf_release    = solo_enc_buf_release,
-};
-
-static unsigned int solo_enc_poll(struct file *file,
-                                 struct poll_table_struct *wait)
-{
-       struct solo_enc_fh *fh = file->private_data;
-
-       return videobuf_poll_stream(file, &fh->vidq, wait);
-}
-
-static int solo_enc_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct solo_enc_fh *fh = file->private_data;
-
-       return videobuf_mmap_mapper(&fh->vidq, vma);
-}
-
-static int solo_enc_open(struct file *file)
-{
-       struct solo_enc_dev *solo_enc = video_drvdata(file);
-       struct solo_enc_fh *fh;
-
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (fh == NULL)
-               return -ENOMEM;
-
-       fh->enc = solo_enc;
-       file->private_data = fh;
-       INIT_LIST_HEAD(&fh->vidq_active);
-       fh->fmt = V4L2_PIX_FMT_MPEG;
-       fh->type = SOLO_ENC_TYPE_STD;
-
-       videobuf_queue_sg_init(&fh->vidq, &solo_enc_video_qops,
-                              &solo_enc->solo_dev->pdev->dev,
-                              &solo_enc->lock,
-                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                              V4L2_FIELD_INTERLACED,
-                              sizeof(struct videobuf_buffer), fh, NULL);
-
-       return 0;
-}
-
-static ssize_t solo_enc_read(struct file *file, char __user *data,
-                            size_t count, loff_t *ppos)
-{
-       struct solo_enc_fh *fh = file->private_data;
-       struct solo_enc_dev *solo_enc = fh->enc;
-
-       /* Make sure the encoder is on */
-       if (!fh->enc_on) {
-               int ret;
-
-               spin_lock(&solo_enc->lock);
-               ret = solo_enc_on(fh);
-               spin_unlock(&solo_enc->lock);
-               if (ret)
-                       return ret;
-
-               ret = solo_start_fh_thread(fh);
-               if (ret)
-                       return ret;
-       }
-
-       return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
-                                   file->f_flags & O_NONBLOCK);
-}
-
-static int solo_enc_release(struct file *file)
-{
-       struct solo_enc_fh *fh = file->private_data;
-       struct solo_enc_dev *solo_enc = fh->enc;
-
-       videobuf_stop(&fh->vidq);
-       videobuf_mmap_free(&fh->vidq);
-
-       spin_lock(&solo_enc->lock);
-       solo_enc_off(fh);
-       spin_unlock(&solo_enc->lock);
-
-       kfree(fh);
-
-       return 0;
-}
-
-static int solo_enc_querycap(struct file *file, void  *priv,
-                            struct v4l2_capability *cap)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-       strcpy(cap->driver, SOLO6X10_NAME);
-       snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
-                solo_enc->ch);
-       snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
-                pci_name(solo_dev->pdev));
-       cap->version = SOLO6X10_VER_NUM;
-       cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
-                               V4L2_CAP_READWRITE |
-                               V4L2_CAP_STREAMING;
-       return 0;
-}
-
-static int solo_enc_enum_input(struct file *file, void *priv,
-                              struct v4l2_input *input)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-       if (input->index)
-               return -EINVAL;
-
-       snprintf(input->name, sizeof(input->name), "Encoder %d",
-                solo_enc->ch + 1);
-       input->type = V4L2_INPUT_TYPE_CAMERA;
-
-       if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
-               input->std = V4L2_STD_NTSC_M;
-       else
-               input->std = V4L2_STD_PAL_B;
-
-       if (!tw28_get_video_status(solo_dev, solo_enc->ch))
-               input->status = V4L2_IN_ST_NO_SIGNAL;
-
-       return 0;
-}
-
-static int solo_enc_set_input(struct file *file, void *priv, unsigned int index)
-{
-       if (index)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int solo_enc_get_input(struct file *file, void *priv,
-                             unsigned int *index)
-{
-       *index = 0;
-
-       return 0;
-}
-
-static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
-                                struct v4l2_fmtdesc *f)
-{
-       switch (f->index) {
-       case 0:
-               f->pixelformat = V4L2_PIX_FMT_MPEG;
-               strcpy(f->description, "MPEG-4 AVC");
-               break;
-       case 1:
-               f->pixelformat = V4L2_PIX_FMT_MJPEG;
-               strcpy(f->description, "MJPEG");
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       f->flags = V4L2_FMT_FLAG_COMPRESSED;
-
-       return 0;
-}
-
-static int solo_enc_try_fmt_cap(struct file *file, void *priv,
-                           struct v4l2_format *f)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-       struct v4l2_pix_format *pix = &f->fmt.pix;
-
-       if (pix->pixelformat != V4L2_PIX_FMT_MPEG &&
-           pix->pixelformat != V4L2_PIX_FMT_MJPEG)
-               return -EINVAL;
-
-       /* We cannot change width/height in mid read */
-       if (atomic_read(&solo_enc->readers) > 0) {
-               if (pix->width != solo_enc->width ||
-                   pix->height != solo_enc->height)
-                       return -EBUSY;
-       }
-
-       if (pix->width < solo_dev->video_hsize ||
-           pix->height < solo_dev->video_vsize << 1) {
-               /* Default to CIF 1/2 size */
-               pix->width = solo_dev->video_hsize >> 1;
-               pix->height = solo_dev->video_vsize;
-       } else {
-               /* Full frame */
-               pix->width = solo_dev->video_hsize;
-               pix->height = solo_dev->video_vsize << 1;
-       }
-
-       if (pix->field == V4L2_FIELD_ANY)
-               pix->field = V4L2_FIELD_INTERLACED;
-       else if (pix->field != V4L2_FIELD_INTERLACED)
-               pix->field = V4L2_FIELD_INTERLACED;
-
-       /* Just set these */
-       pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
-       pix->sizeimage = FRAME_BUF_SIZE;
-
-       return 0;
-}
-
-static int solo_enc_set_fmt_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-       struct v4l2_pix_format *pix = &f->fmt.pix;
-       int ret;
-
-       spin_lock(&solo_enc->lock);
-
-       ret = solo_enc_try_fmt_cap(file, priv, f);
-       if (ret) {
-               spin_unlock(&solo_enc->lock);
-               return ret;
-       }
-
-       if (pix->width == solo_dev->video_hsize)
-               solo_enc->mode = SOLO_ENC_MODE_D1;
-       else
-               solo_enc->mode = SOLO_ENC_MODE_CIF;
-
-       /* This does not change the encoder at all */
-       fh->fmt = pix->pixelformat;
-
-       if (pix->priv)
-               fh->type = SOLO_ENC_TYPE_EXT;
-       ret = solo_enc_on(fh);
-
-       spin_unlock(&solo_enc->lock);
-
-       if (ret)
-               return ret;
-
-       return solo_start_fh_thread(fh);
-}
-
-static int solo_enc_get_fmt_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
-       struct v4l2_pix_format *pix = &f->fmt.pix;
-
-       pix->width = solo_enc->width;
-       pix->height = solo_enc->height;
-       pix->pixelformat = fh->fmt;
-       pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
-                    V4L2_FIELD_NONE;
-       pix->sizeimage = FRAME_BUF_SIZE;
-       pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
-
-       return 0;
-}
-
-static int solo_enc_reqbufs(struct file *file, void *priv,
-                           struct v4l2_requestbuffers *req)
-{
-       struct solo_enc_fh *fh = priv;
-
-       return videobuf_reqbufs(&fh->vidq, req);
-}
-
-static int solo_enc_querybuf(struct file *file, void *priv,
-                            struct v4l2_buffer *buf)
-{
-       struct solo_enc_fh *fh = priv;
-
-       return videobuf_querybuf(&fh->vidq, buf);
-}
-
-static int solo_enc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-       struct solo_enc_fh *fh = priv;
-
-       return videobuf_qbuf(&fh->vidq, buf);
-}
-
-static int solo_enc_dqbuf(struct file *file, void *priv,
-                         struct v4l2_buffer *buf)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
-       int ret;
-
-       /* Make sure the encoder is on */
-       if (!fh->enc_on) {
-               spin_lock(&solo_enc->lock);
-               ret = solo_enc_on(fh);
-               spin_unlock(&solo_enc->lock);
-               if (ret)
-                       return ret;
-
-               ret = solo_start_fh_thread(fh);
-               if (ret)
-                       return ret;
-       }
-
-       ret = videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
-       if (ret)
-               return ret;
-
-       /* Signal motion detection */
-       if (solo_is_motion_on(solo_enc)) {
-               buf->flags |= V4L2_BUF_FLAG_MOTION_ON;
-               if (solo_enc->motion_detected) {
-                       buf->flags |= V4L2_BUF_FLAG_MOTION_DETECTED;
-                       solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR,
-                                      1 << solo_enc->ch);
-                       solo_enc->motion_detected = 0;
-               }
-       }
-
-       /* Check for key frame on mpeg data */
-       if (fh->fmt == V4L2_PIX_FMT_MPEG) {
-               struct videobuf_dmabuf *vbuf =
-                               videobuf_to_dma(fh->vidq.bufs[buf->index]);
-
-               if (vbuf) {
-                       u8 *p = sg_virt(vbuf->sglist);
-                       if (p[3] == 0x00)
-                               buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
-                       else
-                               buf->flags |= V4L2_BUF_FLAG_PFRAME;
-               }
-       }
-
-       return 0;
-}
-
-static int solo_enc_streamon(struct file *file, void *priv,
-                            enum v4l2_buf_type i)
-{
-       struct solo_enc_fh *fh = priv;
-
-       if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       return videobuf_streamon(&fh->vidq);
-}
-
-static int solo_enc_streamoff(struct file *file, void *priv,
-                             enum v4l2_buf_type i)
-{
-       struct solo_enc_fh *fh = priv;
-
-       if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       return videobuf_streamoff(&fh->vidq);
-}
-
-static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id *i)
-{
-       return 0;
-}
-
-static int solo_enum_framesizes(struct file *file, void *priv,
-                               struct v4l2_frmsizeenum *fsize)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_dev *solo_dev = fh->enc->solo_dev;
-
-       if (fsize->pixel_format != V4L2_PIX_FMT_MPEG)
-               return -EINVAL;
-
-       switch (fsize->index) {
-       case 0:
-               fsize->discrete.width = solo_dev->video_hsize >> 1;
-               fsize->discrete.height = solo_dev->video_vsize;
-               break;
-       case 1:
-               fsize->discrete.width = solo_dev->video_hsize;
-               fsize->discrete.height = solo_dev->video_vsize << 1;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
-
-       return 0;
-}
-
-static int solo_enum_frameintervals(struct file *file, void *priv,
-                                   struct v4l2_frmivalenum *fintv)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_dev *solo_dev = fh->enc->solo_dev;
-
-       if (fintv->pixel_format != V4L2_PIX_FMT_MPEG || fintv->index)
-               return -EINVAL;
-
-       fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
-
-       fintv->stepwise.min.numerator = solo_dev->fps;
-       fintv->stepwise.min.denominator = 1;
-
-       fintv->stepwise.max.numerator = solo_dev->fps;
-       fintv->stepwise.max.denominator = 15;
-
-       fintv->stepwise.step.numerator = 1;
-       fintv->stepwise.step.denominator = 1;
-
-       return 0;
-}
-
-static int solo_g_parm(struct file *file, void *priv,
-                      struct v4l2_streamparm *sp)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-       struct v4l2_captureparm *cp = &sp->parm.capture;
-
-       cp->capability = V4L2_CAP_TIMEPERFRAME;
-       cp->timeperframe.numerator = solo_enc->interval;
-       cp->timeperframe.denominator = solo_dev->fps;
-       cp->capturemode = 0;
-       /* XXX: Shouldn't we be able to get/set this from videobuf? */
-       cp->readbuffers = 2;
-
-       return 0;
-}
-
-static int solo_s_parm(struct file *file, void *priv,
-                      struct v4l2_streamparm *sp)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-       struct v4l2_captureparm *cp = &sp->parm.capture;
-
-       spin_lock(&solo_enc->lock);
-
-       if (atomic_read(&solo_enc->readers) > 0) {
-               spin_unlock(&solo_enc->lock);
-               return -EBUSY;
-       }
-
-       if ((cp->timeperframe.numerator == 0) ||
-           (cp->timeperframe.denominator == 0)) {
-               /* reset framerate */
-               cp->timeperframe.numerator = 1;
-               cp->timeperframe.denominator = solo_dev->fps;
-       }
-
-       if (cp->timeperframe.denominator != solo_dev->fps)
-               cp->timeperframe.denominator = solo_dev->fps;
-
-       if (cp->timeperframe.numerator > 15)
-               cp->timeperframe.numerator = 15;
-
-       solo_enc->interval = cp->timeperframe.numerator;
-
-       cp->capability = V4L2_CAP_TIMEPERFRAME;
-
-       solo_enc->gop = max(solo_dev->fps / solo_enc->interval, 1);
-       solo_update_mode(solo_enc);
-
-       spin_unlock(&solo_enc->lock);
-
-       return 0;
-}
-
-static int solo_queryctrl(struct file *file, void *priv,
-                         struct v4l2_queryctrl *qc)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-       qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
-       if (!qc->id)
-               return -EINVAL;
-
-       switch (qc->id) {
-       case V4L2_CID_BRIGHTNESS:
-       case V4L2_CID_CONTRAST:
-       case V4L2_CID_SATURATION:
-       case V4L2_CID_HUE:
-               return v4l2_ctrl_query_fill(qc, 0x00, 0xff, 1, 0x80);
-       case V4L2_CID_SHARPNESS:
-               return v4l2_ctrl_query_fill(qc, 0x00, 0x0f, 1, 0x00);
-       case V4L2_CID_MPEG_VIDEO_ENCODING:
-               return v4l2_ctrl_query_fill(
-                       qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
-                       V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
-                       V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
-       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-               return v4l2_ctrl_query_fill(qc, 1, 255, 1, solo_dev->fps);
-#ifdef PRIVATE_CIDS
-       case V4L2_CID_MOTION_THRESHOLD:
-               qc->flags |= V4L2_CTRL_FLAG_SLIDER;
-               qc->type = V4L2_CTRL_TYPE_INTEGER;
-               qc->minimum = 0;
-               qc->maximum = 0xffff;
-               qc->step = 1;
-               qc->default_value = SOLO_DEF_MOT_THRESH;
-               strlcpy(qc->name, "Motion Detection Threshold",
-                       sizeof(qc->name));
-               return 0;
-       case V4L2_CID_MOTION_ENABLE:
-               qc->type = V4L2_CTRL_TYPE_BOOLEAN;
-               qc->minimum = 0;
-               qc->maximum = qc->step = 1;
-               qc->default_value = 0;
-               strlcpy(qc->name, "Motion Detection Enable", sizeof(qc->name));
-               return 0;
-#else
-       case V4L2_CID_MOTION_THRESHOLD:
-               return v4l2_ctrl_query_fill(qc, 0, 0xffff, 1,
-                                           SOLO_DEF_MOT_THRESH);
-       case V4L2_CID_MOTION_ENABLE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
-#endif
-       case V4L2_CID_RDS_TX_RADIO_TEXT:
-               qc->type = V4L2_CTRL_TYPE_STRING;
-               qc->minimum = 0;
-               qc->maximum = OSD_TEXT_MAX;
-               qc->step = 1;
-               qc->default_value = 0;
-               strlcpy(qc->name, "OSD Text", sizeof(qc->name));
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static int solo_querymenu(struct file *file, void *priv,
-                         struct v4l2_querymenu *qmenu)
-{
-       struct v4l2_queryctrl qctrl;
-       int err;
-
-       qctrl.id = qmenu->id;
-       err = solo_queryctrl(file, priv, &qctrl);
-       if (err)
-               return err;
-
-       return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
-}
-
-static int solo_g_ctrl(struct file *file, void *priv,
-                      struct v4l2_control *ctrl)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-       case V4L2_CID_CONTRAST:
-       case V4L2_CID_SATURATION:
-       case V4L2_CID_HUE:
-       case V4L2_CID_SHARPNESS:
-               return tw28_get_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
-                                        &ctrl->value);
-       case V4L2_CID_MPEG_VIDEO_ENCODING:
-               ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
-               break;
-       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-               ctrl->value = solo_enc->gop;
-               break;
-       case V4L2_CID_MOTION_THRESHOLD:
-               ctrl->value = solo_enc->motion_thresh;
-               break;
-       case V4L2_CID_MOTION_ENABLE:
-               ctrl->value = solo_is_motion_on(solo_enc);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int solo_s_ctrl(struct file *file, void *priv,
-                      struct v4l2_control *ctrl)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
-       struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-       switch (ctrl->id) {
-       case V4L2_CID_BRIGHTNESS:
-       case V4L2_CID_CONTRAST:
-       case V4L2_CID_SATURATION:
-       case V4L2_CID_HUE:
-       case V4L2_CID_SHARPNESS:
-               return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
-                                        ctrl->value);
-       case V4L2_CID_MPEG_VIDEO_ENCODING:
-               if (ctrl->value != V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC)
-                       return -ERANGE;
-               break;
-       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
-               if (ctrl->value < 1 || ctrl->value > 255)
-                       return -ERANGE;
-               solo_enc->gop = ctrl->value;
-               solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch),
-                              solo_enc->gop);
-               solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch),
-                              solo_enc->gop);
-               break;
-       case V4L2_CID_MOTION_THRESHOLD:
-               /* TODO accept value on lower 16-bits and use high
-                * 16-bits to assign the value to a specific block */
-               if (ctrl->value < 0 || ctrl->value > 0xffff)
-                       return -ERANGE;
-               solo_enc->motion_thresh = ctrl->value;
-               solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->value);
-               break;
-       case V4L2_CID_MOTION_ENABLE:
-               solo_motion_toggle(solo_enc, ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int solo_s_ext_ctrls(struct file *file, void *priv,
-                           struct v4l2_ext_controls *ctrls)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
-       int i;
-
-       for (i = 0; i < ctrls->count; i++) {
-               struct v4l2_ext_control *ctrl = (ctrls->controls + i);
-               int err;
-
-               switch (ctrl->id) {
-               case V4L2_CID_RDS_TX_RADIO_TEXT:
-                       if (ctrl->size - 1 > OSD_TEXT_MAX)
-                               err = -ERANGE;
-                       else {
-                               err = copy_from_user(solo_enc->osd_text,
-                                                    ctrl->string,
-                                                    OSD_TEXT_MAX);
-                               solo_enc->osd_text[OSD_TEXT_MAX] = '\0';
-                               if (!err)
-                                       err = solo_osd_print(solo_enc);
-                       }
-                       break;
-               default:
-                       err = -EINVAL;
-               }
-
-               if (err < 0) {
-                       ctrls->error_idx = i;
-                       return err;
-               }
-       }
-
-       return 0;
-}
-
-static int solo_g_ext_ctrls(struct file *file, void *priv,
-                           struct v4l2_ext_controls *ctrls)
-{
-       struct solo_enc_fh *fh = priv;
-       struct solo_enc_dev *solo_enc = fh->enc;
-       int i;
-
-       for (i = 0; i < ctrls->count; i++) {
-               struct v4l2_ext_control *ctrl = (ctrls->controls + i);
-               int err;
-
-               switch (ctrl->id) {
-               case V4L2_CID_RDS_TX_RADIO_TEXT:
-                       if (ctrl->size < OSD_TEXT_MAX) {
-                               ctrl->size = OSD_TEXT_MAX;
-                               err = -ENOSPC;
-                       } else {
-                               err = copy_to_user(ctrl->string,
-                                                  solo_enc->osd_text,
-                                                  OSD_TEXT_MAX);
-                       }
-                       break;
-               default:
-                       err = -EINVAL;
-               }
-
-               if (err < 0) {
-                       ctrls->error_idx = i;
-                       return err;
-               }
-       }
-
-       return 0;
-}
-
-static const struct v4l2_file_operations solo_enc_fops = {
-       .owner                  = THIS_MODULE,
-       .open                   = solo_enc_open,
-       .release                = solo_enc_release,
-       .read                   = solo_enc_read,
-       .poll                   = solo_enc_poll,
-       .mmap                   = solo_enc_mmap,
-       .ioctl                  = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
-       .vidioc_querycap                = solo_enc_querycap,
-       .vidioc_s_std                   = solo_enc_s_std,
-       /* Input callbacks */
-       .vidioc_enum_input              = solo_enc_enum_input,
-       .vidioc_s_input                 = solo_enc_set_input,
-       .vidioc_g_input                 = solo_enc_get_input,
-       /* Video capture format callbacks */
-       .vidioc_enum_fmt_vid_cap        = solo_enc_enum_fmt_cap,
-       .vidioc_try_fmt_vid_cap         = solo_enc_try_fmt_cap,
-       .vidioc_s_fmt_vid_cap           = solo_enc_set_fmt_cap,
-       .vidioc_g_fmt_vid_cap           = solo_enc_get_fmt_cap,
-       /* Streaming I/O */
-       .vidioc_reqbufs                 = solo_enc_reqbufs,
-       .vidioc_querybuf                = solo_enc_querybuf,
-       .vidioc_qbuf                    = solo_enc_qbuf,
-       .vidioc_dqbuf                   = solo_enc_dqbuf,
-       .vidioc_streamon                = solo_enc_streamon,
-       .vidioc_streamoff               = solo_enc_streamoff,
-       /* Frame size and interval */
-       .vidioc_enum_framesizes         = solo_enum_framesizes,
-       .vidioc_enum_frameintervals     = solo_enum_frameintervals,
-       /* Video capture parameters */
-       .vidioc_s_parm                  = solo_s_parm,
-       .vidioc_g_parm                  = solo_g_parm,
-       /* Controls */
-       .vidioc_queryctrl               = solo_queryctrl,
-       .vidioc_querymenu               = solo_querymenu,
-       .vidioc_g_ctrl                  = solo_g_ctrl,
-       .vidioc_s_ctrl                  = solo_s_ctrl,
-       .vidioc_g_ext_ctrls             = solo_g_ext_ctrls,
-       .vidioc_s_ext_ctrls             = solo_s_ext_ctrls,
-};
-
-static struct video_device solo_enc_template = {
-       .name                   = SOLO6X10_NAME,
-       .fops                   = &solo_enc_fops,
-       .ioctl_ops              = &solo_enc_ioctl_ops,
-       .minor                  = -1,
-       .release                = video_device_release,
-
-       .tvnorms                = V4L2_STD_NTSC_M | V4L2_STD_PAL_B,
-       .current_norm           = V4L2_STD_NTSC_M,
-};
-
-static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, u8 ch)
-{
-       struct solo_enc_dev *solo_enc;
-       int ret;
-
-       solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
-       if (!solo_enc)
-               return ERR_PTR(-ENOMEM);
-
-       solo_enc->vfd = video_device_alloc();
-       if (!solo_enc->vfd) {
-               kfree(solo_enc);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       solo_enc->solo_dev = solo_dev;
-       solo_enc->ch = ch;
-
-       *solo_enc->vfd = solo_enc_template;
-       solo_enc->vfd->parent = &solo_dev->pdev->dev;
-       ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER,
-                                   video_nr);
-       if (ret < 0) {
-               video_device_release(solo_enc->vfd);
-               kfree(solo_enc);
-               return ERR_PTR(ret);
-       }
-
-       video_set_drvdata(solo_enc->vfd, solo_enc);
-
-       snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
-                "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num,
-                solo_enc->vfd->num);
-
-       if (video_nr != -1)
-               video_nr++;
-
-       spin_lock_init(&solo_enc->lock);
-       init_waitqueue_head(&solo_enc->thread_wait);
-       atomic_set(&solo_enc->readers, 0);
-
-       solo_enc->qp = SOLO_DEFAULT_QP;
-       solo_enc->gop = solo_dev->fps;
-       solo_enc->interval = 1;
-       solo_enc->mode = SOLO_ENC_MODE_CIF;
-       solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
-
-       spin_lock(&solo_enc->lock);
-       solo_update_mode(solo_enc);
-       spin_unlock(&solo_enc->lock);
-
-       return solo_enc;
-}
-
-static void solo_enc_free(struct solo_enc_dev *solo_enc)
-{
-       if (solo_enc == NULL)
-               return;
-
-       video_unregister_device(solo_enc->vfd);
-       kfree(solo_enc);
-}
-
-int solo_enc_v4l2_init(struct solo_dev *solo_dev)
-{
-       int i;
-
-       for (i = 0; i < solo_dev->nr_chans; i++) {
-               solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i);
-               if (IS_ERR(solo_dev->v4l2_enc[i]))
-                       break;
-       }
-
-       if (i != solo_dev->nr_chans) {
-               int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
-               while (i--)
-                       solo_enc_free(solo_dev->v4l2_enc[i]);
-               return ret;
-       }
-
-       /* D1@MAX-FPS * 4 */
-       solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4;
-
-       dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n",
-                solo_dev->v4l2_enc[0]->vfd->num,
-                solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
-
-       return 0;
-}
-
-void solo_enc_v4l2_exit(struct solo_dev *solo_dev)
-{
-       int i;
-
-       solo_irq_off(solo_dev, SOLO_IRQ_MOTION);
-
-       for (i = 0; i < solo_dev->nr_chans; i++)
-               solo_enc_free(solo_dev->v4l2_enc[i]);
-}
diff --git a/drivers/staging/solo6x10/v4l2.c b/drivers/staging/solo6x10/v4l2.c
deleted file mode 100644 (file)
index 571c3a3..0000000
+++ /dev/null
@@ -1,964 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-common.h>
-#include <media/videobuf-dma-sg.h>
-#include "solo6x10.h"
-#include "tw28.h"
-
-#define SOLO_HW_BPL            2048
-#define SOLO_DISP_PIX_FIELD    V4L2_FIELD_INTERLACED
-
-/* Image size is two fields, SOLO_HW_BPL is one horizontal line */
-#define solo_vlines(__solo)    (__solo->video_vsize * 2)
-#define solo_image_size(__solo) (solo_bytesperline(__solo) * \
-                                solo_vlines(__solo))
-#define solo_bytesperline(__solo) (__solo->video_hsize * 2)
-
-#define MIN_VID_BUFFERS                4
-
-/* Simple file handle */
-struct solo_filehandle {
-       struct solo_dev         *solo_dev;
-       struct videobuf_queue   vidq;
-       struct task_struct      *kthread;
-       spinlock_t              slock;
-       int                     old_write;
-       struct list_head        vidq_active;
-       struct p2m_desc         desc[SOLO_NR_P2M_DESC];
-       int                     desc_idx;
-};
-
-unsigned video_nr = -1;
-module_param(video_nr, uint, 0644);
-MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)");
-
-static void erase_on(struct solo_dev *solo_dev)
-{
-       solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
-       solo_dev->erasing = 1;
-       solo_dev->frame_blank = 0;
-}
-
-static int erase_off(struct solo_dev *solo_dev)
-{
-       if (!solo_dev->erasing)
-               return 0;
-
-       /* First time around, assert erase off */
-       if (!solo_dev->frame_blank)
-               solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0);
-       /* Keep the erasing flag on for 8 frames minimum */
-       if (solo_dev->frame_blank++ >= 8)
-               solo_dev->erasing = 0;
-
-       return 1;
-}
-
-void solo_video_in_isr(struct solo_dev *solo_dev)
-{
-       solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_VIDEO_IN);
-       wake_up_interruptible(&solo_dev->disp_thread_wait);
-}
-
-static void solo_win_setup(struct solo_dev *solo_dev, u8 ch,
-                          int sx, int sy, int ex, int ey, int scale)
-{
-       if (ch >= solo_dev->nr_chans)
-               return;
-
-       /* Here, we just keep window/channel the same */
-       solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch),
-                      SOLO_VI_WIN_CHANNEL(ch) |
-                      SOLO_VI_WIN_SX(sx) |
-                      SOLO_VI_WIN_EX(ex) |
-                      SOLO_VI_WIN_SCALE(scale));
-
-       solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
-                      SOLO_VI_WIN_SY(sy) |
-                      SOLO_VI_WIN_EY(ey));
-}
-
-static int solo_v4l2_ch_ext_4up(struct solo_dev *solo_dev, u8 idx, int on)
-{
-       u8 ch = idx * 4;
-
-       if (ch >= solo_dev->nr_chans)
-               return -EINVAL;
-
-       if (!on) {
-               u8 i;
-               for (i = ch; i < ch + 4; i++)
-                       solo_win_setup(solo_dev, i, solo_dev->video_hsize,
-                                      solo_vlines(solo_dev),
-                                      solo_dev->video_hsize,
-                                      solo_vlines(solo_dev), 0);
-               return 0;
-       }
-
-       /* Row 1 */
-       solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2,
-                      solo_vlines(solo_dev) / 2, 3);
-       solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0,
-                      solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3);
-       /* Row 2 */
-       solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2,
-                      solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3);
-       solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2,
-                      solo_vlines(solo_dev) / 2, solo_dev->video_hsize,
-                      solo_vlines(solo_dev), 3);
-
-       return 0;
-}
-
-static int solo_v4l2_ch_ext_16up(struct solo_dev *solo_dev, int on)
-{
-       int sy, ysize, hsize, i;
-
-       if (!on) {
-               for (i = 0; i < 16; i++)
-                       solo_win_setup(solo_dev, i, solo_dev->video_hsize,
-                                      solo_vlines(solo_dev),
-                                      solo_dev->video_hsize,
-                                      solo_vlines(solo_dev), 0);
-               return 0;
-       }
-
-       ysize = solo_vlines(solo_dev) / 4;
-       hsize = solo_dev->video_hsize / 4;
-
-       for (sy = 0, i = 0; i < 4; i++, sy += ysize) {
-               solo_win_setup(solo_dev, i * 4, 0, sy, hsize,
-                              sy + ysize, 5);
-               solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy,
-                              hsize * 2, sy + ysize, 5);
-               solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy,
-                              hsize * 3, sy + ysize, 5);
-               solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy,
-                              solo_dev->video_hsize, sy + ysize, 5);
-       }
-
-       return 0;
-}
-
-static int solo_v4l2_ch(struct solo_dev *solo_dev, u8 ch, int on)
-{
-       u8 ext_ch;
-
-       if (ch < solo_dev->nr_chans) {
-               solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize,
-                              on ? 0 : solo_vlines(solo_dev),
-                              solo_dev->video_hsize, solo_vlines(solo_dev),
-                              on ? 1 : 0);
-               return 0;
-       }
-
-       if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
-               return -EINVAL;
-
-       ext_ch = ch - solo_dev->nr_chans;
-
-       /* 4up's first */
-       if (ext_ch < 4)
-               return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on);
-
-       /* Remaining case is 16up for 16-port */
-       return solo_v4l2_ch_ext_16up(solo_dev, on);
-}
-
-static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch)
-{
-       if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
-               return -EINVAL;
-
-       erase_on(solo_dev);
-
-       solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0);
-       solo_v4l2_ch(solo_dev, ch, 1);
-
-       solo_dev->cur_disp_ch = ch;
-
-       return 0;
-}
-
-static void disp_reset_desc(struct solo_filehandle *fh)
-{
-       /* We use desc mode, which ignores desc 0 */
-       memset(fh->desc, 0, sizeof(*fh->desc));
-       fh->desc_idx = 1;
-}
-
-static int disp_flush_descs(struct solo_filehandle *fh)
-{
-       int ret;
-
-       if (!fh->desc_idx)
-               return 0;
-
-       ret = solo_p2m_dma_desc(fh->solo_dev, SOLO_P2M_DMA_ID_DISP,
-                               fh->desc, fh->desc_idx);
-       disp_reset_desc(fh);
-
-       return ret;
-}
-
-static int disp_push_desc(struct solo_filehandle *fh, dma_addr_t dma_addr,
-                     u32 ext_addr, int size, int repeat, int ext_size)
-{
-       if (fh->desc_idx >= SOLO_NR_P2M_DESC) {
-               int ret = disp_flush_descs(fh);
-               if (ret)
-                       return ret;
-       }
-
-       solo_p2m_push_desc(&fh->desc[fh->desc_idx], 0, dma_addr, ext_addr,
-                          size, repeat, ext_size);
-       fh->desc_idx++;
-
-       return 0;
-}
-
-static void solo_fillbuf(struct solo_filehandle *fh,
-                        struct videobuf_buffer *vb)
-{
-       struct solo_dev *solo_dev = fh->solo_dev;
-       struct videobuf_dmabuf *vbuf;
-       unsigned int fdma_addr;
-       int error = 1;
-       int i;
-       struct scatterlist *sg;
-       dma_addr_t sg_dma;
-       int sg_size_left;
-
-       vbuf = videobuf_to_dma(vb);
-       if (!vbuf)
-               goto finish_buf;
-
-       if (erase_off(solo_dev)) {
-               int i;
-
-               /* Just blit to the entire sg list, ignoring size */
-               for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) {
-                       void *p = sg_virt(sg);
-                       size_t len = sg_dma_len(sg);
-
-                       for (i = 0; i < len; i += 2) {
-                               ((u8 *)p)[i] = 0x80;
-                               ((u8 *)p)[i + 1] = 0x00;
-                       }
-               }
-
-               error = 0;
-               goto finish_buf;
-       }
-
-       disp_reset_desc(fh);
-       sg = vbuf->sglist;
-       sg_dma = sg_dma_address(sg);
-       sg_size_left = sg_dma_len(sg);
-
-       fdma_addr = SOLO_DISP_EXT_ADDR + (fh->old_write *
-                       (SOLO_HW_BPL * solo_vlines(solo_dev)));
-
-       for (i = 0; i < solo_vlines(solo_dev); i++) {
-               int line_len = solo_bytesperline(solo_dev);
-               int lines;
-
-               if (!sg_size_left) {
-                       sg = sg_next(sg);
-                       if (sg == NULL)
-                               goto finish_buf;
-                       sg_dma = sg_dma_address(sg);
-                       sg_size_left = sg_dma_len(sg);
-               }
-
-               /* No room for an entire line, so chunk it up */
-               if (sg_size_left < line_len) {
-                       int this_addr = fdma_addr;
-
-                       while (line_len > 0) {
-                               int this_write;
-
-                               if (!sg_size_left) {
-                                       sg = sg_next(sg);
-                                       if (sg == NULL)
-                                               goto finish_buf;
-                                       sg_dma = sg_dma_address(sg);
-                                       sg_size_left = sg_dma_len(sg);
-                               }
-
-                               this_write = min(sg_size_left, line_len);
-
-                               if (disp_push_desc(fh, sg_dma, this_addr,
-                                                  this_write, 0, 0))
-                                       goto finish_buf;
-
-                               line_len -= this_write;
-                               sg_size_left -= this_write;
-                               sg_dma += this_write;
-                               this_addr += this_write;
-                       }
-
-                       fdma_addr += SOLO_HW_BPL;
-                       continue;
-               }
-
-               /* Shove as many lines into a repeating descriptor as possible */
-               lines = min(sg_size_left / line_len,
-                           solo_vlines(solo_dev) - i);
-
-               if (disp_push_desc(fh, sg_dma, fdma_addr, line_len,
-                                  lines - 1, SOLO_HW_BPL))
-                       goto finish_buf;
-
-               i += lines - 1;
-               fdma_addr += SOLO_HW_BPL * lines;
-               sg_dma += lines * line_len;
-               sg_size_left -= lines * line_len;
-       }
-
-       error = disp_flush_descs(fh);
-
-finish_buf:
-       if (error) {
-               vb->state = VIDEOBUF_ERROR;
-       } else {
-               vb->size = solo_vlines(solo_dev) * solo_bytesperline(solo_dev);
-               vb->state = VIDEOBUF_DONE;
-               vb->field_count++;
-               do_gettimeofday(&vb->ts);
-       }
-
-       wake_up(&vb->done);
-
-       return;
-}
-
-static void solo_thread_try(struct solo_filehandle *fh)
-{
-       struct videobuf_buffer *vb;
-       unsigned int cur_write;
-
-       for (;;) {
-               spin_lock(&fh->slock);
-
-               if (list_empty(&fh->vidq_active))
-                       break;
-
-               vb = list_first_entry(&fh->vidq_active, struct videobuf_buffer,
-                                     queue);
-
-               if (!waitqueue_active(&vb->done))
-                       break;
-
-               cur_write = SOLO_VI_STATUS0_PAGE(solo_reg_read(fh->solo_dev,
-                                                SOLO_VI_STATUS0));
-               if (cur_write == fh->old_write)
-                       break;
-
-               fh->old_write = cur_write;
-               list_del(&vb->queue);
-
-               spin_unlock(&fh->slock);
-
-               solo_fillbuf(fh, vb);
-       }
-
-       assert_spin_locked(&fh->slock);
-       spin_unlock(&fh->slock);
-}
-
-static int solo_thread(void *data)
-{
-       struct solo_filehandle *fh = data;
-       struct solo_dev *solo_dev = fh->solo_dev;
-       DECLARE_WAITQUEUE(wait, current);
-
-       set_freezable();
-       add_wait_queue(&solo_dev->disp_thread_wait, &wait);
-
-       for (;;) {
-               long timeout = schedule_timeout_interruptible(HZ);
-               if (timeout == -ERESTARTSYS || kthread_should_stop())
-                       break;
-               solo_thread_try(fh);
-               try_to_freeze();
-       }
-
-       remove_wait_queue(&solo_dev->disp_thread_wait, &wait);
-
-       return 0;
-}
-
-static int solo_start_thread(struct solo_filehandle *fh)
-{
-       fh->kthread = kthread_run(solo_thread, fh, SOLO6X10_NAME "_disp");
-
-       if (IS_ERR(fh->kthread))
-               return PTR_ERR(fh->kthread);
-
-       return 0;
-}
-
-static void solo_stop_thread(struct solo_filehandle *fh)
-{
-       if (fh->kthread) {
-               kthread_stop(fh->kthread);
-               fh->kthread = NULL;
-       }
-}
-
-static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count,
-                         unsigned int *size)
-{
-       struct solo_filehandle *fh = vq->priv_data;
-       struct solo_dev *solo_dev  = fh->solo_dev;
-
-       *size = solo_image_size(solo_dev);
-
-       if (*count < MIN_VID_BUFFERS)
-               *count = MIN_VID_BUFFERS;
-
-       return 0;
-}
-
-static int solo_buf_prepare(struct videobuf_queue *vq,
-                           struct videobuf_buffer *vb, enum v4l2_field field)
-{
-       struct solo_filehandle *fh  = vq->priv_data;
-       struct solo_dev *solo_dev = fh->solo_dev;
-
-       vb->size = solo_image_size(solo_dev);
-       if (vb->baddr != 0 && vb->bsize < vb->size)
-               return -EINVAL;
-
-       /* XXX: These properties only change when queue is idle */
-       vb->width  = solo_dev->video_hsize;
-       vb->height = solo_vlines(solo_dev);
-       vb->bytesperline = solo_bytesperline(solo_dev);
-       vb->field  = field;
-
-       if (vb->state == VIDEOBUF_NEEDS_INIT) {
-               int rc = videobuf_iolock(vq, vb, NULL);
-               if (rc < 0) {
-                       struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
-                       videobuf_dma_unmap(vq->dev, dma);
-                       videobuf_dma_free(dma);
-                       vb->state = VIDEOBUF_NEEDS_INIT;
-                       return rc;
-               }
-       }
-       vb->state = VIDEOBUF_PREPARED;
-
-       return 0;
-}
-
-static void solo_buf_queue(struct videobuf_queue *vq,
-                          struct videobuf_buffer *vb)
-{
-       struct solo_filehandle *fh = vq->priv_data;
-       struct solo_dev *solo_dev = fh->solo_dev;
-
-       vb->state = VIDEOBUF_QUEUED;
-       list_add_tail(&vb->queue, &fh->vidq_active);
-       wake_up_interruptible(&solo_dev->disp_thread_wait);
-}
-
-static void solo_buf_release(struct videobuf_queue *vq,
-                            struct videobuf_buffer *vb)
-{
-       struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
-
-       videobuf_dma_unmap(vq->dev, dma);
-       videobuf_dma_free(dma);
-       vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static struct videobuf_queue_ops solo_video_qops = {
-       .buf_setup      = solo_buf_setup,
-       .buf_prepare    = solo_buf_prepare,
-       .buf_queue      = solo_buf_queue,
-       .buf_release    = solo_buf_release,
-};
-
-static unsigned int solo_v4l2_poll(struct file *file,
-                                  struct poll_table_struct *wait)
-{
-       struct solo_filehandle *fh = file->private_data;
-
-       return videobuf_poll_stream(file, &fh->vidq, wait);
-}
-
-static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct solo_filehandle *fh = file->private_data;
-
-       return videobuf_mmap_mapper(&fh->vidq, vma);
-}
-
-static int solo_v4l2_open(struct file *file)
-{
-       struct solo_dev *solo_dev = video_drvdata(file);
-       struct solo_filehandle *fh;
-       int ret;
-
-       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-       if (fh == NULL)
-               return -ENOMEM;
-
-       spin_lock_init(&fh->slock);
-       INIT_LIST_HEAD(&fh->vidq_active);
-       fh->solo_dev = solo_dev;
-       file->private_data = fh;
-
-       ret = solo_start_thread(fh);
-       if (ret) {
-               kfree(fh);
-               return ret;
-       }
-
-       videobuf_queue_sg_init(&fh->vidq, &solo_video_qops,
-                              &solo_dev->pdev->dev, &fh->slock,
-                              V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                              SOLO_DISP_PIX_FIELD,
-                              sizeof(struct videobuf_buffer), fh, NULL);
-
-       return 0;
-}
-
-static ssize_t solo_v4l2_read(struct file *file, char __user *data,
-                             size_t count, loff_t *ppos)
-{
-       struct solo_filehandle *fh = file->private_data;
-
-       return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
-                                   file->f_flags & O_NONBLOCK);
-}
-
-static int solo_v4l2_release(struct file *file)
-{
-       struct solo_filehandle *fh = file->private_data;
-
-       videobuf_stop(&fh->vidq);
-       videobuf_mmap_free(&fh->vidq);
-       solo_stop_thread(fh);
-       kfree(fh);
-
-       return 0;
-}
-
-static int solo_querycap(struct file *file, void  *priv,
-                        struct v4l2_capability *cap)
-{
-       struct solo_filehandle  *fh  = priv;
-       struct solo_dev *solo_dev = fh->solo_dev;
-
-       strcpy(cap->driver, SOLO6X10_NAME);
-       strcpy(cap->card, "Softlogic 6x10");
-       snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
-                pci_name(solo_dev->pdev));
-       cap->version = SOLO6X10_VER_NUM;
-       cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
-                               V4L2_CAP_READWRITE |
-                               V4L2_CAP_STREAMING;
-       return 0;
-}
-
-static int solo_enum_ext_input(struct solo_dev *solo_dev,
-                              struct v4l2_input *input)
-{
-       static const char *dispnames_1[] = { "4UP" };
-       static const char *dispnames_2[] = { "4UP-1", "4UP-2" };
-       static const char *dispnames_5[] = {
-               "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP"
-       };
-       const char **dispnames;
-
-       if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext))
-               return -EINVAL;
-
-       if (solo_dev->nr_ext == 5)
-               dispnames = dispnames_5;
-       else if (solo_dev->nr_ext == 2)
-               dispnames = dispnames_2;
-       else
-               dispnames = dispnames_1;
-
-       snprintf(input->name, sizeof(input->name), "Multi %s",
-                dispnames[input->index - solo_dev->nr_chans]);
-
-       return 0;
-}
-
-static int solo_enum_input(struct file *file, void *priv,
-                          struct v4l2_input *input)
-{
-       struct solo_filehandle *fh  = priv;
-       struct solo_dev *solo_dev = fh->solo_dev;
-
-       if (input->index >= solo_dev->nr_chans) {
-               int ret = solo_enum_ext_input(solo_dev, input);
-               if (ret < 0)
-                       return ret;
-       } else {
-               snprintf(input->name, sizeof(input->name), "Camera %d",
-                        input->index + 1);
-
-               /* We can only check this for normal inputs */
-               if (!tw28_get_video_status(solo_dev, input->index))
-                       input->status = V4L2_IN_ST_NO_SIGNAL;
-       }
-
-       input->type = V4L2_INPUT_TYPE_CAMERA;
-
-       if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
-               input->std = V4L2_STD_NTSC_M;
-       else
-               input->std = V4L2_STD_PAL_B;
-
-       return 0;
-}
-
-static int solo_set_input(struct file *file, void *priv, unsigned int index)
-{
-       struct solo_filehandle *fh = priv;
-
-       return solo_v4l2_set_ch(fh->solo_dev, index);
-}
-
-static int solo_get_input(struct file *file, void *priv, unsigned int *index)
-{
-       struct solo_filehandle *fh = priv;
-
-       *index = fh->solo_dev->cur_disp_ch;
-
-       return 0;
-}
-
-static int solo_enum_fmt_cap(struct file *file, void *priv,
-                            struct v4l2_fmtdesc *f)
-{
-       if (f->index)
-               return -EINVAL;
-
-       f->pixelformat = V4L2_PIX_FMT_UYVY;
-       strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
-
-       return 0;
-}
-
-static int solo_try_fmt_cap(struct file *file, void *priv,
-                           struct v4l2_format *f)
-{
-       struct solo_filehandle *fh = priv;
-       struct solo_dev *solo_dev = fh->solo_dev;
-       struct v4l2_pix_format *pix = &f->fmt.pix;
-       int image_size = solo_image_size(solo_dev);
-
-       /* Check supported sizes */
-       if (pix->width != solo_dev->video_hsize)
-               pix->width = solo_dev->video_hsize;
-       if (pix->height != solo_vlines(solo_dev))
-               pix->height = solo_vlines(solo_dev);
-       if (pix->sizeimage != image_size)
-               pix->sizeimage = image_size;
-
-       /* Check formats */
-       if (pix->field == V4L2_FIELD_ANY)
-               pix->field = SOLO_DISP_PIX_FIELD;
-
-       if (pix->pixelformat != V4L2_PIX_FMT_UYVY ||
-           pix->field       != SOLO_DISP_PIX_FIELD ||
-           pix->colorspace  != V4L2_COLORSPACE_SMPTE170M)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int solo_set_fmt_cap(struct file *file, void *priv,
-                           struct v4l2_format *f)
-{
-       struct solo_filehandle *fh = priv;
-
-       if (videobuf_queue_is_busy(&fh->vidq))
-               return -EBUSY;
-
-       /* For right now, if it doesn't match our running config,
-        * then fail */
-       return solo_try_fmt_cap(file, priv, f);
-}
-
-static int solo_get_fmt_cap(struct file *file, void *priv,
-                           struct v4l2_format *f)
-{
-       struct solo_filehandle *fh = priv;
-       struct solo_dev *solo_dev = fh->solo_dev;
-       struct v4l2_pix_format *pix = &f->fmt.pix;
-
-       pix->width = solo_dev->video_hsize;
-       pix->height = solo_vlines(solo_dev);
-       pix->pixelformat = V4L2_PIX_FMT_UYVY;
-       pix->field = SOLO_DISP_PIX_FIELD;
-       pix->sizeimage = solo_image_size(solo_dev);
-       pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
-       pix->bytesperline = solo_bytesperline(solo_dev);
-
-       return 0;
-}
-
-static int solo_reqbufs(struct file *file, void *priv,
-                       struct v4l2_requestbuffers *req)
-{
-       struct solo_filehandle *fh = priv;
-
-       return videobuf_reqbufs(&fh->vidq, req);
-}
-
-static int solo_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-       struct solo_filehandle *fh = priv;
-
-       return videobuf_querybuf(&fh->vidq, buf);
-}
-
-static int solo_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-       struct solo_filehandle *fh = priv;
-
-       return videobuf_qbuf(&fh->vidq, buf);
-}
-
-static int solo_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-       struct solo_filehandle *fh = priv;
-
-       return videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
-}
-
-static int solo_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct solo_filehandle *fh = priv;
-
-       if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       return videobuf_streamon(&fh->vidq);
-}
-
-static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
-       struct solo_filehandle *fh = priv;
-
-       if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       return videobuf_streamoff(&fh->vidq);
-}
-
-static int solo_s_std(struct file *file, void *priv, v4l2_std_id *i)
-{
-       return 0;
-}
-
-static const u32 solo_motion_ctrls[] = {
-       V4L2_CID_MOTION_TRACE,
-       0
-};
-
-static const u32 *solo_ctrl_classes[] = {
-       solo_motion_ctrls,
-       NULL
-};
-
-static int solo_disp_queryctrl(struct file *file, void *priv,
-                              struct v4l2_queryctrl *qc)
-{
-       qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
-       if (!qc->id)
-               return -EINVAL;
-
-       switch (qc->id) {
-#ifdef PRIVATE_CIDS
-       case V4L2_CID_MOTION_TRACE:
-               qc->type = V4L2_CTRL_TYPE_BOOLEAN;
-               qc->minimum = 0;
-               qc->maximum = qc->step = 1;
-               qc->default_value = 0;
-               strlcpy(qc->name, "Motion Detection Trace", sizeof(qc->name));
-               return 0;
-#else
-       case V4L2_CID_MOTION_TRACE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
-#endif
-       }
-       return -EINVAL;
-}
-
-static int solo_disp_g_ctrl(struct file *file, void *priv,
-                           struct v4l2_control *ctrl)
-{
-       struct solo_filehandle *fh = priv;
-       struct solo_dev *solo_dev = fh->solo_dev;
-
-       switch (ctrl->id) {
-       case V4L2_CID_MOTION_TRACE:
-               ctrl->value = solo_reg_read(solo_dev, SOLO_VI_MOTION_BAR)
-                       ? 1 : 0;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int solo_disp_s_ctrl(struct file *file, void *priv,
-                           struct v4l2_control *ctrl)
-{
-       struct solo_filehandle *fh = priv;
-       struct solo_dev *solo_dev = fh->solo_dev;
-
-       switch (ctrl->id) {
-       case V4L2_CID_MOTION_TRACE:
-               if (ctrl->value) {
-                       solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER,
-                                       SOLO_VI_MOTION_Y_ADD |
-                                       SOLO_VI_MOTION_Y_VALUE(0x20) |
-                                       SOLO_VI_MOTION_CB_VALUE(0x10) |
-                                       SOLO_VI_MOTION_CR_VALUE(0x10));
-                       solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR,
-                                       SOLO_VI_MOTION_CR_ADD |
-                                       SOLO_VI_MOTION_Y_VALUE(0x10) |
-                                       SOLO_VI_MOTION_CB_VALUE(0x80) |
-                                       SOLO_VI_MOTION_CR_VALUE(0x10));
-               } else {
-                       solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
-                       solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
-               }
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static const struct v4l2_file_operations solo_v4l2_fops = {
-       .owner                  = THIS_MODULE,
-       .open                   = solo_v4l2_open,
-       .release                = solo_v4l2_release,
-       .read                   = solo_v4l2_read,
-       .poll                   = solo_v4l2_poll,
-       .mmap                   = solo_v4l2_mmap,
-       .ioctl                  = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
-       .vidioc_querycap                = solo_querycap,
-       .vidioc_s_std                   = solo_s_std,
-       /* Input callbacks */
-       .vidioc_enum_input              = solo_enum_input,
-       .vidioc_s_input                 = solo_set_input,
-       .vidioc_g_input                 = solo_get_input,
-       /* Video capture format callbacks */
-       .vidioc_enum_fmt_vid_cap        = solo_enum_fmt_cap,
-       .vidioc_try_fmt_vid_cap         = solo_try_fmt_cap,
-       .vidioc_s_fmt_vid_cap           = solo_set_fmt_cap,
-       .vidioc_g_fmt_vid_cap           = solo_get_fmt_cap,
-       /* Streaming I/O */
-       .vidioc_reqbufs                 = solo_reqbufs,
-       .vidioc_querybuf                = solo_querybuf,
-       .vidioc_qbuf                    = solo_qbuf,
-       .vidioc_dqbuf                   = solo_dqbuf,
-       .vidioc_streamon                = solo_streamon,
-       .vidioc_streamoff               = solo_streamoff,
-       /* Controls */
-       .vidioc_queryctrl               = solo_disp_queryctrl,
-       .vidioc_g_ctrl                  = solo_disp_g_ctrl,
-       .vidioc_s_ctrl                  = solo_disp_s_ctrl,
-};
-
-static struct video_device solo_v4l2_template = {
-       .name                   = SOLO6X10_NAME,
-       .fops                   = &solo_v4l2_fops,
-       .ioctl_ops              = &solo_v4l2_ioctl_ops,
-       .minor                  = -1,
-       .release                = video_device_release,
-
-       .tvnorms                = V4L2_STD_NTSC_M | V4L2_STD_PAL_B,
-       .current_norm           = V4L2_STD_NTSC_M,
-};
-
-int solo_v4l2_init(struct solo_dev *solo_dev)
-{
-       int ret;
-       int i;
-
-       init_waitqueue_head(&solo_dev->disp_thread_wait);
-
-       solo_dev->vfd = video_device_alloc();
-       if (!solo_dev->vfd)
-               return -ENOMEM;
-
-       *solo_dev->vfd = solo_v4l2_template;
-       solo_dev->vfd->parent = &solo_dev->pdev->dev;
-
-       ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, video_nr);
-       if (ret < 0) {
-               video_device_release(solo_dev->vfd);
-               solo_dev->vfd = NULL;
-               return ret;
-       }
-
-       video_set_drvdata(solo_dev->vfd, solo_dev);
-
-       snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
-                SOLO6X10_NAME, solo_dev->vfd->num);
-
-       if (video_nr != -1)
-               video_nr++;
-
-       dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with "
-                "%d inputs (%d extended)\n", solo_dev->vfd->num,
-                solo_dev->nr_chans, solo_dev->nr_ext);
-
-       /* Cycle all the channels and clear */
-       for (i = 0; i < solo_dev->nr_chans; i++) {
-               solo_v4l2_set_ch(solo_dev, i);
-               while (erase_off(solo_dev))
-                       ;/* Do nothing */
-       }
-
-       /* Set the default display channel */
-       solo_v4l2_set_ch(solo_dev, 0);
-       while (erase_off(solo_dev))
-               ;/* Do nothing */
-
-       solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
-
-       return 0;
-}
-
-void solo_v4l2_exit(struct solo_dev *solo_dev)
-{
-       solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
-       if (solo_dev->vfd) {
-               video_unregister_device(solo_dev->vfd);
-               solo_dev->vfd = NULL;
-       }
-}