Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
0e8f510d
Commit
0e8f510d
authored
Jan 16, 2004
by
Luca Risolia
Committed by
Greg Kroah-Hartman
Jan 16, 2004
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] USB: W996[87]CF driver update
This patch contains updates and one bug fix.
parent
8d4f1c82
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
552 additions
and
541 deletions
+552
-541
CREDITS
CREDITS
+3
-3
Documentation/usb/w9968cf.txt
Documentation/usb/w9968cf.txt
+75
-78
MAINTAINERS
MAINTAINERS
+1
-1
drivers/usb/media/Kconfig
drivers/usb/media/Kconfig
+8
-11
drivers/usb/media/w9968cf.c
drivers/usb/media/w9968cf.c
+430
-410
drivers/usb/media/w9968cf.h
drivers/usb/media/w9968cf.h
+28
-30
drivers/usb/media/w9968cf_decoder.h
drivers/usb/media/w9968cf_decoder.h
+1
-1
drivers/usb/media/w9968cf_externaldef.h
drivers/usb/media/w9968cf_externaldef.h
+6
-7
No files found.
CREDITS
View file @
0e8f510d
...
...
@@ -2670,9 +2670,9 @@ S: 70110 Kuopio
S: Finland
N: Luca Risolia
E: luca
_ing@liber
o.it
D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chip
S: Via Libert
à 41/a
E: luca
.risolia@studio.unib
o.it
D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chip
s
S: Via Libert
a' 41/A
S: Osio Sotto, 24046, Bergamo
S: Italy
...
...
Documentation/usb/w9968cf.txt
View file @
0e8f510d
W996[87]CF JPEG USB Dual Mode Camera Chip driver for Linux 2.6
==============================================================
W996[87]CF JPEG USB Dual Mode Camera Chip
Driver for Linux 2.6 (basic version)
=========================================
- Documentation -
...
...
@@ -11,15 +12,16 @@ Index
2. License
3. Overview
4. Supported devices
5.
Kernel configuration and third-part module compilation
5.
Module dependencies
6. Module loading
7. Module paramaters
8. Credits
8. Contact information
9. Credits
1. Copyright
============
Copyright (C) 2002
2003 by Luca Risolia <luca_ing@liber
o.it>
Copyright (C) 2002
-2004 by Luca Risolia <luca.risolia@studio.unib
o.it>
2. License
...
...
@@ -43,23 +45,25 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
===========
This driver supports the video streaming capabilities of the devices mounting
Winbond W9967CF and Winbond W9968CF JPEG USB Dual Mode Camera Chips, when they
are being commanded by USB.
are being commanded by USB.
OV681 based cameras should be supported as well.
The driver relies on the Video4Linux, USB and I2C core modules of the Linux
kernel, version 2.6.0 or greater, and is not compatible in any way with
previous versions. It has been designed to run properly on SMP systems
as well. At the moment, an additional module, "ovcamchip", is mandatory; it
provides support for some OmniVision CMOS sensors connected to the W996[87]CF
chips.
The driver is split into two modules: the basic one, "w9968cf", is needed for
The driver is divided into two modules: the basic one, "w9968cf", is needed for
the supported devices to work; the second one, "w9968cf-vpp", is an optional
module, which provides some useful video post-processing functions like video
decoding, up-scaling and colour conversions. These routines can't be included
into official kernels for performance purposes. Once the driver is installed,
decoding, up-scaling and colour conversions. Once the driver is installed,
every time an application tries to open a recognized device, "w9968cf" checks
the presence of the "w9968cf-vpp" module and loads it automatically by default.
Please keep in mind that official kernels do NOT include the second module for
performance purposes. However it is always recommended to download and install
the latest and complete release of the driver, replacing the existing one, if
present: it will be still even possible not to load the "w9968cf-vpp" module at
all, if you ever want to.
The latest and full-featured version of the W996[87]CF driver can be found at:
http://go.lamarinapunto.com/ . Please refer to the documentation included in
that package, if you are going to use it.
Up to 32 cameras can be handled at the same time. They can be connected and
disconnected from the host many times without turning off the computer, if
your system supports the hotplug facility.
...
...
@@ -67,18 +71,21 @@ your system supports the hotplug facility.
To change the default settings for each camera, many paramaters can be passed
through command line when the module is loaded into memory.
The latest and full featured version of the W996[87]CF driver can be found at:
http://go.lamarinapunto.com/
The driver relies on the Video4Linux, USB and I2C core modules of the official
Linux kernels. It has been designed to run properly on SMP systems as well.
At the moment, an additional module, "ovcamchip", is mandatory; it provides
support for some OmniVision CMOS sensors connected to the W996[87]CF chips.
The "ovcamchip" module is part of the OV511 driver, version 2.2
5
, which can be
The "ovcamchip" module is part of the OV511 driver, version 2.2
7
, which can be
downloaded from internet:
http://alpha.dyndns.org/ov511/
To know how to patch, compile and load it, read the paragraphs below.
To know how to compile it, read the documentation included in the OV511
package.
4. Supported devices
====================
At the moment, known W996[87]CF based devices are:
At the moment, known W996[87]CF
and OV681
based devices are:
- Aroma Digi Pen ADG-5000 Refurbished
- AVerTV USB
- Creative Labs Video Blaster WebCam Go
...
...
@@ -87,27 +94,26 @@ At the moment, known W996[87]CF based devices are:
- Ezonics EZ-802 EZMega Cam
- OPCOM Digi Pen VGA Dual Mode Pen Camera
If you know any other W996[87]CF based cameras, please contact me.
If you know any other W996[87]CF
or OV681
based cameras, please contact me.
The list above does NOT imply that all those devices work with this driver: up
until now only webcams that have a CMOS sensor supported by the "ovcamchip"
module work.
For a list of supported CMOS sensors, please visit the
module author homepage:
http://alpha.dyndns.org/ov511/
For a list of supported CMOS sensors, please visit the
author's homepage on
this module:
http://alpha.dyndns.org/ov511/
Possible external microcontrollers of those webcams are not supported: this
means that still images can
'
t be downloaded from the device memory.
means that still images can
no
t be downloaded from the device memory.
Furthermore, it's worth to note that I was only able to run tests on my
"Creative Labs Video Blaster WebCam Go". Donations of other models, for
additional testing and full support, would be much appreciated.
5. Kernel configuration and third-part module compilation
=========================================================
As noted above, kernel 2.6.0 is the minimum for this driver; for it to work
properly, the driver needs kernel support for Video4Linux, USB and I2C, and a
third-part module for the CMOS sensor.
5. Module dependencies
======================
For it to work properly, the driver needs kernel support for Video4Linux,
USB and I2C, and a third-party module for the CMOS sensor.
The following options of the kernel configuration file must be enabled and
corresponding modules must be compiled:
...
...
@@ -126,7 +132,7 @@ The I2C core module can be compiled statically in the kernel as well.
#
CONFIG_USB=m
In addition, depending on the hardware being used,
just
one of the modules
In addition, depending on the hardware being used,
only
one of the modules
below is necessary:
# USB Host Controller Drivers
...
...
@@ -137,31 +143,16 @@ below is necessary:
Also, make sure "Enforce bandwidth allocation" is NOT enabled.
And finally:
# USB Multimedia devices
#
CONFIG_USB_W9968CF=m
The last module we need is "ovcamchip.o". To obtain it, you have to download
the OV511 driver, version 2.25 - don't use other versions - which is available
at http://alpha.dyndns.org/ov511/ . Then you have to download the latest
version of the full featured W996[87]CF driver, which contains a patch for the
"ovcamchip" module; it is available at http://go.lamarinapunto.com .
Once you have obtained the packages, decompress, patch and compile the
"ovcamchip" module. In other words:
[user@localhost home]$ tar xvzf w9968cf-x.x.tar.gz
[user@localhost home]$ tar xvjf ov511-2.25.tar.bz2
[user@localhost home]$ cd ov511-2.25
[user@localhost ov511-2.25]$ patch -p1 < \
/path/to/w9968cf-x.x/ov511-2.25.patch
[user@localhost ov511-2.25]$ make
It's worth to note that the full featured version of the W996[87]CF driver
can also be installed overwriting the one in the kernel; in this case, read the
documentation included in the package.
If everything went well, the W996[87]CF driver can be immediatly used (see next
paragraph).
the OV511 package, version 2.27 - don't use other versions - and compile it
according to its documentation.
The package is available at http://alpha.dyndns.org/ov511/ .
6. Module loading
...
...
@@ -169,7 +160,7 @@ paragraph).
To use the driver, it is necessary to load the "w9968cf" module into memory
after every other module required.
For example, loading can be done this way, as
root:
Loading can be done this way, from
root:
[root@localhost home]# modprobe usbcore
[root@localhost home]# modprobe i2c-core
...
...
@@ -191,11 +182,10 @@ explanation about them and which syntax to use, it is recommended to run the
7. Module paramaters
====================
Module paramaters are listed below:
-------------------------------------------------------------------------------
Name: vppmod_load
Type:
int
Type:
bool
Syntax: <0|1>
Description: Automatic 'w9968cf-vpp' module loading: 0 disabled, 1 enabled.
If enabled, every time an application attempts to open a
...
...
@@ -219,7 +209,7 @@ Syntax: <-1|n[,...]>
Description: Specify V4L minor mode number.
-1 = use next available
n = use minor number n
You can specify 32 cameras this way.
You can specify
up to
32 cameras this way.
For example:
video_nr=-1,2,-1 would assign minor number 2 to the second
recognized camera and use auto for the first one and for every
...
...
@@ -236,22 +226,22 @@ Default: 1023
Name: max_buffers
Type: int array (min = 0, max = 32)
Syntax: <n[,...]>
Description:
Only f
or advanced users.
Description:
F
or advanced users.
Specify the maximum number of video frame buffers to allocate
for each device, from 2 to 32.
Default: 2
-------------------------------------------------------------------------------
Name: double_buffer
Type:
int
array (min = 0, max = 32)
Type:
bool
array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Hardware double buffering: 0 disabled, 1 enabled.
It should be enabled if you want smooth video output: if you
obtain out of sync. video, disable it
at all
, or try to
obtain out of sync. video, disable it, or try to
decrease the 'clockdiv' module paramater value.
Default: 1 for every device.
-------------------------------------------------------------------------------
Name: clamping
Type:
int
array (min = 0, max = 32)
Type:
bool
array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Video data clamping: 0 disabled, 1 enabled.
Default: 0 for every device.
...
...
@@ -266,13 +256,13 @@ Description: Video filter type.
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: largeview
Type:
int
array (min = 0, max = 32)
Type:
bool
array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Large view: 0 disabled, 1 enabled.
Default: 1 for every device.
-------------------------------------------------------------------------------
Name: upscaling
Type:
int
array (min = 0, max = 32)
Type:
bool
array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Software scaling (for non-compressed video only):
0 disabled, 1 enabled.
...
...
@@ -319,7 +309,7 @@ Default: 0 for every device. Initial palette is 9 (UYVY).
Note: If 'w9968cf-vpp' is not loaded, this paramater is set to 9.
-------------------------------------------------------------------------------
Name: force_rgb
Type:
int
array (min = 0, max = 32)
Type:
bool
array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Read RGB video data instead of BGR:
1 = use RGB component ordering.
...
...
@@ -328,28 +318,28 @@ Description: Read RGB video data instead of BGR:
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: autobright
Type:
long
array (min = 0, max = 32)
Type:
bool
array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: CMOS sensor automatically changes brightness:
0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: autoexp
Type:
long
array (min = 0, max = 32)
Type:
bool
array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: CMOS sensor automatically changes exposure:
0 = no, 1 = yes
Default: 1 for every device.
-------------------------------------------------------------------------------
Name: lightfreq
Type:
long
array (min = 0, max = 32)
Type:
int
array (min = 0, max = 32)
Syntax: <50|60[,...]>
Description: Light frequency in Hz:
50 for European and Asian lighting, 60 for American lighting.
Default: 50 for every device.
-------------------------------------------------------------------------------
Name: bandingfilter
Type:
long
array (min = 0, max = 32)
Type:
bool
array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Banding filter to reduce effects of fluorescent
lighting:
...
...
@@ -359,7 +349,7 @@ Description: Banding filter to reduce effects of fluorescent
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: clockdiv
Type:
long
array (min = 0, max = 32)
Type:
int
array (min = 0, max = 32)
Syntax: <-1|n[,...]>
Description: Force pixel clock divisor to a specific value (for experts):
n may vary from 0 to 127.
...
...
@@ -368,21 +358,21 @@ Description: Force pixel clock divisor to a specific value (for experts):
Default: -1 for every device.
-------------------------------------------------------------------------------
Name: backlight
Type:
long
array (min = 0, max = 32)
Type:
bool
array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Objects are lit from behind:
0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: mirror
Type:
long
array (min = 0, max = 32)
Type:
bool
array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Reverse image horizontally:
0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name:
sensor_mono
Type:
long
array (min = 0, max = 32)
Name:
monochrome
Type:
bool
array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: The CMOS sensor is monochrome:
0 = no, 1 = yes
...
...
@@ -423,7 +413,7 @@ Name: debug
Type: int
Syntax: <n>
Description: Debugging information level, from 0 to 6:
0 = none (
be cautious
)
0 = none (
use carefully
)
1 = critical errors
2 = significant informations
3 = configuration or general messages
...
...
@@ -435,7 +425,7 @@ Description: Debugging information level, from 0 to 6:
Default: 2
-------------------------------------------------------------------------------
Name: specific_debug
Type:
int
Type:
bool
Syntax: <0|1>
Description: Enable or disable specific debugging messages:
0 = print messages concerning every level <= 'debug' level.
...
...
@@ -444,7 +434,16 @@ Default: 0
-------------------------------------------------------------------------------
8. Credits
8. Contact information
======================
I may be contacted by e-mail at <luca.risolia@studio.unibo.it>.
I can accept GPG/PGP encrypted e-mail. My GPG key ID is 'FCE635A4'.
My public 1024-bit key should be available at your keyserver; the fingerprint
is: '88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4'.
9. Credits
==========
The development would not have proceed much further without having looked at
the source code of other drivers and without the help of several persons; in
...
...
@@ -456,8 +455,6 @@ particular:
- memory management code has been copied from the bttv driver by Ralph Metzler,
Marcus Metzler and Gerd Knorr;
- the low-level I2C read function has been written by Frédéric Jouault, who
also gave me commented logs about sniffed USB traffic taken from another
driver for another system;
- the low-level I2C read function has been written by Frederic Jouault;
- the low-level I2C fast write function has been written by Piotr Czerczak
;
- the low-level I2C fast write function has been written by Piotr Czerczak
.
MAINTAINERS
View file @
0e8f510d
...
...
@@ -2223,7 +2223,7 @@ S: Maintained
USB W996[87]CF DRIVER
P: Luca Risolia
M: luca
_ing@liber
o.it
M: luca
.risolia@studio.unib
o.it
L: linux-usb-devel@lists.sourceforge.net
W: http://go.lamarinapunto.com
S: Maintained
...
...
drivers/usb/media/Kconfig
View file @
0e8f510d
...
...
@@ -182,24 +182,21 @@ config USB_W9968CF
tristate "USB W996[87]CF JPEG Dual Mode Camera support"
depends on USB && VIDEO_DEV && I2C
---help---
Say Y here if you want support for cameras based on
Say Y here if you want support for cameras based on
OV681 or
Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
This driver has an optional plugin, which is distributed as a
separate module only (released under GPL). It contains code that
allows you to use higher resolutions and framerates, and can't
be included into the official Linux kernel for performance
purposes.
At the moment the driver needs a third-part module for the CMOS
separate module only (released under GPL). It allows to use higher
resolutions and framerates, but cannot be included in the official
Linux kernel for performance purposes.
At the moment the driver needs a third-party module for the CMOS
sensors, which is available on internet: it is recommended to read
<file:Documentation/usb/w9968cf.txt> for more informations and for
a list of supported cameras.
This driver uses the Video For Linux and the I2C APIs.
You must say Y or M to both "Video For Linux" and
"I2C Support" to use this driver.
Information on this API and pointers to "v4l" programs may be found
on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
This driver uses the Video For Linux and the I2C APIs. You must say
Y or M to both "Video For Linux" and "I2C Support" to use this
driver.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
...
...
drivers/usb/media/w9968cf.c
View file @
0e8f510d
/***************************************************************************
* Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. *
* *
* Copyright (C) 2002
2003 by Luca Risolia <luca_ing@libero.it>
*
* Copyright (C) 2002
-2004 by Luca Risolia <luca.risolia@studio.unibo.it>
*
* *
* - Memory management code from bttv driver by Ralph Metzler, *
* Marcus Metzler and Gerd Knorr. *
* - I2C interface to kernel, high-level CMOS sensor control routines and *
* some symbolic names from OV511 driver by Mark W. McClelland. *
* - Low-level I2C fast write function by Piotr Czerczak. *
* - Low-level I2C read function by Fr
édé
ric Jouault. *
* - Low-level I2C read function by Fr
ede
ric Jouault. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
...
...
@@ -27,6 +27,7 @@
#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
...
...
@@ -48,81 +49,86 @@
/****************************************************************************
* Module
s paramaters
*
* Module
macros and paramaters
*
****************************************************************************/
static
u8
vppmod_load
=
W9968CF_VPPMOD_LOAD
;
static
u8
simcams
=
W9968CF_SIMCAMS
;
static
int
video_nr
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
-
1
};
/* -1=first free */
static
u16
packet_size
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_PACKET_SIZE
};
static
u8
max_buffers
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_BUFFERS
};
static
u8
double_buffer
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_DOUBLE_BUFFER
};
static
u8
clamping
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_CLAMPING
};
static
u8
filter_type
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_FILTER_TYPE
};
static
u8
largeview
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_LARGEVIEW
};
static
u8
decompression
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_DECOMPRESSION
};
static
u8
upscaling
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_UPSCALING
};
static
u8
force_palette
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
0
};
static
u8
force_rgb
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_FORCE_RGB
};
static
u8
autobright
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_AUTOBRIGHT
};
static
u8
autoexp
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_AUTOEXP
};
static
u8
lightfreq
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_LIGHTFREQ
};
static
u8
bandingfilter
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_BANDINGFILTER
};
static
int
clockdiv
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_CLOCKDIV
};
static
u8
backlight
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_BACKLIGHT
};
static
u8
mirror
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_MIRROR
};
static
u8
sensor_mono
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_SENSOR_MONO
};
static
u16
brightness
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_BRIGHTNESS
};
static
u16
hue
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_HUE
};
static
u16
colour
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_COLOUR
};
static
u16
contrast
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_CONTRAST
};
static
u16
whiteness
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_WHITENESS
};
MODULE_AUTHOR
(
W9968CF_MODULE_AUTHOR
" "
W9968CF_AUTHOR_EMAIL
);
MODULE_DESCRIPTION
(
W9968CF_MODULE_NAME
" "
W9968CF_MODULE_VERSION
);
MODULE_LICENSE
(
W9968CF_MODULE_LICENSE
);
MODULE_SUPPORTED_DEVICE
(
"Video"
);
static
int
vppmod_load
=
W9968CF_VPPMOD_LOAD
;
static
unsigned
short
simcams
=
W9968CF_SIMCAMS
;
static
short
video_nr
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
-
1
};
/*-1=first free*/
static
unsigned
int
packet_size
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_PACKET_SIZE
};
static
unsigned
short
max_buffers
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_BUFFERS
};
static
int
double_buffer
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_DOUBLE_BUFFER
};
static
int
clamping
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_CLAMPING
};
static
unsigned
short
filter_type
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_FILTER_TYPE
};
static
int
largeview
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_LARGEVIEW
};
static
unsigned
short
decompression
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_DECOMPRESSION
};
static
int
upscaling
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_UPSCALING
};
static
unsigned
short
force_palette
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
0
};
static
int
force_rgb
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_FORCE_RGB
};
static
int
autobright
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_AUTOBRIGHT
};
static
int
autoexp
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_AUTOEXP
};
static
unsigned
short
lightfreq
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_LIGHTFREQ
};
static
int
bandingfilter
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_BANDINGFILTER
};
static
short
clockdiv
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_CLOCKDIV
};
static
int
backlight
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_BACKLIGHT
};
static
int
mirror
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_MIRROR
};
static
int
monochrome
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_MONOCHROME
};
static
unsigned
int
brightness
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_BRIGHTNESS
};
static
unsigned
int
hue
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_HUE
};
static
unsigned
int
colour
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_COLOUR
};
static
unsigned
int
contrast
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_CONTRAST
};
static
unsigned
int
whiteness
[]
=
{[
0
...
W9968CF_MAX_DEVICES
-
1
]
=
W9968CF_WHITENESS
};
#ifdef W9968CF_DEBUG
static
u
8
debug
=
W9968CF_DEBUG_LEVEL
;
static
u8
specific_debug
=
W9968CF_SPECIFIC_DEBUG
;
static
u
nsigned
short
debug
=
W9968CF_DEBUG_LEVEL
;
static
int
specific_debug
=
W9968CF_SPECIFIC_DEBUG
;
#endif
MODULE_AUTHOR
(
"Luca Risolia <luca_ing@libero.it>"
);
MODULE_DESCRIPTION
(
"Video4Linux driver for "
"W996[87]CF JPEG USB Dual Mode Camera Chip"
);
MODULE_SUPPORTED_DEVICE
(
"Video"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_PARM
(
vppmod_load
,
"i"
);
MODULE_PARM
(
simcams
,
"i"
);
MODULE_PARM
(
video_nr
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"i"
);
MODULE_PARM
(
packet_size
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"i"
);
MODULE_PARM
(
max_buffers
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"i"
);
MODULE_PARM
(
double_buffer
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"i"
);
MODULE_PARM
(
clamping
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"i"
);
MODULE_PARM
(
filter_type
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"i"
);
MODULE_PARM
(
largeview
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"i"
);
MODULE_PARM
(
decompression
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"i"
);
MODULE_PARM
(
upscaling
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"i"
);
MODULE_PARM
(
force_palette
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"i"
);
MODULE_PARM
(
force_rgb
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"i"
);
MODULE_PARM
(
autobright
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"l"
);
MODULE_PARM
(
autoexp
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"l"
);
MODULE_PARM
(
lightfreq
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"l"
);
MODULE_PARM
(
bandingfilter
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"l"
);
MODULE_PARM
(
clockdiv
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"l"
);
MODULE_PARM
(
backlight
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"l"
);
MODULE_PARM
(
mirror
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"l"
);
MODULE_PARM
(
sensor_mono
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"l"
);
MODULE_PARM
(
brightness
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"l"
);
MODULE_PARM
(
hue
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"l"
);
MODULE_PARM
(
colour
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"l"
);
MODULE_PARM
(
contrast
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"l"
);
MODULE_PARM
(
whiteness
,
"0-"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"l"
);
static
unsigned
int
param_nv
[
23
];
/* number of values per paramater */
module_param
(
vppmod_load
,
bool
,
0444
);
module_param
(
simcams
,
ushort
,
0444
);
module_param_array
(
video_nr
,
short
,
param_nv
[
0
],
0444
);
module_param_array
(
packet_size
,
uint
,
param_nv
[
1
],
0444
);
module_param_array
(
max_buffers
,
ushort
,
param_nv
[
2
],
0444
);
module_param_array
(
double_buffer
,
bool
,
param_nv
[
3
],
0444
);
module_param_array
(
clamping
,
bool
,
param_nv
[
4
],
0444
);
module_param_array
(
filter_type
,
ushort
,
param_nv
[
5
],
0444
);
module_param_array
(
largeview
,
bool
,
param_nv
[
6
],
0444
);
module_param_array
(
decompression
,
ushort
,
param_nv
[
7
],
0444
);
module_param_array
(
upscaling
,
bool
,
param_nv
[
8
],
0444
);
module_param_array
(
force_palette
,
ushort
,
param_nv
[
9
],
0444
);
module_param_array
(
force_rgb
,
ushort
,
param_nv
[
10
],
0444
);
module_param_array
(
autobright
,
bool
,
param_nv
[
11
],
0444
);
module_param_array
(
autoexp
,
bool
,
param_nv
[
12
],
0444
);
module_param_array
(
lightfreq
,
ushort
,
param_nv
[
13
],
0444
);
module_param_array
(
bandingfilter
,
bool
,
param_nv
[
14
],
0444
);
module_param_array
(
clockdiv
,
short
,
param_nv
[
15
],
0444
);
module_param_array
(
backlight
,
bool
,
param_nv
[
16
],
0444
);
module_param_array
(
mirror
,
bool
,
param_nv
[
17
],
0444
);
module_param_array
(
monochrome
,
bool
,
param_nv
[
18
],
0444
);
module_param_array
(
brightness
,
uint
,
param_nv
[
19
],
0444
);
module_param_array
(
hue
,
uint
,
param_nv
[
20
],
0444
);
module_param_array
(
colour
,
uint
,
param_nv
[
21
],
0444
);
module_param_array
(
contrast
,
uint
,
param_nv
[
22
],
0444
);
module_param_array
(
whiteness
,
uint
,
param_nv
[
23
],
0444
);
#ifdef W9968CF_DEBUG
MODULE_PARM
(
debug
,
"i"
);
MODULE_PARM
(
specific_debug
,
"i"
);
module_param
(
debug
,
ushort
,
0444
);
module_param
(
specific_debug
,
bool
,
0444
);
#endif
MODULE_PARM_DESC
(
vppmod_load
,
...
...
@@ -146,7 +152,7 @@ MODULE_PARM_DESC(video_nr,
"
\n
<-1|n[,...]> Specify V4L minor mode number."
"
\n
-1 = use next available (default)"
"
\n
n = use minor number n (integer >= 0)"
"
\n
You can specify
"
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
"
\n
You can specify
up to "
__MODULE_STRING
(
W9968CF_MAX_DEVICES
)
" cameras this way."
"
\n
For example:"
"
\n
video_nr=-1,2,-1 would assign minor number 2 to"
...
...
@@ -160,7 +166,7 @@ MODULE_PARM_DESC(packet_size,
"(default is "
__MODULE_STRING
(
W9968CF_PACKET_SIZE
)
")."
"
\n
"
);
MODULE_PARM_DESC
(
max_buffers
,
"
\n
<n[,...]>
Only f
or advanced users."
"
\n
<n[,...]>
F
or advanced users."
"
\n
Specify the maximum number of video frame buffers"
"
\n
to allocate for each device, from 2 to "
__MODULE_STRING
(
W9968CF_MAX_BUFFERS
)
...
...
@@ -203,7 +209,8 @@ MODULE_PARM_DESC(upscaling,
"
\n
Default value is "
__MODULE_STRING
(
W9968CF_UPSCALING
)
" for every device."
"
\n
If 'w9968cf-vpp' is not loaded, this paramater is"
" set to 0."
);
" set to 0."
"
\n
"
);
MODULE_PARM_DESC
(
decompression
,
"
\n
<0|1|2[,...]> Software video decompression:"
"
\n
- 0 disables decompression (doesn't allow formats needing"
...
...
@@ -218,7 +225,8 @@ MODULE_PARM_DESC(decompression,
"
\n
Default value is "
__MODULE_STRING
(
W9968CF_DECOMPRESSION
)
" for every device."
"
\n
If 'w9968cf-vpp' is not loaded, forcing decompression is "
"
\n
not allowed; in this case this paramater is set to 2."
);
"
\n
not allowed; in this case this paramater is set to 2."
"
\n
"
);
MODULE_PARM_DESC
(
force_palette
,
"
\n
<0"
"|"
__MODULE_STRING
(
VIDEO_PALETTE_UYVY
)
...
...
@@ -252,7 +260,8 @@ MODULE_PARM_DESC(force_palette,
"
\n
Initial palette is "
__MODULE_STRING
(
W9968CF_PALETTE_DECOMP_ON
)
"."
"
\n
If 'w9968cf-vpp' is not loaded, this paramater is"
" set to 9 (UYVY)."
);
" set to 9 (UYVY)."
"
\n
"
);
MODULE_PARM_DESC
(
force_rgb
,
"
\n
<0|1[,...]> Read RGB video data instead of BGR:"
"
\n
1 = use RGB component ordering."
...
...
@@ -311,10 +320,11 @@ MODULE_PARM_DESC(mirror,
"
\n
Default value is "
__MODULE_STRING
(
W9968CF_MIRROR
)
" for every device."
"
\n
"
);
MODULE_PARM_DESC
(
sensor_mono
,
"
\n
<0|1[,...]>
The OV CMOS sensor is monochrome
:"
MODULE_PARM_DESC
(
monochrome
,
"
\n
<0|1[,...]>
Use OV CMOS sensor as monochrome sensor
:"
"
\n
0 = no, 1 = yes"
"
\n
Default value is "
__MODULE_STRING
(
W9968CF_SENSOR_MONO
)
"
\n
Not all the sensors support monochrome color."
"
\n
Default value is "
__MODULE_STRING
(
W9968CF_MONOCHROME
)
" for every device."
"
\n
"
);
MODULE_PARM_DESC
(
brightness
,
...
...
@@ -346,7 +356,7 @@ MODULE_PARM_DESC(whiteness,
#ifdef W9968CF_DEBUG
MODULE_PARM_DESC
(
debug
,
"
\n
<n> Debugging information level, from 0 to 6:"
"
\n
0 = none (
be cautious
)"
"
\n
0 = none (
use carefully
)"
"
\n
1 = critical errors"
"
\n
2 = significant informations"
"
\n
3 = configuration or general messages"
...
...
@@ -380,13 +390,12 @@ static int w9968cf_open(struct inode*, struct file*);
static
int
w9968cf_release
(
struct
inode
*
,
struct
file
*
);
static
ssize_t
w9968cf_read
(
struct
file
*
,
char
*
,
size_t
,
loff_t
*
);
static
int
w9968cf_mmap
(
struct
file
*
,
struct
vm_area_struct
*
);
static
int
w9968cf_ioctl
(
struct
inode
*
,
struct
file
*
,
unsigned
int
,
unsigned
long
);
static
int
w9968cf_do_ioctl
(
struct
w9968cf_device
*
,
unsigned
int
,
void
*
);
static
int
w9968cf_ioctl
(
struct
inode
*
,
struct
file
*
,
unsigned
,
unsigned
long
);
static
int
w9968cf_v4l_ioctl
(
struct
inode
*
,
struct
file
*
,
unsigned
int
,
void
*
);
/* USB-specific */
static
void
w9968cf_urb_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
);
static
int
w9968cf_start_transfer
(
struct
w9968cf_device
*
);
static
void
w9968cf_urb_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
);
static
int
w9968cf_stop_transfer
(
struct
w9968cf_device
*
);
static
int
w9968cf_write_reg
(
struct
w9968cf_device
*
,
u16
value
,
u16
index
);
static
int
w9968cf_read_reg
(
struct
w9968cf_device
*
,
u16
index
);
...
...
@@ -402,6 +411,7 @@ static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v);
static
int
w9968cf_smbus_read_byte
(
struct
w9968cf_device
*
,
u8
*
v
);
static
int
w9968cf_smbus_write_ack
(
struct
w9968cf_device
*
);
static
int
w9968cf_smbus_read_ack
(
struct
w9968cf_device
*
);
static
int
w9968cf_smbus_refresh_bus
(
struct
w9968cf_device
*
);
static
int
w9968cf_i2c_adap_read_byte
(
struct
w9968cf_device
*
cam
,
u16
address
,
u8
*
value
);
static
int
w9968cf_i2c_adap_read_byte_data
(
struct
w9968cf_device
*
,
u16
address
,
...
...
@@ -436,12 +446,11 @@ static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val);
static
int
w9968cf_sensor_get_control
(
struct
w9968cf_device
*
,
int
cid
,
int
*
val
);
static
inline
int
w9968cf_sensor_cmd
(
struct
w9968cf_device
*
,
unsigned
int
cmd
,
void
*
arg
);
static
void
w9968cf_sensor_configure
(
struct
w9968cf_device
*
);
static
int
w9968cf_sensor_change_settings
(
struct
w9968cf_device
*
);
static
int
w9968cf_sensor_get_picture
(
struct
w9968cf_device
*
,
struct
video_picture
*
);
static
int
w9968cf_sensor_set_picture
(
struct
w9968cf_device
*
,
struct
video_picture
pict
);
static
int
w9968cf_sensor_init
(
struct
w9968cf_device
*
);
static
int
w9968cf_sensor_update_settings
(
struct
w9968cf_device
*
);
static
int
w9968cf_sensor_get_picture
(
struct
w9968cf_device
*
);
static
int
w9968cf_sensor_update_picture
(
struct
w9968cf_device
*
,
struct
video_picture
pict
);
/* Other helper functions */
static
void
w9968cf_configure_camera
(
struct
w9968cf_device
*
,
struct
usb_device
*
,
...
...
@@ -587,8 +596,6 @@ static struct w9968cf_symbolic_list urb_errlist[] = {
* Memory management functions *
****************************************************************************/
/* Shameless copy from bttv-driver.c */
/* Here we want the physical address of the memory.
This is used when initializing the contents of the area. */
static
inline
unsigned
long
kvirt_to_pa
(
unsigned
long
adr
)
...
...
@@ -639,7 +646,6 @@ static void rvfree(void* mem, unsigned long size)
}
vfree
(
mem
);
}
/* End of shameless copy */
/*--------------------------------------------------------------------------
...
...
@@ -820,9 +826,9 @@ static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs)
}
for
(
i
=
0
;
i
<
urb
->
number_of_packets
;
i
++
)
{
len
=
urb
->
iso_frame_desc
[
i
].
actual_length
;
len
=
urb
->
iso_frame_desc
[
i
].
actual_length
;
status
=
urb
->
iso_frame_desc
[
i
].
status
;
pos
=
urb
->
iso_frame_desc
[
i
].
offset
+
urb
->
transfer_buffer
;
pos
=
urb
->
iso_frame_desc
[
i
].
offset
+
urb
->
transfer_buffer
;
if
(
status
&&
len
!=
0
)
{
DBG
(
4
,
"URB failed, error in data packet "
...
...
@@ -923,7 +929,6 @@ static int w9968cf_start_transfer(struct w9968cf_device* cam)
for
(
i
=
0
;
i
<
W9968CF_URBS
;
i
++
)
{
urb
=
usb_alloc_urb
(
W9968CF_ISO_PACKETS
,
GFP_KERNEL
);
cam
->
urb
[
i
]
=
urb
;
if
(
!
urb
)
{
for
(
j
=
0
;
j
<
i
;
j
++
)
usb_free_urb
(
cam
->
urb
[
j
]);
...
...
@@ -953,7 +958,7 @@ static int w9968cf_start_transfer(struct w9968cf_device* cam)
t_size
=
(
w
*
h
*
d
)
/
16
;
err
=
w9968cf_write_reg
(
cam
,
0xbf17
,
0x00
);
/* reset
everything */
err
=
w9968cf_write_reg
(
cam
,
0xbf17
,
0x00
);
/* reset everything */
err
+=
w9968cf_write_reg
(
cam
,
0xbf10
,
0x00
);
/* normal operation */
/* Transfer size */
...
...
@@ -1026,11 +1031,12 @@ static int w9968cf_stop_transfer(struct w9968cf_device* cam)
spin_unlock_irqrestore
(
&
cam
->
urb_lock
,
lock_flags
);
for
(
i
=
W9968CF_URBS
-
1
;
i
>=
0
;
i
--
)
if
(
cam
->
urb
[
i
])
if
(
cam
->
urb
[
i
])
{
if
(
!
usb_unlink_urb
(
cam
->
urb
[
i
]))
{
usb_free_urb
(
cam
->
urb
[
i
]);
cam
->
urb
[
i
]
=
NULL
;
}
}
if
(
cam
->
disconnected
)
goto
exit
;
...
...
@@ -1086,8 +1092,7 @@ static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index)
res
=
usb_control_msg
(
udev
,
usb_rcvctrlpipe
(
udev
,
0
),
1
,
USB_DIR_IN
|
USB_TYPE_VENDOR
|
USB_RECIP_DEVICE
,
0
,
index
,
(
void
*
)
buff
,
2
,
W9968CF_USB_CTRL_TIMEOUT
);
0
,
index
,
buff
,
2
,
W9968CF_USB_CTRL_TIMEOUT
);
if
(
res
<
0
)
DBG
(
4
,
"Failed to read a register "
...
...
@@ -1099,7 +1104,7 @@ static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index)
/*--------------------------------------------------------------------------
Write data to the fast serial bus registers.
Write
64-bit
data to the fast serial bus registers.
Return 0 on success, -1 otherwise.
--------------------------------------------------------------------------*/
static
int
w9968cf_write_fsb
(
struct
w9968cf_device
*
cam
,
u16
*
data
)
...
...
@@ -1112,8 +1117,7 @@ static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data)
res
=
usb_control_msg
(
udev
,
usb_sndctrlpipe
(
udev
,
0
),
0
,
USB_TYPE_VENDOR
|
USB_DIR_OUT
|
USB_RECIP_DEVICE
,
value
,
0x06
,
(
void
*
)
data
,
6
,
W9968CF_USB_CTRL_TIMEOUT
);
value
,
0x06
,
data
,
6
,
W9968CF_USB_CTRL_TIMEOUT
);
if
(
res
<
0
)
DBG
(
4
,
"Failed to write the FSB registers "
...
...
@@ -1275,6 +1279,22 @@ static int w9968cf_smbus_read_ack(struct w9968cf_device* cam)
}
/* This seems to refresh the communication through the serial bus */
static
int
w9968cf_smbus_refresh_bus
(
struct
w9968cf_device
*
cam
)
{
int
err
=
0
,
j
;
for
(
j
=
1
;
j
<=
10
;
j
++
)
{
err
=
w9968cf_write_reg
(
cam
,
0x0020
,
0x01
);
err
+=
w9968cf_write_reg
(
cam
,
0x0000
,
0x01
);
if
(
err
)
break
;
}
return
err
;
}
/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
static
int
w9968cf_i2c_adap_fastwrite_byte_data
(
struct
w9968cf_device
*
cam
,
...
...
@@ -1283,8 +1303,10 @@ w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam,
u16
*
data
=
cam
->
data_buffer
;
int
err
=
0
;
/* Enable SBUS outputs */
err
+=
w9968cf_write_reg
(
cam
,
0x0020
,
0x01
);
err
+=
w9968cf_smbus_refresh_bus
(
cam
);
/* Enable SBUS outputs */
err
+=
w9968cf_write_sb
(
cam
,
0x0020
);
data
[
0
]
=
0x082f
|
((
address
&
0x80
)
?
0x1500
:
0x0
);
data
[
0
]
|=
(
address
&
0x40
)
?
0x4000
:
0x0
;
...
...
@@ -1328,7 +1350,7 @@ w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam,
err
+=
w9968cf_write_fsb
(
cam
,
data
);
/* Disable SBUS outputs */
err
+=
w9968cf_write_
reg
(
cam
,
0x0000
,
0x01
);
err
+=
w9968cf_write_
sb
(
cam
,
0x0000
);
if
(
!
err
)
DBG
(
5
,
"I2C write byte data done, addr.0x%04X, subaddr.0x%02X "
...
...
@@ -1365,7 +1387,7 @@ w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam,
err
+=
w9968cf_smbus_read_byte
(
cam
,
value
);
err
+=
w9968cf_smbus_write_ack
(
cam
);
err
+=
w9968cf_smbus_stop
(
cam
);
/* Serial data disable */
err
+=
w9968cf_write_sb
(
cam
,
0x0000
);
...
...
@@ -1434,8 +1456,8 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
int
size
,
union
i2c_smbus_data
*
data
)
{
struct
w9968cf_device
*
cam
=
i2c_get_adapdata
(
adapter
);
u8
i
,
j
;
int
rc
=
0
,
err
=
0
;
u8
i
;
int
err
=
0
;
switch
(
addr
)
{
case
OV6xx0_SID
:
...
...
@@ -1451,31 +1473,26 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
addr
<<=
1
;
if
(
read_write
==
I2C_SMBUS_WRITE
)
rc
=
w9968cf_i2c_adap_write_byte
(
cam
,
addr
,
command
);
err
=
w9968cf_i2c_adap_write_byte
(
cam
,
addr
,
command
);
else
if
(
read_write
==
I2C_SMBUS_READ
)
rc
=
w9968cf_i2c_adap_read_byte
(
cam
,
addr
,
&
data
->
byte
);
err
=
w9968cf_i2c_adap_read_byte
(
cam
,
addr
,
&
data
->
byte
);
}
else
if
(
size
==
I2C_SMBUS_BYTE_DATA
)
{
addr
<<=
1
;
if
(
read_write
==
I2C_SMBUS_WRITE
)
rc
=
w9968cf_i2c_adap_fastwrite_byte_data
(
cam
,
addr
,
err
=
w9968cf_i2c_adap_fastwrite_byte_data
(
cam
,
addr
,
command
,
data
->
byte
);
else
if
(
read_write
==
I2C_SMBUS_READ
)
{
for
(
i
=
1
;
i
<=
W9968CF_I2C_RW_RETRIES
;
i
++
)
{
rc
=
w9968cf_i2c_adap_read_byte_data
(
cam
,
addr
,
err
=
w9968cf_i2c_adap_read_byte_data
(
cam
,
addr
,
command
,
&
data
->
byte
);
if
(
rc
<
0
)
{
/* Work around: this seems to wake up
the EEPROM from the stall state */
for
(
j
=
0
;
j
<=
10
;
j
++
)
{
err
+=
w9968cf_write_sb
(
cam
,
0x0020
);
err
+=
w9968cf_write_sb
(
cam
,
0x0000
);
if
(
err
)
break
;
if
(
err
)
{
if
(
w9968cf_smbus_refresh_bus
(
cam
))
{
err
=
-
EIO
;
break
;
}
}
else
}
else
break
;
}
...
...
@@ -1487,11 +1504,7 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
return
-
EINVAL
;
}
/* This works around a bug in the I2C core */
if
(
rc
>
0
)
rc
=
0
;
return
rc
;
return
err
;
}
...
...
@@ -1507,41 +1520,22 @@ static int w9968cf_i2c_attach_inform(struct i2c_client* client)
{
struct
w9968cf_device
*
cam
=
i2c_get_adapdata
(
client
->
adapter
);
const
char
*
clientname
=
i2c_clientname
(
client
);
int
id
=
client
->
driver
->
id
;
int
id
=
client
->
driver
->
id
,
err
=
0
;
if
(
id
==
I2C_DRIVERID_OVCAMCHIP
)
{
int
rc
=
0
;
cam
->
sensor_client
=
client
;
rc
=
w9968cf_sensor_cmd
(
cam
,
OVCAMCHIP_CMD_INITIALIZE
,
&
cam
->
sensor_mono
);
if
(
rc
<
0
)
{
DBG
(
1
,
"CMOS sensor initialization failed (rc=%d)"
,
rc
);
cam
->
sensor_client
=
NULL
;
return
rc
;
}
if
(
w9968cf_sensor_cmd
(
cam
,
OVCAMCHIP_CMD_Q_SUBTYPE
,
&
cam
->
sensor
)
<
0
)
rc
=
-
EIO
;
else
if
(
client
->
addr
==
OV7xx0_SID
||
client
->
addr
==
OV6xx0_SID
)
w9968cf_sensor_configure
(
cam
);
else
rc
=
-
EINVAL
;
if
(
rc
<
0
)
{
err
=
w9968cf_sensor_init
(
cam
);
if
(
err
)
{
cam
->
sensor_client
=
NULL
;
cam
->
sensor
=
CC_UNKNOWN
;
return
rc
;
return
err
;
}
}
else
{
DBG
(
4
,
"Rejected client [%s] with [%s]"
,
}
else
{
DBG
(
4
,
"Rejected client [%s] with
driver
[%s]"
,
clientname
,
client
->
driver
->
name
)
return
-
1
;
return
-
EINVAL
;
}
DBG
(
2
,
"I2C attach client [%s] with
[%s]"
,
DBG
(
5
,
"I2C attach client [%s] with driver
[%s]"
,
clientname
,
client
->
driver
->
name
)
return
0
;
...
...
@@ -1557,7 +1551,7 @@ static int w9968cf_i2c_detach_inform(struct i2c_client* client)
cam
->
sensor_client
=
NULL
;
}
DBG
(
2
,
"I2C detach
[%s]"
,
clientname
)
DBG
(
5
,
"I2C detach client
[%s]"
,
clientname
)
return
0
;
}
...
...
@@ -1573,7 +1567,7 @@ w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd,
static
int
w9968cf_i2c_init
(
struct
w9968cf_device
*
cam
)
{
int
rc
=
0
;
int
err
=
0
;
static
struct
i2c_algorithm
algo
=
{
.
name
=
"W996[87]CF algorithm"
,
...
...
@@ -1596,15 +1590,15 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
strcpy
(
cam
->
i2c_adapter
.
name
,
"w9968cf"
);
i2c_set_adapdata
(
&
cam
->
i2c_adapter
,
cam
);
DBG
(
6
,
"Registering I2C
bus
with kernel..."
)
DBG
(
6
,
"Registering I2C
adapter
with kernel..."
)
rc
=
i2c_add_adapter
(
&
cam
->
i2c_adapter
);
if
(
rc
)
DBG
(
5
,
"Failed to register the I2C bus
."
)
err
=
i2c_add_adapter
(
&
cam
->
i2c_adapter
);
if
(
err
)
DBG
(
1
,
"Failed to register the I2C adapter
."
)
else
DBG
(
5
,
"I2C
bus
registered."
)
DBG
(
5
,
"I2C
adapter
registered."
)
return
rc
;
return
err
;
}
...
...
@@ -1644,7 +1638,7 @@ static int w9968cf_turn_on_led(struct w9968cf_device* cam)
--------------------------------------------------------------------------*/
static
int
w9968cf_init_chip
(
struct
w9968cf_device
*
cam
)
{
int
err
=
0
,
rc
=
0
;
int
err
=
0
;
err
+=
w9968cf_write_reg
(
cam
,
0xff00
,
0x00
);
/* power off */
err
+=
w9968cf_write_reg
(
cam
,
0xbf10
,
0x00
);
/* power on */
...
...
@@ -1679,22 +1673,11 @@ static int w9968cf_init_chip(struct w9968cf_device* cam)
err
+=
w9968cf_set_window
(
cam
,
cam
->
window
);
if
(
err
)
goto
error
;
rc
=
w9968cf_sensor_change_settings
(
cam
);
if
(
rc
)
goto
error
;
DBG
(
5
,
"Chip successfully initialized."
);
return
0
;
error:
DBG
(
1
,
"Chip initialization failed."
)
if
(
err
)
return
err
;
DBG
(
1
,
"Chip initialization failed."
)
else
return
rc
;
DBG
(
5
,
"Chip successfully initialized."
)
return
err
;
}
...
...
@@ -1706,7 +1689,7 @@ static int
w9968cf_set_picture
(
struct
w9968cf_device
*
cam
,
struct
video_picture
pict
)
{
u16
fmt
,
hw_depth
,
hw_palette
,
reg_v
=
0x0000
;
int
err
=
0
,
rc
=
0
;
int
err
=
0
;
/* Make sure we are using a valid depth */
pict
.
depth
=
w9968cf_valid_depth
(
pict
.
palette
);
...
...
@@ -1767,12 +1750,10 @@ w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
else
if
(
cam
->
filter_type
==
2
)
reg_v
|=
0x000c
;
err
=
w9968cf_write_reg
(
cam
,
reg_v
,
0x16
);
if
(
err
)
if
((
err
=
w9968cf_write_reg
(
cam
,
reg_v
,
0x16
)))
goto
error
;
rc
=
w9968cf_sensor_set_picture
(
cam
,
pict
);
if
(
rc
)
if
((
err
=
w9968cf_sensor_update_picture
(
cam
,
pict
)))
goto
error
;
/* If all went well, update the device data structure */
...
...
@@ -1791,10 +1772,7 @@ w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
error:
DBG
(
1
,
"Failed to change picture settings."
)
if
(
err
)
return
err
;
else
return
rc
;
return
err
;
}
...
...
@@ -1809,7 +1787,7 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
u16
x
,
y
,
w
,
h
,
scx
,
scy
,
cw
,
ch
,
ax
,
ay
;
unsigned
long
fw
,
fh
;
struct
ovcamchip_window
s_win
;
int
err
=
0
,
rc
=
0
;
int
err
=
0
;
/* Work around to avoid FP arithmetics */
#define __SC(x) ((x) << 10)
...
...
@@ -1853,8 +1831,8 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
ch
=
h
;
}
/* Setup the
sensor window
*/
s_win
.
format
=
SENSOR_FORMAT
;
/* Setup the
window of the sensor
*/
s_win
.
format
=
VIDEO_PALETTE_UYVY
;
s_win
.
width
=
cam
->
maxwidth
;
s_win
.
height
=
cam
->
maxheight
;
s_win
.
quarter
=
0
;
/* full progressive video */
...
...
@@ -1883,7 +1861,7 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
s_win
.
clockdiv
=
W9968CF_DEF_CLOCKDIVISOR
;
}
/* We have to scale win.x and win.y offsets */
/* We have to scale win.x and win.y offsets */
if
(
(
cam
->
largeview
&&
!
(
cam
->
vpp_flag
&
VPP_UPSCALE
))
||
(
cam
->
vpp_flag
&
VPP_UPSCALE
)
)
{
ax
=
__SC
(
win
.
x
)
/
fw
;
...
...
@@ -1914,7 +1892,7 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
y
=
ay
+
s_win
.
y
;
/* Go ! */
if
((
rc
=
w9968cf_sensor_cmd
(
cam
,
OVCAMCHIP_CMD_S_MODE
,
&
s_win
)))
if
((
err
=
w9968cf_sensor_cmd
(
cam
,
OVCAMCHIP_CMD_S_MODE
,
&
s_win
)))
goto
error
;
err
+=
w9968cf_write_reg
(
cam
,
scx
+
x
,
0x10
);
...
...
@@ -1959,10 +1937,7 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
error:
DBG
(
1
,
"Failed to change the capture area size."
)
if
(
err
)
return
err
;
else
return
rc
;
return
err
;
}
...
...
@@ -2177,173 +2152,192 @@ static int
w9968cf_sensor_set_control
(
struct
w9968cf_device
*
cam
,
int
cid
,
int
val
)
{
struct
ovcamchip_control
ctl
;
int
rc
;
int
err
;
ctl
.
id
=
cid
;
ctl
.
value
=
val
;
rc
=
w9968cf_sensor_cmd
(
cam
,
OVCAMCHIP_CMD_S_CTRL
,
&
ctl
);
err
=
w9968cf_sensor_cmd
(
cam
,
OVCAMCHIP_CMD_S_CTRL
,
&
ctl
);
return
rc
;
return
err
;
}
static
int
w9968cf_sensor_get_control
(
struct
w9968cf_device
*
cam
,
int
cid
,
int
*
val
)
w9968cf_sensor_get_control
(
struct
w9968cf_device
*
cam
,
int
cid
,
int
*
val
)
{
struct
ovcamchip_control
ctl
;
int
rc
;
int
err
;
ctl
.
id
=
cid
;
rc
=
w9968cf_sensor_cmd
(
cam
,
OVCAMCHIP_CMD_G_CTRL
,
&
ctl
);
if
(
rc
>=
0
)
err
=
w9968cf_sensor_cmd
(
cam
,
OVCAMCHIP_CMD_G_CTRL
,
&
ctl
);
if
(
!
err
)
*
val
=
ctl
.
value
;
return
rc
;
return
err
;
}
static
inline
int
w9968cf_sensor_cmd
(
struct
w9968cf_device
*
cam
,
unsigned
int
cmd
,
void
*
arg
)
w9968cf_sensor_cmd
(
struct
w9968cf_device
*
cam
,
unsigned
int
cmd
,
void
*
arg
)
{
struct
i2c_client
*
c
=
cam
->
sensor_client
;
int
rc
=
0
;
DBG
(
6
,
"Executing CMOS sensor command..."
)
if
(
c
&&
c
->
driver
->
command
)
return
c
->
driver
->
command
(
cam
->
sensor_client
,
cmd
,
arg
)
;
else
if
(
c
->
driver
->
command
)
{
rc
=
c
->
driver
->
command
(
cam
->
sensor_client
,
cmd
,
arg
);
/* The I2C driver returns -EPERM on non-supported controls */
return
(
rc
<
0
&&
rc
!=
-
EPERM
)
?
rc
:
0
;
}
else
return
-
ENODEV
;
}
/*--------------------------------------------------------------------------
Chang
e some settings of the CMOS sensor.
Returns: 0
for
success, a negative number otherwise.
Updat
e some settings of the CMOS sensor.
Returns: 0
on
success, a negative number otherwise.
--------------------------------------------------------------------------*/
static
int
w9968cf_sensor_
chang
e_settings
(
struct
w9968cf_device
*
cam
)
static
int
w9968cf_sensor_
updat
e_settings
(
struct
w9968cf_device
*
cam
)
{
int
rc
;
int
err
=
0
;
/* Auto brightness */
rc
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_AUTOBRIGHT
,
cam
->
auto_brt
);
if
(
SENSOR_FATAL_ERROR
(
rc
)
)
return
rc
;
err
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_AUTOBRIGHT
,
cam
->
auto_brt
);
if
(
err
)
return
err
;
/* Auto exposure */
rc
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_AUTOEXP
,
cam
->
auto_exp
);
if
(
SENSOR_FATAL_ERROR
(
rc
)
)
return
rc
;
err
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_AUTOEXP
,
cam
->
auto_exp
);
if
(
err
)
return
err
;
/* Banding filter */
rc
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_BANDFILT
,
cam
->
bandfilt
);
if
(
SENSOR_FATAL_ERROR
(
rc
)
)
return
rc
;
err
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_BANDFILT
,
cam
->
bandfilt
);
if
(
err
)
return
err
;
/* Light frequency */
rc
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_FREQ
,
cam
->
lightfreq
);
if
(
SENSOR_FATAL_ERROR
(
rc
)
)
return
rc
;
err
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_FREQ
,
cam
->
lightfreq
);
if
(
err
)
return
err
;
/* Back light */
rc
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_BACKLIGHT
,
cam
->
backlight
);
if
(
SENSOR_FATAL_ERROR
(
rc
)
)
return
rc
;
err
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_BACKLIGHT
,
cam
->
backlight
);
if
(
err
)
return
err
;
/* Mirror */
rc
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_MIRROR
,
cam
->
mirror
);
if
(
SENSOR_FATAL_ERROR
(
rc
)
)
return
rc
;
err
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_MIRROR
,
cam
->
mirror
);
if
(
err
)
return
err
;
return
0
;
}
/*--------------------------------------------------------------------------
Get some current picture settings from the CMOS sensor.
Returns: 0 for success, a negative number otherwise.
Get some current picture settings from the CMOS sensor and update the
internal 'picture' structure of the camera.
Returns: 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/
static
int
w9968cf_sensor_get_picture
(
struct
w9968cf_device
*
cam
,
struct
video_picture
*
pict
)
static
int
w9968cf_sensor_get_picture
(
struct
w9968cf_device
*
cam
)
{
int
rc
,
v
;
/* Don't return error if a setting is unsupported, or rest of settings
will not be performed */
rc
=
w9968cf_sensor_get_control
(
cam
,
OVCAMCHIP_CID_CONT
,
&
v
);
if
(
SENSOR_FATAL_ERROR
(
rc
))
return
rc
;
pict
->
contrast
=
v
;
int
err
,
v
;
rc
=
w9968cf_sensor_get_control
(
cam
,
OVCAMCHIP_CID_BRIGH
T
,
&
v
);
if
(
SENSOR_FATAL_ERROR
(
rc
)
)
return
rc
;
pict
->
brightness
=
v
;
err
=
w9968cf_sensor_get_control
(
cam
,
OVCAMCHIP_CID_CON
T
,
&
v
);
if
(
err
)
return
err
;
cam
->
picture
.
contrast
=
v
;
rc
=
w9968cf_sensor_get_control
(
cam
,
OVCAMCHIP_CID_SA
T
,
&
v
);
if
(
SENSOR_FATAL_ERROR
(
rc
)
)
return
rc
;
pict
->
colour
=
v
;
err
=
w9968cf_sensor_get_control
(
cam
,
OVCAMCHIP_CID_BRIGH
T
,
&
v
);
if
(
err
)
return
err
;
cam
->
picture
.
brightness
=
v
;
rc
=
w9968cf_sensor_get_control
(
cam
,
OVCAMCHIP_CID_HUE
,
&
v
);
if
(
SENSOR_FATAL_ERROR
(
rc
)
)
return
rc
;
pict
->
hue
=
v
;
err
=
w9968cf_sensor_get_control
(
cam
,
OVCAMCHIP_CID_SAT
,
&
v
);
if
(
err
)
return
err
;
cam
->
picture
.
colour
=
v
;
pict
->
whiteness
=
W9968CF_WHITENESS
;
/* to do! */
err
=
w9968cf_sensor_get_control
(
cam
,
OVCAMCHIP_CID_HUE
,
&
v
);
if
(
err
)
return
err
;
cam
->
picture
.
hue
=
v
;
DBG
(
5
,
"Got picture settings from the CMOS sensor."
)
PDBGG
(
"Brightness, contrast, hue, colour, whiteness are "
"%d,%d,%d,%d,%d."
,
pict
->
brightness
,
pict
->
contrast
,
pict
->
hue
,
pict
->
colour
,
pict
->
whiteness
)
"%d,%d,%d,%d,%d."
,
cam
->
picture
.
brightness
,
cam
->
picture
.
contrast
,
cam
->
picture
.
hue
,
cam
->
picture
.
colour
,
cam
->
picture
.
whiteness
)
return
0
;
}
/*--------------------------------------------------------------------------
Chang
e picture settings of the CMOS sensor.
Returns: 0
for
success, a negative number otherwise.
Updat
e picture settings of the CMOS sensor.
Returns: 0
on
success, a negative number otherwise.
--------------------------------------------------------------------------*/
static
int
w9968cf_sensor_
set
_picture
(
struct
w9968cf_device
*
cam
,
struct
video_picture
pict
)
w9968cf_sensor_
update
_picture
(
struct
w9968cf_device
*
cam
,
struct
video_picture
pict
)
{
int
rc
;
rc
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_CONT
,
pict
.
contrast
);
if
(
SENSOR_FATAL_ERROR
(
rc
))
return
rc
;
int
err
=
0
;
if
(
!
cam
->
auto_brt
)
{
rc
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_BRIGHT
,
pict
.
brightness
);
if
(
SENSOR_FATAL_ERROR
(
rc
))
return
rc
;
if
((
!
cam
->
sensor_initialized
)
||
pict
.
contrast
!=
cam
->
picture
.
contrast
)
{
err
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_CONT
,
pict
.
contrast
);
if
(
err
)
goto
fail
;
DBG
(
4
,
"Contrast changed from %d to %d."
,
cam
->
picture
.
contrast
,
pict
.
contrast
)
cam
->
picture
.
contrast
=
pict
.
contrast
;
}
rc
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_SAT
,
pict
.
colour
);
if
(
SENSOR_FATAL_ERROR
(
rc
))
return
rc
;
if
(((
!
cam
->
sensor_initialized
)
||
pict
.
brightness
!=
cam
->
picture
.
brightness
)
&&
(
!
cam
->
auto_brt
))
{
err
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_BRIGHT
,
pict
.
brightness
);
if
(
err
)
goto
fail
;
DBG
(
4
,
"Brightness changed from %d to %d."
,
cam
->
picture
.
brightness
,
pict
.
brightness
)
cam
->
picture
.
brightness
=
pict
.
brightness
;
}
rc
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_HUE
,
pict
.
hue
);
if
(
SENSOR_FATAL_ERROR
(
rc
))
return
rc
;
if
((
!
cam
->
sensor_initialized
)
||
pict
.
colour
!=
cam
->
picture
.
colour
)
{
err
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_SAT
,
pict
.
colour
);
if
(
err
)
goto
fail
;
DBG
(
4
,
"Colour changed from %d to %d."
,
cam
->
picture
.
colour
,
pict
.
colour
)
cam
->
picture
.
colour
=
pict
.
colour
;
}
PDBGG
(
"Brightness, contrast, hue, colour, whiteness are "
"%d,%d,%d,%d,%d."
,
pict
.
brightness
,
pict
.
contrast
,
pict
.
hue
,
pict
.
colour
,
pict
.
whiteness
)
if
((
!
cam
->
sensor_initialized
)
||
pict
.
hue
!=
cam
->
picture
.
hue
)
{
err
=
w9968cf_sensor_set_control
(
cam
,
OVCAMCHIP_CID_HUE
,
pict
.
hue
);
if
(
err
)
goto
fail
;
DBG
(
4
,
"Hue changed from %d to %d."
,
cam
->
picture
.
hue
,
pict
.
hue
)
cam
->
picture
.
hue
=
pict
.
hue
;
}
return
0
;
fail:
DBG
(
4
,
"Failed to change sensor picture setting."
)
return
err
;
}
...
...
@@ -2353,12 +2347,22 @@ w9968cf_sensor_set_picture(struct w9968cf_device* cam,
****************************************************************************/
/*--------------------------------------------------------------------------
This function is called when the CMOS sensor is detected.
This function is called when a supported CMOS sensor is detected.
Return 0 if the initialization succeeds, a negative number otherwise.
--------------------------------------------------------------------------*/
static
void
w9968cf_sensor_configure
(
struct
w9968cf_device
*
cam
)
static
int
w9968cf_sensor_init
(
struct
w9968cf_device
*
cam
)
{
/* NOTE: Make sure width and height are a multiple of 16 */
int
err
=
0
;
if
((
err
=
w9968cf_sensor_cmd
(
cam
,
OVCAMCHIP_CMD_INITIALIZE
,
&
cam
->
monochrome
)))
goto
error
;
if
((
err
=
w9968cf_sensor_cmd
(
cam
,
OVCAMCHIP_CMD_Q_SUBTYPE
,
&
cam
->
sensor
)))
goto
error
;
/* NOTE: Make sure width and height are a multiple of 16 */
switch
(
cam
->
sensor_client
->
addr
)
{
case
OV6xx0_SID
:
cam
->
maxwidth
=
352
;
...
...
@@ -2372,6 +2376,10 @@ static void w9968cf_sensor_configure(struct w9968cf_device* cam)
cam
->
minwidth
=
64
;
cam
->
minheight
=
48
;
break
;
default:
DBG
(
1
,
"Not supported CMOS sensor detected for %s."
,
symbolic
(
camlist
,
cam
->
id
))
return
-
EINVAL
;
}
/* These values depend on the ones in the ovxxx0.c sources */
...
...
@@ -2390,7 +2398,24 @@ static void w9968cf_sensor_configure(struct w9968cf_device* cam)
cam
->
hs_polarity
=
0
;
}
DBG
(
5
,
"CMOS sensor %s configured."
,
symbolic
(
senlist
,
cam
->
sensor
))
if
((
err
=
w9968cf_sensor_update_settings
(
cam
)))
goto
error
;
if
((
err
=
w9968cf_sensor_update_picture
(
cam
,
cam
->
picture
)))
goto
error
;
cam
->
sensor_initialized
=
1
;
DBG
(
2
,
"%s CMOS sensor initialized."
,
symbolic
(
senlist
,
cam
->
sensor
))
return
0
;
error:
cam
->
sensor_initialized
=
0
;
cam
->
sensor
=
CC_UNKNOWN
;
DBG
(
1
,
"CMOS sensor initialization failed for %s (/dev/video%d). "
"Try to detach and attach this device again."
,
symbolic
(
camlist
,
cam
->
id
),
cam
->
v4ldev
->
minor
)
return
err
;
}
...
...
@@ -2415,13 +2440,7 @@ w9968cf_configure_camera(struct w9968cf_device* cam,
cam
->
usbdev
=
udev
;
cam
->
id
=
mod_id
;
cam
->
sensor
=
CC_UNKNOWN
;
strcpy
(
cam
->
v4ldev
.
name
,
symbolic
(
camlist
,
mod_id
));
cam
->
v4ldev
.
type
=
VID_TYPE_CAPTURE
|
VID_TYPE_SCALES
;
cam
->
v4ldev
.
hardware
=
VID_HARDWARE_W9968CF
;
cam
->
v4ldev
.
fops
=
&
w9968cf_fops
;
cam
->
v4ldev
.
priv
=
(
void
*
)
cam
;
cam
->
v4ldev
.
minor
=
video_nr
[
dev_nr
];
cam
->
sensor_initialized
=
0
;
/* Calculate the alternate setting number (from 1 to 16)
according to the 'packet_size' module parameter */
...
...
@@ -2433,66 +2452,66 @@ w9968cf_configure_camera(struct w9968cf_device* cam,
cam
->
max_buffers
=
(
max_buffers
[
dev_nr
]
<
2
||
max_buffers
[
dev_nr
]
>
W9968CF_MAX_BUFFERS
)
?
W9968CF_BUFFERS
:
max_buffers
[
dev_nr
];
?
W9968CF_BUFFERS
:
(
u8
)
max_buffers
[
dev_nr
];
cam
->
double_buffer
=
(
double_buffer
[
dev_nr
]
==
0
||
double_buffer
[
dev_nr
]
==
1
)
?
double_buffer
[
dev_nr
]
:
W9968CF_DOUBLE_BUFFER
;
?
(
u8
)
double_buffer
[
dev_nr
]
:
W9968CF_DOUBLE_BUFFER
;
cam
->
clamping
=
(
clamping
[
dev_nr
]
==
0
||
clamping
[
dev_nr
]
==
1
)
?
clamping
[
dev_nr
]
:
W9968CF_CLAMPING
;
?
(
u8
)
clamping
[
dev_nr
]
:
W9968CF_CLAMPING
;
cam
->
filter_type
=
(
filter_type
[
dev_nr
]
==
0
||
filter_type
[
dev_nr
]
==
1
||
filter_type
[
dev_nr
]
==
2
)
?
filter_type
[
dev_nr
]
:
W9968CF_FILTER_TYPE
;
?
(
u8
)
filter_type
[
dev_nr
]
:
W9968CF_FILTER_TYPE
;
cam
->
capture
=
1
;
cam
->
largeview
=
(
largeview
[
dev_nr
]
==
0
||
largeview
[
dev_nr
]
==
1
)
?
largeview
[
dev_nr
]
:
W9968CF_LARGEVIEW
;
?
(
u8
)
largeview
[
dev_nr
]
:
W9968CF_LARGEVIEW
;
cam
->
decompression
=
(
decompression
[
dev_nr
]
==
0
||
decompression
[
dev_nr
]
==
1
||
decompression
[
dev_nr
]
==
2
)
?
decompression
[
dev_nr
]
:
W9968CF_DECOMPRESSION
;
?
(
u8
)
decompression
[
dev_nr
]
:
W9968CF_DECOMPRESSION
;
cam
->
upscaling
=
(
upscaling
[
dev_nr
]
==
0
||
upscaling
[
dev_nr
]
==
1
)
?
upscaling
[
dev_nr
]
:
W9968CF_UPSCALING
;
?
(
u8
)
upscaling
[
dev_nr
]
:
W9968CF_UPSCALING
;
cam
->
auto_brt
=
(
autobright
[
dev_nr
]
==
0
||
autobright
[
dev_nr
]
==
1
)
?
autobright
[
dev_nr
]
:
W9968CF_AUTOBRIGHT
;
?
(
u8
)
autobright
[
dev_nr
]
:
W9968CF_AUTOBRIGHT
;
cam
->
auto_exp
=
(
autoexp
[
dev_nr
]
==
0
||
autoexp
[
dev_nr
]
==
1
)
?
autoexp
[
dev_nr
]
:
W9968CF_AUTOEXP
;
?
(
u8
)
autoexp
[
dev_nr
]
:
W9968CF_AUTOEXP
;
cam
->
lightfreq
=
(
lightfreq
[
dev_nr
]
==
50
||
lightfreq
[
dev_nr
]
==
60
)
?
lightfreq
[
dev_nr
]
:
W9968CF_LIGHTFREQ
;
?
(
u8
)
lightfreq
[
dev_nr
]
:
W9968CF_LIGHTFREQ
;
cam
->
bandfilt
=
(
bandingfilter
[
dev_nr
]
==
0
||
bandingfilter
[
dev_nr
]
==
1
)
?
bandingfilter
[
dev_nr
]
:
W9968CF_BANDINGFILTER
;
?
(
u8
)
bandingfilter
[
dev_nr
]
:
W9968CF_BANDINGFILTER
;
cam
->
backlight
=
(
backlight
[
dev_nr
]
==
0
||
backlight
[
dev_nr
]
==
1
)
?
backlight
[
dev_nr
]
:
W9968CF_BACKLIGHT
;
?
(
u8
)
backlight
[
dev_nr
]
:
W9968CF_BACKLIGHT
;
cam
->
clockdiv
=
(
clockdiv
[
dev_nr
]
==
-
1
||
clockdiv
[
dev_nr
]
>=
0
)
?
clockdiv
[
dev_nr
]
:
W9968CF_CLOCKDIV
;
?
(
s8
)
clockdiv
[
dev_nr
]
:
W9968CF_CLOCKDIV
;
cam
->
mirror
=
(
mirror
[
dev_nr
]
==
0
||
mirror
[
dev_nr
]
==
1
)
?
mirror
[
dev_nr
]
:
W9968CF_MIRROR
;
cam
->
sensor_mono
=
(
sensor_mono
[
dev_nr
]
==
0
||
sensor_mono
[
dev_nr
]
==
1
)
?
sensor_mono
[
dev_nr
]
:
W9968CF_SENSOR_MONO
;
cam
->
picture
.
brightness
=
brightness
[
dev_nr
];
cam
->
picture
.
hue
=
hue
[
dev_nr
];
cam
->
picture
.
colour
=
colour
[
dev_nr
];
cam
->
picture
.
contrast
=
contrast
[
dev_nr
];
cam
->
picture
.
whiteness
=
whiteness
[
dev_nr
];
if
(
w9968cf_valid_palette
(
force_palette
[
dev_nr
]))
{
cam
->
picture
.
palette
=
force_palette
[
dev_nr
];
?
(
u8
)
mirror
[
dev_nr
]
:
W9968CF_MIRROR
;
cam
->
monochrome
=
(
monochrome
[
dev_nr
]
==
0
||
monochrome
[
dev_nr
]
==
1
)
?
monochrome
[
dev_nr
]
:
W9968CF_MONOCHROME
;
cam
->
picture
.
brightness
=
(
u16
)
brightness
[
dev_nr
];
cam
->
picture
.
hue
=
(
u16
)
hue
[
dev_nr
];
cam
->
picture
.
colour
=
(
u16
)
colour
[
dev_nr
];
cam
->
picture
.
contrast
=
(
u16
)
contrast
[
dev_nr
];
cam
->
picture
.
whiteness
=
(
u16
)
whiteness
[
dev_nr
];
if
(
w9968cf_valid_palette
(
(
u16
)
force_palette
[
dev_nr
]))
{
cam
->
picture
.
palette
=
(
u16
)
force_palette
[
dev_nr
];
cam
->
force_palette
=
1
;
}
else
{
cam
->
force_palette
=
0
;
...
...
@@ -2505,7 +2524,7 @@ w9968cf_configure_camera(struct w9968cf_device* cam,
}
cam
->
force_rgb
=
(
force_rgb
[
dev_nr
]
==
0
||
force_rgb
[
dev_nr
]
==
1
)
?
force_rgb
[
dev_nr
]
:
W9968CF_FORCE_RGB
;
?
(
u8
)
force_rgb
[
dev_nr
]
:
W9968CF_FORCE_RGB
;
cam
->
window
.
x
=
0
;
cam
->
window
.
y
=
0
;
...
...
@@ -2610,7 +2629,7 @@ w9968cf_configure_camera(struct w9968cf_device* cam,
else
DBG
(
3
,
"- Clock divisor: %d"
,
cam
->
clockdiv
)
if
(
cam
->
sensor_mono
)
if
(
cam
->
monochrome
)
DBG
(
3
,
"- CMOS sensor used as monochrome."
)
else
DBG
(
3
,
"- CMOS sensor not used as monochrome."
)
...
...
@@ -2626,9 +2645,9 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
{
down
(
&
w9968cf_devlist_sem
);
DBG
(
2
,
"V4L device deregistered: /dev/video%d"
,
cam
->
v4ldev
.
minor
)
DBG
(
2
,
"V4L device deregistered: /dev/video%d"
,
cam
->
v4ldev
->
minor
)
video_unregister_device
(
&
cam
->
v4ldev
);
video_unregister_device
(
cam
->
v4ldev
);
list_del
(
&
cam
->
v4llist
);
i2c_del_adapter
(
&
cam
->
i2c_adapter
);
w9968cf_deallocate_memory
(
cam
);
...
...
@@ -2648,24 +2667,25 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
static
int
w9968cf_open
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
struct
w9968cf_device
*
cam
=
(
struct
w9968cf_device
*
)
video_devdata
(
filp
)
->
priv
;
struct
w9968cf_device
*
cam
;
int
err
;
cam
=
(
struct
w9968cf_device
*
)
video_get_drvdata
(
video_devdata
(
filp
));
down
(
&
cam
->
dev_sem
);
if
(
cam
->
sensor
==
CC_UNKNOWN
)
{
DBG
(
2
,
"No supported CMOS sensor has been detected by the "
"'ovcamchip' module for the %s (/dev/video%d). Make "
"sure it is loaded *before* the 'w9968cf' module."
,
symbolic
(
camlist
,
cam
->
id
),
cam
->
v4ldev
.
minor
)
symbolic
(
camlist
,
cam
->
id
),
cam
->
v4ldev
->
minor
)
up
(
&
cam
->
dev_sem
);
return
-
ENODEV
;
}
if
(
cam
->
users
)
{
DBG
(
2
,
"%s (/dev/video%d) has been already occupied by '%s'."
,
symbolic
(
camlist
,
cam
->
id
),
cam
->
v4ldev
.
minor
,
cam
->
command
)
symbolic
(
camlist
,
cam
->
id
),
cam
->
v4ldev
->
minor
,
cam
->
command
)
if
((
filp
->
f_flags
&
O_NONBLOCK
)
||
(
filp
->
f_flags
&
O_NDELAY
))
{
up
(
&
cam
->
dev_sem
);
return
-
EWOULDBLOCK
;
...
...
@@ -2680,8 +2700,8 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
down
(
&
cam
->
dev_sem
);
}
DBG
(
5
,
"Opening
the %s
, /dev/video%d ..."
,
symbolic
(
camlist
,
cam
->
id
),
cam
->
v4ldev
.
minor
)
DBG
(
5
,
"Opening
'%s'
, /dev/video%d ..."
,
symbolic
(
camlist
,
cam
->
id
),
cam
->
v4ldev
->
minor
)
cam
->
streaming
=
0
;
cam
->
misconfigured
=
0
;
...
...
@@ -2698,7 +2718,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
if
((
err
=
w9968cf_start_transfer
(
cam
)))
goto
deallocate_memory
;
filp
->
private_data
=
(
void
*
)
cam
;
filp
->
private_data
=
cam
;
cam
->
users
++
;
strcpy
(
cam
->
command
,
current
->
comm
);
...
...
@@ -2720,8 +2740,9 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
static
int
w9968cf_release
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
struct
w9968cf_device
*
cam
=
(
struct
w9968cf_device
*
)
video_devdata
(
filp
)
->
priv
;
struct
w9968cf_device
*
cam
;
cam
=
(
struct
w9968cf_device
*
)
video_get_drvdata
(
video_devdata
(
filp
));
down
(
&
cam
->
dev_sem
);
/* prevent disconnect() to be called */
...
...
@@ -2749,11 +2770,12 @@ static int w9968cf_release(struct inode* inode, struct file* filp)
static
ssize_t
w9968cf_read
(
struct
file
*
filp
,
char
*
buf
,
size_t
count
,
loff_t
*
f_pos
)
{
struct
w9968cf_device
*
cam
=
(
struct
w9968cf_device
*
)
video_devdata
(
filp
)
->
priv
;
struct
w9968cf_device
*
cam
;
struct
w9968cf_frame_t
*
fr
;
int
err
=
0
;
cam
=
(
struct
w9968cf_device
*
)
video_get_drvdata
(
video_devdata
(
filp
));
if
(
filp
->
f_flags
&
O_NONBLOCK
)
return
-
EWOULDBLOCK
;
...
...
@@ -2817,9 +2839,8 @@ w9968cf_read(struct file* filp, char* buf, size_t count, loff_t* f_pos)
static
int
w9968cf_mmap
(
struct
file
*
filp
,
struct
vm_area_struct
*
vma
)
{
struct
w9968cf_device
*
cam
=
(
struct
w9968cf_device
*
)
video_devdata
(
filp
)
->
priv
;
struct
w9968cf_device
*
cam
=
(
struct
w9968cf_device
*
)
video_get_drvdata
(
video_devdata
(
filp
));
unsigned
long
vsize
=
vma
->
vm_end
-
vma
->
vm_start
,
psize
=
cam
->
nbuffers
*
w9968cf_get_max_bufsize
(
cam
),
start
=
vma
->
vm_start
,
...
...
@@ -2860,10 +2881,11 @@ static int
w9968cf_ioctl
(
struct
inode
*
inode
,
struct
file
*
filp
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
struct
w9968cf_device
*
cam
=
(
struct
w9968cf_device
*
)
video_devdata
(
filp
)
->
priv
;
struct
w9968cf_device
*
cam
;
int
err
;
cam
=
(
struct
w9968cf_device
*
)
video_get_drvdata
(
video_devdata
(
filp
));
if
(
down_interruptible
(
&
cam
->
fileop_sem
))
return
-
ERESTARTSYS
;
...
...
@@ -2879,7 +2901,7 @@ w9968cf_ioctl(struct inode* inode, struct file* filp,
return
-
EIO
;
}
err
=
w9968cf_
do_ioctl
(
cam
,
cmd
,
(
void
*
)
arg
);
err
=
w9968cf_
v4l_ioctl
(
inode
,
filp
,
cmd
,
(
void
*
)
arg
);
up
(
&
cam
->
fileop_sem
);
return
err
;
...
...
@@ -2887,8 +2909,10 @@ w9968cf_ioctl(struct inode* inode, struct file* filp,
static
int
w9968cf_do_ioctl
(
struct
w9968cf_device
*
cam
,
unsigned
cmd
,
void
*
arg
)
w9968cf_v4l_ioctl
(
struct
inode
*
inode
,
struct
file
*
filp
,
unsigned
int
cmd
,
void
*
arg
)
{
struct
w9968cf_device
*
cam
;
const
char
*
v4l1_ioctls
[]
=
{
"?"
,
"CGAP"
,
"GCHAN"
,
"SCHAN"
,
"GTUNER"
,
"STUNER"
,
"GPICT"
,
"SPICT"
,
"CCAPTURE"
,
"GWIN"
,
"SWIN"
,
"GFBUF"
,
...
...
@@ -2900,7 +2924,9 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
#define V4L1_IOCTL(cmd) \
((_IOC_NR((cmd)) < sizeof(v4l1_ioctls)/sizeof(char*)) ? \
v4l1_ioctls[_IOC_NR((cmd))] : "???")
v4l1_ioctls[_IOC_NR((cmd))] : "?")
cam
=
(
struct
w9968cf_device
*
)
video_get_drvdata
(
video_devdata
(
filp
));
switch
(
cmd
)
{
...
...
@@ -2914,7 +2940,7 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
.
minheight
=
cam
->
minheight
,
};
sprintf
(
cap
.
name
,
"W996[87]CF USB Camera #%d"
,
cam
->
v4ldev
.
minor
);
cam
->
v4ldev
->
minor
);
cap
.
maxwidth
=
(
cam
->
upscaling
&&
w9968cf_vppmod_present
)
?
W9968CF_MAX_WIDTH
:
cam
->
maxwidth
;
cap
.
maxheight
=
(
cam
->
upscaling
&&
w9968cf_vppmod_present
)
...
...
@@ -2965,15 +2991,10 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
case
VIDIOCGPICT
:
/* get image properties of the picture */
{
struct
video_picture
pict
;
if
(
w9968cf_sensor_get_picture
(
cam
,
&
pict
))
if
(
w9968cf_sensor_get_picture
(
cam
))
return
-
EIO
;
pict
.
depth
=
cam
->
picture
.
depth
;
pict
.
palette
=
cam
->
picture
.
palette
;
if
(
copy_to_user
(
arg
,
&
pict
,
sizeof
(
pict
)))
if
(
copy_to_user
(
arg
,
&
cam
->
picture
,
sizeof
(
cam
->
picture
)))
return
-
EFAULT
;
DBG
(
5
,
"VIDIOCGPICT successfully called."
)
...
...
@@ -3002,13 +3023,6 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
return
-
EINVAL
;
}
if
(
pict
.
depth
!=
w9968cf_valid_depth
(
pict
.
palette
))
{
DBG
(
4
,
"Depth %d bpp is not supported for %s palette. "
"VIDIOCSPICT failed."
,
pict
.
depth
,
symbolic
(
v4l1_plist
,
pict
.
palette
))
return
-
EINVAL
;
}
if
(
!
cam
->
force_palette
)
{
if
(
cam
->
decompression
==
0
)
{
if
(
w9968cf_need_decompression
(
pict
.
palette
))
{
...
...
@@ -3027,9 +3041,15 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
}
}
if
(
pict
.
palette
!=
cam
->
picture
.
palette
||
pict
.
depth
!=
cam
->
picture
.
depth
)
{
if
(
pict
.
depth
!=
w9968cf_valid_depth
(
pict
.
palette
))
{
DBG
(
4
,
"Requested depth %d bpp is not valid for %s "
"palette: ignored and changed to %d bpp."
,
pict
.
depth
,
symbolic
(
v4l1_plist
,
pict
.
palette
),
w9968cf_valid_depth
(
pict
.
palette
))
pict
.
depth
=
w9968cf_valid_depth
(
pict
.
palette
);
}
if
(
pict
.
palette
!=
cam
->
picture
.
palette
)
{
if
(
*
cam
->
requested_frame
||
cam
->
frame_current
->
queued
)
{
err
=
wait_event_interruptible
...
...
@@ -3052,15 +3072,9 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
if
(
w9968cf_start_transfer
(
cam
))
goto
ioctl_fail
;
}
else
if
(
((
pict
.
brightness
!=
cam
->
picture
.
brightness
)
&&
(
!
cam
->
auto_brt
))
||
pict
.
hue
!=
cam
->
picture
.
hue
||
pict
.
colour
!=
cam
->
picture
.
colour
||
pict
.
contrast
!=
cam
->
picture
.
contrast
||
pict
.
whiteness
!=
cam
->
picture
.
whiteness
)
{
if
(
w9968cf_sensor_set_picture
(
cam
,
pict
))
return
-
EIO
;
}
}
else
if
(
w9968cf_sensor_update_picture
(
cam
,
pict
))
return
-
EIO
;
DBG
(
5
,
"VIDIOCSPICT successfully called."
)
return
0
;
...
...
@@ -3092,7 +3106,6 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
win
.
y
!=
cam
->
window
.
y
||
win
.
width
!=
cam
->
window
.
width
||
win
.
height
!=
cam
->
window
.
height
)
{
if
(
*
cam
->
requested_frame
||
cam
->
frame_current
->
queued
)
{
err
=
wait_event_interruptible
...
...
@@ -3203,12 +3216,12 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
}
}
if
(
w9968cf_adjust_window_size
(
cam
,
(
u16
*
)
&
mmap
.
width
,
(
u16
*
)
&
mmap
.
height
))
{
if
(
(
err
=
w9968cf_adjust_window_size
(
cam
,
(
u16
*
)
&
mmap
.
width
,
(
u16
*
)
&
mmap
.
height
)
))
{
DBG
(
4
,
"Resolution not supported (%dx%d). "
"VIDIOCMCAPTURE failed."
,
mmap
.
width
,
mmap
.
height
)
return
-
EINVAL
;
return
err
;
}
fr
=
&
cam
->
frame
[
mmap
.
frame
];
...
...
@@ -3276,10 +3289,13 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
case
VIDIOCSYNC
:
/* wait until the capture of a frame is finished */
{
unsigned
int
f_num
=
*
((
unsigned
int
*
)
arg
)
;
unsigned
int
f_num
;
struct
w9968cf_frame_t
*
fr
;
int
err
=
0
;
if
(
copy_from_user
(
&
f_num
,
arg
,
sizeof
(
f_num
)))
return
-
EFAULT
;
if
(
f_num
>=
cam
->
nbuffers
)
{
DBG
(
4
,
"Invalid frame number (%d). "
"VIDIOCMCAPTURE failed."
,
f_num
)
...
...
@@ -3323,7 +3339,7 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
case
VIDIOCGUNIT
:
/* report the unit numbers of the associated devices*/
{
struct
video_unit
unit
=
{
.
video
=
cam
->
v4ldev
.
minor
,
.
video
=
cam
->
v4ldev
->
minor
,
.
vbi
=
VIDEO_NO_UNIT
,
.
radio
=
VIDEO_NO_UNIT
,
.
audio
=
VIDEO_NO_UNIT
,
...
...
@@ -3342,9 +3358,8 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
case
VIDIOCGFBUF
:
{
struct
video_buffer
*
buffer
=
(
struct
video_buffer
*
)
arg
;
memset
(
buffer
,
0
,
sizeof
(
struct
video_buffer
));
if
(
clear_user
(
arg
,
sizeof
(
struct
video_buffer
)))
return
-
EFAULT
;
DBG
(
5
,
"VIDIOCGFBUF successfully called."
)
return
0
;
...
...
@@ -3470,10 +3485,6 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
else
return
-
ENODEV
;
/* We don't handle multi-config cameras */
if
(
udev
->
descriptor
.
bNumConfigurations
!=
1
)
return
-
ENODEV
;
DBG
(
2
,
"%s detected."
,
symbolic
(
camlist
,
mod_id
))
if
(
simcams
>
W9968CF_MAX_DEVICES
)
...
...
@@ -3491,14 +3502,6 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
return
-
EPERM
;
}
err
=
usb_set_configuration
(
udev
,
1
);
err
+=
usb_set_interface
(
udev
,
0
,
0
);
if
(
err
)
{
DBG
(
1
,
"Device configuration failed."
)
return
-
EIO
;
}
cam
=
(
struct
w9968cf_device
*
)
kmalloc
(
sizeof
(
struct
w9968cf_device
),
GFP_KERNEL
);
...
...
@@ -3530,10 +3533,24 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
}
memset
(
cam
->
data_buffer
,
0
,
8
);
/* Set some basic constants */
w9968cf_configure_camera
(
cam
,
udev
,
mod_id
,
dev_nr
);
/* Register the V4L device */
cam
->
v4ldev
=
video_device_alloc
();
if
(
!
cam
->
v4ldev
)
{
DBG
(
1
,
"Could not allocate memory for a V4L structure."
)
err
=
-
ENOMEM
;
goto
fail
;
}
err
=
video_register_device
(
&
cam
->
v4ldev
,
VFL_TYPE_GRABBER
,
strcpy
(
cam
->
v4ldev
->
name
,
symbolic
(
camlist
,
mod_id
));
cam
->
v4ldev
->
owner
=
THIS_MODULE
;
cam
->
v4ldev
->
type
=
VID_TYPE_CAPTURE
|
VID_TYPE_SCALES
;
cam
->
v4ldev
->
hardware
=
VID_HARDWARE_W9968CF
;
cam
->
v4ldev
->
fops
=
&
w9968cf_fops
;
cam
->
v4ldev
->
minor
=
video_nr
[
dev_nr
];
cam
->
v4ldev
->
release
=
video_device_release
;
video_set_drvdata
(
cam
->
v4ldev
,
cam
);
err
=
video_register_device
(
cam
->
v4ldev
,
VFL_TYPE_GRABBER
,
video_nr
[
dev_nr
]);
if
(
err
)
{
DBG
(
1
,
"V4L device registration failed."
)
...
...
@@ -3544,13 +3561,15 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto
fail
;
}
DBG
(
2
,
"V4L device registered as /dev/video%d
"
,
cam
->
v4ldev
.
minor
)
DBG
(
2
,
"V4L device registered as /dev/video%d
."
,
cam
->
v4ldev
->
minor
)
/* Ok, add a new entry into the list of V4L registered devices */
/* Set some basic constants */
w9968cf_configure_camera
(
cam
,
udev
,
mod_id
,
dev_nr
);
/* Add a new entry into the list of V4L registered devices */
down
(
&
w9968cf_devlist_sem
);
list_add
(
&
cam
->
v4llist
,
&
w9968cf_dev_list
);
up
(
&
w9968cf_devlist_sem
);
dev_nr
=
(
dev_nr
<
W9968CF_MAX_DEVICES
-
1
)
?
dev_nr
+
1
:
0
;
w9968cf_turn_on_led
(
cam
);
...
...
@@ -3559,8 +3578,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
up
(
&
cam
->
dev_sem
);
dev_set_drvdata
(
&
intf
->
dev
,
(
void
*
)
cam
);
usb_set_intfdata
(
intf
,
cam
);
return
0
;
fail:
/* Free unused memory */
...
...
@@ -3569,6 +3587,8 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
kfree
(
cam
->
control_buffer
);
if
(
cam
->
data_buffer
)
kfree
(
cam
->
data_buffer
);
if
(
cam
->
v4ldev
)
video_device_release
(
cam
->
v4ldev
);
up
(
&
cam
->
dev_sem
);
kfree
(
cam
);
}
...
...
@@ -3579,9 +3599,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
static
void
w9968cf_usb_disconnect
(
struct
usb_interface
*
intf
)
{
struct
w9968cf_device
*
cam
=
(
struct
w9968cf_device
*
)
dev_get_drvdata
(
&
intf
->
dev
);
dev_set_drvdata
(
&
intf
->
dev
,
NULL
);
(
struct
w9968cf_device
*
)
usb_get_intfdata
(
intf
);
if
(
cam
)
{
/* Prevent concurrent accesses to data */
...
...
@@ -3599,7 +3617,7 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
DBG
(
2
,
"The device is open (/dev/video%d)! "
"Process name: %s. Deregistration and memory "
"deallocation are deferred on close."
,
cam
->
v4ldev
.
minor
,
cam
->
command
)
cam
->
v4ldev
->
minor
,
cam
->
command
)
cam
->
misconfigured
=
1
;
...
...
@@ -3613,6 +3631,8 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
if
(
!
cam
->
users
)
kfree
(
cam
);
}
usb_set_intfdata
(
intf
,
NULL
);
}
...
...
drivers/usb/media/w9968cf.h
View file @
0e8f510d
/***************************************************************************
* Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. *
* *
* Copyright (C) 2002
2003 by Luca Risolia <luca_ing@libero.it>
*
* Copyright (C) 2002
-2004 by Luca Risolia <luca.risolia@studio.unibo.it>
*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
...
...
@@ -28,6 +28,7 @@
#include <linux/list.h>
#include <linux/wait.h>
#include <linux/config.h>
#include <linux/param.h>
#include <asm/semaphore.h>
#include <asm/types.h>
...
...
@@ -105,7 +106,7 @@ static const struct w9968cf_format w9968cf_formatlist[] = {
#define W9968CF_LARGEVIEW 1
/* 0 disable, 1 enable */
#define W9968CF_UPSCALING 0
/* 0 disable, 1 enable */
#define W9968CF_
SENSOR_MONO
0
/* 0 not monochrome, 1 monochrome sensor */
#define W9968CF_
MONOCHROME
0
/* 0 not monochrome, 1 monochrome sensor */
#define W9968CF_BRIGHTNESS 31000
/* from 0 to 65535 */
#define W9968CF_HUE 32768
/* from 0 to 65535 */
#define W9968CF_COLOUR 32768
/* from 0 to 65535 */
...
...
@@ -129,9 +130,10 @@ static const struct w9968cf_format w9968cf_formatlist[] = {
#define W9968CF_MODULE_NAME "V4L driver for W996[87]CF JPEG USB " \
"Dual Mode Camera Chip"
#define W9968CF_MODULE_VERSION "v1.22"
#define W9968CF_MODULE_AUTHOR "(C) 2002 2003 Luca Risolia"
#define W9968CF_AUTHOR_EMAIL "<luca_ing@libero.it>"
#define W9968CF_MODULE_VERSION "v1.25-basic"
#define W9968CF_MODULE_AUTHOR "(C) 2002-2004 Luca Risolia"
#define W9968CF_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define W9968CF_MODULE_LICENSE "GPL"
static
u8
w9968cf_vppmod_present
;
/* status flag: yes=1, no=0 */
...
...
@@ -171,6 +173,7 @@ enum w9968cf_frame_status {
};
struct
w9968cf_frame_t
{
#define W9968CF_HW_BUF_SIZE 640*480*2
/* buf.size of original frames */
void
*
buffer
;
u32
length
;
enum
w9968cf_frame_status
status
;
...
...
@@ -194,8 +197,8 @@ struct semaphore w9968cf_devlist_sem; /* semaphore for list traversal */
struct
w9968cf_device
{
enum
w9968cf_model_id
id
;
/* private device identifier */
struct
video_device
v4ldev
;
/*
V4L structure */
struct
list_head
v4llist
;
/* entry of the list of V4L cameras */
struct
video_device
*
v4ldev
;
/* ->
V4L structure */
struct
list_head
v4llist
;
/* entry of the list of V4L cameras */
struct
usb_device
*
usbdev
;
/* -> main USB structure */
struct
urb
*
urb
[
W9968CF_URBS
];
/* -> USB request block structs */
...
...
@@ -207,9 +210,9 @@ struct w9968cf_device {
struct
w9968cf_frame_t
frame_tmp
;
/* temporary frame */
struct
w9968cf_frame_t
*
frame_current
;
/* -> frame being grabbed */
struct
w9968cf_frame_t
*
requested_frame
[
W9968CF_MAX_BUFFERS
];
void
*
vpp_buffer
;
/*
-> helper buffer for
post-processing routines */
void
*
vpp_buffer
;
/*
-> helper buf.for video
post-processing routines */
u8
max_buffers
,
/* number of requested buffers */
u8
max_buffers
,
/* number of requested buffers */
force_palette
,
/* yes=1/no=0 */
force_rgb
,
/* read RGB instead of BGR, yes=1, no=0 */
double_buffer
,
/* hardware double buffering yes=1/no=0 */
...
...
@@ -220,15 +223,17 @@ struct w9968cf_device {
decompression
,
/* 0=disabled, 1=forced, 2=allowed */
upscaling
;
/* software image scaling, 0=enabled, 1=disabled */
struct
video_picture
picture
;
/* current
window
settings */
struct
video_window
window
;
/* current
picture
settings */
struct
video_picture
picture
;
/* current
picture
settings */
struct
video_window
window
;
/* current
window
settings */
u16
hw_depth
,
/* depth (used by the chip) */
hw_palette
,
/* palette (used by the chip) */
hw_width
,
/* width (used by the chip) */
hw_height
,
/* height (used by the chip) */
hs_polarity
,
/* 0=negative sync pulse, 1=positive sync pulse */
vs_polarity
;
/* 0=negative sync pulse, 1=positive sync pulse */
vs_polarity
,
/* 0=negative sync pulse, 1=positive sync pulse */
start_cropx
,
/* pixels from HS inactive edge to 1st cropped pixel*/
start_cropy
;
/* pixels from VS incative edge to 1st cropped pixel*/
enum
w9968cf_vpp_flag
vpp_flag
;
/* post-processing routines in use */
...
...
@@ -239,16 +244,15 @@ struct w9968cf_device {
users
,
/* flag: number of users holding the device */
streaming
;
/* flag: yes=1, no=0 */
int
sensor
;
/* type of image CMOS sensor chip (CC_*) */
/* Determined by CMOS sensor type */
u16
maxwidth
,
maxheight
,
minwidth
,
minheight
,
start_cropx
,
start_cropy
;
u8
sensor_initialized
;
/* flag: yes=1, no=0 */
/* Determined by CMOS sensor type: */
int
sensor
,
/* type of image sensor chip (CC_*) */
monochrome
;
/* CMOS sensor is (probably) monochrome */
u16
maxwidth
,
/* maximum width supported by the CMOS sensor */
maxheight
,
/* maximum height supported by the CMOS sensor */
minwidth
,
/* minimum width supported by the CMOS sensor */
minheight
;
/* minimum height supported by the CMOS sensor */
u8
auto_brt
,
/* auto brightness enabled flag */
auto_exp
,
/* auto exposure enabled flag */
backlight
,
/* backlight exposure algorithm flag */
...
...
@@ -256,7 +260,6 @@ struct w9968cf_device {
lightfreq
,
/* power (lighting) frequency */
bandfilt
;
/* banding filter enabled flag */
s8
clockdiv
;
/* clock divisor */
int
sensor_mono
;
/* CMOS sensor is (probably) monochrome */
/* I2C interface to kernel */
struct
i2c_adapter
i2c_adapter
;
...
...
@@ -271,14 +274,9 @@ struct w9968cf_device {
wait_queue_head_t
open
,
wait_queue
;
};
#define W9968CF_HW_BUF_SIZE 640*480*2
/* buf. size for original video frames */
#define SENSOR_FORMAT VIDEO_PALETTE_UYVY
#define SENSOR_FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
/****************************************************************************
* Macros
and other constants
*
* Macros
for debugging
*
****************************************************************************/
#undef DBG
...
...
@@ -294,7 +292,7 @@ if ( ((specific_debug) && (debug == (level))) || \
else if ((level) == 4) \
warn(fmt, ## args); \
else if ((level) >= 5) \
info("[%s
,
%d] " fmt, \
info("[%s
:
%d] " fmt, \
__PRETTY_FUNCTION__, __LINE__ , ## args); \
} \
}
...
...
@@ -305,7 +303,7 @@ if ( ((specific_debug) && (debug == (level))) || \
#undef PDBG
#undef PDBGG
#define PDBG(fmt, args...) info("[%s
,
%d] "fmt, \
#define PDBG(fmt, args...) info("[%s
:
%d] "fmt, \
__PRETTY_FUNCTION__, __LINE__ , ## args);
#define PDBGG(fmt, args...) do {;} while(0);
/* nothing: it's a placeholder */
...
...
drivers/usb/media/w9968cf_decoder.h
View file @
0e8f510d
/***************************************************************************
* Video decoder for the W996[87]CF driver for Linux. *
* *
* Copyright (C) 2003
by Luca Risolia <luca_ing@libero.it>
*
* Copyright (C) 2003
2004 by Luca Risolia <luca.risolia@studio.unibo.it>
*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
...
...
drivers/usb/media/w9968cf_externaldef.h
View file @
0e8f510d
/***************************************************************************
* Various definitions for compatibility with
external modules.
*
* Various definitions for compatibility with
OVCAMCHIP external module.
*
* This file is part of the W996[87]CF driver for Linux. *
* *
* Copyright (C) 2002 2003 by Luca Risolia <luca_ing@libero.it> *
* The definitions have been taken from the OVCAMCHIP module written by *
* Mark McClelland. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
...
...
@@ -27,10 +28,8 @@
#include <asm/ioctl.h>
#include <asm/types.h>
/* The following values have been copied from the "ovcamchip" module. */
#ifndef I2C_DRIVERID_OVCAMCHIP
# define I2C_DRIVERID_OVCAMCHIP
0xf00f
# define I2C_DRIVERID_OVCAMCHIP 0xf00f
#endif
/* Controls */
...
...
@@ -77,10 +76,10 @@ struct ovcamchip_window {
int
width
;
int
height
;
int
format
;
int
quarter
;
/* Scale width and height down 2x */
int
quarter
;
/* Scale width and height down 2x */
/* This stuff will be removed eventually */
int
clockdiv
;
/* Clock divisor setting */
int
clockdiv
;
/* Clock divisor setting */
};
/* Commands.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment