Commit d7b09335 authored by Mark W. McClelland's avatar Mark W. McClelland Committed by Linus Torvalds

Update USB ov511 driver to version 1.53

parent cf16aaca
...@@ -182,9 +182,9 @@ MODULE PARAMETERS: ...@@ -182,9 +182,9 @@ MODULE PARAMETERS:
DEFAULT: 1 (Always on) DEFAULT: 1 (Always on)
DESC: Controls whether the LED (the little light) on the front of the camera DESC: Controls whether the LED (the little light) on the front of the camera
is always off (0), always on (1), or only on when driver is open (2). is always off (0), always on (1), or only on when driver is open (2).
This is only supported with the OV511+ chipset, and even then only on This is not supported with the OV511, and might only work with certain
some cameras (ones that actually have the LED wired to the control pin, cameras (ones that actually have the LED wired to the control pin, and
and not just hardwired to be on all the time). not just hard-wired to be on all the time).
NAME: dump_bridge NAME: dump_bridge
TYPE: integer (Boolean) TYPE: integer (Boolean)
......
/* /*
* OmniVision OV511 Camera-to-USB Bridge Driver * OmniVision OV511 Camera-to-USB Bridge Driver
* *
* Copyright (c) 1999-2001 Mark W. McClelland * Copyright (c) 1999-2002 Mark W. McClelland
* Original decompression code Copyright 1998-2000 OmniVision Technologies * Original decompression code Copyright 1998-2000 OmniVision Technologies
* Many improvements by Bret Wallach <bwallac1@san.rr.com> * Many improvements by Bret Wallach <bwallac1@san.rr.com>
* Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000) * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
* Changes by Claudio Matsuoka <claudio@conectiva.com> * Changes by Claudio Matsuoka <claudio@conectiva.com>
* Original SAA7111A code by Dave Perks <dperks@ibm.net> * Original SAA7111A code by Dave Perks <dperks@ibm.net>
* Kernel I2C interface adapted from nt1003 driver * Kernel I2C interface adapted from nt1003 driver
* URB error messages from pwc driver by Nemosoft
* generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
* *
* Based on the Linux CPiA driver written by Peter Pregler, * Based on the Linux CPiA driver written by Peter Pregler,
* Scott J. Bertin and Johannes Erdfelt. * Scott J. Bertin and Johannes Erdfelt.
...@@ -53,22 +55,35 @@ ...@@ -53,22 +55,35 @@
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#endif #endif
/* A new implementation of the V4L 1 API exists that gives drivers direct
* access to file_operations. The old API is compatible with all 2.2 and 2.4
* kernels, and all 2.5 kernels through 2.5.5 (at least).
*
* Remove this #define to enable the new API
*
* Note: This has nothing to do with the V4L 2 API.
*/
#define OV511_OLD_V4L
#include "ov511.h" #include "ov511.h"
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v1.49 for Linux 2.5" #define DRIVER_VERSION "v1.53 for Linux 2.5"
#define EMAIL "mmcclell@bigfoot.com" #define EMAIL "mmcclell@bigfoot.com"
#define DRIVER_AUTHOR "Mark McClelland <mmcclell@bigfoot.com> & Bret Wallach \ #define DRIVER_AUTHOR "Mark McClelland <mmcclell@bigfoot.com> & Bret Wallach \
& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \ & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
<cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>" <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
#define DRIVER_DESC "OV511 USB Camera Driver" #define DRIVER_DESC "ov511 USB Camera Driver"
#define OV511_I2C_RETRIES 3 #define OV511_I2C_RETRIES 3
#define ENABLE_Y_QUANTABLE 1 #define ENABLE_Y_QUANTABLE 1
#define ENABLE_UV_QUANTABLE 1 #define ENABLE_UV_QUANTABLE 1
/* If you change this, you must also change the MODULE_PARM definition */
#define OV511_MAX_UNIT_VIDEO 16
/* Pixel count * 3 bytes for RGB */ /* Pixel count * 3 bytes for RGB */
#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3) #define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3)
#define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval)) #define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval))
...@@ -78,128 +93,55 @@ ...@@ -78,128 +93,55 @@
#define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM) #define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
/* PARAMETER VARIABLES: */ /**********************************************************************
/* (See ov511.txt for detailed descriptions of these.) */ * Module Parameters
* (See ov511.txt for detailed descriptions of these)
/* Sensor automatically changes brightness */ **********************************************************************/
static int autobright = 1;
/* Sensor automatically changes gain */
static int autogain = 1;
/* Sensor automatically changes exposure */
static int autoexp = 1;
/* 0=no debug messages
* 1=init/detection/unload and other significant messages,
* 2=some warning messages
* 3=config/control function calls
* 4=most function calls and data parsing messages
* 5=highly repetitive mesgs
* NOTE: This should be changed to 0, 1, or 2 for production kernels
*/
static int debug; /* = 0 */
/* Fix vertical misalignment of red and blue at 640x480 */
static int fix_rgb_offset; /* = 0 */
/* Snapshot mode enabled flag */
static int snapshot; /* = 0 */
/* Force image to be read in RGB instead of BGR. This option allow
* programs that expect RGB data (e.g. gqcam) to work with this driver. */
static int force_rgb; /* = 0 */
/* Number of seconds before inactive buffers are deallocated */
static int buf_timeout = 5;
/* Number of cameras to stream from simultaneously */
static int cams = 1;
/* Enable compression. Needs a fast (>300 MHz) CPU. */
static int compress; /* = 0 */
/* Display test pattern - doesn't work yet either */
static int testpat; /* = 0 */
/* Setting this to 1 will make the sensor output GBR422 instead of YUV420. Only
* affects RGB24 mode. */
static int sensor_gbr; /* = 0 */
/* Dump raw pixel data. */
static int dumppix; /* = 0 */
/* LED policy. Only works on some OV511+ cameras. 0=off, 1=on (default), 2=auto
* (on when open) */
static int led = 1;
/* Set this to 1 to dump the bridge register contents after initialization */
static int dump_bridge; /* = 0 */
/* Set this to 1 to dump the sensor register contents after initialization */
static int dump_sensor; /* = 0 */
/* Temporary option for debugging "works, but no image" problem. Prints the
* first 12 bytes of data (potentially a packet header) in each isochronous
* data frame. */
static int printph; /* = 0 */
/* Compression parameters - I'm not exactly sure what these do yet */
static int phy = 0x1f;
static int phuv = 0x05;
static int pvy = 0x06;
static int pvuv = 0x06;
static int qhy = 0x14;
static int qhuv = 0x03;
static int qvy = 0x04;
static int qvuv = 0x04;
/* Light frequency. Set to 50 or 60 (Hz), or zero for default settings */
static int lightfreq; /* = 0 */
/* Set this to 1 to enable banding filter by default. Compensates for /* These variables (and all static globals) default to zero */
* alternating horizontal light/dark bands caused by (usually fluorescent) static int autobright = 1;
* lights */ static int autogain = 1;
static int bandingfilter; /* = 0 */ static int autoexp = 1;
static int debug;
static int fix_rgb_offset;
static int snapshot;
static int force_rgb;
static int buf_timeout = 5;
static int cams = 1;
static int compress;
static int testpat;
static int sensor_gbr;
static int dumppix;
static int led = 1;
static int dump_bridge;
static int dump_sensor;
static int printph;
static int phy = 0x1f;
static int phuv = 0x05;
static int pvy = 0x06;
static int pvuv = 0x06;
static int qhy = 0x14;
static int qhuv = 0x03;
static int qvy = 0x04;
static int qvuv = 0x04;
static int lightfreq;
static int bandingfilter;
/* Pixel clock divisor */ /* Pixel clock divisor */
static int clockdiv = -1; static int clockdiv = -1;
/* Isoc packet size */ /* Isoc packet size */
static int packetsize = -1; static int packetsize = -1;
/* Frame drop register (16h) */ /* Frame drop register (16h) */
static int framedrop = -1; static int framedrop = -1;
/* Allows picture settings (brightness, hue, etc...) to take effect immediately,
* even in the middle of a frame. This reduces the time to change settings, but
* can ruin frames during the change. Only affects OmniVision sensors. */
static int fastset; /* = 0 */
/* Forces the palette to a specific value. If an application requests a
* different palette, it will be rejected. */
static int force_palette; /* = 0 */
/* Set tuner type, if not autodetected */
static int tuner = -1;
/* Allows proper exposure of objects that are illuminated from behind. Only static int fastset;
* affects OmniVision sensors. */ static int force_palette;
static int backlight; /* = 0 */ static int tuner = -1;
static int backlight;
/* If you change this, you must also change the MODULE_PARM definition */
#define OV511_MAX_UNIT_VIDEO 16
/* Allows specified minor numbers to be forced. They will be assigned in the
* order that devices are detected. Note that you cannot specify 0 as a minor
* number. If you do not specify any, the next available one will be used. This
* requires kernel 2.4.5 or later. */
static int unit_video[OV511_MAX_UNIT_VIDEO]; static int unit_video[OV511_MAX_UNIT_VIDEO];
static int remove_zeros;
/* Remove zero-padding from uncompressed incoming data. This will compensate for
* the blocks of corruption that appear when the camera cannot keep up with the
* speed of the USB bus (eg. at low frame resolutions) */
static int remove_zeros; /* = 0 */
MODULE_PARM(autobright, "i"); MODULE_PARM(autobright, "i");
MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness"); MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness");
...@@ -289,6 +231,10 @@ MODULE_AUTHOR(DRIVER_AUTHOR); ...@@ -289,6 +231,10 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/**********************************************************************
* Miscellaneous Globals
**********************************************************************/
static struct usb_driver ov511_driver; static struct usb_driver ov511_driver;
static struct ov51x_decomp_ops *ov511_decomp_ops; static struct ov51x_decomp_ops *ov511_decomp_ops;
...@@ -303,20 +249,28 @@ static int i2c_detect_tries = 5; ...@@ -303,20 +249,28 @@ static int i2c_detect_tries = 5;
/* MMX support is present in kernel and CPU. Checked upon decomp module load. */ /* MMX support is present in kernel and CPU. Checked upon decomp module load. */
static int ov51x_mmx_available; static int ov51x_mmx_available;
/* Function prototypes */ static __devinitdata struct usb_device_id device_table [] = {
static void ov51x_clear_snapshot(struct usb_ov511 *); { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
static int ov51x_check_snapshot(struct usb_ov511 *); { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
static inline int sensor_get_picture(struct usb_ov511 *, { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
struct video_picture *); { USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
static int sensor_get_exposure(struct usb_ov511 *, unsigned char *); { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int, { } /* Terminating entry */
unsigned long); };
MODULE_DEVICE_TABLE (usb, device_table);
static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
/********************************************************************** /**********************************************************************
* List of known OV511-based cameras * Symbolic Names
**********************************************************************/ **********************************************************************/
static struct cam_list clist[] = { /* Known OV511-based cameras */
static struct symbolic_list camlist[] = {
{ 0, "Generic Camera (no ID)" }, { 0, "Generic Camera (no ID)" },
{ 1, "Mustek WCam 3X" }, { 1, "Mustek WCam 3X" },
{ 3, "D-Link DSB-C300" }, { 3, "D-Link DSB-C300" },
...@@ -336,46 +290,78 @@ static struct cam_list clist[] = { ...@@ -336,46 +290,78 @@ static struct cam_list clist[] = {
{ -1, NULL } { -1, NULL }
}; };
static __devinitdata struct usb_device_id device_table [] = { /* Video4Linux1 Palettes */
{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511) }, static struct symbolic_list v4l1_plist[] = {
{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
{ USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, device_table);
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
static struct palette_list plist[] = {
{ VIDEO_PALETTE_GREY, "GREY" }, { VIDEO_PALETTE_GREY, "GREY" },
{ VIDEO_PALETTE_HI240, "HI240" }, { VIDEO_PALETTE_HI240, "HI240" },
{ VIDEO_PALETTE_RGB565, "RGB565" }, { VIDEO_PALETTE_RGB565, "RGB565" },
{ VIDEO_PALETTE_RGB24, "RGB24" }, { VIDEO_PALETTE_RGB24, "RGB24" },
{ VIDEO_PALETTE_RGB32, "RGB32" }, { VIDEO_PALETTE_RGB32, "RGB32" },
{ VIDEO_PALETTE_RGB555, "RGB555" }, { VIDEO_PALETTE_RGB555, "RGB555" },
{ VIDEO_PALETTE_YUV422, "YUV422" }, { VIDEO_PALETTE_YUV422, "YUV422" },
{ VIDEO_PALETTE_YUYV, "YUYV" }, { VIDEO_PALETTE_YUYV, "YUYV" },
{ VIDEO_PALETTE_UYVY, "UYVY" }, { VIDEO_PALETTE_UYVY, "UYVY" },
{ VIDEO_PALETTE_YUV420, "YUV420" }, { VIDEO_PALETTE_YUV420, "YUV420" },
{ VIDEO_PALETTE_YUV411, "YUV411" }, { VIDEO_PALETTE_YUV411, "YUV411" },
{ VIDEO_PALETTE_RAW, "RAW" }, { VIDEO_PALETTE_RAW, "RAW" },
{ VIDEO_PALETTE_YUV422P,"YUV422P" }, { VIDEO_PALETTE_YUV422P,"YUV422P" },
{ VIDEO_PALETTE_YUV411P,"YUV411P" }, { VIDEO_PALETTE_YUV411P,"YUV411P" },
{ VIDEO_PALETTE_YUV420P,"YUV420P" }, { VIDEO_PALETTE_YUV420P,"YUV420P" },
{ VIDEO_PALETTE_YUV410P,"YUV410P" }, { VIDEO_PALETTE_YUV410P,"YUV410P" },
{ -1, NULL } { -1, NULL }
}; };
#endif
static unsigned char yQuanTable511[] = OV511_YQUANTABLE; static struct symbolic_list brglist[] = {
static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE; { BRG_OV511, "OV511" },
static unsigned char yQuanTable518[] = OV518_YQUANTABLE; { BRG_OV511PLUS, "OV511+" },
static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE; { BRG_OV518, "OV518" },
{ BRG_OV518PLUS, "OV518+" },
{ -1, NULL }
};
static struct symbolic_list senlist[] = {
{ SEN_OV76BE, "OV76BE" },
{ SEN_OV7610, "OV7610" },
{ SEN_OV7620, "OV7620" },
{ SEN_OV7620AE, "OV7620AE" },
{ SEN_OV6620, "OV6620" },
{ SEN_OV6630, "OV6630" },
{ SEN_OV6630AE, "OV6630AE" },
{ SEN_OV6630AF, "OV6630AF" },
{ SEN_OV8600, "OV8600" },
{ SEN_KS0127, "KS0127" },
{ SEN_KS0127B, "KS0127B" },
{ SEN_SAA7111A, "SAA7111A" },
{ -1, NULL }
};
/* URB error codes: */
static struct symbolic_list urb_errlist[] = {
{ -ENOSR, "Buffer error (overrun)" },
{ -EPIPE, "Stalled (device not responding)" },
{ -EOVERFLOW, "Babble (bad cable?)" },
{ -EPROTO, "Bit-stuff error (bad cable?)" },
{ -EILSEQ, "CRC/Timeout" },
{ -ETIMEDOUT, "NAK (device does not respond)" },
{ -1, NULL }
};
/**********************************************************************
* Prototypes
**********************************************************************/
static void ov51x_clear_snapshot(struct usb_ov511 *);
static int ov51x_check_snapshot(struct usb_ov511 *);
static inline int sensor_get_picture(struct usb_ov511 *,
struct video_picture *);
static int sensor_get_exposure(struct usb_ov511 *, unsigned char *);
static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
/********************************************************************** /**********************************************************************
*
* Memory management * Memory management
*
**********************************************************************/ **********************************************************************/
/* Here we want the physical address of the memory. /* Here we want the physical address of the memory.
...@@ -453,7 +439,7 @@ ov511_read_proc_info(char *page, char **start, off_t off, int count, int *eof, ...@@ -453,7 +439,7 @@ ov511_read_proc_info(char *page, char **start, off_t off, int count, int *eof,
void *data) void *data)
{ {
char *out = page; char *out = page;
int i, j, len; int i, len;
struct usb_ov511 *ov = data; struct usb_ov511 *ov = data;
struct video_picture p; struct video_picture p;
unsigned char exp; unsigned char exp;
...@@ -469,8 +455,7 @@ ov511_read_proc_info(char *page, char **start, off_t off, int count, int *eof, ...@@ -469,8 +455,7 @@ ov511_read_proc_info(char *page, char **start, off_t off, int count, int *eof,
out += sprintf(out, "driver_version : %s\n", DRIVER_VERSION); out += sprintf(out, "driver_version : %s\n", DRIVER_VERSION);
out += sprintf(out, "custom_id : %d\n", ov->customid); out += sprintf(out, "custom_id : %d\n", ov->customid);
out += sprintf(out, "model : %s\n", ov->desc ? out += sprintf(out, "model : %s\n", ov->desc);
clist[ov->desc].description : "unknown");
out += sprintf(out, "streaming : %s\n", YES_NO(ov->streaming)); out += sprintf(out, "streaming : %s\n", YES_NO(ov->streaming));
out += sprintf(out, "grabbing : %s\n", YES_NO(ov->grabbing)); out += sprintf(out, "grabbing : %s\n", YES_NO(ov->grabbing));
out += sprintf(out, "compress : %s\n", YES_NO(ov->compress)); out += sprintf(out, "compress : %s\n", YES_NO(ov->compress));
...@@ -491,36 +476,16 @@ ov511_read_proc_info(char *page, char **start, off_t off, int count, int *eof, ...@@ -491,36 +476,16 @@ ov511_read_proc_info(char *page, char **start, off_t off, int count, int *eof,
ov->frame[i].depth); ov->frame[i].depth);
out += sprintf(out, " size : %d %d\n", out += sprintf(out, " size : %d %d\n",
ov->frame[i].width, ov->frame[i].height); ov->frame[i].width, ov->frame[i].height);
out += sprintf(out, " format : "); out += sprintf(out, " format : %s\n",
for (j = 0; plist[j].num >= 0; j++) { symbolic(v4l1_plist, ov->frame[i].format));
if (plist[j].num == ov->frame[i].format) {
out += sprintf(out, "%s\n", plist[j].name);
break;
}
}
if (plist[j].num < 0)
out += sprintf(out, "unknown\n");
out += sprintf(out, " data_buffer : 0x%p\n", out += sprintf(out, " data_buffer : 0x%p\n",
ov->frame[i].data); ov->frame[i].data);
} }
out += sprintf(out, "snap_enabled : %s\n", YES_NO(ov->snap_enabled)); out += sprintf(out, "snap_enabled : %s\n", YES_NO(ov->snap_enabled));
out += sprintf(out, "bridge : %s\n", out += sprintf(out, "bridge : %s\n",
ov->bridge == BRG_OV511 ? "OV511" : symbolic(brglist, ov->bridge));
ov->bridge == BRG_OV511PLUS ? "OV511+" :
ov->bridge == BRG_OV518 ? "OV518" :
ov->bridge == BRG_OV518PLUS ? "OV518+" :
"unknown");
out += sprintf(out, "sensor : %s\n", out += sprintf(out, "sensor : %s\n",
ov->sensor == SEN_OV6620 ? "OV6620" : symbolic(senlist, ov->sensor));
ov->sensor == SEN_OV6630 ? "OV6630" :
ov->sensor == SEN_OV7610 ? "OV7610" :
ov->sensor == SEN_OV7620 ? "OV7620" :
ov->sensor == SEN_OV7620AE ? "OV7620AE" :
ov->sensor == SEN_OV8600 ? "OV8600" :
ov->sensor == SEN_KS0127 ? "KS0127" :
ov->sensor == SEN_KS0127B ? "KS0127B" :
ov->sensor == SEN_SAA7111A ? "SAA7111A" :
"unknown");
out += sprintf(out, "packet_size : %d\n", ov->packet_size); out += sprintf(out, "packet_size : %d\n", ov->packet_size);
out += sprintf(out, "framebuffer : 0x%p\n", ov->fbuf); out += sprintf(out, "framebuffer : 0x%p\n", ov->fbuf);
...@@ -582,89 +547,91 @@ ov511_read_proc_button(char *page, char **start, off_t off, int count, int *eof, ...@@ -582,89 +547,91 @@ ov511_read_proc_button(char *page, char **start, off_t off, int count, int *eof,
} }
static void static void
create_proc_ov511_cam(struct usb_ov511 *ov511) create_proc_ov511_cam(struct usb_ov511 *ov)
{ {
char dirname[4]; char dirname[10];
if (!ov511_proc_entry || !ov511) if (!ov511_proc_entry || !ov)
return; return;
/* Create per-device directory */ /* Create per-device directory */
sprintf(dirname, "%d", ov511->vdev.minor); snprintf(dirname, 10, "%d", ov->vdev.minor);
PDEBUG(4, "creating /proc/video/ov511/%s/", dirname); PDEBUG(4, "creating /proc/video/ov511/%s/", dirname);
ov511->proc_devdir = create_proc_entry(dirname, S_IFDIR, ov->proc_devdir = create_proc_entry(dirname, S_IFDIR, ov511_proc_entry);
ov511_proc_entry); if (!ov->proc_devdir)
if (!ov511->proc_devdir)
return; return;
ov->proc_devdir->owner = THIS_MODULE;
/* Create "info" entry (human readable device information) */ /* Create "info" entry (human readable device information) */
PDEBUG(4, "creating /proc/video/ov511/%s/info", dirname); PDEBUG(4, "creating /proc/video/ov511/%s/info", dirname);
ov511->proc_info = create_proc_read_entry("info", ov->proc_info = create_proc_read_entry("info", S_IFREG|S_IRUGO|S_IWUSR,
S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir, ov->proc_devdir, ov511_read_proc_info, ov);
ov511_read_proc_info, ov511); if (!ov->proc_info)
if (!ov511->proc_info)
return; return;
ov->proc_info->owner = THIS_MODULE;
/* Don't create it if old snapshot mode on (would cause race cond.) */ /* Don't create it if old snapshot mode on (would cause race cond.) */
if (!snapshot) { if (!snapshot) {
/* Create "button" entry (snapshot button status) */ /* Create "button" entry (snapshot button status) */
PDEBUG(4, "creating /proc/video/ov511/%s/button", dirname); PDEBUG(4, "creating /proc/video/ov511/%s/button", dirname);
ov511->proc_button = create_proc_read_entry("button", ov->proc_button = create_proc_read_entry("button",
S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir, S_IFREG|S_IRUGO|S_IWUSR, ov->proc_devdir,
ov511_read_proc_button, ov511); ov511_read_proc_button, ov);
if (!ov511->proc_button) if (!ov->proc_button)
return; return;
} }
ov->proc_button->owner = THIS_MODULE;
/* Create "control" entry (ioctl() interface) */ /* Create "control" entry (ioctl() interface) */
PDEBUG(4, "creating /proc/video/ov511/%s/control", dirname); PDEBUG(4, "creating /proc/video/ov511/%s/control", dirname);
lock_kernel(); lock_kernel();
ov511->proc_control = create_proc_entry("control", ov->proc_control = create_proc_entry("control", S_IFREG|S_IRUGO|S_IWUSR,
S_IFREG|S_IRUGO|S_IWUSR, ov511->proc_devdir); ov->proc_devdir);
if (!ov511->proc_control) { if (!ov->proc_control) {
unlock_kernel(); unlock_kernel();
return; return;
} }
ov511->proc_control->data = ov511; ov->proc_control->owner = THIS_MODULE;
ov511->proc_control->proc_fops = &ov511_control_fops; ov->proc_control->data = ov;
ov->proc_control->proc_fops = &ov511_control_fops;
unlock_kernel(); unlock_kernel();
} }
static void static void
destroy_proc_ov511_cam(struct usb_ov511 *ov511) destroy_proc_ov511_cam(struct usb_ov511 *ov)
{ {
char dirname[4]; char dirname[10];
if (!ov511 || !ov511->proc_devdir) if (!ov || !ov->proc_devdir)
return; return;
sprintf(dirname, "%d", ov511->vdev.minor); snprintf(dirname, 10, "%d", ov->vdev.minor);
/* Destroy "control" entry */ /* Destroy "control" entry */
if (ov511->proc_control) { if (ov->proc_control) {
PDEBUG(4, "destroying /proc/video/ov511/%s/control", dirname); PDEBUG(4, "destroying /proc/video/ov511/%s/control", dirname);
remove_proc_entry("control", ov511->proc_devdir); remove_proc_entry("control", ov->proc_devdir);
ov511->proc_control = NULL; ov->proc_control = NULL;
} }
/* Destroy "button" entry */ /* Destroy "button" entry */
if (ov511->proc_button) { if (ov->proc_button) {
PDEBUG(4, "destroying /proc/video/ov511/%s/button", dirname); PDEBUG(4, "destroying /proc/video/ov511/%s/button", dirname);
remove_proc_entry("button", ov511->proc_devdir); remove_proc_entry("button", ov->proc_devdir);
ov511->proc_button = NULL; ov->proc_button = NULL;
} }
/* Destroy "info" entry */ /* Destroy "info" entry */
if (ov511->proc_info) { if (ov->proc_info) {
PDEBUG(4, "destroying /proc/video/ov511/%s/info", dirname); PDEBUG(4, "destroying /proc/video/ov511/%s/info", dirname);
remove_proc_entry("info", ov511->proc_devdir); remove_proc_entry("info", ov->proc_devdir);
ov511->proc_info = NULL; ov->proc_info = NULL;
} }
/* Destroy per-device directory */ /* Destroy per-device directory */
PDEBUG(4, "destroying /proc/video/ov511/%s/", dirname); PDEBUG(4, "destroying /proc/video/ov511/%s/", dirname);
remove_proc_entry(dirname, ov511_proc_entry); remove_proc_entry(dirname, ov511_proc_entry);
ov511->proc_devdir = NULL; ov->proc_devdir = NULL;
} }
static void static void
...@@ -724,7 +691,7 @@ reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value) ...@@ -724,7 +691,7 @@ reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
up(&ov->cbuf_lock); up(&ov->cbuf_lock);
if (rc < 0) if (rc < 0)
err("reg write: error %d", rc); err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
return rc; return rc;
} }
...@@ -746,7 +713,7 @@ reg_r(struct usb_ov511 *ov, unsigned char reg) ...@@ -746,7 +713,7 @@ reg_r(struct usb_ov511 *ov, unsigned char reg)
PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]); PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
if (rc < 0) if (rc < 0)
err("reg read: error %d", rc); err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
else else
rc = ov->cbuf[0]; rc = ov->cbuf[0];
...@@ -805,7 +772,8 @@ ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n) ...@@ -805,7 +772,8 @@ ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
up(&ov->cbuf_lock); up(&ov->cbuf_lock);
if (rc < 0) if (rc < 0)
err("reg write multiple: error %d", rc); err("reg write multiple: error %d: %s", rc,
symbolic(urb_errlist, rc));
return rc; return rc;
} }
...@@ -937,21 +905,17 @@ ov518_i2c_write_internal(struct usb_ov511 *ov, ...@@ -937,21 +905,17 @@ ov518_i2c_write_internal(struct usb_ov511 *ov,
/* Select camera register */ /* Select camera register */
rc = reg_w(ov, R51x_I2C_SADDR_3, reg); rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
if (rc < 0) goto error; if (rc < 0) return rc;
/* Write "value" to I2C data port of OV511 */ /* Write "value" to I2C data port of OV511 */
rc = reg_w(ov, R51x_I2C_DATA, value); rc = reg_w(ov, R51x_I2C_DATA, value);
if (rc < 0) goto error; if (rc < 0) return rc;
/* Initiate 3-byte write cycle */ /* Initiate 3-byte write cycle */
rc = reg_w(ov, R518_I2C_CTL, 0x01); rc = reg_w(ov, R518_I2C_CTL, 0x01);
if (rc < 0) goto error; if (rc < 0) return rc;
return 0; return 0;
error:
err("ov518 i2c write: error %d", rc);
return rc;
} }
/* NOTE: Do not call this function directly! */ /* NOTE: Do not call this function directly! */
...@@ -968,19 +932,19 @@ ov511_i2c_write_internal(struct usb_ov511 *ov, ...@@ -968,19 +932,19 @@ ov511_i2c_write_internal(struct usb_ov511 *ov,
for (retries = OV511_I2C_RETRIES; ; ) { for (retries = OV511_I2C_RETRIES; ; ) {
/* Select camera register */ /* Select camera register */
rc = reg_w(ov, R51x_I2C_SADDR_3, reg); rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
if (rc < 0) goto error; if (rc < 0) return rc;
/* Write "value" to I2C data port of OV511 */ /* Write "value" to I2C data port of OV511 */
rc = reg_w(ov, R51x_I2C_DATA, value); rc = reg_w(ov, R51x_I2C_DATA, value);
if (rc < 0) goto error; if (rc < 0) return rc;
/* Initiate 3-byte write cycle */ /* Initiate 3-byte write cycle */
rc = reg_w(ov, R511_I2C_CTL, 0x01); rc = reg_w(ov, R511_I2C_CTL, 0x01);
if (rc < 0) goto error; if (rc < 0) return rc;
do rc = reg_r(ov, R511_I2C_CTL); do rc = reg_r(ov, R511_I2C_CTL);
while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
if (rc < 0) goto error; if (rc < 0) return rc;
if ((rc&2) == 0) /* Ack? */ if ((rc&2) == 0) /* Ack? */
break; break;
...@@ -990,16 +954,11 @@ ov511_i2c_write_internal(struct usb_ov511 *ov, ...@@ -990,16 +954,11 @@ ov511_i2c_write_internal(struct usb_ov511 *ov,
#endif #endif
if (--retries < 0) { if (--retries < 0) {
err("i2c write retries exhausted"); err("i2c write retries exhausted");
rc = -1; return -1;
goto error;
} }
} }
return 0; return 0;
error:
err("i2c write: error %d", rc);
return rc;
} }
/* NOTE: Do not call this function directly! /* NOTE: Do not call this function directly!
...@@ -1014,25 +973,21 @@ ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) ...@@ -1014,25 +973,21 @@ ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
/* Select camera register */ /* Select camera register */
rc = reg_w(ov, R51x_I2C_SADDR_2, reg); rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
if (rc < 0) goto error; if (rc < 0) return rc;
/* Initiate 2-byte write cycle */ /* Initiate 2-byte write cycle */
rc = reg_w(ov, R518_I2C_CTL, 0x03); rc = reg_w(ov, R518_I2C_CTL, 0x03);
if (rc < 0) goto error; if (rc < 0) return rc;
/* Initiate 2-byte read cycle */ /* Initiate 2-byte read cycle */
rc = reg_w(ov, R518_I2C_CTL, 0x05); rc = reg_w(ov, R518_I2C_CTL, 0x05);
if (rc < 0) goto error; if (rc < 0) return rc;
value = reg_r(ov, R51x_I2C_DATA); value = reg_r(ov, R51x_I2C_DATA);
PDEBUG(5, "0x%02X:0x%02X", reg, value); PDEBUG(5, "0x%02X:0x%02X", reg, value);
return value; return value;
error:
err("ov518 i2c read: error %d", rc);
return rc;
} }
/* NOTE: Do not call this function directly! /* NOTE: Do not call this function directly!
...@@ -1046,15 +1001,15 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) ...@@ -1046,15 +1001,15 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
for (retries = OV511_I2C_RETRIES; ; ) { for (retries = OV511_I2C_RETRIES; ; ) {
/* Select camera register */ /* Select camera register */
rc = reg_w(ov, R51x_I2C_SADDR_2, reg); rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
if (rc < 0) goto error; if (rc < 0) return rc;
/* Initiate 2-byte write cycle */ /* Initiate 2-byte write cycle */
rc = reg_w(ov, R511_I2C_CTL, 0x03); rc = reg_w(ov, R511_I2C_CTL, 0x03);
if (rc < 0) goto error; if (rc < 0) return rc;
do rc = reg_r(ov, R511_I2C_CTL); do rc = reg_r(ov, R511_I2C_CTL);
while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
if (rc < 0) goto error; if (rc < 0) return rc;
if ((rc&2) == 0) /* Ack? */ if ((rc&2) == 0) /* Ack? */
break; break;
...@@ -1064,8 +1019,7 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) ...@@ -1064,8 +1019,7 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
if (--retries < 0) { if (--retries < 0) {
err("i2c write retries exhausted"); err("i2c write retries exhausted");
rc = -1; return -1;
goto error;
} }
} }
...@@ -1073,23 +1027,22 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) ...@@ -1073,23 +1027,22 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
for (retries = OV511_I2C_RETRIES; ; ) { for (retries = OV511_I2C_RETRIES; ; ) {
/* Initiate 2-byte read cycle */ /* Initiate 2-byte read cycle */
rc = reg_w(ov, R511_I2C_CTL, 0x05); rc = reg_w(ov, R511_I2C_CTL, 0x05);
if (rc < 0) goto error; if (rc < 0) return rc;
do rc = reg_r(ov, R511_I2C_CTL); do rc = reg_r(ov, R511_I2C_CTL);
while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */ while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
if (rc < 0) goto error; if (rc < 0) return rc;
if ((rc&2) == 0) /* Ack? */ if ((rc&2) == 0) /* Ack? */
break; break;
/* I2C abort */ /* I2C abort */
rc = reg_w(ov, R511_I2C_CTL, 0x10); rc = reg_w(ov, R511_I2C_CTL, 0x10);
if (rc < 0) goto error; if (rc < 0) return rc;
if (--retries < 0) { if (--retries < 0) {
err("i2c read retries exhausted"); err("i2c read retries exhausted");
rc = -1; return -1;
goto error;
} }
} }
...@@ -1100,13 +1053,9 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) ...@@ -1100,13 +1053,9 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
/* This is needed to make i2c_w() work */ /* This is needed to make i2c_w() work */
rc = reg_w(ov, R511_I2C_CTL, 0x05); rc = reg_w(ov, R511_I2C_CTL, 0x05);
if (rc < 0) if (rc < 0)
goto error; return rc;
return value; return value;
error:
err("i2c read: error %d", rc);
return rc;
} }
/* returns: negative is error, pos or zero is data */ /* returns: negative is error, pos or zero is data */
...@@ -1311,22 +1260,17 @@ write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals) ...@@ -1311,22 +1260,17 @@ write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals)
while (pRegvals->bus != OV511_DONE_BUS) { while (pRegvals->bus != OV511_DONE_BUS) {
if (pRegvals->bus == OV511_REG_BUS) { if (pRegvals->bus == OV511_REG_BUS) {
if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0) if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0)
goto error; return rc;
} else if (pRegvals->bus == OV511_I2C_BUS) { } else if (pRegvals->bus == OV511_I2C_BUS) {
if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0) if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0)
goto error; return rc;
} else { } else {
err("Bad regval array"); err("Bad regval array");
rc = -1; return -1;
goto error;
} }
pRegvals++; pRegvals++;
} }
return 0; return 0;
error:
err("write regvals: error %d", rc);
return rc;
} }
#ifdef OV511_DEBUG #ifdef OV511_DEBUG
...@@ -2394,13 +2338,13 @@ get_depth(int palette) ...@@ -2394,13 +2338,13 @@ get_depth(int palette)
{ {
switch (palette) { switch (palette) {
case VIDEO_PALETTE_GREY: return 8; case VIDEO_PALETTE_GREY: return 8;
case VIDEO_PALETTE_YUV420: return 12;
case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
case VIDEO_PALETTE_RGB565: return 16; case VIDEO_PALETTE_RGB565: return 16;
case VIDEO_PALETTE_RGB24: return 24; case VIDEO_PALETTE_RGB24: return 24;
case VIDEO_PALETTE_YUV422: return 16; case VIDEO_PALETTE_YUV422: return 16;
case VIDEO_PALETTE_YUYV: return 16; case VIDEO_PALETTE_YUYV: return 16;
case VIDEO_PALETTE_YUV420: return 12;
case VIDEO_PALETTE_YUV422P: return 16; /* Planar */ case VIDEO_PALETTE_YUV422P: return 16; /* Planar */
case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
default: return 0; /* Invalid format */ default: return 0; /* Invalid format */
} }
} }
...@@ -2803,11 +2747,11 @@ ov518_mode_init_regs(struct usb_ov511 *ov, ...@@ -2803,11 +2747,11 @@ ov518_mode_init_regs(struct usb_ov511 *ov,
// /* Here I'm assuming that snapshot size == image size. // /* Here I'm assuming that snapshot size == image size.
// * I hope that's always true. --claudio // * I hope that's always true. --claudio
// */ // */
// pxcnt = sub_flag ? (ov511->subw >> 3) - 1 : mlist[i].pxcnt; // pxcnt = sub_flag ? (ov->subw >> 3) - 1 : mlist[i].pxcnt;
// lncnt = sub_flag ? (ov511->subh >> 3) - 1 : mlist[i].lncnt; // lncnt = sub_flag ? (ov->subh >> 3) - 1 : mlist[i].lncnt;
// //
// reg_w(ov511, 0x12, pxcnt); // reg_w(ov, 0x12, pxcnt);
// reg_w(ov511, 0x13, lncnt); // reg_w(ov, 0x13, lncnt);
/******** Set the mode ********/ /******** Set the mode ********/
...@@ -3475,6 +3419,7 @@ decompress(struct usb_ov511 *ov, struct ov511_frame *frame, ...@@ -3475,6 +3419,7 @@ decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
int ret = ov->decomp_ops->decomp_400( int ret = ov->decomp_ops->decomp_400(
pIn0, pIn0,
pOut0, pOut0,
frame->compbuf,
frame->rawwidth, frame->rawwidth,
frame->rawheight, frame->rawheight,
frame->bytes_recvd); frame->bytes_recvd);
...@@ -3483,6 +3428,7 @@ decompress(struct usb_ov511 *ov, struct ov511_frame *frame, ...@@ -3483,6 +3428,7 @@ decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
int ret = ov->decomp_ops->decomp_420( int ret = ov->decomp_ops->decomp_420(
pIn0, pIn0,
pOut0, pOut0,
frame->compbuf,
frame->rawwidth, frame->rawwidth,
frame->rawheight, frame->rawheight,
frame->bytes_recvd); frame->bytes_recvd);
...@@ -3682,7 +3628,7 @@ ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame) ...@@ -3682,7 +3628,7 @@ ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
memset(frame->data, 0, memset(frame->data, 0,
MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)); MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd); PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
memmove(frame->data, frame->rawdata, frame->bytes_recvd); memcpy(frame->data, frame->rawdata, frame->bytes_recvd);
return; return;
} }
...@@ -3719,7 +3665,7 @@ ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame) ...@@ -3719,7 +3665,7 @@ ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
/* Deinterlace frame, if necessary */ /* Deinterlace frame, if necessary */
if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) { if (ov->sensor == SEN_SAA7111A && frame->rawheight == 480) {
memmove(frame->rawdata, frame->tempdata, memcpy(frame->rawdata, frame->tempdata,
MAX_RAW_DATA_SIZE(frame->width, frame->height)); MAX_RAW_DATA_SIZE(frame->width, frame->height));
deinterlace(frame, RAWFMT_YUV420, frame->rawdata, deinterlace(frame, RAWFMT_YUV420, frame->rawdata,
frame->tempdata); frame->tempdata);
...@@ -3747,18 +3693,19 @@ ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame) ...@@ -3747,18 +3693,19 @@ ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
break; break;
case VIDEO_PALETTE_YUV420: case VIDEO_PALETTE_YUV420:
case VIDEO_PALETTE_YUV420P: case VIDEO_PALETTE_YUV420P:
memmove(frame->data, frame->tempdata, memcpy(frame->data, frame->tempdata,
MAX_RAW_DATA_SIZE(frame->width, frame->height)); MAX_RAW_DATA_SIZE(frame->width, frame->height));
break; break;
case VIDEO_PALETTE_YUV422P: case VIDEO_PALETTE_YUV422P:
/* Data is converted in place, so copy it in advance */ /* Data is converted in place, so copy it in advance */
memmove(frame->data, frame->tempdata, memcpy(frame->data, frame->tempdata,
MAX_RAW_DATA_SIZE(frame->width, frame->height)); MAX_RAW_DATA_SIZE(frame->width, frame->height));
yuv420p_to_yuv422p(frame, frame->data); yuv420p_to_yuv422p(frame, frame->data);
break; break;
default: default:
err("Cannot convert data to this format"); err("Cannot convert data to %s",
symbolic(v4l1_plist, frame->format));
} }
if (fix_rgb_offset) if (fix_rgb_offset)
...@@ -3771,324 +3718,64 @@ ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame) ...@@ -3771,324 +3718,64 @@ ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
* *
**********************************************************************/ **********************************************************************/
static int static inline void
ov511_move_data(struct usb_ov511 *ov, struct urb *urb) ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
{ {
unsigned char *cdata; int num, offset;
int data_size, num, offset, i, totlen = 0; int pnum = in[ov->packet_size - 1]; /* Get packet number */
int aPackNum[FRAMES_PER_DESC]; int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
struct ov511_frame *frame; struct ov511_frame *frame = &ov->frame[ov->curframe];
struct timeval *ts; struct timeval *ts;
PDEBUG(5, "Moving %d packets", urb->number_of_packets); /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
* byte non-zero. The EOF packet has image width/height in the
data_size = ov->packet_size - 1; * 10th and 11th bytes. The 9th byte is given as follows:
*
for (i = 0; i < urb->number_of_packets; i++) { * bit 7: EOF
int n = urb->iso_frame_desc[i].actual_length; * 6: compression enabled
int st = urb->iso_frame_desc[i].status; * 5: 422/420/400 modes
* 4: 422/420/400 modes
urb->iso_frame_desc[i].actual_length = 0; * 3: 1
urb->iso_frame_desc[i].status = 0; * 2: snapshot button on
* 1: snapshot frame
cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; * 0: even/odd field
*/
aPackNum[i] = n ? cdata[ov->packet_size - 1] : -1;
if (!n || ov->curframe == -1)
continue;
if (st)
PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st);
frame = &ov->frame[ov->curframe];
/* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
* byte non-zero. The EOF packet has image width/height in the
* 10th and 11th bytes. The 9th byte is given as follows:
*
* bit 7: EOF
* 6: compression enabled
* 5: 422/420/400 modes
* 4: 422/420/400 modes
* 3: 1
* 2: snapshot button on
* 1: snapshot frame
* 0: even/odd field
*/
if (printph) {
info("packet header (%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
cdata[ov->packet_size - 1],
cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5],
cdata[6], cdata[7], cdata[8], cdata[9], cdata[10], cdata[11]);
}
/* Check for SOF/EOF packet */
if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] |
cdata[4] | cdata[5] | cdata[6] | cdata[7]) ||
(~cdata[8] & 0x08))
goto check_middle;
/* Frame end */
if (cdata[8] & 0x80) {
ts = (struct timeval *)(frame->data
+ MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
do_gettimeofday(ts);
/* Get the actual frame size from the EOF header */
frame->rawwidth = ((int)(cdata[9]) + 1) * 8;
frame->rawheight = ((int)(cdata[10]) + 1) * 8;
PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d, recvd=%d",
ov->curframe,
(int)(cdata[ov->packet_size - 1]),
frame->rawwidth,
frame->rawheight,
frame->bytes_recvd);
/* Validate the header data */
RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
/* Don't allow byte count to exceed buffer size */
RESTRICT_TO_RANGE(frame->bytes_recvd,
8,
MAX_RAW_DATA_SIZE(ov->maxwidth,
ov->maxheight));
if (frame->scanstate == STATE_LINES) {
int iFrameNext;
frame->grabstate = FRAME_DONE; // FIXME: Is this right?
if (waitqueue_active(&frame->wq)) {
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
}
/* If next frame is ready or grabbing,
* point to it */
iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES;
if (ov->frame[iFrameNext].grabstate == FRAME_READY
|| ov->frame[iFrameNext].grabstate == FRAME_GRABBING) {
ov->curframe = iFrameNext;
ov->frame[iFrameNext].scanstate = STATE_SCANNING;
} else {
if (frame->grabstate == FRAME_DONE) {
PDEBUG(4, "Frame done! congratulations");
} else {
PDEBUG(4, "Frame not ready? state = %d",
ov->frame[iFrameNext].grabstate);
}
ov->curframe = -1;
}
} else {
PDEBUG(5, "Frame done, but not scanning");
}
/* Image corruption caused by misplaced frame->segment = 0
* fixed by carlosf@conectiva.com.br
*/
} else {
/* Frame start */
PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
/* Check to see if it's a snapshot frame */
/* FIXME?? Should the snapshot reset go here? Performance? */
if (cdata[8] & 0x02) {
frame->snapshot = 1;
PDEBUG(3, "snapshot detected");
}
frame->scanstate = STATE_LINES;
frame->bytes_recvd = 0;
frame->compressed = cdata[8] & 0x40;
}
check_middle:
/* Are we in a frame? */
if (frame->scanstate != STATE_LINES) {
PDEBUG(5, "Not in a frame; packet skipped");
continue;
}
#if 0
/* Skip packet if first 9 bytes are zero. These are common, so
* we use a less expensive test here instead of later */
if (frame->compressed) {
int b, skip = 1;
for (b = 0; b < 9; b++) {
if (cdata[b])
skip=0;
}
if (skip) {
PDEBUG(5, "Skipping packet (all zero)");
continue;
}
}
#endif
/* If frame start, skip header */
if (frame->bytes_recvd == 0)
offset = 9;
else
offset = 0;
num = n - offset - 1;
/* Dump all data exactly as received */
if (dumppix == 2) {
frame->bytes_recvd += n - 1;
if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight))
memmove(frame->rawdata + frame->bytes_recvd - (n - 1),
&cdata[0], n - 1);
else
PDEBUG(3, "Raw data buffer overrun!! (%d)",
frame->bytes_recvd
- MAX_RAW_DATA_SIZE(ov->maxwidth,
ov->maxheight));
} else if (!frame->compressed && !remove_zeros) {
frame->bytes_recvd += num;
if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight))
memmove(frame->rawdata + frame->bytes_recvd - num,
&cdata[offset], num);
else
PDEBUG(3, "Raw data buffer overrun!! (%d)",
frame->bytes_recvd
- MAX_RAW_DATA_SIZE(ov->maxwidth,
ov->maxheight));
} else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
int b, in = 0, allzero, copied=0;
if (offset) {
frame->bytes_recvd += 32 - offset; // Bytes out
memmove(frame->rawdata,
&cdata[offset], 32 - offset);
in += 32;
}
while (in < n - 1) {
allzero = 1;
for (b = 0; b < 32; b++) {
if (cdata[in + b]) {
allzero = 0;
break;
}
}
if (allzero) {
/* Don't copy it */
} else {
if (frame->bytes_recvd + copied + 32
<= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) {
memmove(frame->rawdata + frame->bytes_recvd + copied,
&cdata[in], 32);
copied += 32;
} else {
PDEBUG(3, "Raw data buffer overrun!!");
}
}
in += 32;
}
frame->bytes_recvd += copied;
}
if (printph) {
info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
in[7], in[8], in[9], in[10], in[11]);
} }
PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d", /* Check for SOF/EOF packet */
aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4], if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) ||
aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]); (~in[8] & 0x08))
goto check_middle;
return totlen;
}
static int
ov518_move_data(struct usb_ov511 *ov, struct urb *urb)
{
unsigned char *cdata;
int i, data_size, totlen = 0;
struct ov511_frame *frame;
struct timeval *ts;
PDEBUG(5, "Moving %d packets", urb->number_of_packets);
/* OV518(+) has no packet numbering */
data_size = ov->packet_size;
for (i = 0; i < urb->number_of_packets; i++) { /* Frame end */
int n = urb->iso_frame_desc[i].actual_length; if (in[8] & 0x80) {
int st = urb->iso_frame_desc[i].status; ts = (struct timeval *)(frame->data
urb->iso_frame_desc[i].actual_length = 0;
urb->iso_frame_desc[i].status = 0;
cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
if (!n) {
PDEBUG(4, "Zero-length packet");
continue;
}
if (ov->curframe == -1) {
PDEBUG(4, "No frame currently active");
continue;
}
if (st)
PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st);
frame = &ov->frame[ov->curframe];
if (printph) {
info("packet header: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
cdata[0], cdata[1], cdata[2], cdata[3], cdata[4], cdata[5],
cdata[6], cdata[7], cdata[8], cdata[9], cdata[10], cdata[11]);
}
/* A false positive here is likely, until OVT gives me
* the definitive SOF/EOF format */
if ((!(cdata[0] | cdata[1] | cdata[2] | cdata[3] |
cdata[5])) && cdata[6]) {
if (frame->scanstate == STATE_LINES) {
PDEBUG(4, "Detected frame end/start");
goto eof;
} else { //scanstate == STATE_SCANNING
/* Frame start */
PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
goto sof;
}
} else {
goto check_middle;
}
eof:
ts = (struct timeval *)(frame->data
+ MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight)); + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
do_gettimeofday(ts); do_gettimeofday(ts);
PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d", /* Get the actual frame size from the EOF header */
ov->curframe, frame->rawwidth = ((int)(in[9]) + 1) * 8;
(int)(cdata[9]), (int)(cdata[10]), frame->bytes_recvd); frame->rawheight = ((int)(in[10]) + 1) * 8;
// FIXME: Since we don't know the header formats yet, PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d",
// there is no way to know what the actual image size is ov->curframe, pnum, frame->rawwidth, frame->rawheight,
frame->rawwidth = frame->width; frame->bytes_recvd);
frame->rawheight = frame->height;
/* Validate the header data */ /* Validate the header data */
RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth); RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight); RESTRICT_TO_RANGE(frame->rawheight, ov->minheight,
ov->maxheight);
/* Don't allow byte count to exceed buffer size */ /* Don't allow byte count to exceed buffer size */
RESTRICT_TO_RANGE(frame->bytes_recvd, RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
8,
MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight));
if (frame->scanstate == STATE_LINES) { if (frame->scanstate == STATE_LINES) {
int iFrameNext; int nextf;
frame->grabstate = FRAME_DONE; // FIXME: Is this right? frame->grabstate = FRAME_DONE; // FIXME: Is this right?
...@@ -4099,115 +3786,277 @@ ov518_move_data(struct usb_ov511 *ov, struct urb *urb) ...@@ -4099,115 +3786,277 @@ ov518_move_data(struct usb_ov511 *ov, struct urb *urb)
/* If next frame is ready or grabbing, /* If next frame is ready or grabbing,
* point to it */ * point to it */
iFrameNext = (ov->curframe + 1) % OV511_NUMFRAMES; nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
if (ov->frame[iFrameNext].grabstate == FRAME_READY if (ov->frame[nextf].grabstate == FRAME_READY
|| ov->frame[iFrameNext].grabstate == FRAME_GRABBING) { || ov->frame[nextf].grabstate == FRAME_GRABBING) {
ov->curframe = iFrameNext; ov->curframe = nextf;
ov->frame[iFrameNext].scanstate = STATE_SCANNING; ov->frame[nextf].scanstate = STATE_SCANNING;
frame = &ov->frame[iFrameNext];
} else { } else {
if (frame->grabstate == FRAME_DONE) { if (frame->grabstate == FRAME_DONE) {
PDEBUG(4, "Frame done! congratulations"); PDEBUG(4, "** Frame done **");
} else { } else {
PDEBUG(4, "Frame not ready? state = %d", PDEBUG(4, "Frame not ready? state = %d",
ov->frame[iFrameNext].grabstate); ov->frame[nextf].grabstate);
} }
ov->curframe = -1; ov->curframe = -1;
PDEBUG(4, "SOF dropped (no active frame)");
continue; /* Nowhere to store this frame */
} }
} else {
PDEBUG(5, "Frame done, but not scanning");
} }
/* Image corruption caused by misplaced frame->segment = 0 /* Image corruption caused by misplaced frame->segment = 0
* fixed by carlosf@conectiva.com.br * fixed by carlosf@conectiva.com.br
*/ */
sof: } else {
PDEBUG(4, "Starting capture on frame %d", frame->framenum); /* Frame start */
// Snapshot not reverse-engineered yet. PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
#if 0
/* Check to see if it's a snapshot frame */ /* Check to see if it's a snapshot frame */
/* FIXME?? Should the snapshot reset go here? Performance? */ /* FIXME?? Should the snapshot reset go here? Performance? */
if (cdata[8] & 0x02) { if (in[8] & 0x02) {
frame->snapshot = 1; frame->snapshot = 1;
PDEBUG(3, "snapshot detected"); PDEBUG(3, "snapshot detected");
} }
#endif
frame->scanstate = STATE_LINES; frame->scanstate = STATE_LINES;
frame->bytes_recvd = 0; frame->bytes_recvd = 0;
// frame->compressed = 1; frame->compressed = in[8] & 0x40;
}
check_middle: check_middle:
/* Are we in a frame? */ /* Are we in a frame? */
if (frame->scanstate != STATE_LINES) { if (frame->scanstate != STATE_LINES) {
PDEBUG(4, "scanstate: no SOF yet"); PDEBUG(5, "Not in a frame; packet skipped");
continue; return;
}
/* If frame start, skip header */
if (frame->bytes_recvd == 0)
offset = 9;
else
offset = 0;
num = n - offset - 1;
/* Dump all data exactly as received */
if (dumppix == 2) {
frame->bytes_recvd += n - 1;
if (frame->bytes_recvd <= max_raw)
memcpy(frame->rawdata + frame->bytes_recvd - (n - 1),
in, n - 1);
else
PDEBUG(3, "Raw data buffer overrun!! (%d)",
frame->bytes_recvd - max_raw);
} else if (!frame->compressed && !remove_zeros) {
frame->bytes_recvd += num;
if (frame->bytes_recvd <= max_raw)
memcpy(frame->rawdata + frame->bytes_recvd - num,
in + offset, num);
else
PDEBUG(3, "Raw data buffer overrun!! (%d)",
frame->bytes_recvd - max_raw);
} else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
int b, read = 0, allzero, copied = 0;
if (offset) {
frame->bytes_recvd += 32 - offset; // Bytes out
memcpy(frame->rawdata, in + offset, 32 - offset);
read += 32;
} }
/* Dump all data exactly as received */ while (read < n - 1) {
if (dumppix == 2) { allzero = 1;
frame->bytes_recvd += n; for (b = 0; b < 32; b++) {
if (frame->bytes_recvd <= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) if (in[read + b]) {
memmove(frame->rawdata + frame->bytes_recvd - n, allzero = 0;
&cdata[0], n); break;
else
PDEBUG(3, "Raw data buffer overrun!! (%d)",
frame->bytes_recvd
- MAX_RAW_DATA_SIZE(ov->maxwidth,
ov->maxheight));
} else {
/* All incoming data are divided into 8-byte segments. If the
* segment contains all zero bytes, it must be skipped. These
* zero-segments allow the OV518 to mainain a constant data rate
* regardless of the effectiveness of the compression. Segments
* are aligned relative to the beginning of each isochronous
* packet. The first segment is a header (the decompressor
* skips it later).
*/
int b, in = 0, allzero, copied=0;
while (in < n) {
allzero = 1;
for (b = 0; b < 8; b++) {
if (cdata[in + b]) {
allzero = 0;
break;
}
} }
}
if (allzero) { if (allzero) {
/* Don't copy it */ /* Don't copy it */
} else {
if (frame->bytes_recvd + copied + 32 <= max_raw)
{
memcpy(frame->rawdata
+ frame->bytes_recvd + copied,
in + read, 32);
copied += 32;
} else { } else {
if (frame->bytes_recvd + copied + 8 PDEBUG(3, "Raw data buffer overrun!!");
<= MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight)) {
memmove(frame->rawdata + frame->bytes_recvd + copied,
&cdata[in], 8);
copied += 8;
} else {
PDEBUG(3, "Raw data buffer overrun!!");
}
} }
in += 8;
} }
frame->bytes_recvd += copied; read += 32;
} }
}
return totlen; frame->bytes_recvd += copied;
}
}
static inline void
ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
{
int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
struct ov511_frame *frame = &ov->frame[ov->curframe];
struct timeval *ts;
if (printph) {
info("ph: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7],
in[8], in[9], in[10], in[11]);
}
/* A false positive here is likely, until OVT gives me
* the definitive SOF/EOF format */
if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) {
if (frame->scanstate == STATE_LINES) {
PDEBUG(4, "Detected frame end/start");
goto eof;
} else { //scanstate == STATE_SCANNING
/* Frame start */
PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
goto sof;
}
} else {
goto check_middle;
}
eof:
ts = (struct timeval *)(frame->data
+ MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
do_gettimeofday(ts);
PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
ov->curframe,
(int)(in[9]), (int)(in[10]), frame->bytes_recvd);
// FIXME: Since we don't know the header formats yet,
// there is no way to know what the actual image size is
frame->rawwidth = frame->width;
frame->rawheight = frame->height;
/* Validate the header data */
RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
/* Don't allow byte count to exceed buffer size */
RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
if (frame->scanstate == STATE_LINES) {
int nextf;
frame->grabstate = FRAME_DONE; // FIXME: Is this right?
if (waitqueue_active(&frame->wq)) {
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
}
/* If next frame is ready or grabbing,
* point to it */
nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
if (ov->frame[nextf].grabstate == FRAME_READY
|| ov->frame[nextf].grabstate == FRAME_GRABBING) {
ov->curframe = nextf;
ov->frame[nextf].scanstate = STATE_SCANNING;
frame = &ov->frame[nextf];
} else {
if (frame->grabstate == FRAME_DONE) {
PDEBUG(4, "** Frame done **");
} else {
PDEBUG(4, "Frame not ready? state = %d",
ov->frame[nextf].grabstate);
}
ov->curframe = -1;
PDEBUG(4, "SOF dropped (no active frame)");
return; /* Nowhere to store this frame */
}
}
sof:
PDEBUG(4, "Starting capture on frame %d", frame->framenum);
// Snapshot not reverse-engineered yet.
#if 0
/* Check to see if it's a snapshot frame */
/* FIXME?? Should the snapshot reset go here? Performance? */
if (in[8] & 0x02) {
frame->snapshot = 1;
PDEBUG(3, "snapshot detected");
}
#endif
frame->scanstate = STATE_LINES;
frame->bytes_recvd = 0;
// frame->compressed = 1;
check_middle:
/* Are we in a frame? */
if (frame->scanstate != STATE_LINES) {
PDEBUG(4, "scanstate: no SOF yet");
return;
}
/* Dump all data exactly as received */
if (dumppix == 2) {
frame->bytes_recvd += n;
if (frame->bytes_recvd <= max_raw)
memcpy(frame->rawdata + frame->bytes_recvd - n, in, n);
else
PDEBUG(3, "Raw data buffer overrun!! (%d)",
frame->bytes_recvd - max_raw);
} else {
/* All incoming data are divided into 8-byte segments. If the
* segment contains all zero bytes, it must be skipped. These
* zero-segments allow the OV518 to mainain a constant data rate
* regardless of the effectiveness of the compression. Segments
* are aligned relative to the beginning of each isochronous
* packet. The first segment is a header (the decompressor
* skips it later).
*/
int b, read = 0, allzero, copied = 0;
while (read < n) {
allzero = 1;
for (b = 0; b < 8; b++) {
if (in[read + b]) {
allzero = 0;
break;
}
}
if (allzero) {
/* Don't copy it */
} else {
if (frame->bytes_recvd + copied + 8 <= max_raw)
{
memcpy(frame->rawdata
+ frame->bytes_recvd + copied,
in + read, 8);
copied += 8;
} else {
PDEBUG(3, "Raw data buffer overrun!!");
}
}
read += 8;
}
frame->bytes_recvd += copied;
}
} }
static void static void
ov51x_isoc_irq(struct urb *urb) ov51x_isoc_irq(struct urb *urb)
{ {
int len; int i;
struct usb_ov511 *ov; struct usb_ov511 *ov;
struct ov511_sbuf *sbuf;
if (!urb->context) { if (!urb->context) {
PDEBUG(4, "no context"); PDEBUG(4, "no context");
return; return;
} }
ov = (struct usb_ov511 *) urb->context; sbuf = urb->context;
ov = sbuf->ov;
if (!ov || !ov->dev || !ov->user) { if (!ov || !ov->dev || !ov->user) {
PDEBUG(4, "no device, or not open"); PDEBUG(4, "no device, or not open");
...@@ -4219,16 +4068,52 @@ ov51x_isoc_irq(struct urb *urb) ...@@ -4219,16 +4068,52 @@ ov51x_isoc_irq(struct urb *urb)
return; return;
} }
if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
PDEBUG(4, "URB unlinked");
return;
}
if (urb->status != -EINPROGRESS && urb->status != 0) {
err("ERROR: urb->status=%d: %s", urb->status,
symbolic(urb_errlist, urb->status));
return;
}
/* Copy the data received into our frame buffer */ /* Copy the data received into our frame buffer */
if (ov->curframe >= 0) { PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n,
if (ov->bclass == BCL_OV511) urb->number_of_packets);
len = ov511_move_data(ov, urb); for (i = 0; i < urb->number_of_packets; i++) {
else if (ov->bclass == BCL_OV518) /* Warning: Don't call *_move_data() if no frame active! */
len = ov518_move_data(ov, urb); if (ov->curframe >= 0) {
else int n = urb->iso_frame_desc[i].actual_length;
err("Unknown bridge device (%d)", ov->bridge); int st = urb->iso_frame_desc[i].status;
} else if (waitqueue_active(&ov->wq)) { unsigned char *cdata;
wake_up_interruptible(&ov->wq);
urb->iso_frame_desc[i].actual_length = 0;
urb->iso_frame_desc[i].status = 0;
cdata = urb->transfer_buffer
+ urb->iso_frame_desc[i].offset;
if (!n) {
PDEBUG(4, "Zero-length packet");
continue;
}
if (st)
PDEBUG(2, "data error: [%d] len=%d, status=%d",
i, n, st);
if (ov->bclass == BCL_OV511)
ov511_move_data(ov, cdata, n);
else if (ov->bclass == BCL_OV518)
ov518_move_data(ov, cdata, n);
else
err("Unknown bridge device (%d)", ov->bridge);
} else if (waitqueue_active(&ov->wq)) {
wake_up_interruptible(&ov->wq);
}
} }
urb->dev = ov->dev; urb->dev = ov->dev;
...@@ -4297,14 +4182,13 @@ ov51x_init_isoc(struct usb_ov511 *ov) ...@@ -4297,14 +4182,13 @@ ov51x_init_isoc(struct usb_ov511 *ov)
for (n = 0; n < OV511_NUMSBUF; n++) { for (n = 0; n < OV511_NUMSBUF; n++) {
urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
if (!urb) { if (!urb) {
err("init isoc: usb_alloc_urb ret. NULL"); err("init isoc: usb_alloc_urb ret. NULL");
return -ENOMEM; return -ENOMEM;
} }
ov->sbuf[n].urb = urb; ov->sbuf[n].urb = urb;
urb->dev = ov->dev; urb->dev = ov->dev;
urb->context = ov; urb->context = &ov->sbuf[n];
urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS); urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS);
urb->transfer_flags = USB_ISO_ASAP; urb->transfer_flags = USB_ISO_ASAP;
urb->transfer_buffer = ov->sbuf[n].data; urb->transfer_buffer = ov->sbuf[n].data;
...@@ -4334,10 +4218,23 @@ ov51x_init_isoc(struct usb_ov511 *ov) ...@@ -4334,10 +4218,23 @@ ov51x_init_isoc(struct usb_ov511 *ov)
} }
static void static void
ov51x_stop_isoc(struct usb_ov511 *ov) ov51x_unlink_isoc(struct usb_ov511 *ov)
{ {
int n; int n;
/* Unschedule all of the iso td's */
for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
if (ov->sbuf[n].urb) {
usb_unlink_urb(ov->sbuf[n].urb);
usb_free_urb(ov->sbuf[n].urb);
ov->sbuf[n].urb = NULL;
}
}
}
static void
ov51x_stop_isoc(struct usb_ov511 *ov)
{
if (!ov->streaming || !ov->dev) if (!ov->streaming || !ov->dev)
return; return;
...@@ -4347,15 +4244,7 @@ ov51x_stop_isoc(struct usb_ov511 *ov) ...@@ -4347,15 +4244,7 @@ ov51x_stop_isoc(struct usb_ov511 *ov)
ov->streaming = 0; ov->streaming = 0;
/* Unschedule all of the iso td's */ ov51x_unlink_isoc(ov);
for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
if (ov->sbuf[n].urb) {
ov->sbuf[n].urb->next = NULL;
usb_unlink_urb(ov->sbuf[n].urb);
usb_free_urb(ov->sbuf[n].urb);
ov->sbuf[n].urb = NULL;
}
}
} }
static int static int
...@@ -4409,6 +4298,55 @@ ov51x_new_frame(struct usb_ov511 *ov, int framenum) ...@@ -4409,6 +4298,55 @@ ov51x_new_frame(struct usb_ov511 *ov, int framenum)
* *
***************************************************************************/ ***************************************************************************/
/*
* - You must acquire buf_lock before entering this function.
* - Because this code will free any non-null pointer, you must be sure to null
* them if you explicitly free them somewhere else!
*/
static void
ov51x_do_dealloc(struct usb_ov511 *ov)
{
int i;
PDEBUG(4, "entered");
if (ov->fbuf) {
rvfree(ov->fbuf, OV511_NUMFRAMES
* MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
ov->fbuf = NULL;
}
if (ov->rawfbuf) {
vfree(ov->rawfbuf);
ov->rawfbuf = NULL;
}
if (ov->tempfbuf) {
vfree(ov->tempfbuf);
ov->tempfbuf = NULL;
}
for (i = 0; i < OV511_NUMSBUF; i++) {
if (ov->sbuf[i].data) {
kfree(ov->sbuf[i].data);
ov->sbuf[i].data = NULL;
}
}
for (i = 0; i < OV511_NUMFRAMES; i++) {
ov->frame[i].data = NULL;
ov->frame[i].rawdata = NULL;
ov->frame[i].tempdata = NULL;
if (ov->frame[i].compbuf) {
free_page((unsigned long) ov->frame[i].compbuf);
ov->frame[i].compbuf = NULL;
}
}
PDEBUG(4, "buffer memory deallocated");
ov->buf_state = BUF_NOT_ALLOCATED;
PDEBUG(4, "leaving");
}
static int static int
ov51x_alloc(struct usb_ov511 *ov) ov51x_alloc(struct usb_ov511 *ov)
{ {
...@@ -4434,40 +4372,23 @@ ov51x_alloc(struct usb_ov511 *ov) ...@@ -4434,40 +4372,23 @@ ov51x_alloc(struct usb_ov511 *ov)
goto error; goto error;
ov->rawfbuf = vmalloc(raw_bufsize); ov->rawfbuf = vmalloc(raw_bufsize);
if (!ov->rawfbuf) { if (!ov->rawfbuf)
rvfree(ov->fbuf, data_bufsize);
ov->fbuf = NULL;
goto error; goto error;
}
memset(ov->rawfbuf, 0, raw_bufsize); memset(ov->rawfbuf, 0, raw_bufsize);
ov->tempfbuf = vmalloc(raw_bufsize); ov->tempfbuf = vmalloc(raw_bufsize);
if (!ov->tempfbuf) { if (!ov->tempfbuf)
vfree(ov->rawfbuf);
ov->rawfbuf = NULL;
rvfree(ov->fbuf, data_bufsize);
ov->fbuf = NULL;
goto error; goto error;
}
memset(ov->tempfbuf, 0, raw_bufsize); memset(ov->tempfbuf, 0, raw_bufsize);
for (i = 0; i < OV511_NUMSBUF; i++) { for (i = 0; i < OV511_NUMSBUF; i++) {
ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC * ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL); MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
if (!ov->sbuf[i].data) { if (!ov->sbuf[i].data)
while (--i) {
kfree(ov->sbuf[i].data);
ov->sbuf[i].data = NULL;
}
vfree(ov->tempfbuf);
ov->tempfbuf = NULL;
vfree(ov->rawfbuf);
ov->rawfbuf = NULL;
rvfree(ov->fbuf, data_bufsize);
ov->fbuf = NULL;
goto error; goto error;
}
PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data); PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
} }
...@@ -4477,6 +4398,12 @@ ov51x_alloc(struct usb_ov511 *ov) ...@@ -4477,6 +4398,12 @@ ov51x_alloc(struct usb_ov511 *ov)
+ i * MAX_RAW_DATA_SIZE(w, h); + i * MAX_RAW_DATA_SIZE(w, h);
ov->frame[i].tempdata = ov->tempfbuf ov->frame[i].tempdata = ov->tempfbuf
+ i * MAX_RAW_DATA_SIZE(w, h); + i * MAX_RAW_DATA_SIZE(w, h);
ov->frame[i].compbuf =
(unsigned char *) __get_free_page(GFP_KERNEL);
if (!ov->frame[i].compbuf)
goto error;
PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data); PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
} }
...@@ -4486,57 +4413,12 @@ ov51x_alloc(struct usb_ov511 *ov) ...@@ -4486,57 +4413,12 @@ ov51x_alloc(struct usb_ov511 *ov)
PDEBUG(4, "leaving"); PDEBUG(4, "leaving");
return 0; return 0;
error: error:
ov->buf_state = BUF_NOT_ALLOCATED; ov51x_do_dealloc(ov);
up(&ov->buf_lock); up(&ov->buf_lock);
PDEBUG(4, "errored"); PDEBUG(4, "errored");
return -ENOMEM; return -ENOMEM;
} }
/*
* - You must acquire buf_lock before entering this function.
* - Because this code will free any non-null pointer, you must be sure to null
* them if you explicitly free them somewhere else!
*/
static void
ov51x_do_dealloc(struct usb_ov511 *ov)
{
int i;
PDEBUG(4, "entered");
if (ov->fbuf) {
rvfree(ov->fbuf, OV511_NUMFRAMES
* MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
ov->fbuf = NULL;
}
if (ov->rawfbuf) {
vfree(ov->rawfbuf);
ov->rawfbuf = NULL;
}
if (ov->tempfbuf) {
vfree(ov->tempfbuf);
ov->tempfbuf = NULL;
}
for (i = 0; i < OV511_NUMSBUF; i++) {
if (ov->sbuf[i].data) {
kfree(ov->sbuf[i].data);
ov->sbuf[i].data = NULL;
}
}
for (i = 0; i < OV511_NUMFRAMES; i++) {
ov->frame[i].data = NULL;
ov->frame[i].rawdata = NULL;
ov->frame[i].tempdata = NULL;
}
PDEBUG(4, "buffer memory deallocated");
ov->buf_state = BUF_NOT_ALLOCATED;
PDEBUG(4, "leaving");
}
static void static void
ov51x_buf_callback(unsigned long data) ov51x_buf_callback(unsigned long data)
{ {
...@@ -4585,9 +4467,16 @@ ov51x_dealloc(struct usb_ov511 *ov, int now) ...@@ -4585,9 +4467,16 @@ ov51x_dealloc(struct usb_ov511 *ov, int now)
* *
***************************************************************************/ ***************************************************************************/
#ifdef OV511_OLD_V4L
static int static int
ov51x_v4l1_open(struct video_device *vdev, int flags) ov51x_v4l1_open(struct video_device *vdev, int flags)
{ {
#else
static int
ov51x_v4l1_open(struct inode *inode, struct file *file)
{
struct video_device *vdev = video_devdata(file);
#endif
struct usb_ov511 *ov = vdev->priv; struct usb_ov511 *ov = vdev->priv;
int err, i; int err, i;
...@@ -4639,9 +4528,16 @@ ov51x_v4l1_open(struct video_device *vdev, int flags) ...@@ -4639,9 +4528,16 @@ ov51x_v4l1_open(struct video_device *vdev, int flags)
return err; return err;
} }
#ifdef OV511_OLD_V4L
static void static void
ov51x_v4l1_close(struct video_device *vdev) ov51x_v4l1_close(struct video_device *vdev)
{ {
#else
static int
ov51x_v4l1_close(struct inode *inode, struct file *file)
{
struct video_device *vdev = video_devdata(file);
#endif
struct usb_ov511 *ov = vdev->priv; struct usb_ov511 *ov = vdev->priv;
PDEBUG(4, "ov511_close"); PDEBUG(4, "ov511_close");
...@@ -4674,32 +4570,19 @@ ov51x_v4l1_close(struct video_device *vdev) ...@@ -4674,32 +4570,19 @@ ov51x_v4l1_close(struct video_device *vdev)
kfree(ov); kfree(ov);
ov = NULL; ov = NULL;
} }
}
static int
ov51x_v4l1_init_done(struct video_device *vdev)
{
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
create_proc_ov511_cam(vdev->priv);
#endif
#ifdef OV511_OLD_V4L
return;
#else
return 0; return 0;
} #endif
static long
ov51x_v4l1_write(struct video_device *vdev, const char *buf,
unsigned long count, int noblock)
{
return -EINVAL;
} }
/* Do not call this function directly! */ /* Do not call this function directly! */
static int static int
ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd, ov51x_v4l1_ioctl_internal(struct usb_ov511 *ov, unsigned int cmd,
void *arg) void *arg)
{ {
struct usb_ov511 *ov = vdev->priv;
PDEBUG(5, "IOCtl: 0x%X", cmd); PDEBUG(5, "IOCtl: 0x%X", cmd);
if (!ov->dev) if (!ov->dev)
...@@ -4708,95 +4591,79 @@ ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd, ...@@ -4708,95 +4591,79 @@ ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd,
switch (cmd) { switch (cmd) {
case VIDIOCGCAP: case VIDIOCGCAP:
{ {
struct video_capability b; struct video_capability *b = arg;
PDEBUG(4, "VIDIOCGCAP"); PDEBUG(4, "VIDIOCGCAP");
memset(&b, 0, sizeof(b)); memset(b, 0, sizeof(struct video_capability));
sprintf(b.name, "%s USB Camera", sprintf(b->name, "%s USB Camera",
ov->bridge == BRG_OV511 ? "OV511" : symbolic(brglist, ov->bridge));
ov->bridge == BRG_OV511PLUS ? "OV511+" : b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
ov->bridge == BRG_OV518 ? "OV518" :
ov->bridge == BRG_OV518PLUS ? "OV518+" :
"unknown");
b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
if (ov->has_tuner) if (ov->has_tuner)
b.type |= VID_TYPE_TUNER; b->type |= VID_TYPE_TUNER;
b.channels = ov->num_inputs; b->channels = ov->num_inputs;
b.audios = ov->has_audio_proc ? 1:0; b->audios = ov->has_audio_proc ? 1:0;
b.maxwidth = ov->maxwidth; b->maxwidth = ov->maxwidth;
b.maxheight = ov->maxheight; b->maxheight = ov->maxheight;
b.minwidth = ov->minwidth; b->minwidth = ov->minwidth;
b.minheight = ov->minheight; b->minheight = ov->minheight;
if (copy_to_user(arg, &b, sizeof(b)))
return -EFAULT;
return 0; return 0;
} }
case VIDIOCGCHAN: case VIDIOCGCHAN:
{ {
struct video_channel v; struct video_channel *v = arg;
PDEBUG(4, "VIDIOCGCHAN"); PDEBUG(4, "VIDIOCGCHAN");
if (copy_from_user(&v, arg, sizeof(v))) if ((unsigned)(v->channel) >= ov->num_inputs) {
return -EFAULT; err("Invalid channel (%d)", v->channel);
if ((unsigned)(v.channel) >= ov->num_inputs) {
err("Invalid channel (%d)", v.channel);
return -EINVAL; return -EINVAL;
} }
v.norm = ov->norm; v->norm = ov->norm;
v.type = (ov->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA; v->type = (ov->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA;
v.flags = (ov->has_tuner) ? VIDEO_VC_TUNER : 0; v->flags = (ov->has_tuner) ? VIDEO_VC_TUNER : 0;
v.flags |= (ov->has_audio_proc) ? VIDEO_VC_AUDIO : 0; v->flags |= (ov->has_audio_proc) ? VIDEO_VC_AUDIO : 0;
// v.flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0; // v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
v.tuners = (ov->has_tuner) ? 1:0; v->tuners = (ov->has_tuner) ? 1:0;
decoder_get_input_name(ov, v.channel, v.name); decoder_get_input_name(ov, v->channel, v->name);
if (copy_to_user(arg, &v, sizeof(v)))
return -EFAULT;
return 0; return 0;
} }
case VIDIOCSCHAN: case VIDIOCSCHAN:
{ {
struct video_channel v; struct video_channel *v = arg;
int err; int err;
PDEBUG(4, "VIDIOCSCHAN"); PDEBUG(4, "VIDIOCSCHAN");
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
/* Make sure it's not a camera */ /* Make sure it's not a camera */
if (!ov->has_decoder) { if (!ov->has_decoder) {
if (v.channel == 0) if (v->channel == 0)
return 0; return 0;
else else
return -EINVAL; return -EINVAL;
} }
if (v.norm != VIDEO_MODE_PAL && if (v->norm != VIDEO_MODE_PAL &&
v.norm != VIDEO_MODE_NTSC && v->norm != VIDEO_MODE_NTSC &&
v.norm != VIDEO_MODE_SECAM && v->norm != VIDEO_MODE_SECAM &&
v.norm != VIDEO_MODE_AUTO) { v->norm != VIDEO_MODE_AUTO) {
err("Invalid norm (%d)", v.norm); err("Invalid norm (%d)", v->norm);
return -EINVAL; return -EINVAL;
} }
if ((unsigned)(v.channel) >= ov->num_inputs) { if ((unsigned)(v->channel) >= ov->num_inputs) {
err("Invalid channel (%d)", v.channel); err("Invalid channel (%d)", v->channel);
return -EINVAL; return -EINVAL;
} }
err = decoder_set_input(ov, v.channel); err = decoder_set_input(ov, v->channel);
if (err) if (err)
return err; return err;
err = decoder_set_norm(ov, v.norm); err = decoder_set_norm(ov, v->norm);
if (err) if (err)
return err; return err;
...@@ -4804,43 +4671,37 @@ ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd, ...@@ -4804,43 +4671,37 @@ ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd,
} }
case VIDIOCGPICT: case VIDIOCGPICT:
{ {
struct video_picture p; struct video_picture *p = arg;
PDEBUG(4, "VIDIOCGPICT"); PDEBUG(4, "VIDIOCGPICT");
memset(&p, 0, sizeof(p)); memset(p, 0, sizeof(struct video_picture));
if (sensor_get_picture(ov, p))
if (sensor_get_picture(ov, &p))
return -EIO; return -EIO;
if (copy_to_user(arg, &p, sizeof(p)))
return -EFAULT;
return 0; return 0;
} }
case VIDIOCSPICT: case VIDIOCSPICT:
{ {
struct video_picture p; struct video_picture *p = arg;
int i; int i;
PDEBUG(4, "VIDIOCSPICT"); PDEBUG(4, "VIDIOCSPICT");
if (copy_from_user(&p, arg, sizeof(p))) if (!get_depth(p->palette))
return -EFAULT;
if (!get_depth(p.palette))
return -EINVAL; return -EINVAL;
if (sensor_set_picture(ov, &p)) if (sensor_set_picture(ov, p))
return -EIO; return -EIO;
if (force_palette && p.palette != force_palette) { if (force_palette && p->palette != force_palette) {
info("Palette rejected (%d)", p.palette); info("Palette rejected (%s)",
symbolic(v4l1_plist, p->palette));
return -EINVAL; return -EINVAL;
} }
// FIXME: Format should be independent of frames // FIXME: Format should be independent of frames
if (p.palette != ov->frame[0].format) { if (p->palette != ov->frame[0].format) {
PDEBUG(4, "Detected format change"); PDEBUG(4, "Detected format change");
/* If we're collecting previous frame wait /* If we're collecting previous frame wait
...@@ -4849,79 +4710,73 @@ ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd, ...@@ -4849,79 +4710,73 @@ ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd,
if (signal_pending(current)) return -EINTR; if (signal_pending(current)) return -EINTR;
mode_init_regs(ov, ov->frame[0].width, mode_init_regs(ov, ov->frame[0].width,
ov->frame[0].height, p.palette, ov->sub_flag); ov->frame[0].height, p->palette, ov->sub_flag);
} }
PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette); PDEBUG(4, "Setting depth=%d, palette=%s",
p->depth, symbolic(v4l1_plist, p->palette));
for (i = 0; i < OV511_NUMFRAMES; i++) { for (i = 0; i < OV511_NUMFRAMES; i++) {
ov->frame[i].depth = p.depth; ov->frame[i].depth = p->depth;
ov->frame[i].format = p.palette; ov->frame[i].format = p->palette;
} }
return 0; return 0;
} }
case VIDIOCGCAPTURE: case VIDIOCGCAPTURE:
{ {
int vf; int *vf = arg;
PDEBUG(4, "VIDIOCGCAPTURE"); PDEBUG(4, "VIDIOCGCAPTURE");
if (copy_from_user(&vf, arg, sizeof(vf))) ov->sub_flag = *vf;
return -EFAULT;
ov->sub_flag = vf;
return 0; return 0;
} }
case VIDIOCSCAPTURE: case VIDIOCSCAPTURE:
{ {
struct video_capture vc; struct video_capture *vc = arg;
PDEBUG(4, "VIDIOCSCAPTURE"); PDEBUG(4, "VIDIOCSCAPTURE");
if (copy_from_user(&vc, arg, sizeof(vc))) if (vc->flags)
return -EFAULT;
if (vc.flags)
return -EINVAL; return -EINVAL;
if (vc.decimation) if (vc->decimation)
return -EINVAL; return -EINVAL;
vc.x &= ~3L; vc->x &= ~3L;
vc.y &= ~1L; vc->y &= ~1L;
vc.y &= ~31L; vc->y &= ~31L;
if (vc.width == 0) if (vc->width == 0)
vc.width = 32; vc->width = 32;
vc.height /= 16; vc->height /= 16;
vc.height *= 16; vc->height *= 16;
if (vc.height == 0) if (vc->height == 0)
vc.height = 16; vc->height = 16;
ov->subx = vc.x; ov->subx = vc->x;
ov->suby = vc.y; ov->suby = vc->y;
ov->subw = vc.width; ov->subw = vc->width;
ov->subh = vc.height; ov->subh = vc->height;
return 0; return 0;
} }
case VIDIOCSWIN: case VIDIOCSWIN:
{ {
struct video_window vw; struct video_window *vw = arg;
int i, result; int i, result;
if (copy_from_user(&vw, arg, sizeof(vw))) PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
return -EFAULT;
PDEBUG(4, "VIDIOCSWIN: width=%d, height=%d",
vw.width, vw.height);
#if 0 #if 0
if (vw.flags) if (vw->flags)
return -EINVAL; return -EINVAL;
if (vw.clipcount) if (vw->clipcount)
return -EINVAL; return -EINVAL;
if (vw.height != ov->maxheight) if (vw->height != ov->maxheight)
return -EINVAL; return -EINVAL;
if (vw.width != ov->maxwidth) if (vw->width != ov->maxwidth)
return -EINVAL; return -EINVAL;
#endif #endif
...@@ -4930,140 +4785,132 @@ ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd, ...@@ -4930,140 +4785,132 @@ ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd,
interruptible_sleep_on(&ov->wq); interruptible_sleep_on(&ov->wq);
if (signal_pending(current)) return -EINTR; if (signal_pending(current)) return -EINTR;
result = mode_init_regs(ov, vw.width, vw.height, result = mode_init_regs(ov, vw->width, vw->height,
ov->frame[0].format, ov->sub_flag); ov->frame[0].format, ov->sub_flag);
if (result < 0) if (result < 0)
return result; return result;
for (i = 0; i < OV511_NUMFRAMES; i++) { for (i = 0; i < OV511_NUMFRAMES; i++) {
ov->frame[i].width = vw.width; ov->frame[i].width = vw->width;
ov->frame[i].height = vw.height; ov->frame[i].height = vw->height;
} }
return 0; return 0;
} }
case VIDIOCGWIN: case VIDIOCGWIN:
{ {
struct video_window vw; struct video_window *vw = arg;
memset(&vw, 0, sizeof(vw));
vw.x = 0; /* FIXME */
vw.y = 0;
vw.width = ov->frame[0].width;
vw.height = ov->frame[0].height;
vw.flags = 30;
PDEBUG(4, "VIDIOCGWIN: %dx%d", vw.width, vw.height); memset(vw, 0, sizeof(struct video_window));
vw->x = 0; /* FIXME */
vw->y = 0;
vw->width = ov->frame[0].width;
vw->height = ov->frame[0].height;
vw->flags = 30;
if (copy_to_user(arg, &vw, sizeof(vw))) PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height);
return -EFAULT;
return 0; return 0;
} }
case VIDIOCGMBUF: case VIDIOCGMBUF:
{ {
struct video_mbuf vm; struct video_mbuf *vm = arg;
int i; int i;
PDEBUG(4, "VIDIOCGMBUF"); PDEBUG(4, "VIDIOCGMBUF");
memset(&vm, 0, sizeof(vm)); memset(vm, 0, sizeof(struct video_mbuf));
vm.size = OV511_NUMFRAMES vm->size = OV511_NUMFRAMES
* MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
vm.frames = OV511_NUMFRAMES; vm->frames = OV511_NUMFRAMES;
vm.offsets[0] = 0; vm->offsets[0] = 0;
for (i = 1; i < OV511_NUMFRAMES; i++) { for (i = 1; i < OV511_NUMFRAMES; i++) {
vm.offsets[i] = vm.offsets[i-1] vm->offsets[i] = vm->offsets[i-1]
+ MAX_DATA_SIZE(ov->maxwidth, ov->maxheight); + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
} }
if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
return -EFAULT;
return 0; return 0;
} }
case VIDIOCMCAPTURE: case VIDIOCMCAPTURE:
{ {
struct video_mmap vm; struct video_mmap *vm = arg;
int ret, depth; int ret, depth;
unsigned int f = vm->frame;
if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width,
return -EFAULT; vm->height, symbolic(v4l1_plist, vm->format));
PDEBUG(4, "CMCAPTURE");
PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
vm.frame, vm.width, vm.height, vm.format);
depth = get_depth(vm.format); depth = get_depth(vm->format);
if (!depth) { if (!depth) {
err("VIDIOCMCAPTURE: invalid format (%d)", vm.format); err("VIDIOCMCAPTURE: invalid format (%s)",
symbolic(v4l1_plist, vm->format));
return -EINVAL; return -EINVAL;
} }
if ((unsigned)vm.frame >= OV511_NUMFRAMES) { if (f >= OV511_NUMFRAMES) {
err("VIDIOCMCAPTURE: invalid frame (%d)", vm.frame); err("VIDIOCMCAPTURE: invalid frame (%d)", f);
return -EINVAL; return -EINVAL;
} }
if (vm.width > ov->maxwidth if (vm->width > ov->maxwidth
|| vm.height > ov->maxheight) { || vm->height > ov->maxheight) {
err("VIDIOCMCAPTURE: requested dimensions too big"); err("VIDIOCMCAPTURE: requested dimensions too big");
return -EINVAL; return -EINVAL;
} }
if (ov->frame[vm.frame].grabstate == FRAME_GRABBING) { if (ov->frame[f].grabstate == FRAME_GRABBING) {
PDEBUG(4, "VIDIOCMCAPTURE: already grabbing"); PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
return -EBUSY; return -EBUSY;
} }
if (force_palette && vm.format != force_palette) { if (force_palette && (vm->format != force_palette)) {
info("palette rejected (%d)", vm.format); info("palette rejected (%s)",
symbolic(v4l1_plist, vm->format));
return -EINVAL; return -EINVAL;
} }
if ((ov->frame[vm.frame].width != vm.width) || if ((ov->frame[f].width != vm->width) ||
(ov->frame[vm.frame].height != vm.height) || (ov->frame[f].height != vm->height) ||
(ov->frame[vm.frame].format != vm.format) || (ov->frame[f].format != vm->format) ||
(ov->frame[vm.frame].sub_flag != ov->sub_flag) || (ov->frame[f].sub_flag != ov->sub_flag) ||
(ov->frame[vm.frame].depth != depth)) { (ov->frame[f].depth != depth)) {
PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters"); PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
/* If we're collecting previous frame wait /* If we're collecting previous frame wait
before changing modes */ before changing modes */
interruptible_sleep_on(&ov->wq); interruptible_sleep_on(&ov->wq);
if (signal_pending(current)) return -EINTR; if (signal_pending(current)) return -EINTR;
ret = mode_init_regs(ov, vm.width, vm.height, ret = mode_init_regs(ov, vm->width, vm->height,
vm.format, ov->sub_flag); vm->format, ov->sub_flag);
#if 0 #if 0
if (ret < 0) { if (ret < 0) {
PDEBUG(1, "Got error while initializing regs "); PDEBUG(1, "Got error while initializing regs ");
return ret; return ret;
} }
#endif #endif
ov->frame[vm.frame].width = vm.width; ov->frame[f].width = vm->width;
ov->frame[vm.frame].height = vm.height; ov->frame[f].height = vm->height;
ov->frame[vm.frame].format = vm.format; ov->frame[f].format = vm->format;
ov->frame[vm.frame].sub_flag = ov->sub_flag; ov->frame[f].sub_flag = ov->sub_flag;
ov->frame[vm.frame].depth = depth; ov->frame[f].depth = depth;
} }
/* Mark it as ready */ /* Mark it as ready */
ov->frame[vm.frame].grabstate = FRAME_READY; ov->frame[f].grabstate = FRAME_READY;
PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", vm.frame); PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f);
return ov51x_new_frame(ov, vm.frame); return ov51x_new_frame(ov, f);
} }
case VIDIOCSYNC: case VIDIOCSYNC:
{ {
int fnum, rc; unsigned int fnum = *((unsigned int *) arg);
struct ov511_frame *frame; struct ov511_frame *frame;
int rc;
if (copy_from_user((void *)&fnum, arg, sizeof(int)))
return -EFAULT;
if ((unsigned)fnum >= OV511_NUMFRAMES) { if (fnum >= OV511_NUMFRAMES) {
err("VIDIOCSYNC: invalid frame (%d)", fnum); err("VIDIOCSYNC: invalid frame (%d)", fnum);
return -EINVAL; return -EINVAL;
} }
...@@ -5125,124 +4972,105 @@ ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd, ...@@ -5125,124 +4972,105 @@ ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd,
} }
case VIDIOCGFBUF: case VIDIOCGFBUF:
{ {
struct video_buffer vb; struct video_buffer *vb = arg;
PDEBUG(4, "VIDIOCSCHAN"); PDEBUG(4, "VIDIOCGFBUF");
memset(&vb, 0, sizeof(vb)); memset(vb, 0, sizeof(struct video_buffer));
vb.base = NULL; /* frame buffer not supported, not used */
if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
return -EFAULT;
return 0; return 0;
} }
case VIDIOCGUNIT: case VIDIOCGUNIT:
{ {
struct video_unit vu; struct video_unit *vu = arg;
PDEBUG(4, "VIDIOCGUNIT"); PDEBUG(4, "VIDIOCGUNIT");
memset(&vu, 0, sizeof(vu)); memset(vu, 0, sizeof(struct video_unit));
vu.video = ov->vdev.minor; /* Video minor */
vu.vbi = VIDEO_NO_UNIT; /* VBI minor */
vu.radio = VIDEO_NO_UNIT; /* Radio minor */
vu.audio = VIDEO_NO_UNIT; /* Audio minor */
vu.teletext = VIDEO_NO_UNIT; /* Teletext minor */
if (copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) vu->video = ov->vdev.minor;
return -EFAULT; vu->vbi = VIDEO_NO_UNIT;
vu->radio = VIDEO_NO_UNIT;
vu->audio = VIDEO_NO_UNIT;
vu->teletext = VIDEO_NO_UNIT;
return 0; return 0;
} }
case VIDIOCGTUNER: case VIDIOCGTUNER:
{ {
struct video_tuner v; struct video_tuner *v = arg;
PDEBUG(4, "VIDIOCGTUNER"); PDEBUG(4, "VIDIOCGTUNER");
if (copy_from_user(&v, arg, sizeof(v))) if (!ov->has_tuner || v->tuner) // Only tuner 0
return -EFAULT;
if (!ov->has_tuner || v.tuner) // Only tuner 0
return -EINVAL; return -EINVAL;
strcpy(v.name, "Television"); strcpy(v->name, "Television");
// FIXME: Need a way to get the real values // FIXME: Need a way to get the real values
v.rangelow = 0; v->rangelow = 0;
v.rangehigh = ~0; v->rangehigh = ~0;
v.flags = VIDEO_TUNER_PAL | VIDEO_TUNER_NTSC | v->flags = VIDEO_TUNER_PAL | VIDEO_TUNER_NTSC
VIDEO_TUNER_SECAM; | VIDEO_TUNER_SECAM;
v.mode = 0; /* FIXME: Not sure what this is yet */ v->mode = 0; /* FIXME: Not sure what this is yet */
v.signal = 0xFFFF; /* unknown */ v->signal = 0xFFFF; /* unknown */
call_i2c_clients(ov, cmd, &v); call_i2c_clients(ov, cmd, v);
if (copy_to_user(arg, &v, sizeof(v)))
return -EFAULT;
return 0; return 0;
} }
case VIDIOCSTUNER: case VIDIOCSTUNER:
{ {
struct video_tuner v; struct video_tuner *v = arg;
int err; int err;
PDEBUG(4, "VIDIOCSTUNER"); PDEBUG(4, "VIDIOCSTUNER");
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
/* Only no or one tuner for now */ /* Only no or one tuner for now */
if (!ov->has_tuner || v.tuner) if (!ov->has_tuner || v->tuner)
return -EINVAL; return -EINVAL;
/* and it only has certain valid modes */ /* and it only has certain valid modes */
if (v.mode != VIDEO_MODE_PAL && if (v->mode != VIDEO_MODE_PAL &&
v.mode != VIDEO_MODE_NTSC && v->mode != VIDEO_MODE_NTSC &&
v.mode != VIDEO_MODE_SECAM) return -EOPNOTSUPP; v->mode != VIDEO_MODE_SECAM)
return -EOPNOTSUPP;
/* Is this right/necessary? */ /* Is this right/necessary? */
err = decoder_set_norm(ov, v.mode); err = decoder_set_norm(ov, v->mode);
if (err) if (err)
return err; return err;
call_i2c_clients(ov, cmd, &v); call_i2c_clients(ov, cmd, v);
return 0; return 0;
} }
case VIDIOCGFREQ: case VIDIOCGFREQ:
{ {
unsigned long v = ov->freq; unsigned long v = *((unsigned long *) arg);
PDEBUG(4, "VIDIOCGFREQ"); PDEBUG(4, "VIDIOCGFREQ");
if (!ov->has_tuner) if (!ov->has_tuner)
return -EINVAL; return -EINVAL;
v = ov->freq;
#if 0 #if 0
/* FIXME: this is necessary for testing */ /* FIXME: this is necessary for testing */
v = 46*16; v = 46*16;
#endif #endif
if (copy_to_user(arg, &v, sizeof(v)))
return -EFAULT;
return 0; return 0;
} }
case VIDIOCSFREQ: case VIDIOCSFREQ:
{ {
unsigned long v; unsigned long v = *((unsigned long *) arg);
PDEBUG(4, "VIDIOCSFREQ: %lx", v);
if (!ov->has_tuner) if (!ov->has_tuner)
return -EINVAL; return -EINVAL;
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
PDEBUG(4, "VIDIOCSFREQ: %lx", v);
ov->freq = v; ov->freq = v;
call_i2c_clients(ov, cmd, &v); call_i2c_clients(ov, cmd, &v);
...@@ -5262,25 +5090,110 @@ ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd, ...@@ -5262,25 +5090,110 @@ ov51x_v4l1_ioctl_internal(struct video_device *vdev, unsigned int cmd,
return 0; return 0;
} }
#ifdef OV511_OLD_V4L
/* This is implemented as video_generic_ioctl() in the new V4L's videodev.c */
int
ov51x_v4l1_generic_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
{
char sbuf[128];
void *mbuf = NULL;
void *parg = NULL;
int err = -EINVAL;
/* Copy arguments into temp kernel buffer */
switch (_IOC_DIR(cmd)) {
case _IOC_NONE:
parg = arg;
break;
case _IOC_READ: /* some v4l ioctls are marked wrong ... */
case _IOC_WRITE:
case (_IOC_WRITE | _IOC_READ):
if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
parg = sbuf;
} else {
/* too big to allocate from stack */
mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
if (NULL == mbuf)
return -ENOMEM;
parg = mbuf;
}
err = -EFAULT;
if (copy_from_user(parg, arg, _IOC_SIZE(cmd)))
goto out;
break;
}
err = ov51x_v4l1_ioctl_internal(vdev->priv, cmd, parg);
if (err == -ENOIOCTLCMD)
err = -EINVAL;
if (err < 0)
goto out;
/* Copy results into user buffer */
switch (_IOC_DIR(cmd))
{
case _IOC_READ:
case (_IOC_WRITE | _IOC_READ):
if (copy_to_user(arg, parg, _IOC_SIZE(cmd)))
err = -EFAULT;
break;
}
out:
if (mbuf)
kfree(mbuf);
return err;
}
static int static int
ov51x_v4l1_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) ov51x_v4l1_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
{ {
struct usb_ov511 *ov = vdev->priv;
int rc; int rc;
if (down_interruptible(&ov->lock))
return -EINTR;
rc = ov51x_v4l1_generic_ioctl(vdev, cmd, arg);
up(&ov->lock);
return rc;
}
#else /* If new V4L API */
static int
ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
struct usb_ov511 *ov = vdev->priv; struct usb_ov511 *ov = vdev->priv;
int rc;
if (down_interruptible(&ov->lock)) if (down_interruptible(&ov->lock))
return -EINTR; return -EINTR;
rc = ov51x_v4l1_ioctl_internal(vdev, cmd, arg); rc = ov51x_v4l1_ioctl_internal(ov, cmd, arg);
up(&ov->lock); up(&ov->lock);
return rc; return rc;
} }
#endif /* OV511_OLD_V4L */
#ifdef OV511_OLD_V4L
static inline long static inline long
ov51x_v4l1_read(struct video_device *vdev, char *buf, unsigned long count, ov51x_v4l1_read(struct video_device *vdev, char *buf, unsigned long count,
int noblock) int noblock)
{ {
#else
static inline int
ov51x_v4l1_read(struct file *file, char *buf, size_t cnt, loff_t *ppos)
{
struct video_device *vdev = video_devdata(file);
int noblock = file->f_flags&O_NONBLOCK;
unsigned long count = cnt;
#endif
struct usb_ov511 *ov = vdev->priv; struct usb_ov511 *ov = vdev->priv;
int i, rc = 0, frmx = -1; int i, rc = 0, frmx = -1;
struct ov511_frame *frame; struct ov511_frame *frame;
...@@ -5429,12 +5342,23 @@ ov51x_v4l1_read(struct video_device *vdev, char *buf, unsigned long count, ...@@ -5429,12 +5342,23 @@ ov51x_v4l1_read(struct video_device *vdev, char *buf, unsigned long count,
return rc; return rc;
} }
static int static int
#ifdef OV511_OLD_V4L
ov51x_v4l1_mmap(struct vm_area_struct *vma, struct video_device *vdev, ov51x_v4l1_mmap(struct vm_area_struct *vma, struct video_device *vdev,
const char *adr, unsigned long size) const char *adr, unsigned long size)
{ {
struct usb_ov511 *ov = vdev->priv;
unsigned long start = (unsigned long)adr; unsigned long start = (unsigned long)adr;
#else /* New V4L API */
ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
{
struct video_device *vdev = video_devdata(file);
unsigned long start = vma->vm_start;
unsigned long size = vma->vm_end - vma->vm_start;
#endif /* OV511_OLD_V4L */
struct usb_ov511 *ov = vdev->priv;
unsigned long page, pos; unsigned long page, pos;
if (ov->dev == NULL) if (ov->dev == NULL)
...@@ -5453,7 +5377,8 @@ ov51x_v4l1_mmap(struct vm_area_struct *vma, struct video_device *vdev, ...@@ -5453,7 +5377,8 @@ ov51x_v4l1_mmap(struct vm_area_struct *vma, struct video_device *vdev,
pos = (unsigned long)ov->fbuf; pos = (unsigned long)ov->fbuf;
while (size > 0) { while (size > 0) {
page = kvirt_to_pa(pos); page = kvirt_to_pa(pos);
if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { if (remap_page_range(vma, start, page, PAGE_SIZE,
PAGE_SHARED)) {
up(&ov->lock); up(&ov->lock);
return -EAGAIN; return -EAGAIN;
} }
...@@ -5469,6 +5394,7 @@ ov51x_v4l1_mmap(struct vm_area_struct *vma, struct video_device *vdev, ...@@ -5469,6 +5394,7 @@ ov51x_v4l1_mmap(struct vm_area_struct *vma, struct video_device *vdev,
return 0; return 0;
} }
#ifdef OV511_OLD_V4L
static struct video_device vdev_template = { static struct video_device vdev_template = {
owner: THIS_MODULE, owner: THIS_MODULE,
name: "OV511 USB Camera", name: "OV511 USB Camera",
...@@ -5477,12 +5403,32 @@ static struct video_device vdev_template = { ...@@ -5477,12 +5403,32 @@ static struct video_device vdev_template = {
open: ov51x_v4l1_open, open: ov51x_v4l1_open,
close: ov51x_v4l1_close, close: ov51x_v4l1_close,
read: ov51x_v4l1_read, read: ov51x_v4l1_read,
write: ov51x_v4l1_write,
ioctl: ov51x_v4l1_ioctl, ioctl: ov51x_v4l1_ioctl,
mmap: ov51x_v4l1_mmap, mmap: ov51x_v4l1_mmap,
initialize: ov51x_v4l1_init_done,
}; };
#else /* New V4L API */
static struct file_operations ov511_fops = {
owner: THIS_MODULE,
open: ov51x_v4l1_open,
release: ov51x_v4l1_close,
read: ov51x_v4l1_read,
mmap: ov51x_v4l1_mmap,
ioctl: video_generic_ioctl,
llseek: no_llseek,
};
static struct video_device vdev_template = {
owner: THIS_MODULE,
name: "OV511 USB Camera",
type: VID_TYPE_CAPTURE,
hardware: VID_HARDWARE_OV511,
fops: &ov511_fops,
kernel_ioctl: ov51x_v4l1_ioctl,
};
#endif /* OV511_OLD_V4L */
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
static int static int
ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
...@@ -5497,7 +5443,7 @@ ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -5497,7 +5443,7 @@ ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
if (!pde) if (!pde)
return -ENOENT; return -ENOENT;
ov = (struct usb_ov511 *) pde->data; ov = pde->data;
if (!ov) if (!ov)
return -ENODEV; return -ENODEV;
...@@ -6067,19 +6013,18 @@ ov6xx0_configure(struct usb_ov511 *ov) ...@@ -6067,19 +6013,18 @@ ov6xx0_configure(struct usb_ov511 *ov)
if (rc < 0) { if (rc < 0) {
err("Error detecting sensor type"); err("Error detecting sensor type");
return -1; return -1;
} else if ((rc & 3) == 0) { }
info("Sensor is an OV6630");
if ((rc & 3) == 0)
ov->sensor = SEN_OV6630; ov->sensor = SEN_OV6630;
} else if ((rc & 3) == 1) { else if ((rc & 3) == 1)
info("Sensor is an OV6620");
ov->sensor = SEN_OV6620; ov->sensor = SEN_OV6620;
} else if ((rc & 3) == 2) { else if ((rc & 3) == 2)
info("Sensor is an OV6630AE");
ov->sensor = SEN_OV6630; ov->sensor = SEN_OV6630;
} else if ((rc & 3) == 3) { else if ((rc & 3) == 3)
info("Sensor is an OV6630AF");
ov->sensor = SEN_OV6630; ov->sensor = SEN_OV6630;
}
info("Sensor is an %s", symbolic(senlist, ov->sensor));
/* Set sensor-specific vars */ /* Set sensor-specific vars */
ov->maxwidth = 352; ov->maxwidth = 352;
...@@ -6165,7 +6110,7 @@ ks0127_configure(struct usb_ov511 *ov) ...@@ -6165,7 +6110,7 @@ ks0127_configure(struct usb_ov511 *ov)
/* This initializes the SAA7111A video decoder. */ /* This initializes the SAA7111A video decoder. */
static int static int
saa7111a_configure(struct usb_ov511 *ov511) saa7111a_configure(struct usb_ov511 *ov)
{ {
int rc; int rc;
...@@ -6210,44 +6155,44 @@ saa7111a_configure(struct usb_ov511 *ov511) ...@@ -6210,44 +6155,44 @@ saa7111a_configure(struct usb_ov511 *ov511)
#endif #endif
/* Set sensor-specific vars */ /* Set sensor-specific vars */
ov511->maxwidth = 640; ov->maxwidth = 640;
ov511->maxheight = 480; /* Even/Odd fields */ ov->maxheight = 480; /* Even/Odd fields */
ov511->minwidth = 320; ov->minwidth = 320;
ov511->minheight = 240; /* Even field only */ ov->minheight = 240; /* Even field only */
ov511->has_decoder = 1; ov->has_decoder = 1;
ov511->num_inputs = 8; ov->num_inputs = 8;
ov511->norm = VIDEO_MODE_AUTO; ov->norm = VIDEO_MODE_AUTO;
ov511->stop_during_set = 0; /* Decoder guarantees stable image */ ov->stop_during_set = 0; /* Decoder guarantees stable image */
/* Decoder doesn't change these values, so we use these instead of /* Decoder doesn't change these values, so we use these instead of
* acutally reading the registers (which doesn't work) */ * acutally reading the registers (which doesn't work) */
ov511->brightness = 0x80 << 8; ov->brightness = 0x80 << 8;
ov511->contrast = 0x40 << 9; ov->contrast = 0x40 << 9;
ov511->colour = 0x40 << 9; ov->colour = 0x40 << 9;
ov511->hue = 32768; ov->hue = 32768;
PDEBUG(4, "Writing SAA7111A registers"); PDEBUG(4, "Writing SAA7111A registers");
if (write_regvals(ov511, aRegvalsNormSAA7111A)) if (write_regvals(ov, aRegvalsNormSAA7111A))
return -1; return -1;
/* Detect version of decoder. This must be done after writing the /* Detect version of decoder. This must be done after writing the
* initial regs or the decoder will lock up. */ * initial regs or the decoder will lock up. */
rc = i2c_r(ov511, 0x00); rc = i2c_r(ov, 0x00);
if (rc < 0) { if (rc < 0) {
err("Error detecting sensor version"); err("Error detecting sensor version");
return -1; return -1;
} else { } else {
info("Sensor is an SAA7111A (version 0x%x)", rc); info("Sensor is an SAA7111A (version 0x%x)", rc);
ov511->sensor = SEN_SAA7111A; ov->sensor = SEN_SAA7111A;
} }
// FIXME: Fix this for OV518(+) // FIXME: Fix this for OV518(+)
/* Latch to negative edge of clock. Otherwise, we get incorrect /* Latch to negative edge of clock. Otherwise, we get incorrect
* colors and jitter in the digital signal. */ * colors and jitter in the digital signal. */
if (ov511->bclass == BCL_OV511) if (ov->bclass == BCL_OV511)
reg_w(ov511, 0x11, 0x00); reg_w(ov, 0x11, 0x00);
else else
warn("SAA7111A not yet supported with OV518/OV518+"); warn("SAA7111A not yet supported with OV518/OV518+");
...@@ -6258,8 +6203,6 @@ saa7111a_configure(struct usb_ov511 *ov511) ...@@ -6258,8 +6203,6 @@ saa7111a_configure(struct usb_ov511 *ov511)
static int static int
ov511_configure(struct usb_ov511 *ov) ov511_configure(struct usb_ov511 *ov)
{ {
int i;
static struct ov511_regvals aRegvalsInit511[] = { static struct ov511_regvals aRegvalsInit511[] = {
{ OV511_REG_BUS, R51x_SYS_RESET, 0x7f }, { OV511_REG_BUS, R51x_SYS_RESET, 0x7f },
{ OV511_REG_BUS, R51x_SYS_INIT, 0x01 }, { OV511_REG_BUS, R51x_SYS_INIT, 0x01 },
...@@ -6301,24 +6244,18 @@ ov511_configure(struct usb_ov511 *ov) ...@@ -6301,24 +6244,18 @@ ov511_configure(struct usb_ov511 *ov)
goto error; goto error;
} }
ov->desc = -1;
PDEBUG (1, "CustomID = %d", ov->customid); PDEBUG (1, "CustomID = %d", ov->customid);
for (i = 0; clist[i].id >= 0; i++) { ov->desc = symbolic(camlist, ov->customid);
if (ov->customid == clist[i].id) { info("model: %s", ov->desc);
info("model: %s", clist[i].description);
ov->desc = i;
break;
}
}
if (clist[i].id == -1) { if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) {
err("Camera type (%d) not recognized", ov->customid); err("Camera type (%d) not recognized", ov->customid);
err("Please notify " EMAIL " of the name,"); err("Please notify " EMAIL " of the name,");
err("manufacturer, model, and this number of your camera."); err("manufacturer, model, and this number of your camera.");
err("Also include the output of the detection process."); err("Also include the output of the detection process.");
} }
if (clist[i].id == 6) { /* USB Life TV (NTSC) */ if (ov->customid == 6) { /* USB Life TV (NTSC) */
ov->tuner_type = 8; /* Temic 4036FY5 3X 1981 */ ov->tuner_type = 8; /* Temic 4036FY5 3X 1981 */
} }
...@@ -6545,7 +6482,6 @@ ov518_configure(struct usb_ov511 *ov) ...@@ -6545,7 +6482,6 @@ ov518_configure(struct usb_ov511 *ov)
* *
***************************************************************************/ ***************************************************************************/
/* 2.2.x compatibility */
static void * static void *
ov51x_probe(struct usb_device *dev, unsigned int ifnum, ov51x_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id) const struct usb_device_id *id)
...@@ -6592,29 +6528,24 @@ ov51x_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -6592,29 +6528,24 @@ ov51x_probe(struct usb_device *dev, unsigned int ifnum,
switch (dev->descriptor.idProduct) { switch (dev->descriptor.idProduct) {
case PROD_OV511: case PROD_OV511:
info("USB OV511 camera found");
ov->bridge = BRG_OV511; ov->bridge = BRG_OV511;
ov->bclass = BCL_OV511; ov->bclass = BCL_OV511;
break; break;
case PROD_OV511PLUS: case PROD_OV511PLUS:
info("USB OV511+ camera found");
ov->bridge = BRG_OV511PLUS; ov->bridge = BRG_OV511PLUS;
ov->bclass = BCL_OV511; ov->bclass = BCL_OV511;
break; break;
case PROD_OV518: case PROD_OV518:
info("USB OV518 camera found");
ov->bridge = BRG_OV518; ov->bridge = BRG_OV518;
ov->bclass = BCL_OV518; ov->bclass = BCL_OV518;
break; break;
case PROD_OV518PLUS: case PROD_OV518PLUS:
info("USB OV518+ camera found");
ov->bridge = BRG_OV518PLUS; ov->bridge = BRG_OV518PLUS;
ov->bclass = BCL_OV518; ov->bclass = BCL_OV518;
break; break;
case PROD_ME2CAM: case PROD_ME2CAM:
if (dev->descriptor.idVendor != VEND_MATTEL) if (dev->descriptor.idVendor != VEND_MATTEL)
goto error; goto error;
info("Intel Play Me2Cam (OV511+) found");
ov->bridge = BRG_OV511PLUS; ov->bridge = BRG_OV511PLUS;
ov->bclass = BCL_OV511; ov->bclass = BCL_OV511;
break; break;
...@@ -6623,6 +6554,8 @@ ov51x_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -6623,6 +6554,8 @@ ov51x_probe(struct usb_device *dev, unsigned int ifnum,
goto error_dealloc; goto error_dealloc;
} }
info("USB %s video device found", symbolic(brglist, ov->bridge));
/* Workaround for some applications that want data in RGB /* Workaround for some applications that want data in RGB
* instead of BGR. */ * instead of BGR. */
if (force_rgb) if (force_rgb)
...@@ -6656,6 +6589,12 @@ ov51x_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -6656,6 +6589,12 @@ ov51x_probe(struct usb_device *dev, unsigned int ifnum,
init_waitqueue_head(&ov->frame[i].wq); init_waitqueue_head(&ov->frame[i].wq);
} }
for (i = 0; i < OV511_NUMSBUF; i++) {
ov->sbuf[i].ov = ov;
spin_lock_init(&ov->sbuf[i].lock);
ov->sbuf[i].n = i;
}
/* Unnecessary? (This is done on open(). Need to make sure variables /* Unnecessary? (This is done on open(). Need to make sure variables
* are properly initialized without this before removing it, though). */ * are properly initialized without this before removing it, though). */
if (ov51x_set_default_params(ov) < 0) if (ov51x_set_default_params(ov) < 0)
...@@ -6690,11 +6629,13 @@ ov51x_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -6690,11 +6629,13 @@ ov51x_probe(struct usb_device *dev, unsigned int ifnum,
info("Device registered on minor %d", ov->vdev.minor); info("Device registered on minor %d", ov->vdev.minor);
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
create_proc_ov511_cam(ov);
#endif
return ov; return ov;
error: error:
err("Camera initialization failed");
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
/* Safe to call even if entry doesn't exist */ /* Safe to call even if entry doesn't exist */
destroy_proc_ov511_cam(ov); destroy_proc_ov511_cam(ov);
...@@ -6707,9 +6648,6 @@ ov51x_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -6707,9 +6648,6 @@ ov51x_probe(struct usb_device *dev, unsigned int ifnum,
up(&ov->cbuf_lock); up(&ov->cbuf_lock);
} }
usb_driver_release_interface(&ov511_driver,
&dev->actconfig->interface[ov->iface]);
error_dealloc: error_dealloc:
if (ov) { if (ov) {
kfree(ov); kfree(ov);
...@@ -6717,6 +6655,7 @@ ov51x_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -6717,6 +6655,7 @@ ov51x_probe(struct usb_device *dev, unsigned int ifnum,
} }
error_out: error_out:
err("Camera initialization failed");
return NULL; return NULL;
} }
...@@ -6749,22 +6688,12 @@ ov51x_disconnect(struct usb_device *dev, void *ptr) ...@@ -6749,22 +6688,12 @@ ov51x_disconnect(struct usb_device *dev, void *ptr)
ov->streaming = 0; ov->streaming = 0;
/* Unschedule all of the iso td's */ ov51x_unlink_isoc(ov);
for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
if (ov->sbuf[n].urb) {
ov->sbuf[n].urb->next = NULL;
usb_unlink_urb(ov->sbuf[n].urb);
usb_free_urb(ov->sbuf[n].urb);
ov->sbuf[n].urb = NULL;
}
}
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
destroy_proc_ov511_cam(ov); destroy_proc_ov511_cam(ov);
#endif #endif
usb_driver_release_interface(&ov511_driver,
&ov->dev->actconfig->interface[ov->iface]);
ov->dev = NULL; ov->dev = NULL;
/* Free the memory */ /* Free the memory */
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
#ifdef OV511_DEBUG #ifdef OV511_DEBUG
#define PDEBUG(level, fmt, args...) \ #define PDEBUG(level, fmt, args...) \
if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt,\ if (debug >= (level)) info("[%s:%d] " fmt, \
__LINE__ , ## args) __PRETTY_FUNCTION__, __LINE__ , ## args)
#else #else
#define PDEBUG(level, fmt, args...) do {} while(0) #define PDEBUG(level, fmt, args...) do {} while(0)
#endif #endif
...@@ -243,6 +243,16 @@ ...@@ -243,6 +243,16 @@
#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ #define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */
#define OV511_NUMFRAMES 2
#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
#error "OV511_NUMFRAMES is too high"
#endif
#define OV511_NUMSBUF 2
/* Control transfers use up to 4 bytes */
#define OV511_CBUF_SIZE 4
/* Bridge types */ /* Bridge types */
enum { enum {
BRG_UNKNOWN, BRG_UNKNOWN,
...@@ -376,9 +386,14 @@ struct ov511_i2c_struct { ...@@ -376,9 +386,14 @@ struct ov511_i2c_struct {
struct ov511_i2c_struct) struct ov511_i2c_struct)
/* ------------- End IOCTL interface -------------- */ /* ------------- End IOCTL interface -------------- */
struct usb_ov511; /* Forward declaration */
struct ov511_sbuf { struct ov511_sbuf {
char *data; struct usb_ov511 *ov;
unsigned char *data;
struct urb *urb; struct urb *urb;
spinlock_t lock;
int n;
}; };
enum { enum {
...@@ -401,9 +416,10 @@ struct ov511_regvals { ...@@ -401,9 +416,10 @@ struct ov511_regvals {
struct ov511_frame { struct ov511_frame {
int framenum; /* Index of this frame */ int framenum; /* Index of this frame */
char *data; /* Frame buffer */ unsigned char *data; /* Frame buffer */
char *tempdata; /* Temp buffer for multi-stage conversions */ unsigned char *tempdata; /* Temp buffer for multi-stage conversions */
char *rawdata; /* Raw camera data buffer */ unsigned char *rawdata; /* Raw camera data buffer */
unsigned char *compbuf; /* Temp buffer for decompressor */
int depth; /* Bytes per pixel */ int depth; /* Bytes per pixel */
int width; /* Width application is expecting */ int width; /* Width application is expecting */
...@@ -428,27 +444,20 @@ struct ov511_frame { ...@@ -428,27 +444,20 @@ struct ov511_frame {
int snapshot; /* True if frame was a snapshot */ int snapshot; /* True if frame was a snapshot */
}; };
#define DECOMP_INTERFACE_VER 2 #define DECOMP_INTERFACE_VER 3
/* Compression module operations */ /* Compression module operations */
struct ov51x_decomp_ops { struct ov51x_decomp_ops {
int (*decomp_400)(unsigned char *, unsigned char *, int, int, int); int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *,
int (*decomp_420)(unsigned char *, unsigned char *, int, int, int); int, int, int);
int (*decomp_422)(unsigned char *, unsigned char *, int, int, int); int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *,
int, int, int);
int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *,
int, int, int);
void (*decomp_lock)(void); void (*decomp_lock)(void);
void (*decomp_unlock)(void); void (*decomp_unlock)(void);
}; };
#define OV511_NUMFRAMES 2
#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
#error "OV511_NUMFRAMES is too high"
#endif
#define OV511_NUMSBUF 2
/* Control transfers use up to 4 bytes */
#define OV511_CBUF_SIZE 4
struct usb_ov511 { struct usb_ov511 {
struct video_device vdev; struct video_device vdev;
...@@ -456,7 +465,7 @@ struct usb_ov511 { ...@@ -456,7 +465,7 @@ struct usb_ov511 {
struct usb_device *dev; struct usb_device *dev;
int customid; int customid;
int desc; char *desc;
unsigned char iface; unsigned char iface;
/* Determined by sensor type */ /* Determined by sensor type */
...@@ -490,9 +499,9 @@ struct usb_ov511 { ...@@ -490,9 +499,9 @@ struct usb_ov511 {
int lightfreq; /* Power (lighting) frequency */ int lightfreq; /* Power (lighting) frequency */
int bandfilt; /* Banding filter enabled flag */ int bandfilt; /* Banding filter enabled flag */
char *fbuf; /* Videodev buffer area */ unsigned char *fbuf; /* Videodev buffer area */
char *tempfbuf; /* Temporary (intermediate) buffer area */ unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */
char *rawfbuf; /* Raw camera data buffer area */ unsigned char *rawfbuf; /* Raw camera data buffer area */
int sub_flag; /* Pix Array subcapture on flag */ int sub_flag; /* Pix Array subcapture on flag */
int subx; /* Pix Array subcapture x offset */ int subx; /* Pix Array subcapture x offset */
...@@ -556,16 +565,29 @@ struct usb_ov511 { ...@@ -556,16 +565,29 @@ struct usb_ov511 {
struct semaphore cbuf_lock; struct semaphore cbuf_lock;
}; };
struct cam_list { /* Used to represent a list of values and their respective symbolic names */
int id; struct symbolic_list {
char *description;
};
struct palette_list {
int num; int num;
char *name; char *name;
}; };
#define NOT_DEFINED_STR "Unknown"
/* Returns the name of the matching element in the symbolic_list array. The
* end of the list must be marked with an element that has a NULL name.
*/
static inline char *
symbolic(struct symbolic_list list[], int num)
{
int i;
for (i = 0; list[i].name != NULL; i++)
if (list[i].num == num)
return (list[i].name);
return (NOT_DEFINED_STR);
}
struct mode_list_518 { struct mode_list_518 {
int width; int width;
int height; int height;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment