aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/go7007
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/go7007')
-rw-r--r--drivers/staging/go7007/Kconfig10
-rw-r--r--drivers/staging/go7007/Makefile15
-rw-r--r--drivers/staging/go7007/go7007-driver.c5
-rw-r--r--drivers/staging/go7007/go7007-fw.c30
-rw-r--r--drivers/staging/go7007/go7007-priv.h2
-rw-r--r--drivers/staging/go7007/go7007-usb.c95
-rw-r--r--drivers/staging/go7007/go7007-v4l2.c1706
-rw-r--r--drivers/staging/go7007/go7007.txt481
-rw-r--r--drivers/staging/go7007/s2250-board.c630
-rw-r--r--drivers/staging/go7007/s2250-loader.c188
-rw-r--r--drivers/staging/go7007/saa7134-go7007.c52
-rw-r--r--drivers/staging/go7007/wis-i2c.h1
-rw-r--r--drivers/staging/go7007/wis-sony-tuner.c2
13 files changed, 2509 insertions, 708 deletions
diff --git a/drivers/staging/go7007/Kconfig b/drivers/staging/go7007/Kconfig
index 593fdb767aad..f2cf7f66ae05 100644
--- a/drivers/staging/go7007/Kconfig
+++ b/drivers/staging/go7007/Kconfig
@@ -25,3 +25,13 @@ config VIDEO_GO7007_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-board
+
diff --git a/drivers/staging/go7007/Makefile b/drivers/staging/go7007/Makefile
index 9b9310cae1ce..e514b4af6d06 100644
--- a/drivers/staging/go7007/Makefile
+++ b/drivers/staging/go7007/Makefile
@@ -5,14 +5,23 @@
obj-$(CONFIG_VIDEO_GO7007) += go7007.o
obj-$(CONFIG_VIDEO_GO7007_USB) += go7007-usb.o
+obj-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD) += s2250.o
-go7007-objs += go7007-v4l2.o go7007-driver.o go7007-i2c.o go7007-fw.o snd-go7007.o
+go7007-objs += go7007-v4l2.o go7007-driver.o go7007-i2c.o go7007-fw.o \
+ snd-go7007.o wis-saa7113.o
+s2250-objs += s2250-board.o s2250-loader.o
-#ifneq ($(SAA7134_BUILD),)
-#obj-m += saa7134-go7007.o
+# Uncompile when the saa7134 patches get into upstream
+#ifneq ($(CONFIG_VIDEO_SAA7134),)
+#obj-$(CONFIG_VIDEO_SAA7134) += saa7134-go7007.o
+#EXTRA_CFLAGS += -Idrivers/media/video/saa7134
#endif
+ifneq ($(CONFIG_VIDEO_GO7007_USB_S2250_BOARD),)
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-usb
+endif
+
EXTRA_CFLAGS += -Idrivers/staging/saa7134
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c
index e4ead96679c8..58bfc8d81b3b 100644
--- a/drivers/staging/go7007/go7007-driver.c
+++ b/drivers/staging/go7007/go7007-driver.c
@@ -217,6 +217,9 @@ static int init_i2c_module(struct i2c_adapter *adapter, int id, int addr)
case I2C_DRIVERID_WIS_OV7640:
modname = "wis-ov7640";
break;
+ case I2C_DRIVERID_S2250:
+ modname = "s2250-board";
+ break;
default:
modname = NULL;
break;
@@ -227,7 +230,7 @@ static int init_i2c_module(struct i2c_adapter *adapter, int id, int addr)
return 0;
if (modname != NULL)
printk(KERN_INFO
- "go7007: probing for module %s failed", modname);
+ "go7007: probing for module %s failed\n", modname);
else
printk(KERN_INFO
"go7007: sensor %u seems to be unsupported!\n", id);
diff --git a/drivers/staging/go7007/go7007-fw.c b/drivers/staging/go7007/go7007-fw.c
index a0e17b0e0ce3..871ed43e4e05 100644
--- a/drivers/staging/go7007/go7007-fw.c
+++ b/drivers/staging/go7007/go7007-fw.c
@@ -284,7 +284,7 @@ static const int zz[64] = {
58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
};
-static int copy_packages(u16 *dest, u16 *src, int pkg_cnt, int space)
+static int copy_packages(__le16 *dest, u16 *src, int pkg_cnt, int space)
{
int i, cnt = pkg_cnt * 32;
@@ -292,7 +292,7 @@ static int copy_packages(u16 *dest, u16 *src, int pkg_cnt, int space)
return -1;
for (i = 0; i < cnt; ++i)
- dest[i] = __cpu_to_le16(src[i]);
+ dest[i] = cpu_to_le16p(src + i);
return cnt;
}
@@ -372,7 +372,7 @@ static int mjpeg_frame_header(struct go7007 *go, unsigned char *buf, int q)
return p;
}
-static int gen_mjpeghdr_to_package(struct go7007 *go, u16 *code, int space)
+static int gen_mjpeghdr_to_package(struct go7007 *go, __le16 *code, int space)
{
u8 *buf;
u16 mem = 0x3e00;
@@ -643,7 +643,7 @@ static int mpeg1_sequence_header(struct go7007 *go, unsigned char *buf, int ext)
}
static int gen_mpeg1hdr_to_package(struct go7007 *go,
- u16 *code, int space, int *framelen)
+ __le16 *code, int space, int *framelen)
{
u8 *buf;
u16 mem = 0x3e00;
@@ -831,7 +831,7 @@ static int mpeg4_sequence_header(struct go7007 *go, unsigned char *buf, int ext)
}
static int gen_mpeg4hdr_to_package(struct go7007 *go,
- u16 *code, int space, int *framelen)
+ __le16 *code, int space, int *framelen)
{
u8 *buf;
u16 mem = 0x3e00;
@@ -936,7 +936,7 @@ done:
}
static int brctrl_to_package(struct go7007 *go,
- u16 *code, int space, int *framelen)
+ __le16 *code, int space, int *framelen)
{
int converge_speed = 0;
int lambda = (go->format == GO7007_FORMAT_MJPEG || go->dvd_mode) ?
@@ -1091,7 +1091,7 @@ static int brctrl_to_package(struct go7007 *go,
return copy_packages(code, pack, 6, space);
}
-static int config_package(struct go7007 *go, u16 *code, int 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;
@@ -1213,7 +1213,7 @@ static int config_package(struct go7007 *go, u16 *code, int space)
return copy_packages(code, pack, 5, space);
}
-static int seqhead_to_package(struct go7007 *go, u16 *code, int 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))
{
@@ -1292,7 +1292,7 @@ static int relative_prime(int big, int little)
return big;
}
-static int avsync_to_package(struct go7007 *go, u16 *code, int space)
+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;
@@ -1323,7 +1323,7 @@ static int avsync_to_package(struct go7007 *go, u16 *code, int space)
return copy_packages(code, pack, 1, space);
}
-static int final_package(struct go7007 *go, u16 *code, int 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[] = {
@@ -1386,7 +1386,7 @@ static int final_package(struct go7007 *go, u16 *code, int space)
return copy_packages(code, pack, 1, space);
}
-static int audio_to_package(struct go7007 *go, u16 *code, int 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) |
@@ -1436,7 +1436,7 @@ static int audio_to_package(struct go7007 *go, u16 *code, int space)
return copy_packages(code, pack, 2, space);
}
-static int modet_to_package(struct go7007 *go, u16 *code, int space)
+static int modet_to_package(struct go7007 *go, __le16 *code, int space)
{
int ret, mb, i, addr, cnt = 0;
u16 pack[32];
@@ -1505,7 +1505,7 @@ static int modet_to_package(struct go7007 *go, u16 *code, int space)
return cnt;
}
-static int do_special(struct go7007 *go, u16 type, u16 *code, int space,
+static int do_special(struct go7007 *go, u16 type, __le16 *code, int space,
int *framelen)
{
switch (type) {
@@ -1555,7 +1555,7 @@ static int do_special(struct go7007 *go, u16 type, u16 *code, int space,
int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen)
{
const struct firmware *fw_entry;
- u16 *code, *src;
+ __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;
@@ -1590,7 +1590,7 @@ int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen)
goto fw_failed;
}
memset(code, 0, codespace * 2);
- src = (u16 *)fw_entry->data;
+ src = (__le16 *)fw_entry->data;
srclen = fw_entry->size / 2;
while (srclen >= 2) {
chunk_flags = __le16_to_cpu(src[0]);
diff --git a/drivers/staging/go7007/go7007-priv.h b/drivers/staging/go7007/go7007-priv.h
index 005542d16a56..372f1f1c09b2 100644
--- a/drivers/staging/go7007/go7007-priv.h
+++ b/drivers/staging/go7007/go7007-priv.h
@@ -40,6 +40,7 @@ struct go7007;
#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)
@@ -104,6 +105,7 @@ struct go7007_hpi_ops {
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 */
diff --git a/drivers/staging/go7007/go7007-usb.c b/drivers/staging/go7007/go7007-usb.c
index 3f5ee3424e72..83eec920c7d3 100644
--- a/drivers/staging/go7007/go7007-usb.c
+++ b/drivers/staging/go7007/go7007-usb.c
@@ -225,7 +225,7 @@ static struct go7007_usb_board board_px_tv402u = {
.inputs = {
{
.video_input = 1,
- .audio_input = TVAUDIO_INPUT_EXTERN,
+ .audio_input = TVAUDIO_INPUT_EXTERN,
.name = "Composite",
},
{
@@ -398,6 +398,41 @@ static struct go7007_usb_board board_adlink_mpg24 = {
},
};
+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 = {
+ {
+ .id = I2C_DRIVERID_S2250,
+ .addr = 0x34,
+ },
+ },
+ .num_inputs = 2,
+ .inputs = {
+ {
+ .video_input = 0,
+ .name = "Composite",
+ },
+ {
+ .video_input = 1,
+ .name = "S-Video",
+ },
+ },
+ },
+};
+
static struct usb_device_id go7007_usb_id_table[] = {
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
@@ -491,6 +526,14 @@ static struct usb_device_id go7007_usb_id_table[] = {
.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 */
};
@@ -637,9 +680,10 @@ 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 (urb->status != 0) {
- if (urb->status != -ESHUTDOWN &&
+ if (status) {
+ if (status != -ESHUTDOWN &&
go->status != STATUS_SHUTDOWN) {
printk(KERN_ERR
"go7007-usb: error in read interrupt: %d\n",
@@ -680,15 +724,14 @@ static int go7007_usb_read_interrupt(struct go7007 *go)
static void go7007_usb_read_video_pipe_complete(struct urb *urb)
{
struct go7007 *go = (struct go7007 *)urb->context;
- int r;
+ int r, status = urb-> status;
if (!go->streaming) {
wake_up_interruptible(&go->frame_waitq);
return;
}
- if (urb->status != 0) {
- printk(KERN_ERR "go7007-usb: error in video pipe: %d\n",
- urb->status);
+ if (status) {
+ printk(KERN_ERR "go7007-usb: error in video pipe: %d\n", status);
return;
}
if (urb->actual_length != urb->transfer_buffer_length) {
@@ -704,13 +747,12 @@ static void go7007_usb_read_video_pipe_complete(struct urb *urb)
static void go7007_usb_read_audio_pipe_complete(struct urb *urb)
{
struct go7007 *go = (struct go7007 *)urb->context;
- int r;
+ int r, status = urb->status;
if (!go->streaming)
return;
- if (urb->status != 0) {
- printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n",
- urb->status);
+ if (status) {
+ printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", status);
return;
}
if (urb->actual_length != urb->transfer_buffer_length) {
@@ -751,7 +793,7 @@ static int go7007_usb_stream_start(struct go7007 *go)
return 0;
audio_submit_failed:
- for (i = 0; i < 8; ++i)
+ for (i = 0; i < 7; ++i)
usb_kill_urb(usb->audio_urbs[i]);
video_submit_failed:
for (i = 0; i < 8; ++i)
@@ -965,16 +1007,20 @@ static int go7007_usb_probe(struct usb_interface *intf,
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\n";
+ board = &board_sensoray_2250;
+ break;
default:
printk(KERN_ERR "go7007-usb: unknown board ID %d!\n",
(unsigned int)id->driver_info);
return 0;
}
- usb = kmalloc(sizeof(struct go7007_usb), GFP_KERNEL);
+ usb = kzalloc(sizeof(struct go7007_usb), GFP_KERNEL);
if (usb == NULL)
return -ENOMEM;
- memset(usb, 0, sizeof(struct go7007_usb));
/* Allocate the URB and buffer for receiving incoming interrupts */
usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -1179,6 +1225,7 @@ static void go7007_usb_disconnect(struct usb_interface *intf)
{
struct go7007 *go = usb_get_intfdata(intf);
struct go7007_usb *usb = go->hpi_context;
+ struct urb *vurb, *aurb;
int i;
go->status = STATUS_SHUTDOWN;
@@ -1186,15 +1233,19 @@ static void go7007_usb_disconnect(struct usb_interface *intf)
/* Free USB-related structs */
for (i = 0; i < 8; ++i) {
- if (usb->video_urbs[i] != NULL) {
- if (usb->video_urbs[i]->transfer_buffer != NULL)
- kfree(usb->video_urbs[i]->transfer_buffer);
- usb_free_urb(usb->video_urbs[i]);
+ vurb = usb->video_urbs[i];
+ if (vurb) {
+ usb_kill_urb(vurb);
+ if (vurb->transfer_buffer)
+ kfree(vurb->transfer_buffer);
+ usb_free_urb(vurb);
}
- if (usb->audio_urbs[i] != NULL) {
- if (usb->audio_urbs[i]->transfer_buffer != NULL)
- kfree(usb->audio_urbs[i]->transfer_buffer);
- usb_free_urb(usb->audio_urbs[i]);
+ aurb = usb->audio_urbs[i];
+ if (aurb) {
+ usb_kill_urb(aurb);
+ if (aurb->transfer_buffer)
+ kfree(aurb->transfer_buffer);
+ usb_free_urb(aurb);
}
}
kfree(usb->intr_urb->transfer_buffer);
diff --git a/drivers/staging/go7007/go7007-v4l2.c b/drivers/staging/go7007/go7007-v4l2.c
index 94e1141a1fcd..868edb65e7bf 100644
--- a/drivers/staging/go7007/go7007-v4l2.c
+++ b/drivers/staging/go7007/go7007-v4l2.c
@@ -38,6 +38,14 @@
#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
+
static void deactivate_buffer(struct go7007_buffer *gobuf)
{
int i;
@@ -81,7 +89,7 @@ static int go7007_streamoff(struct go7007 *go)
return 0;
}
-static int go7007_open(struct inode *inode, struct file *file)
+static int go7007_open(struct file *file)
{
struct go7007 *go = video_get_drvdata(video_devdata(file));
struct go7007_file *gofh;
@@ -99,7 +107,7 @@ static int go7007_open(struct inode *inode, struct file *file)
return 0;
}
-static int go7007_release(struct inode *inode, struct file *file)
+static int go7007_release(struct file *file)
{
struct go7007_file *gofh = file->private_data;
struct go7007 *go = gofh->go;
@@ -319,6 +327,7 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
return 0;
}
+#if 0
static int clip_to_modet_map(struct go7007 *go, int region,
struct v4l2_clip *clip_list)
{
@@ -375,499 +384,801 @@ static int clip_to_modet_map(struct go7007 *go, int region,
return 0;
}
-static int go7007_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int mpeg_queryctrl(u32 id, struct v4l2_queryctrl *ctrl)
{
- struct go7007_file *gofh = file->private_data;
- struct go7007 *go = gofh->go;
- unsigned long flags;
- int retval = 0;
-
- switch (cmd) {
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
-
- memset(cap, 0, sizeof(*cap));
- strcpy(cap->driver, "go7007");
- strncpy(cap->card, go->name, sizeof(cap->card));
- 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;
+ static const u32 user_ctrls[] = {
+ V4L2_CID_USER_CLASS,
+ 0
+ };
+ 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[] = {
+ user_ctrls,
+ mpeg_ctrls,
+ NULL
+ };
+
+ /* The ctrl may already contain the queried i2c controls,
+ * query the mpeg controls if the existing ctrl id is
+ * greater than the next mpeg ctrl id.
+ */
+ id = v4l2_ctrl_next(ctrl_classes, id);
+ if (id >= ctrl->id && ctrl->name[0])
return 0;
+
+ memset(ctrl, 0, sizeof(*ctrl));
+ ctrl->id = id;
+
+ switch (ctrl->id) {
+ case V4L2_CID_USER_CLASS:
+ case V4L2_CID_MPEG_CLASS:
+ return v4l2_ctrl_query_fill_std(ctrl);
+ 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:
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ return v4l2_ctrl_query_fill_std(ctrl);
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ return v4l2_ctrl_query_fill(ctrl,
+ 64000,
+ 10000000, 1,
+ 9800000);
+ default:
+ break;
}
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *fmt = arg;
- unsigned int index;
- char *desc;
- u32 pixelformat;
+ return -EINVAL;
+}
+
+static int mpeg_s_control(struct v4l2_control *ctrl, struct go7007 *go)
+{
+ /* pretty sure we can't change any of these while streaming */
+ if (go->streaming)
+ return -EBUSY;
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ 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;
- switch (fmt->index) {
- case 0:
- pixelformat = V4L2_PIX_FMT_MJPEG;
- desc = "Motion-JPEG";
+ }
+ 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 1:
- pixelformat = V4L2_PIX_FMT_MPEG;
- desc = "MPEG1/MPEG2/MPEG4";
+ 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;
}
- index = fmt->index;
- memset(fmt, 0, sizeof(*fmt));
- fmt->index = index;
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt->flags = V4L2_FMT_FLAG_COMPRESSED;
- strncpy(fmt->description, desc, sizeof(fmt->description));
- fmt->pixelformat = pixelformat;
-
- return 0;
- }
- case VIDIOC_TRY_FMT:
- {
- struct v4l2_format *fmt = arg;
-
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ 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;
- return set_capture_size(go, fmt, 1);
- }
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *fmt = arg;
-
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ 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;
- memset(fmt, 0, sizeof(*fmt));
- 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;
- }
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *fmt = arg;
-
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ go->gop_size = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ if (ctrl->value != 0 && ctrl->value != 1)
return -EINVAL;
- if (go->streaming)
- return -EBUSY;
- return set_capture_size(go, fmt, 0);
- }
- case VIDIOC_G_FBUF:
- case VIDIOC_S_FBUF:
- return -EINVAL;
- case VIDIOC_REQBUFS:
- {
- struct v4l2_requestbuffers *req = arg;
- unsigned int count, i;
-
- if (go->streaming)
- return -EBUSY;
- if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- req->memory != V4L2_MEMORY_MMAP)
+ 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;
-
- down(&gofh->lock);
- retval = -EBUSY;
- for (i = 0; i < gofh->buf_count; ++i)
- if (gofh->bufs[i].mapped > 0)
- goto unlock_and_return;
- down(&go->hw_lock);
- if (go->in_use > 0 && gofh->buf_count == 0) {
- up(&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 = kmalloc(count *
- sizeof(struct go7007_buffer),
- GFP_KERNEL);
- if (gofh->bufs == NULL) {
- up(&go->hw_lock);
- goto unlock_and_return;
- }
- memset(gofh->bufs, 0,
- count * sizeof(struct go7007_buffer));
- 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;
- up(&go->hw_lock);
- up(&gofh->lock);
- memset(req, 0, sizeof(*req));
- req->count = count;
- req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- req->memory = V4L2_MEMORY_MMAP;
- return 0;
+ go->bitrate = ctrl->value;
+ break;
+ default:
+ return -EINVAL;
}
- case VIDIOC_QUERYBUF:
- {
- struct v4l2_buffer *buf = arg;
- unsigned int index;
+ return 0;
+}
- retval = -EINVAL;
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+static int mpeg_g_control(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;
- index = buf->index;
- down(&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 V4L2_CID_MPEG_VIDEO_ASPECT:
+ switch (go->aspect_ratio) {
+ case GO7007_RATIO_1_1:
+ ctrl->value = V4L2_MPEG_VIDEO_ASPECT_1x1;
break;
- case BUF_STATE_DONE:
- buf->flags = V4L2_BUF_FLAG_DONE;
+ 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:
- buf->flags = 0;
+ return -EINVAL;
}
- 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;
- up(&gofh->lock);
+ 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;
+}
+#endif
- return 0;
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->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;
}
- case VIDIOC_QBUF:
- {
- struct v4l2_buffer *buf = arg;
- struct go7007_buffer *gobuf;
- int ret;
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt->flags = V4L2_FMT_FLAG_COMPRESSED;
- retval = -EINVAL;
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- buf->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
- down(&gofh->lock);
- if (buf->index < 0 || buf->index >= gofh->buf_count)
- goto unlock_and_return;
- gobuf = &gofh->bufs[buf->index];
- if (gobuf->mapped == 0)
- 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;
+ 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_file *gofh = priv;
+ struct go7007 *go = gofh->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_file *gofh = priv;
+ struct go7007 *go = gofh->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_file *gofh = priv;
+ struct go7007 *go = gofh->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;
+
+ down(&gofh->lock);
+ for (i = 0; i < gofh->buf_count; ++i)
+ if (gofh->bufs[i].mapped > 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);
- up(&gofh->lock);
- return 0;
+
+ down(&go->hw_lock);
+ if (go->in_use > 0 && gofh->buf_count == 0) {
+ up(&go->hw_lock);
+ goto unlock_and_return;
}
- case VIDIOC_DQBUF:
- {
- struct v4l2_buffer *buf = arg;
- struct go7007_buffer *gobuf;
- u32 frame_type_flag;
- DEFINE_WAIT(wait);
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (buf->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
- down(&gofh->lock);
- retval = -EINVAL;
- if (list_empty(&go->stream))
+ 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 = kmalloc(count * sizeof(struct go7007_buffer),
+ GFP_KERNEL);
+
+ if (!gofh->bufs) {
+ up(&go->hw_lock);
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;
- up(&gofh->lock);
- return 0;
- }
- case VIDIOC_STREAMON:
- {
- unsigned int *type = arg;
- if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- down(&gofh->lock);
- down(&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;
+ memset(gofh->bufs, 0, count * sizeof(struct go7007_buffer));
+
+ 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;
}
- up(&go->hw_lock);
- up(&gofh->lock);
- return retval;
- }
- case VIDIOC_STREAMOFF:
- {
- unsigned int *type = arg;
- if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- down(&gofh->lock);
- go7007_streamoff(go);
- up(&gofh->lock);
- return 0;
+ go->in_use = 1;
+ } else {
+ go->in_use = 0;
}
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *ctrl = arg;
- u32 id;
- if (!go->i2c_adapter_online)
- return -EIO;
- id = ctrl->id;
- memset(ctrl, 0, sizeof(*ctrl));
- ctrl->id = id;
- i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, arg);
- return ctrl->name[0] == 0 ? -EINVAL : 0;
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- struct v4l2_queryctrl query;
+ gofh->buf_count = count;
+ up(&go->hw_lock);
+ up(&gofh->lock);
- if (!go->i2c_adapter_online)
- return -EIO;
- memset(&query, 0, sizeof(query));
- query.id = ctrl->id;
- i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query);
- if (query.name[0] == 0)
- return -EINVAL;
- i2c_clients_command(&go->i2c_adapter, VIDIOC_G_CTRL, arg);
- return 0;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- struct v4l2_queryctrl query;
+ memset(req, 0, sizeof(*req));
- if (!go->i2c_adapter_online)
- return -EIO;
- memset(&query, 0, sizeof(query));
- query.id = ctrl->id;
- i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query);
- if (query.name[0] == 0)
- return -EINVAL;
- i2c_clients_command(&go->i2c_adapter, VIDIOC_S_CTRL, arg);
- return 0;
- }
- case VIDIOC_G_PARM:
- {
- struct v4l2_streamparm *parm = arg;
- struct v4l2_fract timeperframe = {
- .numerator = 1001 * go->fps_scale,
- .denominator = go->sensor_framerate,
- };
+ req->count = count;
+ req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req->memory = V4L2_MEMORY_MMAP;
- if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- memset(parm, 0, sizeof(*parm));
- parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME;
- parm->parm.capture.timeperframe = timeperframe;
- return 0;
+ return 0;
+
+unlock_and_return:
+ up(&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;
+
+ down(&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;
}
- case VIDIOC_S_PARM:
- {
- struct v4l2_streamparm *parm = arg;
- 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;
+ 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;
+ up(&gofh->lock);
+
+ return 0;
+
+unlock_and_return:
+ up(&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;
+
+ down(&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;
}
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *std = arg;
- if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
- go->input == go->board_info->num_inputs - 1) {
- if (!go->i2c_adapter_online)
- return -EIO;
- i2c_clients_command(&go->i2c_adapter,
- VIDIOC_ENUMSTD, arg);
- if (!std->id) /* hack to indicate EINVAL from tuner */
- return -EINVAL;
- } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) {
- switch (std->index) {
- case 0:
- v4l2_video_std_construct(std,
- V4L2_STD_NTSC, "NTSC");
+ gobuf->state = BUF_STATE_QUEUED;
+ spin_lock_irqsave(&go->spinlock, flags);
+ list_add_tail(&gobuf->stream, &go->stream);
+ spin_unlock_irqrestore(&go->spinlock, flags);
+ up(&gofh->lock);
+
+ return 0;
+
+unlock_and_return:
+ up(&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;
+
+ down(&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;
- case 1:
- v4l2_video_std_construct(std,
- V4L2_STD_PAL | V4L2_STD_SECAM,
- "PAL/SECAM");
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
break;
- default:
- return -EINVAL;
}
- } else {
- if (std->index != 0)
- return -EINVAL;
- memset(std, 0, sizeof(*std));
- snprintf(std->name, sizeof(std->name), "%dx%d, %dfps",
- go->board_info->sensor_width,
- go->board_info->sensor_height,
- go->board_info->sensor_framerate / 1000);
- std->frameperiod.numerator = 1001;
- std->frameperiod.denominator =
- go->board_info->sensor_framerate;
+ schedule();
}
- return 0;
+ finish_wait(&go->frame_waitq, &wait);
}
- case VIDIOC_G_STD:
- {
- v4l2_std_id *std = arg;
+ 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;
- if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
- go->input == go->board_info->num_inputs - 1) {
- if (!go->i2c_adapter_online)
- return -EIO;
- i2c_clients_command(&go->i2c_adapter,
- VIDIOC_G_STD, arg);
- } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) {
- if (go->standard == GO7007_STD_NTSC)
- *std = V4L2_STD_NTSC;
- else
- *std = V4L2_STD_PAL | V4L2_STD_SECAM;
- } else
- *std = 0;
- return 0;
+ up(&gofh->lock);
+ return 0;
+
+unlock_and_return:
+ up(&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;
+
+ down(&gofh->lock);
+ down(&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;
}
- case VIDIOC_S_STD:
- {
- v4l2_std_id *std = arg;
+ up(&go->hw_lock);
+ up(&gofh->lock);
- 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;
- i2c_clients_command(&go->i2c_adapter,
- VIDIOC_S_STD, arg);
- if (!*std) /* hack to indicate EINVAL from tuner */
- 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 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;
+ down(&gofh->lock);
+ go7007_streamoff(go);
+ up(&gofh->lock);
+
+ return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *query)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->go;
+
+ if (!go->i2c_adapter_online)
+ return -EIO;
+
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, query);
+
+ return (!query->name[0]) ? -EINVAL : 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->go;
+ struct v4l2_queryctrl query;
+
+ if (!go->i2c_adapter_online)
+ return -EIO;
+
+ memset(&query, 0, sizeof(query));
+ query.id = ctrl->id;
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query);
+ if (query.name[0] == 0)
+ return -EINVAL;
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_G_CTRL, ctrl);
+
+ return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->go;
+ struct v4l2_queryctrl query;
+
+ if (!go->i2c_adapter_online)
+ return -EIO;
+
+ memset(&query, 0, sizeof(query));
+ query.id = ctrl->id;
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query);
+ if (query.name[0] == 0)
+ return -EINVAL;
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_CTRL, ctrl);
+
+ return 0;
+}
+
+static int vidioc_g_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->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_file *gofh = priv;
+ struct go7007 *go = gofh->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_file *gofh = priv;
+ struct go7007 *go = gofh->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_file *gofh = priv;
+ struct go7007 *go = gofh->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_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->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;
+ i2c_clients_command(&go->i2c_adapter,
+ VIDIOC_S_STD, std);
+ if (!*std) /* hack to indicate EINVAL from tuner */
return -EINVAL;
- if (go->i2c_adapter_online)
- i2c_clients_command(&go->i2c_adapter,
- VIDIOC_S_STD, std);
- set_capture_size(go, NULL, 0);
- return 0;
}
+
+ 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;
+
+ if (go->i2c_adapter_online)
+ i2c_clients_command(&go->i2c_adapter,
+ VIDIOC_S_STD, std);
+ set_capture_size(go, NULL, 0);
+
+ return 0;
+}
+
+#if 0
case VIDIOC_QUERYSTD:
{
v4l2_std_id *std = arg;
@@ -884,219 +1195,269 @@ static int go7007_do_ioctl(struct inode *inode, struct file *file,
*std = 0;
return 0;
}
- case VIDIOC_ENUMINPUT:
- {
- struct v4l2_input *inp = arg;
- int index;
+#endif
- if (inp->index >= go->board_info->num_inputs)
- return -EINVAL;
- index = inp->index;
- memset(inp, 0, sizeof(*inp));
- inp->index = index;
- strncpy(inp->name, go->board_info->inputs[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) &&
- 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;
- }
- case VIDIOC_G_INPUT:
- {
- int *input = arg;
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->go;
- *input = go->input;
- return 0;
- }
- case VIDIOC_S_INPUT:
- {
- int *input = arg;
+ if (inp->index >= go->board_info->num_inputs)
+ return -EINVAL;
- if (*input >= go->board_info->num_inputs)
- return -EINVAL;
- if (go->streaming)
- return -EBUSY;
- go->input = *input;
- if (go->i2c_adapter_online) {
- i2c_clients_command(&go->i2c_adapter, VIDIOC_S_INPUT,
- &go->board_info->inputs[*input].video_input);
- i2c_clients_command(&go->i2c_adapter, VIDIOC_S_AUDIO,
- &go->board_info->inputs[*input].audio_input);
- }
- return 0;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *t = arg;
+ strncpy(inp->name, go->board_info->inputs[inp->index].name,
+ sizeof(inp->name));
- if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
- return -EINVAL;
- if (t->index != 0)
- return -EINVAL;
- if (!go->i2c_adapter_online)
- return -EIO;
- i2c_clients_command(&go->i2c_adapter, VIDIOC_G_TUNER, arg);
- t->index = 0;
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *t = arg;
+ /* 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;
- 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;
- }
- i2c_clients_command(&go->i2c_adapter, VIDIOC_S_TUNER, arg);
- return 0;
- }
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+ 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;
- if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
- return -EINVAL;
- if (!go->i2c_adapter_online)
- return -EIO;
- memset(f, 0, sizeof(*f));
- f->type = V4L2_TUNER_ANALOG_TV;
- i2c_clients_command(&go->i2c_adapter, VIDIOC_G_FREQUENCY, arg);
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
- return -EINVAL;
- if (!go->i2c_adapter_online)
- return -EIO;
- i2c_clients_command(&go->i2c_adapter, VIDIOC_S_FREQUENCY, arg);
- return 0;
- }
- case VIDIOC_CROPCAP:
- {
- struct v4l2_cropcap *cropcap = arg;
+ return 0;
+}
- if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- memset(cropcap, 0, sizeof(*cropcap));
- cropcap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- /* 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;
- }
- case VIDIOC_G_CROP:
- {
- struct v4l2_crop *crop = arg;
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *input)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->go;
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- memset(crop, 0, sizeof(*crop));
- 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;
- }
+ *input = go->input;
- return 0;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int input)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->go;
+
+ if (input >= go->board_info->num_inputs)
+ return -EINVAL;
+ if (go->streaming)
+ return -EBUSY;
+
+ go->input = input;
+ if (go->i2c_adapter_online) {
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_INPUT,
+ &go->board_info->inputs[input].video_input);
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_AUDIO,
+ &go->board_info->inputs[input].audio_input);
}
- case VIDIOC_S_CROP:
- {
- struct v4l2_crop *crop = arg;
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->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;
+
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_G_TUNER, t);
+
+ t->index = 0;
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->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;
- return 0;
+ break;
}
- case VIDIOC_G_JPEGCOMP:
- {
- struct v4l2_jpegcompression *params = arg;
- memset(params, 0, sizeof(*params));
- params->quality = 50; /* ?? */
- params->jpeg_markers = V4L2_JPEG_MARKER_DHT |
- V4L2_JPEG_MARKER_DQT;
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_TUNER, t);
- return 0;
+ return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->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;
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_G_FREQUENCY, f);
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->go;
+
+ if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+ return -EINVAL;
+ if (!go->i2c_adapter_online)
+ return -EIO;
+
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_FREQUENCY, f);
+
+ return 0;
+}
+
+static int vidioc_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *cropcap)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->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;
}
- case VIDIOC_S_JPEGCOMP:
- {
- struct v4l2_jpegcompression *params = arg;
- if (params->quality != 50 ||
- params->jpeg_markers != (V4L2_JPEG_MARKER_DHT |
- V4L2_JPEG_MARKER_DQT))
- return -EINVAL;
- return 0;
+ return 0;
+}
+
+static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+{
+ struct go7007_file *gofh = priv;
+ struct go7007 *go = gofh->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:
{
@@ -1316,27 +1677,7 @@ static int go7007_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
return clip_to_modet_map(go, region->region, region->clips);
}
- default:
- printk(KERN_DEBUG "go7007: unsupported ioctl %d\n", cmd);
- return -ENOIOCTLCMD;
- }
- return 0;
-
-unlock_and_return:
- up(&gofh->lock);
- return retval;
-}
-
-static int go7007_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct go7007_file *gofh = file->private_data;
-
- if (gofh->go->status != STATUS_ONLINE)
- return -EIO;
-
- return video_usercopy(inode, file, cmd, arg, go7007_do_ioctl);
-}
+#endif
static ssize_t go7007_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
@@ -1371,8 +1712,7 @@ static int go7007_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
page = alloc_page(GFP_USER | __GFP_DMA32);
if (!page)
return VM_FAULT_OOM;
- clear_user_page(page_address(page), (unsigned long)vmf->virtual_address,
- page);
+ clear_user_highpage(page, (unsigned long)vmf->virtual_address);
vmf->page = page;
return 0;
}
@@ -1441,23 +1781,59 @@ static void go7007_vfl_release(struct video_device *vfd)
kfree(go);
}
-static struct file_operations go7007_fops = {
+static struct v4l2_file_operations go7007_fops = {
.owner = THIS_MODULE,
.open = go7007_open,
.release = go7007_release,
- .ioctl = go7007_ioctl,
- .llseek = no_llseek,
+ .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_s_std = vidioc_s_std,
+ .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",
.vfl_type = VID_TYPE_CAPTURE,
.fops = &go7007_fops,
.minor = -1,
.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)
@@ -1477,6 +1853,8 @@ int go7007_v4l2_init(struct go7007 *go)
}
video_set_drvdata(go->video_dev, go);
++go->ref_count;
+ printk(KERN_INFO "%s: registered device video%d [v4l2]\n",
+ go->video_dev->name, go->video_dev->num);
return 0;
}
diff --git a/drivers/staging/go7007/go7007.txt b/drivers/staging/go7007/go7007.txt
new file mode 100644
index 000000000000..9f6772bc68c2
--- /dev/null
+++ b/drivers/staging/go7007/go7007.txt
@@ -0,0 +1,481 @@
+This is a driver for the WIS GO7007SB multi-format video encoder.
+
+Pete Eberlein <pete@sensoray.com>
+
+The driver was orignally 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
new file mode 100644
index 000000000000..fb6845e37884
--- /dev/null
+++ b/drivers/staging/go7007/s2250-board.c
@@ -0,0 +1,630 @@
+/*
+ * 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 <media/v4l2-common.h>
+#include "go7007-priv.h"
+#include "wis-i2c.h"
+
+extern int s2250loader_init(void);
+extern void s2250loader_cleanup(void);
+
+#define TLV320_ADDRESS 0x34
+#define S2250_VIDDEC 0x86
+#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 semaphore 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 {
+ int std;
+ int input;
+ int brightness;
+ int contrast;
+ int saturation;
+ int hue;
+ int reg12b_val;
+ int audio_input;
+};
+
+/* 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 = go->hpi_context;
+ int rc;
+ int dev_addr = client->addr;
+ u8 *buf;
+
+ if (go == NULL)
+ return -ENODEV;
+
+ if (go->status == STATUS_SHUTDOWN)
+ return -EBUSY;
+
+ buf = kzalloc(16, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ if (down_interruptible(&usb->i2c_lock) != 0) {
+ printk(KERN_INFO "i2c lock failed\n");
+ return -EINTR;
+ }
+ rc = go7007_usb_vendor_request(go, 0x55, dev_addr,
+ (reg<<8 | value),
+ buf,
+ 16, 1);
+
+ up(&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 = go->hpi_context;
+ 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);
+
+ if (down_interruptible(&usb->i2c_lock) != 0) {
+ printk(KERN_INFO "i2c lock failed\n");
+ return -EINTR;
+ }
+ if (go7007_usb_vendor_request(go, 0x57, addr, val, buf, 16, 1) < 0)
+ return -EFAULT;
+
+ up(&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];
+ 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
+ return -EFAULT;
+
+ /* save last 12b value */
+ if (addr == 0x12b)
+ dec->reg12b_val = val;
+
+ 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_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct s2250 *dec = i2c_get_clientdata(client);
+
+ switch (cmd) {
+ case VIDIOC_S_INPUT:
+ {
+ int vidsys;
+ int *input = arg;
+
+ vidsys = (dec->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 {
+ /* S-Video */
+ write_reg_fp(client, 0x20, 0x040 | vidsys);
+ write_reg_fp(client, 0x21, 0x666);
+ write_reg_fp(client, 0x140, 0x060);
+ }
+ dec->input = *input;
+ break;
+ }
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *std = arg;
+ u16 vidsource;
+
+ vidsource = (dec->input == 1) ? 0x040 : 0x020;
+ dec->std = *std;
+ switch (dec->std) {
+ 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;
+ }
+ break;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *ctrl = arg;
+ static const u32 user_ctrls[] = {
+ V4L2_CID_BRIGHTNESS,
+ V4L2_CID_CONTRAST,
+ V4L2_CID_SATURATION,
+ V4L2_CID_HUE,
+ 0
+ };
+ static const u32 *ctrl_classes[] = {
+ user_ctrls,
+ NULL
+ };
+
+ ctrl->id = v4l2_ctrl_next(ctrl_classes, ctrl->id);
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ v4l2_ctrl_query_fill(ctrl, 0, 100, 1, 50);
+ break;
+ case V4L2_CID_CONTRAST:
+ v4l2_ctrl_query_fill(ctrl, 0, 100, 1, 50);
+ break;
+ case V4L2_CID_SATURATION:
+ v4l2_ctrl_query_fill(ctrl, 0, 100, 1, 50);
+ break;
+ case V4L2_CID_HUE:
+ v4l2_ctrl_query_fill(ctrl, -50, 50, 1, 0);
+ break;
+ default:
+ ctrl->name[0] = '\0';
+ return -EINVAL;
+ }
+ break;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ int value1;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ printk(KERN_INFO "s2250: future setting\n");
+ return -EINVAL;
+ case V4L2_CID_CONTRAST:
+ printk(KERN_INFO "s2250: future setting\n");
+ return -EINVAL;
+ 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;
+
+ value1 = dec->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)
+ dec->hue = 50;
+ else if (ctrl->value < -50)
+ dec->hue = -50;
+ else
+ dec->hue = ctrl->value;
+ /* clamp the hue range */
+ value1 = dec->hue * 280 / 50;
+ write_reg_fp(client, VPX322_ADDR_HUE, value1);
+ 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;
+ }
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *fmt = arg;
+ if (fmt->fmt.pix.height < 640) {
+ write_reg_fp(client, 0x12b, dec->reg12b_val | 0x400);
+ write_reg_fp(client, 0x140, 0x060);
+ } else {
+ write_reg_fp(client, 0x12b, dec->reg12b_val & ~0x400);
+ write_reg_fp(client, 0x140, 0x060);
+ }
+ return 0;
+ }
+ case VIDIOC_G_AUDIO:
+ {
+ struct v4l2_audio *audio = arg;
+
+ memset(audio, 0, sizeof(*audio));
+ audio->index = dec->audio_input;
+ /* fall through */
+ }
+ case VIDIOC_ENUMAUDIO:
+ {
+ struct v4l2_audio *audio = arg;
+
+ switch (audio->index) {
+ case 0:
+ strcpy(audio->name, "Line In");
+ break;
+ case 1:
+ strcpy(audio->name, "Mic");
+ break;
+ case 2:
+ strcpy(audio->name, "Mic Boost");
+ break;
+ default:
+ audio->name[0] = '\0';
+ return 0;
+ }
+ audio->capability = V4L2_AUDCAP_STEREO;
+ audio->mode = 0;
+ return 0;
+ }
+ case VIDIOC_S_AUDIO:
+ {
+ struct v4l2_audio *audio = arg;
+
+ client->addr = TLV320_ADDRESS;
+ switch (audio->index) {
+ case 0:
+ write_reg(client, 0x08, 0x02); /* Line In */
+ break;
+ case 1:
+ write_reg(client, 0x08, 0x04); /* Mic */
+ break;
+ case 2:
+ write_reg(client, 0x08, 0x05); /* Mic Boost */
+ break;
+ default:
+ return -EINVAL;
+ }
+ dec->audio_input = audio->index;
+ return 0;
+ }
+
+ default:
+ printk(KERN_INFO "s2250: unknown command 0x%x\n", cmd);
+ break;
+ }
+ return 0;
+}
+
+static struct i2c_driver s2250_driver;
+
+static struct i2c_client s2250_client_templ = {
+ .name = "Sensoray 2250",
+ .driver = &s2250_driver,
+};
+
+static int s2250_detect(struct i2c_adapter *adapter, int addr, int kind)
+{
+ struct i2c_client *client;
+ struct s2250 *dec;
+ u8 *data;
+ struct go7007 *go = i2c_get_adapdata(adapter);
+ struct go7007_usb *usb = go->hpi_context;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memcpy(client, &s2250_client_templ,
+ sizeof(s2250_client_templ));
+ client->adapter = adapter;
+
+ dec = kmalloc(sizeof(struct s2250), GFP_KERNEL);
+ if (dec == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+
+ dec->std = V4L2_STD_NTSC;
+ dec->brightness = 50;
+ dec->contrast = 50;
+ dec->saturation = 50;
+ dec->hue = 0;
+ client->addr = TLV320_ADDRESS;
+ i2c_set_clientdata(client, dec);
+
+ printk(KERN_DEBUG
+ "s2250: initializing video decoder on %s\n",
+ adapter->name);
+
+ /* initialize the audio */
+ client->addr = TLV320_ADDRESS;
+ if (write_regs(client, aud_regs) < 0) {
+ printk(KERN_ERR
+ "s2250: error initializing audio\n");
+ kfree(client);
+ kfree(dec);
+ return 0;
+ }
+ client->addr = S2250_VIDDEC;
+ i2c_set_clientdata(client, dec);
+
+ if (write_regs(client, vid_regs) < 0) {
+ printk(KERN_ERR
+ "s2250: error initializing decoder\n");
+ kfree(client);
+ kfree(dec);
+ return 0;
+ }
+ if (write_regs_fp(client, vid_regs_fp) < 0) {
+ printk(KERN_ERR
+ "s2250: error initializing decoder\n");
+ kfree(client);
+ kfree(dec);
+ 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 */
+ dec->audio_input = 0;
+ write_reg(client, 0x08, 0x02); /* Line In */
+
+ if (down_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);
+ }
+ up(&usb->i2c_lock);
+ }
+
+ i2c_attach_client(client);
+ printk("s2250: initialized successfully\n");
+ return 0;
+}
+
+static int s2250_detach(struct i2c_client *client)
+{
+ struct s2250 *dec = i2c_get_clientdata(client);
+ int r;
+
+ r = i2c_detach_client(client);
+ if (r < 0)
+ return r;
+
+ kfree(client);
+ kfree(dec);
+ return 0;
+}
+
+static struct i2c_driver s2250_driver = {
+ .driver = {
+ .name = "Sensoray 2250 board driver",
+ },
+ .id = I2C_DRIVERID_S2250,
+ .detach_client = s2250_detach,
+ .command = s2250_command,
+};
+
+static int __init s2250_init(void)
+{
+ int r;
+
+ r = s2250loader_init();
+ if (r < 0)
+ return r;
+
+ r = i2c_add_driver(&s2250_driver);
+ if (r < 0)
+ return r;
+ return wis_i2c_add_driver(s2250_driver.id, s2250_detect);
+}
+
+static void __exit s2250_cleanup(void)
+{
+ wis_i2c_del_driver(s2250_detect);
+ i2c_del_driver(&s2250_driver);
+
+ s2250loader_cleanup();
+}
+
+module_init(s2250_init);
+module_exit(s2250_cleanup);
+
+MODULE_AUTHOR("");
+MODULE_DESCRIPTION("Board driver for Sensoryray 2250");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/s2250-loader.c b/drivers/staging/go7007/s2250-loader.c
new file mode 100644
index 000000000000..a5e4acab089e
--- /dev/null
+++ b/drivers/staging/go7007/s2250-loader.c
@@ -0,0 +1,188 @@
+/*
+ * 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 <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 DECLARE_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;
+ }
+ down(&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));
+
+ up(&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:
+ up(&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 = usb_get_intfdata(interface);
+ printk(KERN_INFO "s2250: disconnect\n");
+ lock_kernel();
+ s = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+ kref_put(&(s->kref), s2250loader_delete);
+ unlock_kernel();
+}
+
+static 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,
+};
+
+int 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;
+}
+EXPORT_SYMBOL(s2250loader_init);
+
+void s2250loader_cleanup(void)
+{
+ printk(KERN_INFO "s2250loader_cleanup\n");
+ usb_deregister(&s2250loader_driver);
+}
+EXPORT_SYMBOL(s2250loader_cleanup);
diff --git a/drivers/staging/go7007/saa7134-go7007.c b/drivers/staging/go7007/saa7134-go7007.c
index c4a6d8ef9078..665bbf59d026 100644
--- a/drivers/staging/go7007/saa7134-go7007.c
+++ b/drivers/staging/go7007/saa7134-go7007.c
@@ -27,7 +27,7 @@
#include <linux/usb.h>
#include <linux/i2c.h>
#include <asm/byteorder.h>
-#include <media/audiochip.h>
+#include <media/v4l2-common.h>
#include "saa7134-reg.h"
#include "saa7134.h"
@@ -314,7 +314,13 @@ static int saa7134_go7007_stream_start(struct go7007 *go)
static int saa7134_go7007_stream_stop(struct go7007 *go)
{
struct saa7134_go7007 *saa = go->hpi_context;
- struct saa7134_dev *dev = saa->dev;
+ 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);
@@ -373,6 +379,47 @@ static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len)
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,
@@ -380,6 +427,7 @@ static struct go7007_hpi_ops saa7134_go7007_hpi_ops = {
.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 *********************/
diff --git a/drivers/staging/go7007/wis-i2c.h b/drivers/staging/go7007/wis-i2c.h
index 993f658ad731..431f41dd3966 100644
--- a/drivers/staging/go7007/wis-i2c.h
+++ b/drivers/staging/go7007/wis-i2c.h
@@ -23,6 +23,7 @@
#define I2C_DRIVERID_WIS_SAA7113 0xf0f4
#define I2C_DRIVERID_WIS_OV7640 0xf0f5
#define I2C_DRIVERID_WIS_TW2804 0xf0f6
+#define I2C_DRIVERID_S2250 0xf0f7
#define I2C_ALGO_GO7007 0xf00000
#define I2C_ALGO_GO7007_USB 0xf10000
diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c
index 5a91ee409a7c..58fddb122372 100644
--- a/drivers/staging/go7007/wis-sony-tuner.c
+++ b/drivers/staging/go7007/wis-sony-tuner.c
@@ -604,7 +604,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_tuner *tun = arg;
- memset(t, 0, sizeof(*tun));
+ memset(tun, 0, sizeof(*tun));
strcpy(tun->name, "Television");
tun->type = V4L2_TUNER_ANALOG_TV;
tun->rangelow = 0UL; /* does anything use these? */