ChangeSet 1.1291, 2003/12/12 14:04:18-08:00, luca.risolia@studio.unibo.it [PATCH] USB: W996[87]CF driver update CREDITS | 6 Documentation/Configure.help | 15 Documentation/usb/w9968cf.txt | 158 +++---- MAINTAINERS | 10 drivers/usb/w9968cf.c | 782 +++++++++++++++++++------------------- drivers/usb/w9968cf.h | 66 +-- drivers/usb/w9968cf_decoder.h | 2 drivers/usb/w9968cf_externaldef.h | 13 8 files changed, 528 insertions(+), 524 deletions(-) diff -Nru a/CREDITS b/CREDITS --- a/CREDITS Fri Dec 12 15:05:19 2003 +++ b/CREDITS Fri Dec 12 15:05:19 2003 @@ -2597,9 +2597,9 @@ S: USA N: Luca Risolia -E: luca_ing@libero.it -D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chip -S: Via Libertà 41/a +E: luca.risolia@studio.unibo.it +D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chips +S: Via Liberta' 41-A S: Osio Sotto, 24046, Bergamo S: Italy diff -Nru a/Documentation/Configure.help b/Documentation/Configure.help --- a/Documentation/Configure.help Fri Dec 12 15:05:19 2003 +++ b/Documentation/Configure.help Fri Dec 12 15:05:19 2003 @@ -15361,19 +15361,18 @@ This driver has an optional plugin, which is distributed as a separate module only (released under GPL). It contains code that - allows you to use higher resolutions and framerates, and can't - be included into the official Linux kernel for performance - purposes. - At the moment the driver needs a third-part module for the CMOS + allows you to use higher resolutions and framerates, and cannot + be included in the official Linux kernel for performance purposes. + At the moment the driver needs a third-party module for the CMOS sensors, which is available on internet: it is recommended to read for more informations and for a list of supported cameras. This driver uses the Video For Linux and the I2C APIs. - You must say Y or M to both "Video For Linux" and - "I2C Support" to use this driver. - Information on this API and pointers to "v4l" programs may be found - on the WWW at . + You must say Y or M to both "Video For Linux" and "I2C Support" + to use this driver. Information on this API and pointers to "v4l" + programs may be found on the WWW at + . This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). diff -Nru a/Documentation/usb/w9968cf.txt b/Documentation/usb/w9968cf.txt --- a/Documentation/usb/w9968cf.txt Fri Dec 12 15:05:19 2003 +++ b/Documentation/usb/w9968cf.txt Fri Dec 12 15:05:19 2003 @@ -1,6 +1,7 @@ - W996[87]CF JPEG USB Dual Mode Camera Chip driver for Linux 2.4 - ============================================================== + W996[87]CF JPEG USB Dual Mode Camera Chip + Linux 2.4 driver (basic version) + ========================================= - Documentation - @@ -11,7 +12,7 @@ 2. License 3. Overview 4. Supported devices -5. Kernel configuration and third-part module compilation +5. Module dependencies 6. Module loading 7. Module paramaters 8. Credits @@ -19,7 +20,7 @@ 1. Copyright ============ -Copyright (C) 2002 2003 by Luca Risolia +Copyright (C) 2002 2003 by Luca Risolia 2. License @@ -45,20 +46,23 @@ Winbond W9967CF and Winbond W9968CF JPEG USB Dual Mode Camera Chips, when they are being commanded by USB. -The driver relies on the Video4Linux, USB and I2C core modules of the Linux -kernel, version 2.4.19 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 -module, which provides some useful video post-processing functions like video -decoding, up-scaling and colour conversions (these routines can't be included -into official kernels). Once the driver is installed, every time an application -tries to open a recognized device, "w9968cf" checks the presence of the -"w9968cf-vpp" module and loads it automatically by default. +The full-featured driver is divided into two modules: the basic one, "w9968cf", +is needed for the supported devices to work; the second one, "w9968cf-vpp", +is an optional module, which provides some useful video post-processing +functions like video decoding, up-scaling and colour conversions. Once the +driver is installed, every time an application tries to open a recognized +device, "w9968cf" checks the presence of the "w9968cf-vpp" module and loads it +automatically by default. + +Please keep in mind that official kernels do NOT include the second module for +performance purposes. However it is always recommended to download and install +the latest and complete release of the driver, replacing the existing one, if +present: it will be still even possible not to load the "w9968cf-vpp" module at +all, if you ever want to. Another important missing feature of the version in +the official Linux 2.4 kernels is the writeable /proc filesystem interface. + +The latest and full-featured version of the W996[87]CF driver can be found at: +http://go.lamarinapunto.com/ 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 @@ -67,15 +71,17 @@ To change the default settings for each camera, many paramaters can be passed through command line when the module is loaded into memory. -It is recommended to install the latest and full featured version of the -W996[87]CF driver, which can be found at: -http://go.lamarinapunto.com/ +The driver relies on the Video4Linux, USB and I2C core modules of the official +Linux kernels, version 2.4.19 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 "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: http://alpha.dyndns.org/ov511/ -To know how to patch, compile and load it, read the "Kernel configuration" -paragraph. +To know how to compile it, read the documentation included in the OV511 +package. 4. Supported devices @@ -94,22 +100,21 @@ The list above does NOT imply that all those devices work with this driver: up until now only webcams that have a CMOS sensor supported by the "ovcamchip" module work. -For a list of supported CMOS sensors, please visit the module author homepage: -http://alpha.dyndns.org/ov511/ +For a list of supported CMOS sensors, please visit the the author's homepage on +this module: http://alpha.dyndns.org/ov511/ Possible external microcontrollers of those webcams are not supported: this -means that still images can't be downloaded from the device memory. +means that still images cannot be downloaded from the device memory. Furthermore, it's worth to note that I was only able to run tests on my "Creative Labs Video Blaster WebCam Go". Donations of other models, for additional testing and full support, would be much appreciated. -5. Kernel configuration and third-part module compilation -========================================================= -As noted above, kernel 2.4.19 is the minimum for this driver; for it to work -properly, the driver needs kernel support for Video4Linux, USB and I2C, and a -third-part module for the CMOS sensor. +5. Module dependencies +====================== +The driver needs kernel support for Video4Linux, USB and I2C, and a third-party +module for the CMOS sensor. The following options of the kernel configuration file must be enabled and corresponding modules must be compiled: @@ -128,7 +133,7 @@ # CONFIG_USB=m -In addition, depending on the hardware being used, just one of the modules +In addition, depending on the hardware being used, only one of the modules below is necessary: # USB Host Controller Drivers @@ -138,6 +143,12 @@ CONFIG_USB_UHCI_ALT=m CONFIG_USB_OHCI=m +And finally: + + # USB Multimedia devices + # + CONFIG_USB_W9968CF=m + Also, make sure "Enforce bandwidth allocation" is NOT enabled. The /proc filesystem can be optionally built into the kernel: @@ -150,39 +161,18 @@ # CONFIG_VIDEO_PROC_FS=y - # USB Multimedia devices - # - CONFIG_USB_W9968CF=m - The last module we need is "ovcamchip.o". To obtain it, you have to download -the OV511 driver, version 2.25 - don't use other versions - which is available -at http://alpha.dyndns.org/ov511/ . Then you have to download the latest -version of the full featured W996[87]CF driver, which contains a patch for the -"ovcamchip" module; it is available at http://go.lamarinapunto.com . -Once you have obtained the packages, decompress, patch and compile the -"ovcamchip" module. In other words: - - [user@localhost home]$ tar xvzf w9968cf-x.x.tar.gz - [user@localhost home]$ tar xvjf ov511-2.25.tar.bz2 - [user@localhost home]$ cd ov511-2.25 - [user@localhost ov511-2.25]$ patch -p1 < \ - /path/to/w9968cf-x.x/ov511-2.25.patch - [user@localhost ov511-2.25]$ make - -It's worth to note that the full featured version of the W996[87]CF driver -can also be installed overwriting the one in the kernel; in this case, read the -documentation included in the package. - -If everything went well, the W996[87]CF driver can be immediatly used (see next -paragraph). +the OV511, version 2.27 - don't use other versions - and compile it according +to its documentation. +The package is available at http://alpha.dyndns.org/ov511/ . 6. Module loading ================= To use the driver, it is necessary to load the "w9968cf" module into memory -after every other module required; they are named, in order: "videodev", -"usbcore", then "ehci-hcd", "usb-uhci", "uhci", "usb-ohci" (just one), and also -"i2c-core" and "ovcamchip". +after every other module required: for the 2.4 series of the kernel, they are +named, in order: "videodev", "usbcore", then "ehci-hcd", "usb-uhci", "uhci", +"usb-ohci" (just one), and also "i2c-core" and "ovcamchip". Loading can be done this way, from root: @@ -213,11 +203,10 @@ 7. Module paramaters ==================== - Module paramaters are listed below: ------------------------------------------------------------------------------- Name: vppmod_load -Type: int +Type: bool Syntax: <0|1> Description: Automatic 'w9968cf-vpp' module loading: 0 disabled, 1 enabled. If enabled, every time an application attempts to open a @@ -258,22 +247,22 @@ Name: max_buffers Type: int array (min = 0, max = 32) Syntax: -Description: Only for advanced users. +Description: For advanced users. Specify the maximum number of video frame buffers to allocate for each device, from 2 to 32. Default: 2 ------------------------------------------------------------------------------- Name: double_buffer -Type: int array (min = 0, max = 32) +Type: bool array (min = 0, max = 32) Syntax: <0|1[,...]> Description: Hardware double buffering: 0 disabled, 1 enabled. It should be enabled if you want smooth video output: if you - obtain out of sync. video, disable it at all, or try to + obtain out of sync. video, disable it, or try to decrease the 'clockdiv' module paramater value. Default: 1 for every device. ------------------------------------------------------------------------------- Name: clamping -Type: int array (min = 0, max = 32) +Type: bool array (min = 0, max = 32) Syntax: <0|1[,...]> Description: Video data clamping: 0 disabled, 1 enabled. Default: 0 for every device. @@ -288,13 +277,13 @@ Default: 0 for every device. ------------------------------------------------------------------------------- Name: largeview -Type: int array (min = 0, max = 32) +Type: bool array (min = 0, max = 32) Syntax: <0|1[,...]> Description: Large view: 0 disabled, 1 enabled. Default: 1 for every device. ------------------------------------------------------------------------------- Name: upscaling -Type: int array (min = 0, max = 32) +Type: bool array (min = 0, max = 32) Syntax: <0|1[,...]> Description: Software scaling (for non-compressed video only): 0 disabled, 1 enabled. @@ -316,9 +305,8 @@ YUV420P/YUV420 in any resolutions where width and height are multiples of 16. Default: 2 for every device. -Note: If 'w9968cf-vpp' is not loaded, this paramater is set to, - forcing decompression is not allowed; in this case this - paramater is set to 2. +Note: If 'w9968cf-vpp' is not loaded, forcing decompression is not + allowed; in this case this paramater is set to 2. ------------------------------------------------------------------------------- Name: force_palette Type: int array (min = 0, max = 32) @@ -342,7 +330,7 @@ Note: If 'w9968cf-vpp' is not loaded, this paramater is set to 9. ------------------------------------------------------------------------------- Name: force_rgb -Type: int array (min = 0, max = 32) +Type: bool array (min = 0, max = 32) Syntax: <0|1[,...]> Description: Read RGB video data instead of BGR: 1 = use RGB component ordering. @@ -351,28 +339,28 @@ Default: 0 for every device. ------------------------------------------------------------------------------- Name: autobright -Type: long array (min = 0, max = 32) +Type: bool array (min = 0, max = 32) Syntax: <0|1[,...]> Description: CMOS sensor automatically changes brightness: 0 = no, 1 = yes Default: 0 for every device. ------------------------------------------------------------------------------- Name: autoexp -Type: long array (min = 0, max = 32) +Type: bool array (min = 0, max = 32) Syntax: <0|1[,...]> Description: CMOS sensor automatically changes exposure: 0 = no, 1 = yes Default: 1 for every device. ------------------------------------------------------------------------------- Name: lightfreq -Type: long array (min = 0, max = 32) +Type: int array (min = 0, max = 32) Syntax: <50|60[,...]> Description: Light frequency in Hz: 50 for European and Asian lighting, 60 for American lighting. Default: 50 for every device. ------------------------------------------------------------------------------- Name: bandingfilter -Type: long array (min = 0, max = 32) +Type: bool array (min = 0, max = 32) Syntax: <0|1[,...]> Description: Banding filter to reduce effects of fluorescent lighting: @@ -382,7 +370,7 @@ Default: 0 for every device. ------------------------------------------------------------------------------- Name: clockdiv -Type: long array (min = 0, max = 32) +Type: int array (min = 0, max = 32) Syntax: <-1|n[,...]> Description: Force pixel clock divisor to a specific value (for experts): n may vary from 0 to 127. @@ -391,21 +379,21 @@ Default: -1 for every device. ------------------------------------------------------------------------------- Name: backlight -Type: long array (min = 0, max = 32) +Type: bool array (min = 0, max = 32) Syntax: <0|1[,...]> Description: Objects are lit from behind: 0 = no, 1 = yes Default: 0 for every device. ------------------------------------------------------------------------------- Name: mirror -Type: long array (min = 0, max = 32) +Type: bool array (min = 0, max = 32) Syntax: <0|1[,...]> Description: Reverse image horizontally: 0 = no, 1 = yes Default: 0 for every device. ------------------------------------------------------------------------------- -Name: sensor_mono -Type: long array (min = 0, max = 32) +Name: monochrome +Type: bool array (min = 0, max = 32) Syntax: <0|1[,...]> Description: The CMOS sensor is monochrome: 0 = no, 1 = yes @@ -446,7 +434,7 @@ Type: int Syntax: Description: Debugging information level, from 0 to 6: - 0 = none (be cautious) + 0 = none (use carefully) 1 = critical errors 2 = significant informations 3 = configuration or general messages @@ -458,7 +446,7 @@ Default: 2 ------------------------------------------------------------------------------- Name: specific_debug -Type: int +Type: bool Syntax: <0|1> Description: Enable or disable specific debugging messages: 0 = print messages concerning every level <= 'debug' level. @@ -479,8 +467,6 @@ - memory management code has been copied from the bttv driver by Ralph Metzler, Marcus Metzler and Gerd Knorr; -- the low-level I2C read function has been written by Frédéric Jouault, who - also gave me commented logs about sniffed USB traffic taken from another - driver for another system; +- the low-level I2C read function has been written by Frederic Jouault; -- the low-level I2C fast write function has been written by Piotr Czerczak; +- the low-level I2C fast write function has been written by Piotr Czerczak. diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Fri Dec 12 15:05:19 2003 +++ b/MAINTAINERS Fri Dec 12 15:05:19 2003 @@ -2070,11 +2070,11 @@ S: Maintained USB W9968CF DRIVER -P: Luca Risolia -M: luca_ing@libero.it -L: linux-usb-devel@lists.sourceforge.net -W: http://go.lamarinapunto.com -S: Maintained +P: Luca Risolia +M: luca.risolia@studio.unibo.it +L: linux-usb-devel@lists.sourceforge.net +W: http://go.lamarinapunto.com +S: Maintained VFAT FILESYSTEM: P: Gordon Chaffee diff -Nru a/drivers/usb/w9968cf.c b/drivers/usb/w9968cf.c --- a/drivers/usb/w9968cf.c Fri Dec 12 15:05:19 2003 +++ b/drivers/usb/w9968cf.c Fri Dec 12 15:05:19 2003 @@ -1,14 +1,14 @@ /*************************************************************************** * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. * * * - * Copyright (C) 2002 2003 by Luca Risolia * + * Copyright (C) 2002 2003 by Luca Risolia * * * * - Memory management code from bttv driver by Ralph Metzler, * * Marcus Metzler and Gerd Knorr. * * - I2C interface to kernel, high-level CMOS sensor control routines and * * some symbolic names from OV511 driver by Mark W. McClelland. * * - Low-level I2C fast write function by Piotr Czerczak. * - * - Low-level I2C read function by Frédéric Jouault. * + * - Low-level I2C read function by Frederic Jouault. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -46,17 +46,19 @@ #include "w9968cf.h" #include "w9968cf_decoder.h" -EXPORT_NO_SYMBOLS; - - /**************************************************************************** - * Modules paramaters * + * Module macros and paramaters * ****************************************************************************/ +MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL); +MODULE_DESCRIPTION(W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION); +MODULE_LICENSE(W9968CF_MODULE_LICENSE); +MODULE_SUPPORTED_DEVICE("Video"); + static u8 vppmod_load = W9968CF_VPPMOD_LOAD; static u8 simcams = W9968CF_SIMCAMS; -static int video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /* -1=first free */ +static s8 video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /* -1=first free */ static u16 packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_PACKET_SIZE}; static u8 max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BUFFERS}; static u8 double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] = @@ -74,10 +76,10 @@ static u8 lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LIGHTFREQ}; static u8 bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]= W9968CF_BANDINGFILTER}; -static int clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV}; +static s8 clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV}; static u8 backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT}; static u8 mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR}; -static u8 sensor_mono[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_SENSOR_MONO}; +static u8 monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME}; static u16 brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BRIGHTNESS}; static u16 hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE}; static u16 colour[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR}; @@ -88,36 +90,27 @@ static u8 specific_debug = W9968CF_SPECIFIC_DEBUG; #endif -MODULE_AUTHOR("Luca Risolia "); - -MODULE_DESCRIPTION("Video4Linux driver for " - "W996[87]CF JPEG USB Dual Mode Camera Chip"); - -MODULE_SUPPORTED_DEVICE("Video"); - -MODULE_LICENSE("GPL"); - -MODULE_PARM(vppmod_load, "i"); +MODULE_PARM(vppmod_load, "b"); MODULE_PARM(simcams, "i"); MODULE_PARM(video_nr, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); MODULE_PARM(packet_size, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); MODULE_PARM(max_buffers, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); -MODULE_PARM(double_buffer, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); -MODULE_PARM(clamping, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); +MODULE_PARM(double_buffer, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b"); +MODULE_PARM(clamping, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b"); MODULE_PARM(filter_type, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); -MODULE_PARM(largeview, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); +MODULE_PARM(largeview, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b"); MODULE_PARM(decompression, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); -MODULE_PARM(upscaling, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); +MODULE_PARM(upscaling, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b"); MODULE_PARM(force_palette, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); MODULE_PARM(force_rgb, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); -MODULE_PARM(autobright, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); -MODULE_PARM(autoexp, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); -MODULE_PARM(lightfreq, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); -MODULE_PARM(bandingfilter, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); -MODULE_PARM(clockdiv, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); -MODULE_PARM(backlight, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); -MODULE_PARM(mirror, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); -MODULE_PARM(sensor_mono, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); +MODULE_PARM(autobright, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b"); +MODULE_PARM(autoexp, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b"); +MODULE_PARM(lightfreq, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); +MODULE_PARM(bandingfilter, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b"); +MODULE_PARM(clockdiv, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i"); +MODULE_PARM(backlight, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b"); +MODULE_PARM(mirror, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b"); +MODULE_PARM(monochrome, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "b"); 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"); @@ -125,7 +118,7 @@ MODULE_PARM(whiteness, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l"); #ifdef W9968CF_DEBUG MODULE_PARM(debug, "i"); -MODULE_PARM(specific_debug, "i"); +MODULE_PARM(specific_debug, "b"); #endif MODULE_PARM_DESC(vppmod_load, @@ -163,7 +156,7 @@ "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")." "\n"); MODULE_PARM_DESC(max_buffers, - "\n Only for advanced users." + "\n For advanced users." "\nSpecify the maximum number of video frame buffers" "\nto allocate for each device, from 2 to " __MODULE_STRING(W9968CF_MAX_BUFFERS) @@ -206,7 +199,8 @@ "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING) " for every device." "\nIf 'w9968cf-vpp' is not loaded, this paramater is" - " set to 0."); + " set to 0." + "\n"); MODULE_PARM_DESC(decompression, "\n<0|1|2[,...]> Software video decompression:" "\n- 0 disables decompression (doesn't allow formats needing" @@ -221,7 +215,8 @@ "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION) " for every device." "\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, "\n<0" "|" __MODULE_STRING(VIDEO_PALETTE_UYVY) @@ -255,7 +250,8 @@ "\nInitial palette is " __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"." "\nIf 'w9968cf-vpp' is not loaded, this paramater is" - " set to 9 (UYVY)."); + " set to 9 (UYVY)." + "\n"); MODULE_PARM_DESC(force_rgb, "\n<0|1[,...]> Read RGB video data instead of BGR:" "\n 1 = use RGB component ordering." @@ -314,10 +310,11 @@ "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR) " for every device." "\n"); -MODULE_PARM_DESC(sensor_mono, - "\n<0|1[,...]> The OV CMOS sensor is monochrome:" +MODULE_PARM_DESC(monochrome, + "\n<0|1[,...]> Use OV CMOS sensor as monochrome sensor:" "\n 0 = no, 1 = yes" - "\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." "\n"); MODULE_PARM_DESC(brightness, @@ -349,7 +346,7 @@ #ifdef W9968CF_DEBUG MODULE_PARM_DESC(debug, "\n Debugging information level, from 0 to 6:" - "\n0 = none (be cautious)" + "\n0 = none (use carefully)" "\n1 = critical errors" "\n2 = significant informations" "\n3 = configuration or general messages" @@ -383,29 +380,23 @@ static int w9968cf_release(struct inode*, struct file*); static ssize_t w9968cf_read(struct file*, char*, size_t, loff_t*); static int w9968cf_mmap(struct file*, struct vm_area_struct*); -static int w9968cf_ioctl(struct inode*, struct file*, - unsigned int, unsigned long); -static int w9968cf_do_ioctl(struct w9968cf_device*, unsigned int, void*); +static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long); +static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int, void*); -/* /proc interface */ #if defined(CONFIG_VIDEO_PROC_FS) +/* /proc interface */ static void w9968cf_proc_create(void); static void w9968cf_proc_destroy(void); static void w9968cf_proc_create_dev(struct w9968cf_device*); static void w9968cf_proc_destroy_dev(struct w9968cf_device*); static int w9968cf_proc_read_global(char*, char**, off_t, int, int*, void*); static int w9968cf_proc_read_dev(char*, char**, off_t, int, int*, void*); -#else -static inline void w9968cf_proc_create(void) {} -static inline void w9968cf_proc_destroy(void) {} -static inline void w9968cf_proc_create_dev(struct w9968cf_device* cam) {} -static inline void w9968cf_proc_destroy_dev(struct w9968cf_device* cam) {} #endif /* USB-specific */ -static void w9968cf_urb_complete(struct urb *urb); static int w9968cf_start_transfer(struct w9968cf_device*); static int w9968cf_stop_transfer(struct w9968cf_device*); +static void w9968cf_urb_complete(struct urb *urb); 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_write_fsb(struct w9968cf_device*, u16* data); @@ -413,7 +404,6 @@ static int w9968cf_read_sb(struct w9968cf_device*); static int w9968cf_upload_quantizationtables(struct w9968cf_device*); - /* Low-level I2C (SMBus) I/O */ static int w9968cf_smbus_start(struct w9968cf_device*); static int w9968cf_smbus_stop(struct w9968cf_device*); @@ -421,6 +411,7 @@ static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v); static int w9968cf_smbus_write_ack(struct w9968cf_device*); static int w9968cf_smbus_read_ack(struct w9968cf_device*); +static int w9968cf_smbus_refresh_bus(struct w9968cf_device*); static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam, u16 address, u8* value); static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address, @@ -457,12 +448,11 @@ static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val); static inline int w9968cf_sensor_cmd(struct w9968cf_device*, unsigned int cmd, void *arg); -static void w9968cf_sensor_configure(struct w9968cf_device*); -static int w9968cf_sensor_change_settings(struct w9968cf_device*); -static int w9968cf_sensor_get_picture(struct w9968cf_device*, - struct video_picture*); -static int w9968cf_sensor_set_picture(struct w9968cf_device*, - struct video_picture pict); +static int w9968cf_sensor_init(struct w9968cf_device*); +static int w9968cf_sensor_update_settings(struct w9968cf_device*); +static int w9968cf_sensor_get_picture(struct w9968cf_device*); +static int w9968cf_sensor_update_picture(struct w9968cf_device*, + struct video_picture pict); /* Other helper functions */ static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*, @@ -608,8 +598,6 @@ * Memory management functions * ****************************************************************************/ -/* Shameless copy from bttv-driver.c */ - /* Here we want the physical address of the memory. This is used when initializing the contents of the area. */ static inline unsigned long kvirt_to_pa(unsigned long adr) @@ -660,7 +648,6 @@ } vfree(mem); } -/* End of shameless copy */ /*-------------------------------------------------------------------------- @@ -834,7 +821,7 @@ list_for_each(ptr, list) { cam = list_entry(ptr, struct w9968cf_device, v4llist); out += sprintf(out,"/dev/video%d : %s\n", - cam->v4ldev.minor, symbolic(camlist, cam->id)); + cam->v4ldev->minor, symbolic(camlist, cam->id)); } up(&w9968cf_devlist_sem); @@ -865,21 +852,18 @@ int len; char* out = page; - static struct video_picture pict; /* it has to be static */ - static int rc = 0; - if (down_interruptible(&cam->procfs_sem)) return -ERESTARTSYS; if (offset == 0) - rc = w9968cf_sensor_get_picture(cam, &pict); + w9968cf_sensor_get_picture(cam); out += sprintf(out,"camera_model : %s\n", symbolic(camlist, cam->id)); out += sprintf(out,"sensor_model : %s\n", symbolic(senlist, cam->sensor)); out += sprintf(out,"sensor_monochrome : %s\n", - YES_NO(cam->sensor_mono)); + YES_NO(cam->monochrome)); if (cam->users) out += sprintf(out,"user_program : %s\n",cam->command); out += sprintf(out,"packet_size_bytes : %d\n", @@ -920,13 +904,11 @@ out += sprintf(out,"banding_filter : %s\n",YES_NO(cam->bandfilt)); out += sprintf(out,"back_light : %s\n",YES_NO(cam->backlight)); out += sprintf(out,"mirror : %s\n",YES_NO(cam->mirror)); - if (!rc) { - out += sprintf(out,"brightness : %d\n",pict.brightness); - out += sprintf(out,"colour : %d\n",pict.colour); - out += sprintf(out,"contrast : %d\n",pict.contrast); - out += sprintf(out,"hue : %d\n",pict.hue); - out += sprintf(out,"whiteness : %d\n",pict.whiteness); - } + out += sprintf(out,"brightness : %d\n",cam->picture.brightness); + out += sprintf(out,"colour : %d\n",cam->picture.colour); + out += sprintf(out,"contrast : %d\n",cam->picture.contrast); + out += sprintf(out,"hue : %d\n",cam->picture.hue); + out += sprintf(out,"whiteness : %d\n",cam->picture.whiteness); out += sprintf(out,"hs_polarity : %d\n",cam->hs_polarity); out += sprintf(out,"vs_polarity : %d\n",cam->vs_polarity); #ifdef W9968CF_DEBUG @@ -954,34 +936,40 @@ static void w9968cf_proc_create_dev(struct w9968cf_device* cam) { - char name[5]; + char name[6]; if (!w9968cf_proc_entry) return; /* Create per-device readable entry */ - sprintf(name, "dev%d", cam->v4ldev.minor); - cam->proc_dev = create_proc_read_entry(name, S_IFREG|S_IRUGO|S_IWUSR, + sprintf(name, "dev%d", cam->v4ldev->minor); + cam->proc_dev = create_proc_read_entry(name, S_IFREG|S_IRUGO|S_IWUSR, w9968cf_proc_entry, w9968cf_proc_read_dev, (void*)cam); if (!cam->proc_dev) return; cam->proc_dev->owner = THIS_MODULE; + + DBG(2, "Per-device entry /proc/video/w9968cf/dev%d created.", + cam->v4ldev->minor) } static void w9968cf_proc_destroy_dev(struct w9968cf_device* cam) { - char name[5]; + char name[6]; if (!cam->proc_dev) return; - sprintf(name, "dev%d", cam->v4ldev.minor); + sprintf(name, "dev%d", cam->v4ldev->minor); /* Destroy per-device entry */ remove_proc_entry(name, w9968cf_proc_entry); + + DBG(2, "Per-device entry /proc/video/w9968cf/dev%d removed.", + cam->v4ldev->minor) } @@ -1010,7 +998,7 @@ else DBG(2, "Unable to create /proc/video/w9968cf/global") - DBG(5, "/proc entries successfully created.") + DBG(2, "Main entry /proc/video/w9968cf/global created.") } @@ -1024,7 +1012,7 @@ remove_proc_entry("w9968cf", video_proc_entry); - DBG(5, "/proc entries removed.") + DBG(2, "Main entry /proc/video/w9968cf/global removed.") } #endif /* CONFIG_VIDEO_PROC_FS */ @@ -1184,14 +1172,12 @@ for (i = 0; i < W9968CF_URBS; i++) { urb = usb_alloc_urb(W9968CF_ISO_PACKETS); cam->urb[i] = urb; - if (!urb) { for (j = 0; j < i; j++) usb_free_urb(cam->urb[j]); DBG(1, "Couldn't allocate the URB structures.") return -ENOMEM; } - urb->dev = udev; urb->context = (void*)cam; urb->pipe = usb_rcvisocpipe(udev, 1); @@ -1214,7 +1200,7 @@ t_size = (w*h*d)/16; - err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ + err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */ err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */ /* Transfer size */ @@ -1287,11 +1273,12 @@ spin_unlock_irqrestore(&cam->urb_lock, lock_flags); for (i = W9968CF_URBS-1; i >= 0; i--) - if (cam->urb[i]) + if (cam->urb[i]) { if (!usb_unlink_urb(cam->urb[i])) { usb_free_urb(cam->urb[i]); cam->urb[i] = NULL; } + } if (cam->disconnected) goto exit; @@ -1347,8 +1334,7 @@ res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, index, (void*)buff, - 2, W9968CF_USB_CTRL_TIMEOUT); + 0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT); if (res < 0) DBG(4, "Failed to read a register " @@ -1360,7 +1346,7 @@ /*-------------------------------------------------------------------------- - Write data to the fast serial bus registers. + Write 64-bit data to the fast serial bus registers. Return 0 on success, -1 otherwise. --------------------------------------------------------------------------*/ static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data) @@ -1373,8 +1359,7 @@ res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, - value, 0x06, (void*)data, 6, - W9968CF_USB_CTRL_TIMEOUT); + value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT); if (res < 0) DBG(4, "Failed to write the FSB registers " @@ -1536,6 +1521,22 @@ } +/* This is seems to refresh the communication through the serial bus */ +static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam) +{ + int err = 0, j; + + for (j = 1; j <= 10; j++) { + err = w9968cf_write_reg(cam, 0x0020, 0x01); + err += w9968cf_write_reg(cam, 0x0000, 0x01); + if (err) + break; + } + + return err; +} + + /* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */ static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, @@ -1544,8 +1545,10 @@ u16* data = cam->data_buffer; int err = 0; - /* Enable SBUS outputs */ - err += w9968cf_write_reg(cam, 0x0020, 0x01); + err += w9968cf_smbus_refresh_bus(cam); + + /* Enable SBUS outputs */ + err += w9968cf_write_sb(cam, 0x0020); data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0); data[0] |= (address & 0x40) ? 0x4000 : 0x0; @@ -1589,7 +1592,7 @@ err += w9968cf_write_fsb(cam, data); /* Disable SBUS outputs */ - err += w9968cf_write_reg(cam, 0x0000, 0x01); + err += w9968cf_write_sb(cam, 0x0000); if (!err) DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X " @@ -1626,7 +1629,7 @@ err += w9968cf_smbus_read_byte(cam, value); err += w9968cf_smbus_write_ack(cam); err += w9968cf_smbus_stop(cam); - + /* Serial data disable */ err += w9968cf_write_sb(cam, 0x0000); @@ -1695,8 +1698,8 @@ int size, union i2c_smbus_data *data) { struct w9968cf_device* cam = adapter->data; - u8 i, j; - int rc = 0, err = 0; + u8 i; + int err = 0; switch (addr) { case OV6xx0_SID: @@ -1712,31 +1715,26 @@ addr <<= 1; if (read_write == I2C_SMBUS_WRITE) - rc = w9968cf_i2c_adap_write_byte(cam, addr, command); + err = w9968cf_i2c_adap_write_byte(cam, addr, command); else if (read_write == I2C_SMBUS_READ) - rc = w9968cf_i2c_adap_read_byte(cam,addr, &data->byte); + err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte); } else if (size == I2C_SMBUS_BYTE_DATA) { addr <<= 1; if (read_write == I2C_SMBUS_WRITE) - rc = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr, + err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr, command, data->byte); else if (read_write == I2C_SMBUS_READ) { for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) { - rc = w9968cf_i2c_adap_read_byte_data(cam, addr, + err = w9968cf_i2c_adap_read_byte_data(cam,addr, command, &data->byte); - if (rc < 0) { - /* Work around: this seems to wake up - the EEPROM from the stall state */ - for (j = 0; j <= 10; j++) { - err += w9968cf_write_sb(cam,0x0020); - err += w9968cf_write_sb(cam,0x0000); - if (err) - break; + if (err) { + if (w9968cf_smbus_refresh_bus(cam)) { + err = -EIO; + break; } - } - else + } else break; } @@ -1748,11 +1746,7 @@ return -EINVAL; } - /* This works around a bug in the I2C core */ - if (rc > 0) - rc = 0; - - return rc; + return err; } @@ -1768,41 +1762,22 @@ { struct w9968cf_device* cam = client->adapter->data; const char* clientname = client->name; - int id = client->driver->id; + int id = client->driver->id, err = 0; if (id == I2C_DRIVERID_OVCAMCHIP) { - int rc = 0; - cam->sensor_client = client; - - rc = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, - &cam->sensor_mono); - if (rc < 0) { - DBG(1, "CMOS sensor initialization failed (rc=%d)",rc); - cam->sensor_client = NULL; - return rc; - } - - if (w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE, - &cam->sensor) < 0) - rc = -EIO; - else if (client->addr==OV7xx0_SID || client->addr==OV6xx0_SID) - w9968cf_sensor_configure(cam); - else - rc = -EINVAL; - - if (rc < 0) { + err = w9968cf_sensor_init(cam); + if (err) { cam->sensor_client = NULL; - cam->sensor = CC_UNKNOWN; - return rc; + return err; } - } else { - DBG(4, "Rejected client [%s] with [%s]", + } else { + DBG(4, "Rejected client [%s] with driver [%s]", clientname, client->driver->name) - return -1; + return -EINVAL; } - DBG(2, "I2C attach client [%s] with [%s]", + DBG(5, "I2C attach client [%s] with driver [%s]", clientname, client->driver->name) return 0; @@ -1818,7 +1793,7 @@ cam->sensor_client = NULL; } - DBG(2, "I2C detach [%s]", clientname) + DBG(5, "I2C detach client [%s]", clientname) return 0; } @@ -1846,7 +1821,7 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam) { - int rc = 0; + int err = 0; static struct i2c_algorithm algo = { .name = "W996[87]CF algorithm", @@ -1869,15 +1844,15 @@ strcpy(cam->i2c_adapter.name, "w9968cf"); cam->i2c_adapter.data = cam; - DBG(6, "Registering I2C bus with kernel...") + DBG(6, "Registering I2C adapter with kernel...") - rc = i2c_add_adapter(&cam->i2c_adapter); - if (rc) - DBG(5, "Failed to register the I2C bus.") + err = i2c_add_adapter(&cam->i2c_adapter); + if (err) + DBG(1, "Failed to register the I2C adapter.") else - DBG(5, "I2C bus registered.") + DBG(5, "I2C adapter registered.") - return rc; + return err; } @@ -1917,7 +1892,7 @@ --------------------------------------------------------------------------*/ static int w9968cf_init_chip(struct w9968cf_device* cam) { - int err = 0, rc = 0; + int err = 0; err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */ err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */ @@ -1952,22 +1927,11 @@ err += w9968cf_set_window(cam, cam->window); if (err) - goto error; - - rc = w9968cf_sensor_change_settings(cam); - if (rc) - goto error; - - DBG(5, "Chip successfully initialized."); - - return 0; - -error: - DBG(1, "Chip initialization failed.") - if (err) - return err; + DBG(1, "Chip initialization failed.") else - return rc; + DBG(5, "Chip successfully initialized.") + + return err; } @@ -1979,7 +1943,7 @@ w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict) { u16 fmt, hw_depth, hw_palette, reg_v = 0x0000; - int err = 0, rc = 0; + int err = 0; /* Make sure we are using a valid depth */ pict.depth = w9968cf_valid_depth(pict.palette); @@ -2040,12 +2004,10 @@ else if (cam->filter_type == 2) reg_v |= 0x000c; - err = w9968cf_write_reg(cam, reg_v, 0x16); - if (err) + if ((err = w9968cf_write_reg(cam, reg_v, 0x16))) goto error; - rc = w9968cf_sensor_set_picture(cam, pict); - if (rc) + if ((err = w9968cf_sensor_update_picture(cam, pict))) goto error; /* If all went well, update the device data structure */ @@ -2064,10 +2026,7 @@ error: DBG(1, "Failed to change picture settings.") - if (err) - return err; - else - return rc; + return err; } @@ -2082,7 +2041,7 @@ u16 x, y, w, h, scx, scy, cw, ch, ax, ay; unsigned long fw, fh; struct ovcamchip_window s_win; - int err=0, rc=0; + int err = 0; /* Work around to avoid FP arithmetics */ #define __SC(x) ((x) << 10) @@ -2126,8 +2085,8 @@ ch = h; } - /* Setup the sensor window */ - s_win.format = SENSOR_FORMAT; + /* Setup the window of the sensor */ + s_win.format = VIDEO_PALETTE_UYVY; s_win.width = cam->maxwidth; s_win.height = cam->maxheight; s_win.quarter = 0; /* full progressive video */ @@ -2156,7 +2115,7 @@ s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR; } - /* We have to scale win.x and win.y offsets */ + /* We have to scale win.x and win.y offsets */ if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) || (cam->vpp_flag & VPP_UPSCALE) ) { ax = __SC(win.x)/fw; @@ -2187,7 +2146,7 @@ y = ay + s_win.y; /* Go ! */ - if ((rc = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win))) + if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win))) goto error; err += w9968cf_write_reg(cam, scx + x, 0x10); @@ -2232,10 +2191,7 @@ error: DBG(1, "Failed to change the capture area size.") - if (err) - return err; - else - return rc; + return err; } @@ -2450,173 +2406,192 @@ w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val) { struct ovcamchip_control ctl; - int rc; + int err; ctl.id = cid; ctl.value = val; - rc = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl); + err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl); - return rc; + return err; } + static int -w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int *val) +w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val) { struct ovcamchip_control ctl; - int rc; + int err; ctl.id = cid; - rc = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl); - if (rc >= 0) + err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl); + if (!err) *val = ctl.value; - return rc; + return err; } static inline int -w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void *arg) +w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg) { struct i2c_client* c = cam->sensor_client; + int rc = 0; - DBG(6, "Executing CMOS sensor command...") - - if (c && c->driver->command) - return c->driver->command(cam->sensor_client, cmd, arg); - else + if (c->driver->command) { + rc = c->driver->command(cam->sensor_client, cmd, arg); + /* The I2C driver returns -EPERM on non-supported controls */ + return (rc < 0 && rc != -EPERM) ? rc : 0; + } else return -ENODEV; } /*-------------------------------------------------------------------------- - Change some settings of the CMOS sensor. - Returns: 0 for success, a negative number otherwise. + Update some settings of the CMOS sensor. + 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 */ - rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, - cam->auto_brt); - if (SENSOR_FATAL_ERROR(rc)) - return rc; + err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, + cam->auto_brt); + if (err) + return err; /* Auto exposure */ - rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, - cam->auto_exp); - if (SENSOR_FATAL_ERROR(rc)) - return rc; + err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, + cam->auto_exp); + if (err) + return err; /* Banding filter */ - rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, - cam->bandfilt); - if (SENSOR_FATAL_ERROR(rc)) - return rc; + err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, + cam->bandfilt); + if (err) + return err; /* Light frequency */ - rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ, - cam->lightfreq); - if (SENSOR_FATAL_ERROR(rc)) - return rc; + err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ, + cam->lightfreq); + if (err) + return err; /* Back light */ - rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT, - cam->backlight); - if (SENSOR_FATAL_ERROR(rc)) - return rc; + err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT, + cam->backlight); + if (err) + return err; /* Mirror */ - rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR, - cam->mirror); - if (SENSOR_FATAL_ERROR(rc)) - return rc; + err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR, + cam->mirror); + if (err) + return err; return 0; } /*-------------------------------------------------------------------------- - Get some current picture settings from the CMOS sensor. - Returns: 0 for success, a negative number otherwise. + Get some current picture settings from the CMOS sensor and update the + internal 'picture' structure of the camera. + Returns: 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/ -static int -w9968cf_sensor_get_picture(struct w9968cf_device* cam, - struct video_picture* pict) +static int w9968cf_sensor_get_picture(struct w9968cf_device* cam) { - int rc, v; + int err, v; - /* Don't return error if a setting is unsupported, or rest of settings - will not be performed */ + err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v); + if (err) + return err; + cam->picture.contrast = v; - rc = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &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); - if (SENSOR_FATAL_ERROR(rc)) - return rc; - pict->colour = v; - - rc = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v); - if (SENSOR_FATAL_ERROR(rc)) - return rc; - pict->hue = v; + err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v); + if (err) + return err; + cam->picture.brightness = v; - pict->whiteness = W9968CF_WHITENESS; /* to do! */ + err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v); + if (err) + return err; + cam->picture.colour = v; + + err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v); + if (err) + return err; + cam->picture.hue = v; DBG(5, "Got picture settings from the CMOS sensor.") PDBGG("Brightness, contrast, hue, colour, whiteness are " - "%d,%d,%d,%d,%d.", pict->brightness, pict->contrast, - pict->hue, pict->colour, pict->whiteness) + "%d,%d,%d,%d,%d.", cam->picture.brightness,cam->picture.contrast, + cam->picture.hue, cam->picture.colour, cam->picture.whiteness) return 0; } /*-------------------------------------------------------------------------- - Change picture settings of the CMOS sensor. - Returns: 0 for success, a negative number otherwise. + Update picture settings of the CMOS sensor. + Returns: 0 on success, a negative number otherwise. --------------------------------------------------------------------------*/ static int -w9968cf_sensor_set_picture(struct w9968cf_device* cam, - struct video_picture pict) +w9968cf_sensor_update_picture(struct w9968cf_device* cam, + struct video_picture pict) { - int rc; - - rc = w9968cf_sensor_set_control(cam,OVCAMCHIP_CID_CONT, pict.contrast); - if (SENSOR_FATAL_ERROR(rc)) - return rc; + int err = 0; - if (!cam->auto_brt) { - rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, - pict.brightness); - if (SENSOR_FATAL_ERROR(rc)) - return rc; + if ((!cam->sensor_initialized) + || pict.contrast != cam->picture.contrast) { + err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT, + pict.contrast); + if (err) + goto fail; + DBG(4, "Contrast changed from %d to %d.", + cam->picture.contrast, pict.contrast) + cam->picture.contrast = pict.contrast; } - rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT, pict.colour); - if (SENSOR_FATAL_ERROR(rc)) - return rc; + if (((!cam->sensor_initialized) || + pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) { + err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, + pict.brightness); + if (err) + goto fail; + DBG(4, "Brightness changed from %d to %d.", + cam->picture.brightness, pict.brightness) + cam->picture.brightness = pict.brightness; + } - rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, pict.hue); - if (SENSOR_FATAL_ERROR(rc)) - return rc; + if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) { + err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT, + pict.colour); + if (err) + goto fail; + DBG(4, "Colour changed from %d to %d.", + cam->picture.colour, pict.colour) + cam->picture.colour = pict.colour; + } - PDBGG("Brightness, contrast, hue, colour, whiteness are " - "%d,%d,%d,%d,%d.", pict.brightness, pict.contrast, - pict.hue, pict.colour, pict.whiteness) + if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) { + err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, + pict.hue); + if (err) + goto fail; + DBG(4, "Hue changed from %d to %d.", + cam->picture.hue, pict.hue) + cam->picture.hue = pict.hue; + } return 0; + +fail: + DBG(4, "Failed to change sensor picture setting.") + return err; } @@ -2626,12 +2601,22 @@ ****************************************************************************/ /*-------------------------------------------------------------------------- - This function is called when the CMOS sensor is detected. + This function is called when a supported CMOS sensor is detected. + Return 0 if the initialization succeeds, a negative number otherwise. --------------------------------------------------------------------------*/ -static void w9968cf_sensor_configure(struct w9968cf_device* cam) +static int w9968cf_sensor_init(struct w9968cf_device* cam) { - /* NOTE: Make sure width and height are a multiple of 16 */ + int err = 0; + + if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, + &cam->monochrome))) + goto error; + if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE, + &cam->sensor))) + goto error; + + /* NOTE: Make sure width and height are a multiple of 16 */ switch (cam->sensor_client->addr) { case OV6xx0_SID: cam->maxwidth = 352; @@ -2645,6 +2630,10 @@ cam->minwidth = 64; cam->minheight = 48; break; + default: + DBG(1, "Not supported CMOS sensor detected for %s.", + symbolic(camlist, cam->id)) + return -EINVAL; } /* These values depend on the ones in the ovxxx0.c sources */ @@ -2663,7 +2652,24 @@ 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; } @@ -2678,7 +2684,7 @@ enum w9968cf_model_id mod_id, const unsigned short dev_nr) { -#if defined(CONFIG_VIDEO_PROC_FS) +#ifdef CONFIG_VIDEO_PROC_FS init_MUTEX(&cam->procfs_sem); #endif init_MUTEX(&cam->fileop_sem); @@ -2691,13 +2697,7 @@ cam->usbdev = udev; cam->id = mod_id; cam->sensor = CC_UNKNOWN; - - strcpy(cam->v4ldev.name, symbolic(camlist, mod_id)); - cam->v4ldev.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; - cam->v4ldev.hardware = VID_HARDWARE_W9968CF; - cam->v4ldev.fops = &w9968cf_fops; - cam->v4ldev.priv = (void*)cam; - cam->v4ldev.minor = video_nr[dev_nr]; + cam->sensor_initialized = 0; /* Calculate the alternate setting number (from 1 to 16) according to the 'packet_size' module parameter */ @@ -2709,66 +2709,66 @@ cam->max_buffers = (max_buffers[dev_nr] < 2 || max_buffers[dev_nr] > W9968CF_MAX_BUFFERS) - ? W9968CF_BUFFERS : max_buffers[dev_nr]; + ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr]; cam->double_buffer = (double_buffer[dev_nr] == 0 || double_buffer[dev_nr] == 1) - ? double_buffer[dev_nr] : W9968CF_DOUBLE_BUFFER; + ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER; cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1) - ? clamping[dev_nr] : W9968CF_CLAMPING; + ? (u8)clamping[dev_nr] : W9968CF_CLAMPING; cam->filter_type = (filter_type[dev_nr] == 0 || filter_type[dev_nr] == 1 || filter_type[dev_nr] == 2) - ? filter_type[dev_nr] : W9968CF_FILTER_TYPE; + ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE; cam->capture = 1; cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1) - ? largeview[dev_nr] : W9968CF_LARGEVIEW; + ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW; cam->decompression = (decompression[dev_nr] == 0 || decompression[dev_nr] == 1 || decompression[dev_nr] == 2) - ? decompression[dev_nr] : W9968CF_DECOMPRESSION; + ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION; cam->upscaling = (upscaling[dev_nr] == 0 || upscaling[dev_nr] == 1) - ? upscaling[dev_nr] : W9968CF_UPSCALING; + ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING; cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1) - ? autobright[dev_nr] : W9968CF_AUTOBRIGHT; + ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT; cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1) - ? autoexp[dev_nr] : W9968CF_AUTOEXP; + ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP; cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60) - ? lightfreq[dev_nr] : W9968CF_LIGHTFREQ; + ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ; cam->bandfilt = (bandingfilter[dev_nr] == 0 || bandingfilter[dev_nr] == 1) - ? bandingfilter[dev_nr] : W9968CF_BANDINGFILTER; + ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER; cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1) - ? backlight[dev_nr] : W9968CF_BACKLIGHT; + ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT; cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0) - ? clockdiv[dev_nr] : W9968CF_CLOCKDIV; + ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV; cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1) - ? mirror[dev_nr] : W9968CF_MIRROR; + ? (u8)mirror[dev_nr] : W9968CF_MIRROR; - cam->sensor_mono = (sensor_mono[dev_nr]==0 || sensor_mono[dev_nr]==1) - ? sensor_mono[dev_nr] : W9968CF_SENSOR_MONO; + cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1) + ? monochrome[dev_nr] : W9968CF_MONOCHROME; - cam->picture.brightness = brightness[dev_nr]; - cam->picture.hue = hue[dev_nr]; - cam->picture.colour = colour[dev_nr]; - cam->picture.contrast = contrast[dev_nr]; - cam->picture.whiteness = whiteness[dev_nr]; - if (w9968cf_valid_palette(force_palette[dev_nr])) { - cam->picture.palette = force_palette[dev_nr]; + cam->picture.brightness = (u16)brightness[dev_nr]; + cam->picture.hue = (u16)hue[dev_nr]; + cam->picture.colour = (u16)colour[dev_nr]; + cam->picture.contrast = (u16)contrast[dev_nr]; + cam->picture.whiteness = (u16)whiteness[dev_nr]; + if (w9968cf_valid_palette((u16)force_palette[dev_nr])) { + cam->picture.palette = (u16)force_palette[dev_nr]; cam->force_palette = 1; } else { cam->force_palette = 0; @@ -2781,7 +2781,7 @@ } cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1) - ? force_rgb[dev_nr] : W9968CF_FORCE_RGB; + ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB; cam->window.x = 0; cam->window.y = 0; @@ -2886,7 +2886,7 @@ else DBG(3, "- Clock divisor: %d", cam->clockdiv) - if (cam->sensor_mono) + if (cam->monochrome) DBG(3, "- CMOS sensor used as monochrome.") else DBG(3, "- CMOS sensor not used as monochrome.") @@ -2902,10 +2902,12 @@ { 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) +#ifdef CONFIG_VIDEO_PROC_FS w9968cf_proc_destroy_dev(cam); - video_unregister_device(&cam->v4ldev); +#endif + video_unregister_device(cam->v4ldev); list_del(&cam->v4llist); i2c_del_adapter(&cam->i2c_adapter); w9968cf_deallocate_memory(cam); @@ -2925,24 +2927,25 @@ static int w9968cf_open(struct inode* inode, struct file* filp) { - struct w9968cf_device* cam = - (struct w9968cf_device*)video_devdata(filp)->priv; + struct w9968cf_device* cam; int err; + cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); + down(&cam->dev_sem); if (cam->sensor == CC_UNKNOWN) { DBG(2, "No supported CMOS sensor has been detected by the " "'ovcamchip' module for the %s (/dev/video%d). Make " "sure it is loaded *before* the 'w9968cf' module.", - symbolic(camlist, cam->id),cam->v4ldev.minor) + symbolic(camlist, cam->id), cam->v4ldev->minor) up(&cam->dev_sem); return -ENODEV; } if (cam->users) { DBG(2, "%s (/dev/video%d) has been already occupied by '%s'.", - symbolic(camlist, cam->id),cam->v4ldev.minor, cam->command) + symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command) if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { up(&cam->dev_sem); return -EWOULDBLOCK; @@ -2958,7 +2961,7 @@ } DBG(5, "Opening the %s, /dev/video%d ...", - symbolic(camlist, cam->id), cam->v4ldev.minor) + symbolic(camlist, cam->id), cam->v4ldev->minor) cam->streaming = 0; cam->misconfigured = 0; @@ -2975,7 +2978,7 @@ if ((err = w9968cf_start_transfer(cam))) goto deallocate_memory; - filp->private_data = (void*)cam; + filp->private_data = cam; cam->users++; strcpy(cam->command, current->comm); @@ -2997,8 +3000,9 @@ static int w9968cf_release(struct inode* inode, struct file* filp) { - struct w9968cf_device* cam = - (struct w9968cf_device*)video_devdata(filp)->priv; + struct w9968cf_device* cam; + + cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); down(&cam->dev_sem); /* prevent disconnect() to be called */ @@ -3026,11 +3030,12 @@ static ssize_t w9968cf_read(struct file* filp, char* buf, size_t count, loff_t* f_pos) { - struct w9968cf_device* cam = - (struct w9968cf_device*)video_devdata(filp)->priv; + struct w9968cf_device* cam; struct w9968cf_frame_t* fr; int err = 0; + cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); + if (filp->f_flags & O_NONBLOCK) return -EWOULDBLOCK; @@ -3094,9 +3099,8 @@ static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma) { - struct w9968cf_device* cam = - (struct w9968cf_device*)video_devdata(filp)->priv; - + struct w9968cf_device* cam = (struct w9968cf_device*) + video_get_drvdata(video_devdata(filp)); unsigned long vsize = vma->vm_end - vma->vm_start, psize = cam->nbuffers * w9968cf_get_max_bufsize(cam), start = vma->vm_start, @@ -3136,10 +3140,11 @@ w9968cf_ioctl(struct inode* inode, struct file* filp, unsigned int cmd, unsigned long arg) { - struct w9968cf_device* cam = - (struct w9968cf_device*)video_devdata(filp)->priv; + struct w9968cf_device* cam; int err; + cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); + if (down_interruptible(&cam->fileop_sem)) return -ERESTARTSYS; @@ -3155,7 +3160,7 @@ return -EIO; } - err = w9968cf_do_ioctl(cam, cmd, (void*)arg); + err = w9968cf_v4l_ioctl(inode, filp, cmd, (void* )arg); up(&cam->fileop_sem); return err; @@ -3163,8 +3168,10 @@ static int -w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg) +w9968cf_v4l_ioctl(struct inode* inode, struct file* filp, + unsigned int cmd, void* arg) { + struct w9968cf_device* cam; const char* v4l1_ioctls[] = { "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF", @@ -3176,7 +3183,9 @@ #define V4L1_IOCTL(cmd) \ ((_IOC_NR((cmd)) < sizeof(v4l1_ioctls)/sizeof(char*)) ? \ - v4l1_ioctls[_IOC_NR((cmd))] : "???") + v4l1_ioctls[_IOC_NR((cmd))] : "?") + + cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); switch (cmd) { @@ -3190,7 +3199,7 @@ .minheight = cam->minheight, }; sprintf(cap.name, "W996[87]CF USB Camera #%d", - cam->v4ldev.minor); + cam->v4ldev->minor); cap.maxwidth = (cam->upscaling && w9968cf_vppmod_present) ? W9968CF_MAX_WIDTH : cam->maxwidth; cap.maxheight = (cam->upscaling && w9968cf_vppmod_present) @@ -3241,15 +3250,10 @@ case VIDIOCGPICT: /* get image properties of the picture */ { - struct video_picture pict; - - if (w9968cf_sensor_get_picture(cam, &pict)) + if (w9968cf_sensor_get_picture(cam)) return -EIO; - pict.depth = cam->picture.depth; - pict.palette = cam->picture.palette; - - if (copy_to_user(arg, &pict, sizeof(pict))) + if (copy_to_user(arg, &cam->picture, sizeof(cam->picture))) return -EFAULT; DBG(5, "VIDIOCGPICT successfully called.") @@ -3278,13 +3282,6 @@ return -EINVAL; } - if (pict.depth != w9968cf_valid_depth(pict.palette)) { - DBG(4, "Depth %d bpp is not supported for %s palette. " - "VIDIOCSPICT failed.", - pict.depth, symbolic(v4l1_plist, pict.palette)) - return -EINVAL; - } - if (!cam->force_palette) { if (cam->decompression == 0) { if (w9968cf_need_decompression(pict.palette)) { @@ -3303,9 +3300,15 @@ } } - if (pict.palette != cam->picture.palette || - pict.depth != cam->picture.depth) - { + if (pict.depth != w9968cf_valid_depth(pict.palette)) { + DBG(4, "Requested depth %d bpp is not valid for %s " + "palette: ignored and changed to %d bpp.", + pict.depth, symbolic(v4l1_plist, pict.palette), + w9968cf_valid_depth(pict.palette)) + pict.depth = w9968cf_valid_depth(pict.palette); + } + + if (pict.palette != cam->picture.palette) { if(*cam->requested_frame || cam->frame_current->queued) { err = wait_event_interruptible @@ -3328,15 +3331,9 @@ if (w9968cf_start_transfer(cam)) goto ioctl_fail; - } else if ( ((pict.brightness != cam->picture.brightness) && - (!cam->auto_brt)) || - pict.hue != cam->picture.hue || - pict.colour != cam->picture.colour || - pict.contrast != cam->picture.contrast || - pict.whiteness != cam->picture.whiteness ) { - if (w9968cf_sensor_set_picture(cam, pict)) - return -EIO; - } + } else if (w9968cf_sensor_update_picture(cam, pict)) + return -EIO; + DBG(5, "VIDIOCSPICT successfully called.") return 0; @@ -3368,7 +3365,6 @@ win.y != cam->window.y || win.width != cam->window.width || win.height != cam->window.height) { - if(*cam->requested_frame || cam->frame_current->queued) { err = wait_event_interruptible @@ -3479,12 +3475,12 @@ } } - if (w9968cf_adjust_window_size(cam, (u16*)&mmap.width, - (u16*)&mmap.height)) { + if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width, + (u16*)&mmap.height))) { DBG(4, "Resolution not supported (%dx%d). " "VIDIOCMCAPTURE failed.", mmap.width, mmap.height) - return -EINVAL; + return err; } fr = &cam->frame[mmap.frame]; @@ -3599,7 +3595,7 @@ case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/ { struct video_unit unit = { - .video = cam->v4ldev.minor, + .video = cam->v4ldev->minor, .vbi = VIDEO_NO_UNIT, .radio = VIDEO_NO_UNIT, .audio = VIDEO_NO_UNIT, @@ -3767,14 +3763,6 @@ return NULL; } - err = usb_set_configuration(udev, 1); - err += usb_set_interface(udev, 0, 0); - - if (err) { - DBG(1, "Device configuration failed.") - return NULL; - } - cam = (struct w9968cf_device*) kmalloc(sizeof(struct w9968cf_device), GFP_KERNEL); @@ -3806,10 +3794,24 @@ } memset(cam->data_buffer, 0, 8); - /* Set some basic constants */ - w9968cf_configure_camera(cam, udev, mod_id, dev_nr); + /* Register the V4L device */ + cam->v4ldev = video_device_alloc(); + if (!cam->v4ldev) { + DBG(1, "Could not allocate memory for a V4L structure.") + err = -ENOMEM; + goto fail; + } + + 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]); if (err) { DBG(1, "V4L device registration failed.") @@ -3820,22 +3822,27 @@ 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 */ down(&w9968cf_devlist_sem); list_add(&cam->v4llist, &w9968cf_dev_list); up(&w9968cf_devlist_sem); - dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; w9968cf_turn_on_led(cam); w9968cf_i2c_init(cam); +#ifdef CONFIG_VIDEO_PROC_FS w9968cf_proc_create_dev(cam); +#endif up(&cam->dev_sem); + return (void*)cam; fail: /* Free unused memory */ @@ -3844,6 +3851,8 @@ kfree(cam->control_buffer); if (cam->data_buffer) kfree(cam->data_buffer); + if (cam->v4ldev) + video_device_release(cam->v4ldev); up(&cam->dev_sem); kfree(cam); } @@ -3851,7 +3860,8 @@ } -static void w9968cf_usb_disconnect(struct usb_device* udev, void* drv_context) +static void +w9968cf_usb_disconnect(struct usb_device* udev, void* drv_context) { struct w9968cf_device* cam = (struct w9968cf_device*)drv_context; @@ -3871,7 +3881,7 @@ DBG(2, "The device is open (/dev/video%d)! " "Process name: %s. Deregistration and memory " "deallocation are deferred on close.", - cam->v4ldev.minor, cam->command) + cam->v4ldev->minor, cam->command) cam->misconfigured = 1; @@ -3956,14 +3966,18 @@ init_MUTEX(&w9968cf_devlist_sem); +#ifdef CONFIG_VIDEO_PROC_FS w9968cf_proc_create(); +#endif w9968cf_vppmod_detect(); if ((err = usb_register(&w9968cf_usb_driver))) { if (w9968cf_vppmod_present) w9968cf_vppmod_release(); +#ifdef CONFIG_VIDEO_PROC_FS w9968cf_proc_destroy(); +#endif return err; } @@ -3976,7 +3990,9 @@ /* w9968cf_usb_disconnect() will be called */ usb_deregister(&w9968cf_usb_driver); +#ifdef CONFIG_VIDEO_PROC_FS w9968cf_proc_destroy(); +#endif if (w9968cf_vppmod_present) w9968cf_vppmod_release(); @@ -3987,3 +4003,5 @@ module_init(w9968cf_module_init); module_exit(w9968cf_module_exit); + +EXPORT_NO_SYMBOLS; diff -Nru a/drivers/usb/w9968cf.h b/drivers/usb/w9968cf.h --- a/drivers/usb/w9968cf.h Fri Dec 12 15:05:19 2003 +++ b/drivers/usb/w9968cf.h Fri Dec 12 15:05:19 2003 @@ -1,7 +1,7 @@ /*************************************************************************** * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. * * * - * Copyright (C) 2002 2003 by Luca Risolia * + * Copyright (C) 2002 2003 by Luca Risolia * * * * 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 * @@ -24,11 +24,14 @@ #include #include #include -#include +#ifdef CONFIG_VIDEO_PROC_FS +# include +#endif #include #include #include #include +#include #include #include @@ -106,7 +109,7 @@ #define W9968CF_LARGEVIEW 1 /* 0 disable, 1 enable */ #define W9968CF_UPSCALING 0 /* 0 disable, 1 enable */ -#define W9968CF_SENSOR_MONO 0 /* 0 not monochrome, 1 monochrome sensor */ +#define W9968CF_MONOCHROME 0 /* 0 not monochrome, 1 monochrome sensor */ #define W9968CF_BRIGHTNESS 31000 /* from 0 to 65535 */ #define W9968CF_HUE 32768 /* from 0 to 65535 */ #define W9968CF_COLOUR 32768 /* from 0 to 65535 */ @@ -130,9 +133,10 @@ #define W9968CF_MODULE_NAME "V4L driver for W996[87]CF JPEG USB " \ "Dual Mode Camera Chip" -#define W9968CF_MODULE_VERSION "v1.22" +#define W9968CF_MODULE_VERSION "v1.24-basic" #define W9968CF_MODULE_AUTHOR "(C) 2002 2003 Luca Risolia" -#define W9968CF_AUTHOR_EMAIL "" +#define W9968CF_AUTHOR_EMAIL "" +#define W9968CF_MODULE_LICENSE "GPL" static u8 w9968cf_vppmod_present; /* status flag: yes=1, no=0 */ @@ -172,6 +176,7 @@ }; struct w9968cf_frame_t { + #define W9968CF_HW_BUF_SIZE 640*480*2 /* buf.size of original frames */ void* buffer; u32 length; enum w9968cf_frame_status status; @@ -195,8 +200,8 @@ struct w9968cf_device { enum w9968cf_model_id id; /* private device identifier */ - struct video_device v4ldev; /* V4L structure */ - struct list_head v4llist; /* entry of the list of V4L cameras */ + struct video_device* v4ldev; /* -> V4L structure */ + struct list_head v4llist; /* entry of the list of V4L cameras */ struct usb_device* usbdev; /* -> main USB structure */ struct urb* urb[W9968CF_URBS]; /* -> USB request block structs */ @@ -208,9 +213,9 @@ struct w9968cf_frame_t frame_tmp; /* temporary frame */ struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */ struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS]; - void* vpp_buffer; /* -> helper buffer for post-processing routines */ + void* vpp_buffer; /*-> helper buf.for video post-processing routines */ - u8 max_buffers, /* number of requested buffers */ + u8 max_buffers, /* number of requested buffers */ force_palette, /* yes=1/no=0 */ force_rgb, /* read RGB instead of BGR, yes=1, no=0 */ double_buffer, /* hardware double buffering yes=1/no=0 */ @@ -221,15 +226,17 @@ decompression, /* 0=disabled, 1=forced, 2=allowed */ upscaling; /* software image scaling, 0=enabled, 1=disabled */ - struct video_picture picture; /* current window settings */ - struct video_window window; /* current picture settings */ + struct video_picture picture; /* current picture settings */ + struct video_window window; /* current window settings */ u16 hw_depth, /* depth (used by the chip) */ hw_palette, /* palette (used by the chip) */ hw_width, /* width (used by the chip) */ hw_height, /* height (used by the chip) */ hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */ - vs_polarity; /* 0=negative sync pulse, 1=positive sync pulse */ + vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */ + start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/ + start_cropy; /* pixels from VS incative edge to 1st cropped pixel*/ enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */ @@ -240,16 +247,15 @@ users, /* flag: number of users holding the device */ streaming; /* flag: yes=1, no=0 */ - int sensor; /* type of image CMOS sensor chip (CC_*) */ - - /* Determined by CMOS sensor type */ - u16 maxwidth, - maxheight, - minwidth, - minheight, - start_cropx, - start_cropy; + u8 sensor_initialized; /* flag: yes=1, no=0 */ + /* Determined by CMOS sensor type: */ + int sensor, /* type of image sensor chip (CC_*) */ + monochrome; /* CMOS sensor is (probably) monochrome */ + u16 maxwidth, /* maximum width supported by the CMOS sensor */ + maxheight, /* maximum height supported by the CMOS sensor */ + minwidth, /* minimum width supported by the CMOS sensor */ + minheight; /* minimum height supported by the CMOS sensor */ u8 auto_brt, /* auto brightness enabled flag */ auto_exp, /* auto exposure enabled flag */ backlight, /* backlight exposure algorithm flag */ @@ -257,21 +263,20 @@ lightfreq, /* power (lighting) frequency */ bandfilt; /* banding filter enabled flag */ s8 clockdiv; /* clock divisor */ - int sensor_mono; /* CMOS sensor is (probably) monochrome */ /* I2C interface to kernel */ struct i2c_adapter i2c_adapter; struct i2c_client* sensor_client; -#if defined(CONFIG_VIDEO_PROC_FS) +#ifdef CONFIG_VIDEO_PROC_FS /* /proc entries, relative to /proc/video/w9968cf/ */ - struct proc_dir_entry *proc_dev; /* readable per-device entry */ + struct proc_dir_entry *proc_dev; /* rw per-device entry */ #endif /* Locks */ struct semaphore dev_sem, /* for probe, disconnect,open and close */ fileop_sem; /* for read and ioctl */ -#if defined(CONFIG_VIDEO_PROC_FS) +#ifdef CONFIG_VIDEO_PROC_FS struct semaphore procfs_sem; /* for /proc read/write calls */ #endif spinlock_t urb_lock, /* for submit_urb() and unlink_urb() */ @@ -280,14 +285,9 @@ 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 @@ -303,7 +303,7 @@ else if ((level) == 4) \ warn(fmt, ## args); \ else if ((level) >= 5) \ - info("[%s,%d] " fmt, \ + info("[%s:%d] " fmt, \ __PRETTY_FUNCTION__, __LINE__ , ## args); \ } \ } @@ -314,7 +314,7 @@ #undef PDBG #undef PDBGG -#define PDBG(fmt, args...) info("[%s, %d] "fmt, \ +#define PDBG(fmt, args...) info("[%s:%d] "fmt, \ __PRETTY_FUNCTION__, __LINE__ , ## args); #define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */ diff -Nru a/drivers/usb/w9968cf_decoder.h b/drivers/usb/w9968cf_decoder.h --- a/drivers/usb/w9968cf_decoder.h Fri Dec 12 15:05:19 2003 +++ b/drivers/usb/w9968cf_decoder.h Fri Dec 12 15:05:19 2003 @@ -1,7 +1,7 @@ /*************************************************************************** * Video decoder for the W996[87]CF driver for Linux. * * * - * Copyright (C) 2003 by Luca Risolia * + * Copyright (C) 2003 by Luca Risolia * * * * 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 * diff -Nru a/drivers/usb/w9968cf_externaldef.h b/drivers/usb/w9968cf_externaldef.h --- a/drivers/usb/w9968cf_externaldef.h Fri Dec 12 15:05:19 2003 +++ b/drivers/usb/w9968cf_externaldef.h Fri Dec 12 15:05:19 2003 @@ -1,8 +1,9 @@ /*************************************************************************** - * Various definitions for compatibility with external modules. * + * Various definitions for compatibility with OVCAMCHIP external module. * * This file is part of the W996[87]CF driver for Linux. * * * - * Copyright (C) 2002 2003 by Luca Risolia * + * The definitions have been taken from the OVCAMCHIP module written by * + * Mark McClelland. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -27,10 +28,8 @@ #include #include -/* The following values have been copied from the "ovcamchip" module. */ - #ifndef I2C_DRIVERID_OVCAMCHIP -# define I2C_DRIVERID_OVCAMCHIP 0xf00f +# define I2C_DRIVERID_OVCAMCHIP 0xf00f #endif /* Controls */ @@ -77,10 +76,10 @@ int width; int height; int format; - int quarter; /* Scale width and height down 2x */ + int quarter; /* Scale width and height down 2x */ /* This stuff will be removed eventually */ - int clockdiv; /* Clock divisor setting */ + int clockdiv; /* Clock divisor setting */ }; /* Commands.