Commit 0e8f510d authored by Luca Risolia's avatar Luca Risolia Committed by Greg Kroah-Hartman

[PATCH] USB: W996[87]CF driver update

This patch contains updates and one bug fix.
parent 8d4f1c82
...@@ -2670,9 +2670,9 @@ S: 70110 Kuopio ...@@ -2670,9 +2670,9 @@ S: 70110 Kuopio
S: Finland S: Finland
N: Luca Risolia N: Luca Risolia
E: luca_ing@libero.it E: luca.risolia@studio.unibo.it
D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chip D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chips
S: Via Libertà 41/a S: Via Liberta' 41/A
S: Osio Sotto, 24046, Bergamo S: Osio Sotto, 24046, Bergamo
S: Italy S: Italy
......
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 - - Documentation -
...@@ -11,15 +12,16 @@ Index ...@@ -11,15 +12,16 @@ Index
2. License 2. License
3. Overview 3. Overview
4. Supported devices 4. Supported devices
5. Kernel configuration and third-part module compilation 5. Module dependencies
6. Module loading 6. Module loading
7. Module paramaters 7. Module paramaters
8. Credits 8. Contact information
9. Credits
1. Copyright 1. Copyright
============ ============
Copyright (C) 2002 2003 by Luca Risolia <luca_ing@libero.it> Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>
2. License 2. License
...@@ -43,23 +45,25 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ...@@ -43,23 +45,25 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
=========== ===========
This driver supports the video streaming capabilities of the devices mounting This driver supports the video streaming capabilities of the devices mounting
Winbond W9967CF and Winbond W9968CF JPEG USB Dual Mode Camera Chips, when they 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 The driver is divided into two modules: the basic one, "w9968cf", is needed for
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 supported devices to work; the second one, "w9968cf-vpp", is an optional the supported devices to work; the second one, "w9968cf-vpp", is an optional
module, which provides some useful video post-processing functions like video module, which provides some useful video post-processing functions like video
decoding, up-scaling and colour conversions. These routines can't be included decoding, up-scaling and colour conversions. Once the driver is installed,
into official kernels for performance purposes. Once the driver is installed,
every time an application tries to open a recognized device, "w9968cf" checks 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. 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 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 disconnected from the host many times without turning off the computer, if
your system supports the hotplug facility. your system supports the hotplug facility.
...@@ -67,18 +71,21 @@ 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 To change the default settings for each camera, many paramaters can be passed
through command line when the module is loaded into memory. 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: The driver relies on the Video4Linux, USB and I2C core modules of the official
http://go.lamarinapunto.com/ 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.25, which can be The "ovcamchip" module is part of the OV511 driver, version 2.27, which can be
downloaded from internet: downloaded from internet:
http://alpha.dyndns.org/ov511/ 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 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 - Aroma Digi Pen ADG-5000 Refurbished
- AVerTV USB - AVerTV USB
- Creative Labs Video Blaster WebCam Go - Creative Labs Video Blaster WebCam Go
...@@ -87,27 +94,26 @@ At the moment, known W996[87]CF based devices are: ...@@ -87,27 +94,26 @@ At the moment, known W996[87]CF based devices are:
- Ezonics EZ-802 EZMega Cam - Ezonics EZ-802 EZMega Cam
- OPCOM Digi Pen VGA Dual Mode Pen Camera - 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 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" until now only webcams that have a CMOS sensor supported by the "ovcamchip"
module work. module work.
For a list of supported CMOS sensors, please visit the module author homepage: For a list of supported CMOS sensors, please visit the author's homepage on
http://alpha.dyndns.org/ov511/ this module: http://alpha.dyndns.org/ov511/
Possible external microcontrollers of those webcams are not supported: this 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 cannot be downloaded from the device memory.
Furthermore, it's worth to note that I was only able to run tests on my 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 "Creative Labs Video Blaster WebCam Go". Donations of other models, for
additional testing and full support, would be much appreciated. additional testing and full support, would be much appreciated.
5. Kernel configuration and third-part module compilation 5. Module dependencies
========================================================= ======================
As noted above, kernel 2.6.0 is the minimum for this driver; for it to work For it to work properly, the driver needs kernel support for Video4Linux,
properly, the driver needs kernel support for Video4Linux, USB and I2C, and a USB and I2C, and a third-party module for the CMOS sensor.
third-part module for the CMOS sensor.
The following options of the kernel configuration file must be enabled and The following options of the kernel configuration file must be enabled and
corresponding modules must be compiled: corresponding modules must be compiled:
...@@ -126,7 +132,7 @@ The I2C core module can be compiled statically in the kernel as well. ...@@ -126,7 +132,7 @@ The I2C core module can be compiled statically in the kernel as well.
# #
CONFIG_USB=m 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: below is necessary:
# USB Host Controller Drivers # USB Host Controller Drivers
...@@ -137,31 +143,16 @@ below is necessary: ...@@ -137,31 +143,16 @@ below is necessary:
Also, make sure "Enforce bandwidth allocation" is NOT enabled. Also, make sure "Enforce bandwidth allocation" is NOT enabled.
And finally:
# USB Multimedia devices # USB Multimedia devices
# #
CONFIG_USB_W9968CF=m CONFIG_USB_W9968CF=m
The last module we need is "ovcamchip.o". To obtain it, you have to download 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 the OV511 package, version 2.27 - don't use other versions - and compile it
at http://alpha.dyndns.org/ov511/ . Then you have to download the latest according to its documentation.
version of the full featured W996[87]CF driver, which contains a patch for the The package is available at http://alpha.dyndns.org/ov511/ .
"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).
6. Module loading 6. Module loading
...@@ -169,7 +160,7 @@ paragraph). ...@@ -169,7 +160,7 @@ paragraph).
To use the driver, it is necessary to load the "w9968cf" module into memory To use the driver, it is necessary to load the "w9968cf" module into memory
after every other module required. 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 usbcore
[root@localhost home]# modprobe i2c-core [root@localhost home]# modprobe i2c-core
...@@ -191,11 +182,10 @@ explanation about them and which syntax to use, it is recommended to run the ...@@ -191,11 +182,10 @@ explanation about them and which syntax to use, it is recommended to run the
7. Module paramaters 7. Module paramaters
==================== ====================
Module paramaters are listed below: Module paramaters are listed below:
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: vppmod_load Name: vppmod_load
Type: int Type: bool
Syntax: <0|1> Syntax: <0|1>
Description: Automatic 'w9968cf-vpp' module loading: 0 disabled, 1 enabled. Description: Automatic 'w9968cf-vpp' module loading: 0 disabled, 1 enabled.
If enabled, every time an application attempts to open a If enabled, every time an application attempts to open a
...@@ -219,7 +209,7 @@ Syntax: <-1|n[,...]> ...@@ -219,7 +209,7 @@ Syntax: <-1|n[,...]>
Description: Specify V4L minor mode number. Description: Specify V4L minor mode number.
-1 = use next available -1 = use next available
n = use minor number n n = use minor number n
You can specify 32 cameras this way. You can specify up to 32 cameras this way.
For example: For example:
video_nr=-1,2,-1 would assign minor number 2 to the second 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 recognized camera and use auto for the first one and for every
...@@ -236,22 +226,22 @@ Default: 1023 ...@@ -236,22 +226,22 @@ Default: 1023
Name: max_buffers Name: max_buffers
Type: int array (min = 0, max = 32) Type: int array (min = 0, max = 32)
Syntax: <n[,...]> Syntax: <n[,...]>
Description: Only for advanced users. Description: For advanced users.
Specify the maximum number of video frame buffers to allocate Specify the maximum number of video frame buffers to allocate
for each device, from 2 to 32. for each device, from 2 to 32.
Default: 2 Default: 2
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: double_buffer Name: double_buffer
Type: int array (min = 0, max = 32) Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]> Syntax: <0|1[,...]>
Description: Hardware double buffering: 0 disabled, 1 enabled. Description: Hardware double buffering: 0 disabled, 1 enabled.
It should be enabled if you want smooth video output: if you 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. decrease the 'clockdiv' module paramater value.
Default: 1 for every device. Default: 1 for every device.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: clamping Name: clamping
Type: int array (min = 0, max = 32) Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]> Syntax: <0|1[,...]>
Description: Video data clamping: 0 disabled, 1 enabled. Description: Video data clamping: 0 disabled, 1 enabled.
Default: 0 for every device. Default: 0 for every device.
...@@ -266,13 +256,13 @@ Description: Video filter type. ...@@ -266,13 +256,13 @@ Description: Video filter type.
Default: 0 for every device. Default: 0 for every device.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: largeview Name: largeview
Type: int array (min = 0, max = 32) Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]> Syntax: <0|1[,...]>
Description: Large view: 0 disabled, 1 enabled. Description: Large view: 0 disabled, 1 enabled.
Default: 1 for every device. Default: 1 for every device.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: upscaling Name: upscaling
Type: int array (min = 0, max = 32) Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]> Syntax: <0|1[,...]>
Description: Software scaling (for non-compressed video only): Description: Software scaling (for non-compressed video only):
0 disabled, 1 enabled. 0 disabled, 1 enabled.
...@@ -319,7 +309,7 @@ Default: 0 for every device. Initial palette is 9 (UYVY). ...@@ -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. Note: If 'w9968cf-vpp' is not loaded, this paramater is set to 9.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: force_rgb Name: force_rgb
Type: int array (min = 0, max = 32) Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]> Syntax: <0|1[,...]>
Description: Read RGB video data instead of BGR: Description: Read RGB video data instead of BGR:
1 = use RGB component ordering. 1 = use RGB component ordering.
...@@ -328,28 +318,28 @@ Description: Read RGB video data instead of BGR: ...@@ -328,28 +318,28 @@ Description: Read RGB video data instead of BGR:
Default: 0 for every device. Default: 0 for every device.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: autobright Name: autobright
Type: long array (min = 0, max = 32) Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]> Syntax: <0|1[,...]>
Description: CMOS sensor automatically changes brightness: Description: CMOS sensor automatically changes brightness:
0 = no, 1 = yes 0 = no, 1 = yes
Default: 0 for every device. Default: 0 for every device.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: autoexp Name: autoexp
Type: long array (min = 0, max = 32) Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]> Syntax: <0|1[,...]>
Description: CMOS sensor automatically changes exposure: Description: CMOS sensor automatically changes exposure:
0 = no, 1 = yes 0 = no, 1 = yes
Default: 1 for every device. Default: 1 for every device.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: lightfreq Name: lightfreq
Type: long array (min = 0, max = 32) Type: int array (min = 0, max = 32)
Syntax: <50|60[,...]> Syntax: <50|60[,...]>
Description: Light frequency in Hz: Description: Light frequency in Hz:
50 for European and Asian lighting, 60 for American lighting. 50 for European and Asian lighting, 60 for American lighting.
Default: 50 for every device. Default: 50 for every device.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: bandingfilter Name: bandingfilter
Type: long array (min = 0, max = 32) Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]> Syntax: <0|1[,...]>
Description: Banding filter to reduce effects of fluorescent Description: Banding filter to reduce effects of fluorescent
lighting: lighting:
...@@ -359,7 +349,7 @@ Description: Banding filter to reduce effects of fluorescent ...@@ -359,7 +349,7 @@ Description: Banding filter to reduce effects of fluorescent
Default: 0 for every device. Default: 0 for every device.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: clockdiv Name: clockdiv
Type: long array (min = 0, max = 32) Type: int array (min = 0, max = 32)
Syntax: <-1|n[,...]> Syntax: <-1|n[,...]>
Description: Force pixel clock divisor to a specific value (for experts): Description: Force pixel clock divisor to a specific value (for experts):
n may vary from 0 to 127. n may vary from 0 to 127.
...@@ -368,21 +358,21 @@ Description: Force pixel clock divisor to a specific value (for experts): ...@@ -368,21 +358,21 @@ Description: Force pixel clock divisor to a specific value (for experts):
Default: -1 for every device. Default: -1 for every device.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: backlight Name: backlight
Type: long array (min = 0, max = 32) Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]> Syntax: <0|1[,...]>
Description: Objects are lit from behind: Description: Objects are lit from behind:
0 = no, 1 = yes 0 = no, 1 = yes
Default: 0 for every device. Default: 0 for every device.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: mirror Name: mirror
Type: long array (min = 0, max = 32) Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]> Syntax: <0|1[,...]>
Description: Reverse image horizontally: Description: Reverse image horizontally:
0 = no, 1 = yes 0 = no, 1 = yes
Default: 0 for every device. Default: 0 for every device.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: sensor_mono Name: monochrome
Type: long array (min = 0, max = 32) Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]> Syntax: <0|1[,...]>
Description: The CMOS sensor is monochrome: Description: The CMOS sensor is monochrome:
0 = no, 1 = yes 0 = no, 1 = yes
...@@ -423,7 +413,7 @@ Name: debug ...@@ -423,7 +413,7 @@ Name: debug
Type: int Type: int
Syntax: <n> Syntax: <n>
Description: Debugging information level, from 0 to 6: Description: Debugging information level, from 0 to 6:
0 = none (be cautious) 0 = none (use carefully)
1 = critical errors 1 = critical errors
2 = significant informations 2 = significant informations
3 = configuration or general messages 3 = configuration or general messages
...@@ -435,7 +425,7 @@ Description: Debugging information level, from 0 to 6: ...@@ -435,7 +425,7 @@ Description: Debugging information level, from 0 to 6:
Default: 2 Default: 2
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Name: specific_debug Name: specific_debug
Type: int Type: bool
Syntax: <0|1> Syntax: <0|1>
Description: Enable or disable specific debugging messages: Description: Enable or disable specific debugging messages:
0 = print messages concerning every level <= 'debug' level. 0 = print messages concerning every level <= 'debug' level.
...@@ -444,7 +434,16 @@ Default: 0 ...@@ -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 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 the source code of other drivers and without the help of several persons; in
...@@ -456,8 +455,6 @@ particular: ...@@ -456,8 +455,6 @@ particular:
- memory management code has been copied from the bttv driver by Ralph Metzler, - memory management code has been copied from the bttv driver by Ralph Metzler,
Marcus Metzler and Gerd Knorr; Marcus Metzler and Gerd Knorr;
- the low-level I2C read function has been written by Frédéric Jouault, who - the low-level I2C read function has been written by Frederic Jouault;
also gave me commented logs about sniffed USB traffic taken from another
driver for another system;
- 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.
...@@ -2223,7 +2223,7 @@ S: Maintained ...@@ -2223,7 +2223,7 @@ S: Maintained
USB W996[87]CF DRIVER USB W996[87]CF DRIVER
P: Luca Risolia P: Luca Risolia
M: luca_ing@libero.it M: luca.risolia@studio.unibo.it
L: linux-usb-devel@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net
W: http://go.lamarinapunto.com W: http://go.lamarinapunto.com
S: Maintained S: Maintained
......
...@@ -182,24 +182,21 @@ config USB_W9968CF ...@@ -182,24 +182,21 @@ config USB_W9968CF
tristate "USB W996[87]CF JPEG Dual Mode Camera support" tristate "USB W996[87]CF JPEG Dual Mode Camera support"
depends on USB && VIDEO_DEV && I2C depends on USB && VIDEO_DEV && I2C
---help--- ---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. Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
This driver has an optional plugin, which is distributed as a This driver has an optional plugin, which is distributed as a
separate module only (released under GPL). It contains code that separate module only (released under GPL). It allows to use higher
allows you to use higher resolutions and framerates, and can't resolutions and framerates, but cannot be included in the official
be included into the official Linux kernel for performance Linux kernel for performance purposes.
purposes. At the moment the driver needs a third-party module for the CMOS
At the moment the driver needs a third-part module for the CMOS
sensors, which is available on internet: it is recommended to read sensors, which is available on internet: it is recommended to read
<file:Documentation/usb/w9968cf.txt> for more informations and for <file:Documentation/usb/w9968cf.txt> for more informations and for
a list of supported cameras. a list of supported cameras.
This driver uses the Video For Linux and the I2C APIs. This driver uses the Video For Linux and the I2C APIs. You must say
You must say Y or M to both "Video For Linux" and Y or M to both "Video For Linux" and "I2C Support" to use this
"I2C Support" to use this driver. 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 code is also available as a module ( = code which can be This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want). inserted in and removed from the running kernel whenever you want).
......
/*************************************************************************** /***************************************************************************
* Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. * * 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, * * - Memory management code from bttv driver by Ralph Metzler, *
* Marcus Metzler and Gerd Knorr. * * Marcus Metzler and Gerd Knorr. *
* - I2C interface to kernel, high-level CMOS sensor control routines and * * - I2C interface to kernel, high-level CMOS sensor control routines and *
* some symbolic names from OV511 driver by Mark W. McClelland. * * some symbolic names from OV511 driver by Mark W. McClelland. *
* - Low-level I2C fast write function by Piotr Czerczak. * * - 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 Frederic Jouault. *
* * * *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/version.h> #include <linux/version.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/fs.h> #include <linux/fs.h>
...@@ -48,81 +49,86 @@ ...@@ -48,81 +49,86 @@
/**************************************************************************** /****************************************************************************
* Modules paramaters * * Module macros and paramaters *
****************************************************************************/ ****************************************************************************/
static u8 vppmod_load = W9968CF_VPPMOD_LOAD; MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL);
static u8 simcams = W9968CF_SIMCAMS; MODULE_DESCRIPTION(W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION);
static int video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /* -1=first free */ MODULE_LICENSE(W9968CF_MODULE_LICENSE);
static u16 packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_PACKET_SIZE}; MODULE_SUPPORTED_DEVICE("Video");
static u8 max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BUFFERS};
static u8 double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] = 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}; W9968CF_DOUBLE_BUFFER};
static u8 clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING}; static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING};
static u8 filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FILTER_TYPE}; static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] =
static u8 largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW}; W9968CF_FILTER_TYPE};
static u8 decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] = static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW};
static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] =
W9968CF_DECOMPRESSION}; W9968CF_DECOMPRESSION};
static u8 upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING}; static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING};
static u8 force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0}; static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0};
static u8 force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB}; static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB};
static u8 autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT}; static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT};
static u8 autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP}; static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP};
static u8 lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LIGHTFREQ}; static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] =
static u8 bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]= W9968CF_LIGHTFREQ};
static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]=
W9968CF_BANDINGFILTER}; W9968CF_BANDINGFILTER};
static int clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV}; static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV};
static u8 backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT}; static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT};
static u8 mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR}; static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR};
static u8 sensor_mono[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_SENSOR_MONO}; static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME};
static u16 brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BRIGHTNESS}; static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] =
static u16 hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE}; W9968CF_BRIGHTNESS};
static u16 colour[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR}; static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE};
static u16 contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CONTRAST}; static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR};
static u16 whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_WHITENESS}; 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 #ifdef W9968CF_DEBUG
static u8 debug = W9968CF_DEBUG_LEVEL; static unsigned short debug = W9968CF_DEBUG_LEVEL;
static u8 specific_debug = W9968CF_SPECIFIC_DEBUG; static int specific_debug = W9968CF_SPECIFIC_DEBUG;
#endif #endif
MODULE_AUTHOR("Luca Risolia <luca_ing@libero.it>"); static unsigned int param_nv[23]; /* number of values per paramater */
MODULE_DESCRIPTION("Video4Linux driver for " module_param(vppmod_load, bool, 0444);
"W996[87]CF JPEG USB Dual Mode Camera Chip"); module_param(simcams, ushort, 0444);
module_param_array(video_nr, short, param_nv[0], 0444);
MODULE_SUPPORTED_DEVICE("Video"); module_param_array(packet_size, uint, param_nv[1], 0444);
module_param_array(max_buffers, ushort, param_nv[2], 0444);
MODULE_LICENSE("GPL"); module_param_array(double_buffer, bool, param_nv[3], 0444);
module_param_array(clamping, bool, param_nv[4], 0444);
MODULE_PARM(vppmod_load, "i"); module_param_array(filter_type, ushort, param_nv[5], 0444);
MODULE_PARM(simcams, "i"); module_param_array(largeview, bool, param_nv[6], 0444);
MODULE_PARM(video_nr, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); module_param_array(decompression, ushort, param_nv[7], 0444);
MODULE_PARM(packet_size, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); module_param_array(upscaling, bool, param_nv[8], 0444);
MODULE_PARM(max_buffers, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); module_param_array(force_palette, ushort, param_nv[9], 0444);
MODULE_PARM(double_buffer, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); module_param_array(force_rgb, ushort, param_nv[10], 0444);
MODULE_PARM(clamping, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); module_param_array(autobright, bool, param_nv[11], 0444);
MODULE_PARM(filter_type, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); module_param_array(autoexp, bool, param_nv[12], 0444);
MODULE_PARM(largeview, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); module_param_array(lightfreq, ushort, param_nv[13], 0444);
MODULE_PARM(decompression, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); module_param_array(bandingfilter, bool, param_nv[14], 0444);
MODULE_PARM(upscaling, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); module_param_array(clockdiv, short, param_nv[15], 0444);
MODULE_PARM(force_palette, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); module_param_array(backlight, bool, param_nv[16], 0444);
MODULE_PARM(force_rgb, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); module_param_array(mirror, bool, param_nv[17], 0444);
MODULE_PARM(autobright, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); module_param_array(monochrome, bool, param_nv[18], 0444);
MODULE_PARM(autoexp, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); module_param_array(brightness, uint, param_nv[19], 0444);
MODULE_PARM(lightfreq, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); module_param_array(hue, uint, param_nv[20], 0444);
MODULE_PARM(bandingfilter, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); module_param_array(colour, uint, param_nv[21], 0444);
MODULE_PARM(clockdiv, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); module_param_array(contrast, uint, param_nv[22], 0444);
MODULE_PARM(backlight, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); module_param_array(whiteness, uint, param_nv[23], 0444);
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");
#ifdef W9968CF_DEBUG #ifdef W9968CF_DEBUG
MODULE_PARM(debug, "i"); module_param(debug, ushort, 0444);
MODULE_PARM(specific_debug, "i"); module_param(specific_debug, bool, 0444);
#endif #endif
MODULE_PARM_DESC(vppmod_load, MODULE_PARM_DESC(vppmod_load,
...@@ -146,7 +152,7 @@ MODULE_PARM_DESC(video_nr, ...@@ -146,7 +152,7 @@ MODULE_PARM_DESC(video_nr,
"\n<-1|n[,...]> Specify V4L minor mode number." "\n<-1|n[,...]> Specify V4L minor mode number."
"\n -1 = use next available (default)" "\n -1 = use next available (default)"
"\n n = use minor number n (integer >= 0)" "\n n = use minor number n (integer >= 0)"
"\nYou can specify " __MODULE_STRING(W9968CF_MAX_DEVICES) "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES)
" cameras this way." " cameras this way."
"\nFor example:" "\nFor example:"
"\nvideo_nr=-1,2,-1 would assign minor number 2 to" "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
...@@ -160,7 +166,7 @@ MODULE_PARM_DESC(packet_size, ...@@ -160,7 +166,7 @@ MODULE_PARM_DESC(packet_size,
"(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")." "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")."
"\n"); "\n");
MODULE_PARM_DESC(max_buffers, MODULE_PARM_DESC(max_buffers,
"\n<n[,...]> Only for advanced users." "\n<n[,...]> For advanced users."
"\nSpecify the maximum number of video frame buffers" "\nSpecify the maximum number of video frame buffers"
"\nto allocate for each device, from 2 to " "\nto allocate for each device, from 2 to "
__MODULE_STRING(W9968CF_MAX_BUFFERS) __MODULE_STRING(W9968CF_MAX_BUFFERS)
...@@ -203,7 +209,8 @@ MODULE_PARM_DESC(upscaling, ...@@ -203,7 +209,8 @@ MODULE_PARM_DESC(upscaling,
"\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING) "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING)
" for every device." " for every device."
"\nIf 'w9968cf-vpp' is not loaded, this paramater is" "\nIf 'w9968cf-vpp' is not loaded, this paramater is"
" set to 0."); " set to 0."
"\n");
MODULE_PARM_DESC(decompression, MODULE_PARM_DESC(decompression,
"\n<0|1|2[,...]> Software video decompression:" "\n<0|1|2[,...]> Software video decompression:"
"\n- 0 disables decompression (doesn't allow formats needing" "\n- 0 disables decompression (doesn't allow formats needing"
...@@ -218,7 +225,8 @@ MODULE_PARM_DESC(decompression, ...@@ -218,7 +225,8 @@ MODULE_PARM_DESC(decompression,
"\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION) "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION)
" for every device." " for every device."
"\nIf 'w9968cf-vpp' is not loaded, forcing decompression is " "\nIf 'w9968cf-vpp' is not loaded, forcing decompression is "
"\nnot allowed; in this case this paramater is set to 2."); "\nnot allowed; in this case this paramater is set to 2."
"\n");
MODULE_PARM_DESC(force_palette, MODULE_PARM_DESC(force_palette,
"\n<0" "\n<0"
"|" __MODULE_STRING(VIDEO_PALETTE_UYVY) "|" __MODULE_STRING(VIDEO_PALETTE_UYVY)
...@@ -252,7 +260,8 @@ MODULE_PARM_DESC(force_palette, ...@@ -252,7 +260,8 @@ MODULE_PARM_DESC(force_palette,
"\nInitial palette is " "\nInitial palette is "
__MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"." __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"."
"\nIf 'w9968cf-vpp' is not loaded, this paramater is" "\nIf 'w9968cf-vpp' is not loaded, this paramater is"
" set to 9 (UYVY)."); " set to 9 (UYVY)."
"\n");
MODULE_PARM_DESC(force_rgb, MODULE_PARM_DESC(force_rgb,
"\n<0|1[,...]> Read RGB video data instead of BGR:" "\n<0|1[,...]> Read RGB video data instead of BGR:"
"\n 1 = use RGB component ordering." "\n 1 = use RGB component ordering."
...@@ -311,10 +320,11 @@ MODULE_PARM_DESC(mirror, ...@@ -311,10 +320,11 @@ MODULE_PARM_DESC(mirror,
"\nDefault value is "__MODULE_STRING(W9968CF_MIRROR) "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR)
" for every device." " for every device."
"\n"); "\n");
MODULE_PARM_DESC(sensor_mono, MODULE_PARM_DESC(monochrome,
"\n<0|1[,...]> The OV CMOS sensor is monochrome:" "\n<0|1[,...]> Use OV CMOS sensor as monochrome sensor:"
"\n 0 = no, 1 = yes" "\n 0 = no, 1 = yes"
"\nDefault value is "__MODULE_STRING(W9968CF_SENSOR_MONO) "\nNot all the sensors support monochrome color."
"\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME)
" for every device." " for every device."
"\n"); "\n");
MODULE_PARM_DESC(brightness, MODULE_PARM_DESC(brightness,
...@@ -346,7 +356,7 @@ MODULE_PARM_DESC(whiteness, ...@@ -346,7 +356,7 @@ MODULE_PARM_DESC(whiteness,
#ifdef W9968CF_DEBUG #ifdef W9968CF_DEBUG
MODULE_PARM_DESC(debug, MODULE_PARM_DESC(debug,
"\n<n> Debugging information level, from 0 to 6:" "\n<n> Debugging information level, from 0 to 6:"
"\n0 = none (be cautious)" "\n0 = none (use carefully)"
"\n1 = critical errors" "\n1 = critical errors"
"\n2 = significant informations" "\n2 = significant informations"
"\n3 = configuration or general messages" "\n3 = configuration or general messages"
...@@ -380,13 +390,12 @@ static int w9968cf_open(struct inode*, struct file*); ...@@ -380,13 +390,12 @@ static int w9968cf_open(struct inode*, struct file*);
static int w9968cf_release(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 ssize_t w9968cf_read(struct file*, char*, size_t, loff_t*);
static int w9968cf_mmap(struct file*, struct vm_area_struct*); static int w9968cf_mmap(struct file*, struct vm_area_struct*);
static int w9968cf_ioctl(struct inode*, struct file*, static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long);
unsigned int, unsigned long); static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int, void*);
static int w9968cf_do_ioctl(struct w9968cf_device*, unsigned int, void*);
/* USB-specific */ /* USB-specific */
static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs);
static int w9968cf_start_transfer(struct w9968cf_device*); 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_stop_transfer(struct w9968cf_device*);
static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index); static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index);
static int w9968cf_read_reg(struct w9968cf_device*, 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); ...@@ -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_read_byte(struct w9968cf_device*, u8* v);
static int w9968cf_smbus_write_ack(struct w9968cf_device*); static int w9968cf_smbus_write_ack(struct w9968cf_device*);
static int w9968cf_smbus_read_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, static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
u16 address, u8* value); u16 address, u8* value);
static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address, static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address,
...@@ -436,11 +446,10 @@ static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val); ...@@ -436,11 +446,10 @@ 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 int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val);
static inline int w9968cf_sensor_cmd(struct w9968cf_device*, static inline int w9968cf_sensor_cmd(struct w9968cf_device*,
unsigned int cmd, void *arg); unsigned int cmd, void *arg);
static void w9968cf_sensor_configure(struct w9968cf_device*); static int w9968cf_sensor_init(struct w9968cf_device*);
static int w9968cf_sensor_change_settings(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_get_picture(struct w9968cf_device*);
struct video_picture*); static int w9968cf_sensor_update_picture(struct w9968cf_device*,
static int w9968cf_sensor_set_picture(struct w9968cf_device*,
struct video_picture pict); struct video_picture pict);
/* Other helper functions */ /* Other helper functions */
...@@ -587,8 +596,6 @@ static struct w9968cf_symbolic_list urb_errlist[] = { ...@@ -587,8 +596,6 @@ static struct w9968cf_symbolic_list urb_errlist[] = {
* Memory management functions * * Memory management functions *
****************************************************************************/ ****************************************************************************/
/* Shameless copy from bttv-driver.c */
/* Here we want the physical address of the memory. /* Here we want the physical address of the memory.
This is used when initializing the contents of the area. */ This is used when initializing the contents of the area. */
static inline unsigned long kvirt_to_pa(unsigned long adr) static inline unsigned long kvirt_to_pa(unsigned long adr)
...@@ -639,7 +646,6 @@ static void rvfree(void* mem, unsigned long size) ...@@ -639,7 +646,6 @@ static void rvfree(void* mem, unsigned long size)
} }
vfree(mem); vfree(mem);
} }
/* End of shameless copy */
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
...@@ -923,7 +929,6 @@ static int w9968cf_start_transfer(struct w9968cf_device* cam) ...@@ -923,7 +929,6 @@ static int w9968cf_start_transfer(struct w9968cf_device* cam)
for (i = 0; i < W9968CF_URBS; i++) { for (i = 0; i < W9968CF_URBS; i++) {
urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL); urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL);
cam->urb[i] = urb; cam->urb[i] = urb;
if (!urb) { if (!urb) {
for (j = 0; j < i; j++) for (j = 0; j < i; j++)
usb_free_urb(cam->urb[j]); usb_free_urb(cam->urb[j]);
...@@ -1026,11 +1031,12 @@ static int w9968cf_stop_transfer(struct w9968cf_device* cam) ...@@ -1026,11 +1031,12 @@ static int w9968cf_stop_transfer(struct w9968cf_device* cam)
spin_unlock_irqrestore(&cam->urb_lock, lock_flags); spin_unlock_irqrestore(&cam->urb_lock, lock_flags);
for (i = W9968CF_URBS-1; i >= 0; i--) for (i = W9968CF_URBS-1; i >= 0; i--)
if (cam->urb[i]) if (cam->urb[i]) {
if (!usb_unlink_urb(cam->urb[i])) { if (!usb_unlink_urb(cam->urb[i])) {
usb_free_urb(cam->urb[i]); usb_free_urb(cam->urb[i]);
cam->urb[i] = NULL; cam->urb[i] = NULL;
} }
}
if (cam->disconnected) if (cam->disconnected)
goto exit; goto exit;
...@@ -1086,8 +1092,7 @@ static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index) ...@@ -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, res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, index, (void*)buff, 0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT);
2, W9968CF_USB_CTRL_TIMEOUT);
if (res < 0) if (res < 0)
DBG(4, "Failed to read a register " DBG(4, "Failed to read a register "
...@@ -1099,7 +1104,7 @@ static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index) ...@@ -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. Return 0 on success, -1 otherwise.
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data) 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) ...@@ -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, res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
value, 0x06, (void*)data, 6, value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT);
W9968CF_USB_CTRL_TIMEOUT);
if (res < 0) if (res < 0)
DBG(4, "Failed to write the FSB registers " DBG(4, "Failed to write the FSB registers "
...@@ -1275,6 +1279,22 @@ static int w9968cf_smbus_read_ack(struct w9968cf_device* cam) ...@@ -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 */ /* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
static int static int
w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam,
...@@ -1283,8 +1303,10 @@ 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; u16* data = cam->data_buffer;
int err = 0; int err = 0;
err += w9968cf_smbus_refresh_bus(cam);
/* Enable SBUS outputs */ /* Enable SBUS outputs */
err += w9968cf_write_reg(cam, 0x0020, 0x01); err += w9968cf_write_sb(cam, 0x0020);
data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0); data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0);
data[0] |= (address & 0x40) ? 0x4000 : 0x0; data[0] |= (address & 0x40) ? 0x4000 : 0x0;
...@@ -1328,7 +1350,7 @@ w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, ...@@ -1328,7 +1350,7 @@ w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam,
err += w9968cf_write_fsb(cam, data); err += w9968cf_write_fsb(cam, data);
/* Disable SBUS outputs */ /* Disable SBUS outputs */
err += w9968cf_write_reg(cam, 0x0000, 0x01); err += w9968cf_write_sb(cam, 0x0000);
if (!err) if (!err)
DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X " DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X "
...@@ -1434,8 +1456,8 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, ...@@ -1434,8 +1456,8 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
int size, union i2c_smbus_data *data) int size, union i2c_smbus_data *data)
{ {
struct w9968cf_device* cam = i2c_get_adapdata(adapter); struct w9968cf_device* cam = i2c_get_adapdata(adapter);
u8 i, j; u8 i;
int rc = 0, err = 0; int err = 0;
switch (addr) { switch (addr) {
case OV6xx0_SID: case OV6xx0_SID:
...@@ -1451,31 +1473,26 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, ...@@ -1451,31 +1473,26 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
addr <<= 1; addr <<= 1;
if (read_write == I2C_SMBUS_WRITE) 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) 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) { } else if (size == I2C_SMBUS_BYTE_DATA) {
addr <<= 1; addr <<= 1;
if (read_write == I2C_SMBUS_WRITE) 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); command, data->byte);
else if (read_write == I2C_SMBUS_READ) { else if (read_write == I2C_SMBUS_READ) {
for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) { 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); command, &data->byte);
if (rc < 0) { if (err) {
/* Work around: this seems to wake up if (w9968cf_smbus_refresh_bus(cam)) {
the EEPROM from the stall state */ err = -EIO;
for (j = 0; j <= 10; j++) {
err += w9968cf_write_sb(cam,0x0020);
err += w9968cf_write_sb(cam,0x0000);
if (err)
break; break;
} }
} } else
else
break; break;
} }
...@@ -1487,11 +1504,7 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, ...@@ -1487,11 +1504,7 @@ w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
return -EINVAL; return -EINVAL;
} }
/* This works around a bug in the I2C core */ return err;
if (rc > 0)
rc = 0;
return rc;
} }
...@@ -1507,41 +1520,22 @@ static int w9968cf_i2c_attach_inform(struct i2c_client* client) ...@@ -1507,41 +1520,22 @@ static int w9968cf_i2c_attach_inform(struct i2c_client* client)
{ {
struct w9968cf_device* cam = i2c_get_adapdata(client->adapter); struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
const char* clientname = i2c_clientname(client); const char* clientname = i2c_clientname(client);
int id = client->driver->id; int id = client->driver->id, err = 0;
if (id == I2C_DRIVERID_OVCAMCHIP) { if (id == I2C_DRIVERID_OVCAMCHIP) {
int rc = 0;
cam->sensor_client = client; cam->sensor_client = client;
err = w9968cf_sensor_init(cam);
rc = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, if (err) {
&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) {
cam->sensor_client = NULL; cam->sensor_client = NULL;
cam->sensor = CC_UNKNOWN; return err;
return rc;
} }
} else { } else {
DBG(4, "Rejected client [%s] with [%s]", DBG(4, "Rejected client [%s] with driver [%s]",
clientname, client->driver->name) 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) clientname, client->driver->name)
return 0; return 0;
...@@ -1557,7 +1551,7 @@ static int w9968cf_i2c_detach_inform(struct i2c_client* client) ...@@ -1557,7 +1551,7 @@ static int w9968cf_i2c_detach_inform(struct i2c_client* client)
cam->sensor_client = NULL; cam->sensor_client = NULL;
} }
DBG(2, "I2C detach [%s]", clientname) DBG(5, "I2C detach client [%s]", clientname)
return 0; return 0;
} }
...@@ -1573,7 +1567,7 @@ w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd, ...@@ -1573,7 +1567,7 @@ w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd,
static int w9968cf_i2c_init(struct w9968cf_device* cam) static int w9968cf_i2c_init(struct w9968cf_device* cam)
{ {
int rc = 0; int err = 0;
static struct i2c_algorithm algo = { static struct i2c_algorithm algo = {
.name = "W996[87]CF algorithm", .name = "W996[87]CF algorithm",
...@@ -1596,15 +1590,15 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam) ...@@ -1596,15 +1590,15 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
strcpy(cam->i2c_adapter.name, "w9968cf"); strcpy(cam->i2c_adapter.name, "w9968cf");
i2c_set_adapdata(&cam->i2c_adapter, cam); 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); err = i2c_add_adapter(&cam->i2c_adapter);
if (rc) if (err)
DBG(5, "Failed to register the I2C bus.") DBG(1, "Failed to register the I2C adapter.")
else 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) ...@@ -1644,7 +1638,7 @@ static int w9968cf_turn_on_led(struct w9968cf_device* cam)
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
static int w9968cf_init_chip(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, 0xff00, 0x00); /* power off */
err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */ err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */
...@@ -1679,22 +1673,11 @@ static int w9968cf_init_chip(struct w9968cf_device* cam) ...@@ -1679,22 +1673,11 @@ static int w9968cf_init_chip(struct w9968cf_device* cam)
err += w9968cf_set_window(cam, cam->window); err += w9968cf_set_window(cam, cam->window);
if (err) 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.") DBG(1, "Chip initialization failed.")
if (err)
return err;
else else
return rc; DBG(5, "Chip successfully initialized.")
return err;
} }
...@@ -1706,7 +1689,7 @@ static int ...@@ -1706,7 +1689,7 @@ static int
w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict) w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
{ {
u16 fmt, hw_depth, hw_palette, reg_v = 0x0000; 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 */ /* Make sure we are using a valid depth */
pict.depth = w9968cf_valid_depth(pict.palette); pict.depth = w9968cf_valid_depth(pict.palette);
...@@ -1767,12 +1750,10 @@ w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict) ...@@ -1767,12 +1750,10 @@ w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
else if (cam->filter_type == 2) else if (cam->filter_type == 2)
reg_v |= 0x000c; reg_v |= 0x000c;
err = w9968cf_write_reg(cam, reg_v, 0x16); if ((err = w9968cf_write_reg(cam, reg_v, 0x16)))
if (err)
goto error; goto error;
rc = w9968cf_sensor_set_picture(cam, pict); if ((err = w9968cf_sensor_update_picture(cam, pict)))
if (rc)
goto error; goto error;
/* If all went well, update the device data structure */ /* If all went well, update the device data structure */
...@@ -1791,10 +1772,7 @@ w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict) ...@@ -1791,10 +1772,7 @@ w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
error: error:
DBG(1, "Failed to change picture settings.") DBG(1, "Failed to change picture settings.")
if (err)
return err; return err;
else
return rc;
} }
...@@ -1809,7 +1787,7 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) ...@@ -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; u16 x, y, w, h, scx, scy, cw, ch, ax, ay;
unsigned long fw, fh; unsigned long fw, fh;
struct ovcamchip_window s_win; struct ovcamchip_window s_win;
int err=0, rc=0; int err = 0;
/* Work around to avoid FP arithmetics */ /* Work around to avoid FP arithmetics */
#define __SC(x) ((x) << 10) #define __SC(x) ((x) << 10)
...@@ -1853,8 +1831,8 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) ...@@ -1853,8 +1831,8 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
ch = h; ch = h;
} }
/* Setup the sensor window */ /* Setup the window of the sensor */
s_win.format = SENSOR_FORMAT; s_win.format = VIDEO_PALETTE_UYVY;
s_win.width = cam->maxwidth; s_win.width = cam->maxwidth;
s_win.height = cam->maxheight; s_win.height = cam->maxheight;
s_win.quarter = 0; /* full progressive video */ s_win.quarter = 0; /* full progressive video */
...@@ -1914,7 +1892,7 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) ...@@ -1914,7 +1892,7 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
y = ay + s_win.y; y = ay + s_win.y;
/* Go ! */ /* 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; goto error;
err += w9968cf_write_reg(cam, scx + x, 0x10); err += w9968cf_write_reg(cam, scx + x, 0x10);
...@@ -1959,10 +1937,7 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win) ...@@ -1959,10 +1937,7 @@ w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
error: error:
DBG(1, "Failed to change the capture area size.") DBG(1, "Failed to change the capture area size.")
if (err)
return err; return err;
else
return rc;
} }
...@@ -2177,173 +2152,192 @@ static int ...@@ -2177,173 +2152,192 @@ static int
w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val) w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val)
{ {
struct ovcamchip_control ctl; struct ovcamchip_control ctl;
int rc; int err;
ctl.id = cid; ctl.id = cid;
ctl.value = val; 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 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; struct ovcamchip_control ctl;
int rc; int err;
ctl.id = cid; ctl.id = cid;
rc = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl); err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl);
if (rc >= 0) if (!err)
*val = ctl.value; *val = ctl.value;
return rc; return err;
} }
static inline int 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; struct i2c_client* c = cam->sensor_client;
int rc = 0;
DBG(6, "Executing CMOS sensor command...") if (c->driver->command) {
rc = c->driver->command(cam->sensor_client, cmd, arg);
if (c && c->driver->command) /* The I2C driver returns -EPERM on non-supported controls */
return c->driver->command(cam->sensor_client, cmd, arg); return (rc < 0 && rc != -EPERM) ? rc : 0;
else } else
return -ENODEV; return -ENODEV;
} }
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
Change some settings of the CMOS sensor. Update some settings of the CMOS sensor.
Returns: 0 for success, a negative number otherwise. Returns: 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
static int w9968cf_sensor_change_settings(struct w9968cf_device* cam) static int w9968cf_sensor_update_settings(struct w9968cf_device* cam)
{ {
int rc; int err = 0;
/* Auto brightness */ /* Auto brightness */
rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT,
cam->auto_brt); cam->auto_brt);
if (SENSOR_FATAL_ERROR(rc)) if (err)
return rc; return err;
/* Auto exposure */ /* Auto exposure */
rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP,
cam->auto_exp); cam->auto_exp);
if (SENSOR_FATAL_ERROR(rc)) if (err)
return rc; return err;
/* Banding filter */ /* Banding filter */
rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT,
cam->bandfilt); cam->bandfilt);
if (SENSOR_FATAL_ERROR(rc)) if (err)
return rc; return err;
/* Light frequency */ /* Light frequency */
rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ, err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ,
cam->lightfreq); cam->lightfreq);
if (SENSOR_FATAL_ERROR(rc)) if (err)
return rc; return err;
/* Back light */ /* Back light */
rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT, err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT,
cam->backlight); cam->backlight);
if (SENSOR_FATAL_ERROR(rc)) if (err)
return rc; return err;
/* Mirror */ /* Mirror */
rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR, err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR,
cam->mirror); cam->mirror);
if (SENSOR_FATAL_ERROR(rc)) if (err)
return rc; return err;
return 0; return 0;
} }
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
Get some current picture settings from the CMOS sensor. Get some current picture settings from the CMOS sensor and update the
Returns: 0 for success, a negative number otherwise. internal 'picture' structure of the camera.
Returns: 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
static int static int w9968cf_sensor_get_picture(struct w9968cf_device* cam)
w9968cf_sensor_get_picture(struct w9968cf_device* cam,
struct video_picture* pict)
{ {
int rc, v; int err, v;
/* Don't return error if a setting is unsupported, or rest of settings err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v);
will not be performed */ if (err)
return err;
rc = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v); cam->picture.contrast = v;
if (SENSOR_FATAL_ERROR(rc))
return rc;
pict->contrast = v;
rc = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v);
if (SENSOR_FATAL_ERROR(rc))
return rc;
pict->brightness = v;
rc = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v); err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v);
if (SENSOR_FATAL_ERROR(rc)) if (err)
return rc; return err;
pict->colour = v; cam->picture.brightness = v;
rc = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v); err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v);
if (SENSOR_FATAL_ERROR(rc)) if (err)
return rc; return err;
pict->hue = v; 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.") DBG(5, "Got picture settings from the CMOS sensor.")
PDBGG("Brightness, contrast, hue, colour, whiteness are " PDBGG("Brightness, contrast, hue, colour, whiteness are "
"%d,%d,%d,%d,%d.", pict->brightness, pict->contrast, "%d,%d,%d,%d,%d.", cam->picture.brightness,cam->picture.contrast,
pict->hue, pict->colour, pict->whiteness) cam->picture.hue, cam->picture.colour, cam->picture.whiteness)
return 0; return 0;
} }
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
Change picture settings of the CMOS sensor. Update picture settings of the CMOS sensor.
Returns: 0 for success, a negative number otherwise. Returns: 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/ --------------------------------------------------------------------------*/
static int static int
w9968cf_sensor_set_picture(struct w9968cf_device* cam, w9968cf_sensor_update_picture(struct w9968cf_device* cam,
struct video_picture pict) struct video_picture pict)
{ {
int rc; int err = 0;
rc = w9968cf_sensor_set_control(cam,OVCAMCHIP_CID_CONT, pict.contrast); if ((!cam->sensor_initialized)
if (SENSOR_FATAL_ERROR(rc)) || pict.contrast != cam->picture.contrast) {
return rc; 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;
}
if (!cam->auto_brt) { if (((!cam->sensor_initialized) ||
rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) {
err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT,
pict.brightness); pict.brightness);
if (SENSOR_FATAL_ERROR(rc)) if (err)
return rc; 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_SAT, pict.colour); if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) {
if (SENSOR_FATAL_ERROR(rc)) err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT,
return rc; pict.colour);
if (err)
rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, pict.hue); goto fail;
if (SENSOR_FATAL_ERROR(rc)) DBG(4, "Colour changed from %d to %d.",
return rc; cam->picture.colour, pict.colour)
cam->picture.colour = pict.colour;
}
PDBGG("Brightness, contrast, hue, colour, whiteness are " if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) {
"%d,%d,%d,%d,%d.", pict.brightness, pict.contrast, err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE,
pict.hue, pict.colour, pict.whiteness) 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; 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, ...@@ -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) { switch (cam->sensor_client->addr) {
case OV6xx0_SID: case OV6xx0_SID:
cam->maxwidth = 352; cam->maxwidth = 352;
...@@ -2372,6 +2376,10 @@ static void w9968cf_sensor_configure(struct w9968cf_device* cam) ...@@ -2372,6 +2376,10 @@ static void w9968cf_sensor_configure(struct w9968cf_device* cam)
cam->minwidth = 64; cam->minwidth = 64;
cam->minheight = 48; cam->minheight = 48;
break; 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 */ /* These values depend on the ones in the ovxxx0.c sources */
...@@ -2390,7 +2398,24 @@ static void w9968cf_sensor_configure(struct w9968cf_device* cam) ...@@ -2390,7 +2398,24 @@ static void w9968cf_sensor_configure(struct w9968cf_device* cam)
cam->hs_polarity = 0; 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, ...@@ -2415,13 +2440,7 @@ w9968cf_configure_camera(struct w9968cf_device* cam,
cam->usbdev = udev; cam->usbdev = udev;
cam->id = mod_id; cam->id = mod_id;
cam->sensor = CC_UNKNOWN; cam->sensor = CC_UNKNOWN;
cam->sensor_initialized = 0;
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];
/* Calculate the alternate setting number (from 1 to 16) /* Calculate the alternate setting number (from 1 to 16)
according to the 'packet_size' module parameter */ according to the 'packet_size' module parameter */
...@@ -2433,66 +2452,66 @@ w9968cf_configure_camera(struct w9968cf_device* cam, ...@@ -2433,66 +2452,66 @@ w9968cf_configure_camera(struct w9968cf_device* cam,
cam->max_buffers = (max_buffers[dev_nr] < 2 || cam->max_buffers = (max_buffers[dev_nr] < 2 ||
max_buffers[dev_nr] > W9968CF_MAX_BUFFERS) 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 || cam->double_buffer = (double_buffer[dev_nr] == 0 ||
double_buffer[dev_nr] == 1) 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) 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 || cam->filter_type = (filter_type[dev_nr] == 0 ||
filter_type[dev_nr] == 1 || filter_type[dev_nr] == 1 ||
filter_type[dev_nr] == 2) filter_type[dev_nr] == 2)
? filter_type[dev_nr] : W9968CF_FILTER_TYPE; ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE;
cam->capture = 1; cam->capture = 1;
cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 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 || cam->decompression = (decompression[dev_nr] == 0 ||
decompression[dev_nr] == 1 || decompression[dev_nr] == 1 ||
decompression[dev_nr] == 2) decompression[dev_nr] == 2)
? decompression[dev_nr] : W9968CF_DECOMPRESSION; ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION;
cam->upscaling = (upscaling[dev_nr] == 0 || cam->upscaling = (upscaling[dev_nr] == 0 ||
upscaling[dev_nr] == 1) 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) 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) 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) 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 || cam->bandfilt = (bandingfilter[dev_nr] == 0 ||
bandingfilter[dev_nr] == 1) 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) 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) 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) cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1)
? mirror[dev_nr] : W9968CF_MIRROR; ? (u8)mirror[dev_nr] : W9968CF_MIRROR;
cam->sensor_mono = (sensor_mono[dev_nr]==0 || sensor_mono[dev_nr]==1) cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1)
? sensor_mono[dev_nr] : W9968CF_SENSOR_MONO; ? monochrome[dev_nr] : W9968CF_MONOCHROME;
cam->picture.brightness = brightness[dev_nr]; cam->picture.brightness = (u16)brightness[dev_nr];
cam->picture.hue = hue[dev_nr]; cam->picture.hue = (u16)hue[dev_nr];
cam->picture.colour = colour[dev_nr]; cam->picture.colour = (u16)colour[dev_nr];
cam->picture.contrast = contrast[dev_nr]; cam->picture.contrast = (u16)contrast[dev_nr];
cam->picture.whiteness = whiteness[dev_nr]; cam->picture.whiteness = (u16)whiteness[dev_nr];
if (w9968cf_valid_palette(force_palette[dev_nr])) { if (w9968cf_valid_palette((u16)force_palette[dev_nr])) {
cam->picture.palette = force_palette[dev_nr]; cam->picture.palette = (u16)force_palette[dev_nr];
cam->force_palette = 1; cam->force_palette = 1;
} else { } else {
cam->force_palette = 0; cam->force_palette = 0;
...@@ -2505,7 +2524,7 @@ w9968cf_configure_camera(struct w9968cf_device* cam, ...@@ -2505,7 +2524,7 @@ w9968cf_configure_camera(struct w9968cf_device* cam,
} }
cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1) 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.x = 0;
cam->window.y = 0; cam->window.y = 0;
...@@ -2610,7 +2629,7 @@ w9968cf_configure_camera(struct w9968cf_device* cam, ...@@ -2610,7 +2629,7 @@ w9968cf_configure_camera(struct w9968cf_device* cam,
else else
DBG(3, "- Clock divisor: %d", cam->clockdiv) DBG(3, "- Clock divisor: %d", cam->clockdiv)
if (cam->sensor_mono) if (cam->monochrome)
DBG(3, "- CMOS sensor used as monochrome.") DBG(3, "- CMOS sensor used as monochrome.")
else else
DBG(3, "- CMOS sensor not used as monochrome.") DBG(3, "- CMOS sensor not used as monochrome.")
...@@ -2626,9 +2645,9 @@ static void w9968cf_release_resources(struct w9968cf_device* cam) ...@@ -2626,9 +2645,9 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
{ {
down(&w9968cf_devlist_sem); 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); list_del(&cam->v4llist);
i2c_del_adapter(&cam->i2c_adapter); i2c_del_adapter(&cam->i2c_adapter);
w9968cf_deallocate_memory(cam); w9968cf_deallocate_memory(cam);
...@@ -2648,24 +2667,25 @@ static void w9968cf_release_resources(struct w9968cf_device* cam) ...@@ -2648,24 +2667,25 @@ static void w9968cf_release_resources(struct w9968cf_device* cam)
static int w9968cf_open(struct inode* inode, struct file* filp) static int w9968cf_open(struct inode* inode, struct file* filp)
{ {
struct w9968cf_device* cam = struct w9968cf_device* cam;
(struct w9968cf_device*)video_devdata(filp)->priv;
int err; int err;
cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
down(&cam->dev_sem); down(&cam->dev_sem);
if (cam->sensor == CC_UNKNOWN) { if (cam->sensor == CC_UNKNOWN) {
DBG(2, "No supported CMOS sensor has been detected by the " DBG(2, "No supported CMOS sensor has been detected by the "
"'ovcamchip' module for the %s (/dev/video%d). Make " "'ovcamchip' module for the %s (/dev/video%d). Make "
"sure it is loaded *before* the 'w9968cf' module.", "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); up(&cam->dev_sem);
return -ENODEV; return -ENODEV;
} }
if (cam->users) { if (cam->users) {
DBG(2, "%s (/dev/video%d) has been already occupied by '%s'.", 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)) { if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
up(&cam->dev_sem); up(&cam->dev_sem);
return -EWOULDBLOCK; return -EWOULDBLOCK;
...@@ -2680,8 +2700,8 @@ static int w9968cf_open(struct inode* inode, struct file* filp) ...@@ -2680,8 +2700,8 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
down(&cam->dev_sem); down(&cam->dev_sem);
} }
DBG(5, "Opening the %s, /dev/video%d ...", DBG(5, "Opening '%s', /dev/video%d ...",
symbolic(camlist, cam->id), cam->v4ldev.minor) symbolic(camlist, cam->id), cam->v4ldev->minor)
cam->streaming = 0; cam->streaming = 0;
cam->misconfigured = 0; cam->misconfigured = 0;
...@@ -2698,7 +2718,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) ...@@ -2698,7 +2718,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
if ((err = w9968cf_start_transfer(cam))) if ((err = w9968cf_start_transfer(cam)))
goto deallocate_memory; goto deallocate_memory;
filp->private_data = (void*)cam; filp->private_data = cam;
cam->users++; cam->users++;
strcpy(cam->command, current->comm); strcpy(cam->command, current->comm);
...@@ -2720,8 +2740,9 @@ static int w9968cf_open(struct inode* inode, struct file* filp) ...@@ -2720,8 +2740,9 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
static int w9968cf_release(struct inode* inode, struct file* filp) static int w9968cf_release(struct inode* inode, struct file* filp)
{ {
struct w9968cf_device* cam = struct w9968cf_device* cam;
(struct w9968cf_device*)video_devdata(filp)->priv;
cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
down(&cam->dev_sem); /* prevent disconnect() to be called */ down(&cam->dev_sem); /* prevent disconnect() to be called */
...@@ -2749,11 +2770,12 @@ static int w9968cf_release(struct inode* inode, struct file* filp) ...@@ -2749,11 +2770,12 @@ static int w9968cf_release(struct inode* inode, struct file* filp)
static ssize_t static ssize_t
w9968cf_read(struct file* filp, char* buf, size_t count, loff_t* f_pos) w9968cf_read(struct file* filp, char* buf, size_t count, loff_t* f_pos)
{ {
struct w9968cf_device* cam = struct w9968cf_device* cam;
(struct w9968cf_device*)video_devdata(filp)->priv;
struct w9968cf_frame_t* fr; struct w9968cf_frame_t* fr;
int err = 0; int err = 0;
cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
if (filp->f_flags & O_NONBLOCK) if (filp->f_flags & O_NONBLOCK)
return -EWOULDBLOCK; return -EWOULDBLOCK;
...@@ -2817,9 +2839,8 @@ w9968cf_read(struct file* filp, char* buf, size_t count, loff_t* f_pos) ...@@ -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) static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma)
{ {
struct w9968cf_device* cam = struct w9968cf_device* cam = (struct w9968cf_device*)
(struct w9968cf_device*)video_devdata(filp)->priv; video_get_drvdata(video_devdata(filp));
unsigned long vsize = vma->vm_end - vma->vm_start, unsigned long vsize = vma->vm_end - vma->vm_start,
psize = cam->nbuffers * w9968cf_get_max_bufsize(cam), psize = cam->nbuffers * w9968cf_get_max_bufsize(cam),
start = vma->vm_start, start = vma->vm_start,
...@@ -2860,10 +2881,11 @@ static int ...@@ -2860,10 +2881,11 @@ static int
w9968cf_ioctl(struct inode* inode, struct file* filp, w9968cf_ioctl(struct inode* inode, struct file* filp,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct w9968cf_device* cam = struct w9968cf_device* cam;
(struct w9968cf_device*)video_devdata(filp)->priv;
int err; int err;
cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
if (down_interruptible(&cam->fileop_sem)) if (down_interruptible(&cam->fileop_sem))
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -2879,7 +2901,7 @@ w9968cf_ioctl(struct inode* inode, struct file* filp, ...@@ -2879,7 +2901,7 @@ w9968cf_ioctl(struct inode* inode, struct file* filp,
return -EIO; return -EIO;
} }
err = w9968cf_do_ioctl(cam, cmd, (void*)arg); err = w9968cf_v4l_ioctl(inode, filp, cmd, (void* )arg);
up(&cam->fileop_sem); up(&cam->fileop_sem);
return err; return err;
...@@ -2887,8 +2909,10 @@ w9968cf_ioctl(struct inode* inode, struct file* filp, ...@@ -2887,8 +2909,10 @@ w9968cf_ioctl(struct inode* inode, struct file* filp,
static int 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[] = { const char* v4l1_ioctls[] = {
"?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER",
"GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF", "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF",
...@@ -2900,7 +2924,9 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg) ...@@ -2900,7 +2924,9 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
#define V4L1_IOCTL(cmd) \ #define V4L1_IOCTL(cmd) \
((_IOC_NR((cmd)) < sizeof(v4l1_ioctls)/sizeof(char*)) ? \ ((_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) { switch (cmd) {
...@@ -2914,7 +2940,7 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg) ...@@ -2914,7 +2940,7 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
.minheight = cam->minheight, .minheight = cam->minheight,
}; };
sprintf(cap.name, "W996[87]CF USB Camera #%d", sprintf(cap.name, "W996[87]CF USB Camera #%d",
cam->v4ldev.minor); cam->v4ldev->minor);
cap.maxwidth = (cam->upscaling && w9968cf_vppmod_present) cap.maxwidth = (cam->upscaling && w9968cf_vppmod_present)
? W9968CF_MAX_WIDTH : cam->maxwidth; ? W9968CF_MAX_WIDTH : cam->maxwidth;
cap.maxheight = (cam->upscaling && w9968cf_vppmod_present) cap.maxheight = (cam->upscaling && w9968cf_vppmod_present)
...@@ -2965,15 +2991,10 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg) ...@@ -2965,15 +2991,10 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
case VIDIOCGPICT: /* get image properties of the picture */ case VIDIOCGPICT: /* get image properties of the picture */
{ {
struct video_picture pict; if (w9968cf_sensor_get_picture(cam))
if (w9968cf_sensor_get_picture(cam, &pict))
return -EIO; return -EIO;
pict.depth = cam->picture.depth; if (copy_to_user(arg, &cam->picture, sizeof(cam->picture)))
pict.palette = cam->picture.palette;
if (copy_to_user(arg, &pict, sizeof(pict)))
return -EFAULT; return -EFAULT;
DBG(5, "VIDIOCGPICT successfully called.") DBG(5, "VIDIOCGPICT successfully called.")
...@@ -3002,13 +3023,6 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg) ...@@ -3002,13 +3023,6 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
return -EINVAL; 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->force_palette) {
if (cam->decompression == 0) { if (cam->decompression == 0) {
if (w9968cf_need_decompression(pict.palette)) { if (w9968cf_need_decompression(pict.palette)) {
...@@ -3027,9 +3041,15 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg) ...@@ -3027,9 +3041,15 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
} }
} }
if (pict.palette != cam->picture.palette || if (pict.depth != w9968cf_valid_depth(pict.palette)) {
pict.depth != cam->picture.depth) 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 if(*cam->requested_frame
|| cam->frame_current->queued) { || cam->frame_current->queued) {
err = wait_event_interruptible err = wait_event_interruptible
...@@ -3052,15 +3072,9 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg) ...@@ -3052,15 +3072,9 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
if (w9968cf_start_transfer(cam)) if (w9968cf_start_transfer(cam))
goto ioctl_fail; goto ioctl_fail;
} else if ( ((pict.brightness != cam->picture.brightness) && } else if (w9968cf_sensor_update_picture(cam, pict))
(!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; return -EIO;
}
DBG(5, "VIDIOCSPICT successfully called.") DBG(5, "VIDIOCSPICT successfully called.")
return 0; return 0;
...@@ -3092,7 +3106,6 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg) ...@@ -3092,7 +3106,6 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
win.y != cam->window.y || win.y != cam->window.y ||
win.width != cam->window.width || win.width != cam->window.width ||
win.height != cam->window.height) { win.height != cam->window.height) {
if(*cam->requested_frame if(*cam->requested_frame
|| cam->frame_current->queued) { || cam->frame_current->queued) {
err = wait_event_interruptible err = wait_event_interruptible
...@@ -3203,12 +3216,12 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg) ...@@ -3203,12 +3216,12 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
} }
} }
if (w9968cf_adjust_window_size(cam, (u16*)&mmap.width, if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width,
(u16*)&mmap.height)) { (u16*)&mmap.height))) {
DBG(4, "Resolution not supported (%dx%d). " DBG(4, "Resolution not supported (%dx%d). "
"VIDIOCMCAPTURE failed.", "VIDIOCMCAPTURE failed.",
mmap.width, mmap.height) mmap.width, mmap.height)
return -EINVAL; return err;
} }
fr = &cam->frame[mmap.frame]; fr = &cam->frame[mmap.frame];
...@@ -3276,10 +3289,13 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg) ...@@ -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 */ 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; struct w9968cf_frame_t* fr;
int err = 0; int err = 0;
if (copy_from_user(&f_num, arg, sizeof(f_num)))
return -EFAULT;
if (f_num >= cam->nbuffers) { if (f_num >= cam->nbuffers) {
DBG(4, "Invalid frame number (%d). " DBG(4, "Invalid frame number (%d). "
"VIDIOCMCAPTURE failed.", f_num) "VIDIOCMCAPTURE failed.", f_num)
...@@ -3323,7 +3339,7 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg) ...@@ -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*/ case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/
{ {
struct video_unit unit = { struct video_unit unit = {
.video = cam->v4ldev.minor, .video = cam->v4ldev->minor,
.vbi = VIDEO_NO_UNIT, .vbi = VIDEO_NO_UNIT,
.radio = VIDEO_NO_UNIT, .radio = VIDEO_NO_UNIT,
.audio = VIDEO_NO_UNIT, .audio = VIDEO_NO_UNIT,
...@@ -3342,9 +3358,8 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg) ...@@ -3342,9 +3358,8 @@ w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
case VIDIOCGFBUF: case VIDIOCGFBUF:
{ {
struct video_buffer* buffer = (struct video_buffer*)arg; if (clear_user(arg, sizeof(struct video_buffer)))
return -EFAULT;
memset(buffer, 0, sizeof(struct video_buffer));
DBG(5, "VIDIOCGFBUF successfully called.") DBG(5, "VIDIOCGFBUF successfully called.")
return 0; return 0;
...@@ -3470,10 +3485,6 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) ...@@ -3470,10 +3485,6 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
else else
return -ENODEV; return -ENODEV;
/* We don't handle multi-config cameras */
if (udev->descriptor.bNumConfigurations != 1)
return -ENODEV;
DBG(2, "%s detected.", symbolic(camlist, mod_id)) DBG(2, "%s detected.", symbolic(camlist, mod_id))
if (simcams > W9968CF_MAX_DEVICES) if (simcams > W9968CF_MAX_DEVICES)
...@@ -3491,14 +3502,6 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) ...@@ -3491,14 +3502,6 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
return -EPERM; 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*) cam = (struct w9968cf_device*)
kmalloc(sizeof(struct w9968cf_device), GFP_KERNEL); kmalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
...@@ -3530,10 +3533,24 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) ...@@ -3530,10 +3533,24 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
} }
memset(cam->data_buffer, 0, 8); memset(cam->data_buffer, 0, 8);
/* Set some basic constants */ /* Register the V4L device */
w9968cf_configure_camera(cam, udev, mod_id, dev_nr); cam->v4ldev = video_device_alloc();
if (!cam->v4ldev) {
DBG(1, "Could not allocate memory for a V4L structure.")
err = -ENOMEM;
goto fail;
}
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, err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
video_nr[dev_nr]); video_nr[dev_nr]);
if (err) { if (err) {
DBG(1, "V4L device registration failed.") DBG(1, "V4L device registration failed.")
...@@ -3544,13 +3561,15 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) ...@@ -3544,13 +3561,15 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto fail; 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)
/* Set some basic constants */
w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
/* Ok, add a new entry into the list of V4L registered devices */ /* Add a new entry into the list of V4L registered devices */
down(&w9968cf_devlist_sem); down(&w9968cf_devlist_sem);
list_add(&cam->v4llist, &w9968cf_dev_list); list_add(&cam->v4llist, &w9968cf_dev_list);
up(&w9968cf_devlist_sem); up(&w9968cf_devlist_sem);
dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
w9968cf_turn_on_led(cam); w9968cf_turn_on_led(cam);
...@@ -3559,8 +3578,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) ...@@ -3559,8 +3578,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
up(&cam->dev_sem); up(&cam->dev_sem);
dev_set_drvdata(&intf->dev, (void*)cam); usb_set_intfdata(intf, cam);
return 0; return 0;
fail: /* Free unused memory */ fail: /* Free unused memory */
...@@ -3569,6 +3587,8 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) ...@@ -3569,6 +3587,8 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
kfree(cam->control_buffer); kfree(cam->control_buffer);
if (cam->data_buffer) if (cam->data_buffer)
kfree(cam->data_buffer); kfree(cam->data_buffer);
if (cam->v4ldev)
video_device_release(cam->v4ldev);
up(&cam->dev_sem); up(&cam->dev_sem);
kfree(cam); kfree(cam);
} }
...@@ -3579,9 +3599,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) ...@@ -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) static void w9968cf_usb_disconnect(struct usb_interface* intf)
{ {
struct w9968cf_device* cam = struct w9968cf_device* cam =
(struct w9968cf_device*)dev_get_drvdata(&intf->dev); (struct w9968cf_device*)usb_get_intfdata(intf);
dev_set_drvdata(&intf->dev, NULL);
if (cam) { if (cam) {
/* Prevent concurrent accesses to data */ /* Prevent concurrent accesses to data */
...@@ -3599,7 +3617,7 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf) ...@@ -3599,7 +3617,7 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
DBG(2, "The device is open (/dev/video%d)! " DBG(2, "The device is open (/dev/video%d)! "
"Process name: %s. Deregistration and memory " "Process name: %s. Deregistration and memory "
"deallocation are deferred on close.", "deallocation are deferred on close.",
cam->v4ldev.minor, cam->command) cam->v4ldev->minor, cam->command)
cam->misconfigured = 1; cam->misconfigured = 1;
...@@ -3613,6 +3631,8 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf) ...@@ -3613,6 +3631,8 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf)
if (!cam->users) if (!cam->users)
kfree(cam); kfree(cam);
} }
usb_set_intfdata(intf, NULL);
} }
......
/*************************************************************************** /***************************************************************************
* Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. * * 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 * * 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 * * it under the terms of the GNU General Public License as published by *
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/param.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <asm/types.h> #include <asm/types.h>
...@@ -105,7 +106,7 @@ static const struct w9968cf_format w9968cf_formatlist[] = { ...@@ -105,7 +106,7 @@ static const struct w9968cf_format w9968cf_formatlist[] = {
#define W9968CF_LARGEVIEW 1 /* 0 disable, 1 enable */ #define W9968CF_LARGEVIEW 1 /* 0 disable, 1 enable */
#define W9968CF_UPSCALING 0 /* 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_BRIGHTNESS 31000 /* from 0 to 65535 */
#define W9968CF_HUE 32768 /* from 0 to 65535 */ #define W9968CF_HUE 32768 /* from 0 to 65535 */
#define W9968CF_COLOUR 32768 /* from 0 to 65535 */ #define W9968CF_COLOUR 32768 /* from 0 to 65535 */
...@@ -129,9 +130,10 @@ static const struct w9968cf_format w9968cf_formatlist[] = { ...@@ -129,9 +130,10 @@ static const struct w9968cf_format w9968cf_formatlist[] = {
#define W9968CF_MODULE_NAME "V4L driver for W996[87]CF JPEG USB " \ #define W9968CF_MODULE_NAME "V4L driver for W996[87]CF JPEG USB " \
"Dual Mode Camera Chip" "Dual Mode Camera Chip"
#define W9968CF_MODULE_VERSION "v1.22" #define W9968CF_MODULE_VERSION "v1.25-basic"
#define W9968CF_MODULE_AUTHOR "(C) 2002 2003 Luca Risolia" #define W9968CF_MODULE_AUTHOR "(C) 2002-2004 Luca Risolia"
#define W9968CF_AUTHOR_EMAIL "<luca_ing@libero.it>" #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 */ static u8 w9968cf_vppmod_present; /* status flag: yes=1, no=0 */
...@@ -171,6 +173,7 @@ enum w9968cf_frame_status { ...@@ -171,6 +173,7 @@ enum w9968cf_frame_status {
}; };
struct w9968cf_frame_t { struct w9968cf_frame_t {
#define W9968CF_HW_BUF_SIZE 640*480*2 /* buf.size of original frames */
void* buffer; void* buffer;
u32 length; u32 length;
enum w9968cf_frame_status status; enum w9968cf_frame_status status;
...@@ -194,7 +197,7 @@ struct semaphore w9968cf_devlist_sem; /* semaphore for list traversal */ ...@@ -194,7 +197,7 @@ struct semaphore w9968cf_devlist_sem; /* semaphore for list traversal */
struct w9968cf_device { struct w9968cf_device {
enum w9968cf_model_id id; /* private device identifier */ enum w9968cf_model_id id; /* private device identifier */
struct video_device v4ldev; /* V4L structure */ struct video_device* v4ldev; /* -> V4L structure */
struct list_head v4llist; /* entry of the list of V4L cameras */ struct list_head v4llist; /* entry of the list of V4L cameras */
struct usb_device* usbdev; /* -> main USB structure */ struct usb_device* usbdev; /* -> main USB structure */
...@@ -207,7 +210,7 @@ struct w9968cf_device { ...@@ -207,7 +210,7 @@ struct w9968cf_device {
struct w9968cf_frame_t frame_tmp; /* temporary frame */ struct w9968cf_frame_t frame_tmp; /* temporary frame */
struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */ struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */
struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS]; 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_palette, /* yes=1/no=0 */
...@@ -220,15 +223,17 @@ struct w9968cf_device { ...@@ -220,15 +223,17 @@ struct w9968cf_device {
decompression, /* 0=disabled, 1=forced, 2=allowed */ decompression, /* 0=disabled, 1=forced, 2=allowed */
upscaling; /* software image scaling, 0=enabled, 1=disabled */ upscaling; /* software image scaling, 0=enabled, 1=disabled */
struct video_picture picture; /* current window settings */ struct video_picture picture; /* current picture settings */
struct video_window window; /* current picture settings */ struct video_window window; /* current window settings */
u16 hw_depth, /* depth (used by the chip) */ u16 hw_depth, /* depth (used by the chip) */
hw_palette, /* palette (used by the chip) */ hw_palette, /* palette (used by the chip) */
hw_width, /* width (used by the chip) */ hw_width, /* width (used by the chip) */
hw_height, /* height (used by the chip) */ hw_height, /* height (used by the chip) */
hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */ 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 */ enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */
...@@ -239,16 +244,15 @@ struct w9968cf_device { ...@@ -239,16 +244,15 @@ struct w9968cf_device {
users, /* flag: number of users holding the device */ users, /* flag: number of users holding the device */
streaming; /* flag: yes=1, no=0 */ streaming; /* flag: yes=1, no=0 */
int sensor; /* type of image CMOS sensor chip (CC_*) */ u8 sensor_initialized; /* flag: yes=1, no=0 */
/* Determined by CMOS sensor type */
u16 maxwidth,
maxheight,
minwidth,
minheight,
start_cropx,
start_cropy;
/* 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 */ u8 auto_brt, /* auto brightness enabled flag */
auto_exp, /* auto exposure enabled flag */ auto_exp, /* auto exposure enabled flag */
backlight, /* backlight exposure algorithm flag */ backlight, /* backlight exposure algorithm flag */
...@@ -256,7 +260,6 @@ struct w9968cf_device { ...@@ -256,7 +260,6 @@ struct w9968cf_device {
lightfreq, /* power (lighting) frequency */ lightfreq, /* power (lighting) frequency */
bandfilt; /* banding filter enabled flag */ bandfilt; /* banding filter enabled flag */
s8 clockdiv; /* clock divisor */ s8 clockdiv; /* clock divisor */
int sensor_mono; /* CMOS sensor is (probably) monochrome */
/* I2C interface to kernel */ /* I2C interface to kernel */
struct i2c_adapter i2c_adapter; struct i2c_adapter i2c_adapter;
...@@ -271,14 +274,9 @@ struct w9968cf_device { ...@@ -271,14 +274,9 @@ struct w9968cf_device {
wait_queue_head_t open, wait_queue; 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 #undef DBG
...@@ -294,7 +292,7 @@ if ( ((specific_debug) && (debug == (level))) || \ ...@@ -294,7 +292,7 @@ if ( ((specific_debug) && (debug == (level))) || \
else if ((level) == 4) \ else if ((level) == 4) \
warn(fmt, ## args); \ warn(fmt, ## args); \
else if ((level) >= 5) \ else if ((level) >= 5) \
info("[%s,%d] " fmt, \ info("[%s:%d] " fmt, \
__PRETTY_FUNCTION__, __LINE__ , ## args); \ __PRETTY_FUNCTION__, __LINE__ , ## args); \
} \ } \
} }
...@@ -305,7 +303,7 @@ if ( ((specific_debug) && (debug == (level))) || \ ...@@ -305,7 +303,7 @@ if ( ((specific_debug) && (debug == (level))) || \
#undef PDBG #undef PDBG
#undef PDBGG #undef PDBGG
#define PDBG(fmt, args...) info("[%s, %d] "fmt, \ #define PDBG(fmt, args...) info("[%s:%d] "fmt, \
__PRETTY_FUNCTION__, __LINE__ , ## args); __PRETTY_FUNCTION__, __LINE__ , ## args);
#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */ #define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
......
/*************************************************************************** /***************************************************************************
* Video decoder for the W996[87]CF driver for Linux. * * 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 * * 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 * * it under the terms of the GNU General Public License as published by *
......
/*************************************************************************** /***************************************************************************
* 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. * * 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 * * 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 * * it under the terms of the GNU General Public License as published by *
...@@ -27,8 +28,6 @@ ...@@ -27,8 +28,6 @@
#include <asm/ioctl.h> #include <asm/ioctl.h>
#include <asm/types.h> #include <asm/types.h>
/* The following values have been copied from the "ovcamchip" module. */
#ifndef I2C_DRIVERID_OVCAMCHIP #ifndef I2C_DRIVERID_OVCAMCHIP
# define I2C_DRIVERID_OVCAMCHIP 0xf00f # define I2C_DRIVERID_OVCAMCHIP 0xf00f
#endif #endif
......
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