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

[PATCH] Updates for W99[87]CF and new SN9C10[12] driver

This single patch contains some updates and cleanups for
the W996[87]CF driver and a new experimental V4L2 driver
for SONiX SN9C10[12] PC Camera Controllers connected to various
image sensors. I have not divided the patch in two logical
sub-patches becouse of two independent changes in one common
file, KConfigure.

More informations about the SN9C10[12] can be found below in the
documentation. The driver is marked as "EXPERIMENTAL", meaning
that there are no known bugs, but further testing is necessary
before considering it stable. This the first driver using the new
SBGGR8 video format, which has been recently added to the mainline
kernel, so there are no available user application at the moment:
this is one more reason why it should be in the kernel now.

Changes in W996[87]CF:
- remove w9968cf_externaldef.h now that ovcamchip.h is in the kernel;
- mark user pointers with __user in a cleaner way to avoid sparse
  warnings;
- use appropriate exclusive wait macro during open();
- replace info(), err(), warn() with dev_info(), dev_err(), dev_warn(),
  pr_debug(), pr_info();
- replace usb_unlink_urb() + wait_for_completion() with usb_kill_urb();
- fix memory offsets for buffers in the chip to be used with generic
  image sensors;
- 'vppmod_load', 'debug', 'specific_debug' and 'simcams' module
  parameters are now writeable by default;
- fix possible race conditions between disconnect() and open();
- add automatic 'ovcamchip' module loading option with 'ovmod_load'
  module parameter;
- get rid of deprecated intermodule communication routines and use the
  correct module registration/unregistration approach;
- remove period at the end of kernel messages;
- fix several typos;
- use MODULE_VERSION() macro;
- other small internal cleanups;
- documentation updates.
Signed-off-by: default avatarLuca Risolia <luca.risolia@studio.unibo.it>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 75509570
......@@ -2702,7 +2702,9 @@ S: Finland
N: Luca Risolia
E: luca.risolia@studio.unibo.it
P: 1024D/FCE635A4 88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4
D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chips
D: V4L2 driver for SN9C10[12] PC Camera Controllers
S: Via Liberta' 41/A
S: Osio Sotto, 24046, Bergamo
S: Italy
......
SN9C10[12] PC Camera Controllers
Driver for Linux
================================
- Documentation -
Index
=====
1. Copyright
2. License
3. Overview
4. Module dependencies
5. Module loading
6. Module parameters
7. Device control through "sysfs"
8. Supported devices
9. How to add support for new image sensors
10. Note for V4L2 developers
11. Contact information
12. Credits
1. Copyright
============
Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it>
SONiX is a trademark of SONiX Technology Company Limited, inc.
This driver is not sponsored or developed by SONiX.
2. License
==========
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
3. Overview
===========
This driver attempts to support the video streaming capabilities of the devices
mounting the SONiX SN9C101 or SONiX SN9C102 PC Camera Controllers.
- It's worth to note that SONiX has never collaborated with me during the
development of this project, despite of several requests for enough detailed
specifications of the register tables, compression engine and video data format
of the above chips -
Up to 64 cameras can be handled at the same time. They can be connected and
disconnected from the host many times without turning off the computer, if
your system supports the hotplug facility.
The driver relies on the Video4Linux2 and USB core modules. It has been
designed to run properly on SMP systems as well.
The latest version of the SN9C10[12] driver can be found at the following URL:
http://go.lamarinapunto.com/
4. Module dependencies
======================
For it to work properly, the driver needs kernel support for Video4Linux and
USB.
The following options of the kernel configuration file must be enabled and
corresponding modules must be compiled:
# Multimedia devices
#
CONFIG_VIDEO_DEV=m
# USB support
#
CONFIG_USB=m
In addition, depending on the hardware being used, the modules below are
necessary:
# USB Host Controller Drivers
#
CONFIG_USB_EHCI_HCD=m
CONFIG_USB_UHCI_HCD=m
CONFIG_USB_OHCI_HCD=m
And finally:
# USB Multimedia devices
#
CONFIG_USB_SN9C102=m
5. Module loading
=================
To use the driver, it is necessary to load the "sn9c102" module into memory
after every other module required: "videodev", "usbcore" and, depending on
the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
Loading can be done as shown below:
[root@localhost home]# modprobe usbcore
[root@localhost home]# modprobe sn9c102
At this point the devices should be recognized. You can invoke "dmesg" to
analyze kernel messages and verify that the loading process has gone well:
[user@localhost home]$ dmesg
6. Module parameters
====================
Module parameters are listed below:
-------------------------------------------------------------------------------
Name: video_nr
Type: int array (min = 0, max = 32)
Syntax: <-1|n[,...]>
Description: Specify V4L2 minor mode number:
-1 = use next available
n = use minor number n
You can specify up to 32 cameras this way.
For example:
video_nr=-1,2,-1 would assign minor number 2 to the second
recognized camera and use auto for the first one and for every
other camera.
Default: -1
-------------------------------------------------------------------------------
Name: debug
Type: int
Syntax: <n>
Description: Debugging information level, from 0 to 3:
0 = none (use carefully)
1 = critical errors
2 = significant informations
3 = more verbose messages
Level 3 is useful for testing only, when just one device
is used.
Default: 2
-------------------------------------------------------------------------------
7. Device control through "sysfs"
=================================
It is possible to read and write both the SN9C10[12] and the image sensor
registers by using the "sysfs" filesystem interface.
Every time a supported device is recognized, read-only files named "redblue"
and "green" are created in the /sys/class/video4linux/videoX directory. You can
set the red, blue and green channel's gain by writing the desired value to
them. The value may range from 0 to 15 for each channel; this means that
"redblue" accepts 8-bit values, where the low 4 bits are reserved for red and
the others for blue.
There are other four entries in the directory above for each registered camera:
"reg", "val", "i2c_reg" and "i2c_val". The first two files control the
SN9C10[12] bridge, while the other two control the sensor chip. "reg" and
"i2c_reg" hold the values of the current register index where the following
reading/writing operations are addressed at through "val" and "i2c_val". Their
use is not intended for end-users, unless you know what you are doing. Note
that "i2c_reg" and "i2c_val" won't be created if the sensor does not actually
support the standard I2C protocol. Also, remember that you must be logged in as
root before writing to them.
As an example, suppose we were to want to read the value contained in the
register number 1 of the sensor register table - which usually is the product
identifier - of the camera registered as "/dev/video0":
[root@localhost #] cd /sys/class/video4linux/video0
[root@localhost #] echo 1 > i2c_reg
[root@localhost #] cat i2c_val
Now let's set the green gain's register of the SN9C10[12] chip to 2:
[root@localhost #] echo 0x11 > reg
[root@localhost #] echo 2 > val
Note that the SN9C10[12] always returns 0 when some of its registers are read.
To avoid race conditions, all the I/O accesses to the files are serialized.
8. Supported devices
====================
- I won't mention any of the names of the companies as well as their products
here. They have never collaborated with me, so no advertising -
From the point of view of a driver, what unambiguously identify a device are
its vendor and product USB identifiers. Below is a list of known identifiers of
devices mounting the SN9C10[12] PC camera controllers:
Vendor ID Product ID
--------- ----------
0xc45 0x6001
0xc45 0x6005
0xc45 0x6009
0xc45 0x600d
0xc45 0x6024
0xc45 0x6025
0xc45 0x6028
0xc45 0x6029
0xc45 0x602a
0xc45 0x602c
0xc45 0x8001
The list above does NOT imply that all those devices work with this driver: up
until now only the ones that mount the following image sensors are supported.
Kernel messages will always tell you whether this is the case:
Model Manufacturer
----- ------------
PAS106B PixArt Imaging Inc.
TAS5110C1B Taiwan Advanced Sensor Corporation
TAS5130D1B Taiwan Advanced Sensor Corporation
If you think your camera is based on the above hardware and is not actually
listed in the above table, you may try to add the specific USB VendorID and
ProductID identifiers to the sn9c102_id_table[] in the file "sn9c102_sensor.h";
then compile, load the module again and look at the kernel output.
If this works, please send an email to me reporting the kernel messages, so
that I will add a new entry in the list of supported devices.
Donations of new models for further testing and support would be much
appreciated. I won't add official support for hardware that I don't actually
have.
9. How to add support for new image sensors
===========================================
It should be easy to write code for new sensors by using the small API that I
have created for this purpose, which is present in "sn9c102_sensor.h"
(documentation is included there). As an example, have a look at the code in
"sn9c102_pas106b.c", which uses the mentioned interface.
At the moment, not yet supported image sensors are: PAS202B (VGA),
HV7131[D|E1] (VGA), MI03 (VGA), OV7620 (VGA).
10. Note for V4L2 developers
============================
This driver follows the V4L2 API specifications. In particular, it enforces two
rules:
1) Exactly one I/O method, either "mmap" or "read", is associated with each
file descriptor. Once it is selected, the application must close and reopen the
device to switch to the other I/O method.
2) Previously mapped buffer memory must always be unmapped before calling any
of the "VIDIOC_S_CROP", "VIDIOC_TRY_FMT" and "VIDIOC_S_FMT" ioctl's. In case,
the same number of buffers as before will be allocated again to match the size
of the new video frames, so you have to map them again before any I/O attempts.
11. 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 any keyserver; the fingerprint
is: '88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4'.
12. Credits
===========
I would thank the following persons:
- Stefano Mozzi, who donated 45 EU;
- Luca Capello for the donation of a webcam;
- Mizuno Takafumi for the donation of a webcam.
This diff is collapsed.
......@@ -162,6 +162,21 @@ config USB_SE401
To compile this driver as a module, choose M here: the
module will be called se401.
config USB_SN9C102
tristate "USB SN9C10[12] PC Camera Controller support (EXPERIMENTAL)"
depends on USB && VIDEO_DEV && EXPERIMENTAL
---help---
Say Y here if you want support for cameras based on SN9C101 and
SN9C102 PC Camera Controllers.
See <file:Documentation/usb/sn9c102.txt> for more informations.
This driver uses the Video For Linux API. You must say Y or M to
"Video For Linux" to use this driver.
To compile this driver as a module, choose M here: the
module will be called sn9c102.
config USB_STV680
tristate "USB STV680 (Pencam) Camera support"
depends on USB && VIDEO_DEV
......@@ -181,7 +196,7 @@ config USB_STV680
config USB_W9968CF
tristate "USB W996[87]CF JPEG Dual Mode Camera support"
depends on USB && VIDEO_DEV && I2C
depends on USB && VIDEO_DEV && I2C && VIDEO_OVCAMCHIP
---help---
Say Y here if you want support for cameras based on OV681 or
Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
......@@ -190,16 +205,13 @@ config USB_W9968CF
separate module only (released under GPL). It allows to use higher
resolutions and framerates, but cannot be included in the official
Linux kernel for performance purposes.
At the moment the driver needs a third-party module for the CMOS
sensors, which is available on internet: it is recommended to read
<file:Documentation/usb/w9968cf.txt> for more informations and for
a list of supported cameras.
This driver uses the Video For Linux and the I2C APIs. You must say
Y or M to both "Video For Linux" and "I2C Support" to use this
driver.
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called w9968cf.o. If you want to compile it as a
module, say M here and read <file:Documentation/kbuild/modules.txt>.
See <file:Documentation/usb/w9968cf.txt> for more informations.
This driver uses the Video For Linux and the I2C APIs. It needs the
OmniVision Camera Chip support as well. You must say Y or M to
"Video For Linux", "I2C Support" and "OmniVision Camera Chip
support" to use this driver.
To compile this driver as a module, choose M here: the
module will be called w9968cf.
......@@ -3,6 +3,7 @@
#
pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o
sn9c102-objs := sn9c102_core.o sn9c102_pas106b.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_DSBR) += dsbr100.o
......@@ -11,6 +12,7 @@ obj-$(CONFIG_USB_KONICAWC) += konicawc.o usbvideo.o
obj-$(CONFIG_USB_OV511) += ov511.o
obj-$(CONFIG_USB_PWC) += pwc.o
obj-$(CONFIG_USB_SE401) += se401.o
obj-$(CONFIG_USB_SN9C102) += sn9c102.o
obj-$(CONFIG_USB_STV680) += stv680.o
obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o
obj-$(CONFIG_USB_W9968CF) += w9968cf.o
/***************************************************************************
* V4L2 driver for SN9C10[12] PC Camera Controllers *
* *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#ifndef _SN9C102_H_
#define _SN9C102_H_
#include <linux/version.h>
#include <linux/usb.h>
#include <linux/videodev.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/types.h>
#include <linux/param.h>
#include <asm/semaphore.h>
#include <asm/rwsem.h>
#include "sn9c102_sensor.h"
/*****************************************************************************/
#define SN9C102_DEBUG
#define SN9C102_DEBUG_LEVEL 2
#define SN9C102_MAX_DEVICES 64
#define SN9C102_MAX_FRAMES 32
#define SN9C102_URBS 2
#define SN9C102_ISO_PACKETS 7
#define SN9C102_ALTERNATE_SETTING 8
#define SN9C102_CTRL_TIMEOUT 10*HZ
/*****************************************************************************/
#define SN9C102_MODULE_NAME "V4L2 driver for SN9C10[12] PC Camera Controllers"
#define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE "GPL"
#define SN9C102_MODULE_VERSION "1:1.01-beta"
#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 1)
SN9C102_ID_TABLE;
SN9C102_SENSOR_TABLE;
enum sn9c102_frame_state {
F_UNUSED,
F_QUEUED,
F_GRABBING,
F_DONE,
F_ERROR,
};
struct sn9c102_frame_t {
void* bufmem;
struct v4l2_buffer buf;
enum sn9c102_frame_state state;
struct list_head frame;
unsigned long vma_use_count;
};
enum sn9c102_dev_state {
DEV_INITIALIZED = 0x01,
DEV_DISCONNECTED = 0x02,
DEV_MISCONFIGURED = 0x04,
};
enum sn9c102_io_method {
IO_NONE,
IO_READ,
IO_MMAP,
};
enum sn9c102_stream_state {
STREAM_OFF,
STREAM_INTERRUPT,
STREAM_ON,
};
struct sn9c102_sysfs_attr {
u8 reg, val, i2c_reg, i2c_val;
};
static DECLARE_MUTEX(sn9c102_sysfs_lock);
static DECLARE_RWSEM(sn9c102_disconnect);
struct sn9c102_device {
struct device dev;
struct video_device* v4ldev;
struct sn9c102_sensor* sensor;
struct usb_device* usbdev;
struct urb* urb[SN9C102_URBS];
void* transfer_buffer[SN9C102_URBS];
u8* control_buffer;
struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES];
struct list_head inqueue, outqueue;
u32 frame_count, nbuffers;
enum sn9c102_io_method io;
enum sn9c102_stream_state stream;
struct sn9c102_sysfs_attr sysfs;
u16 reg[32];
enum sn9c102_dev_state state;
u8 users;
struct semaphore dev_sem, fileop_sem;
spinlock_t queue_lock;
wait_queue_head_t open, wait_frame, wait_stream;
};
/*****************************************************************************/
void
sn9c102_attach_sensor(struct sn9c102_device* cam,
struct sn9c102_sensor* sensor)
{
cam->sensor = sensor;
cam->sensor->dev = &cam->dev;
cam->sensor->usbdev = cam->usbdev;
}
/*****************************************************************************/
#undef DBG
#undef KDBG
#ifdef SN9C102_DEBUG
# define DBG(level, fmt, args...) \
{ \
if (debug >= (level)) { \
if ((level) == 1) \
dev_err(&cam->dev, fmt "\n", ## args); \
else if ((level) == 2) \
dev_info(&cam->dev, fmt "\n", ## args); \
else if ((level) >= 3) \
dev_info(&cam->dev, "[%s:%d] " fmt "\n", \
__FUNCTION__, __LINE__ , ## args); \
} \
}
# define KDBG(level, fmt, args...) \
{ \
if (debug >= (level)) { \
if ((level) == 1 || (level) == 2) \
pr_info("sn9c102: " fmt "\n", ## args); \
else if ((level) == 3) \
pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__, \
__LINE__ , ## args); \
} \
}
#else
# define KDBG(level, fmt, args...) do {;} while(0);
# define DBG(level, fmt, args...) do {;} while(0);
#endif
#undef PDBG
#define PDBG(fmt, args...) \
dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args);
#undef PDBGG
#define PDBGG(fmt, args...) do {;} while(0); /* placeholder */
#endif /* _SN9C102_H_ */
This diff is collapsed.
/***************************************************************************
* Driver for PAS106B image sensor connected to the SN9C10[12] PC Camera *
* Controllers *
* *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#include <linux/delay.h>
#include "sn9c102_sensor.h"
static struct sn9c102_sensor pas106b;
static int pas106b_init(struct sn9c102_device* cam)
{
int err = 0;
err += sn9c102_write_reg(cam, 0x00, 0x10);
err += sn9c102_write_reg(cam, 0x00, 0x11);
err += sn9c102_write_reg(cam, 0x00, 0x14);
err += sn9c102_write_reg(cam, 0x20, 0x17);
err += sn9c102_write_reg(cam, 0x20, 0x19);
err += sn9c102_write_reg(cam, 0x09, 0x18);
err += sn9c102_i2c_write(cam, 0x02, 0x0c);
err += sn9c102_i2c_write(cam, 0x03, 0x12);
err += sn9c102_i2c_write(cam, 0x04, 0x05);
err += sn9c102_i2c_write(cam, 0x05, 0x22);
err += sn9c102_i2c_write(cam, 0x06, 0xac);
err += sn9c102_i2c_write(cam, 0x07, 0x00);
err += sn9c102_i2c_write(cam, 0x08, 0x01);
err += sn9c102_i2c_write(cam, 0x0a, 0x00);
err += sn9c102_i2c_write(cam, 0x0b, 0x00);
err += sn9c102_i2c_write(cam, 0x0d, 0x00);
err += sn9c102_i2c_write(cam, 0x10, 0x06);
err += sn9c102_i2c_write(cam, 0x11, 0x06);
err += sn9c102_i2c_write(cam, 0x12, 0x00);
err += sn9c102_i2c_write(cam, 0x14, 0x02);
err += sn9c102_i2c_write(cam, 0x13, 0x01);
msleep(400);
return err;
}
static int pas106b_get_ctrl(struct sn9c102_device* cam,
struct v4l2_control* ctrl)
{
switch (ctrl->id) {
case V4L2_CID_RED_BALANCE:
return (ctrl->value = sn9c102_i2c_read(cam, 0x0c))<0 ? -EIO:0;
case V4L2_CID_BLUE_BALANCE:
return (ctrl->value = sn9c102_i2c_read(cam, 0x09))<0 ? -EIO:0;
case V4L2_CID_BRIGHTNESS:
return (ctrl->value = sn9c102_i2c_read(cam, 0x0e))<0 ? -EIO:0;
default:
return -EINVAL;
}
}
static int pas106b_set_ctrl(struct sn9c102_device* cam,
const struct v4l2_control* ctrl)
{
int err = 0;
switch (ctrl->id) {
case V4L2_CID_RED_BALANCE:
err += sn9c102_i2c_write(cam, 0x0c, ctrl->value & 0x1f);
break;
case V4L2_CID_BLUE_BALANCE:
err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x1f);
break;
case V4L2_CID_BRIGHTNESS:
err += sn9c102_i2c_write(cam, 0x0e, ctrl->value & 0x1f);
break;
default:
return -EINVAL;
}
err += sn9c102_i2c_write(cam, 0x13, 0x01);
return err;
}
static int pas106b_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
struct sn9c102_sensor* s = &pas106b;
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
return err;
}
static struct sn9c102_sensor pas106b = {
.name = "PAS106B",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
.slave_read_id = 0x40,
.slave_write_id = 0x40,
.init = &pas106b_init,
.qctrl = {
{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "red balance",
.minimum = 0x00,
.maximum = 0x1f,
.step = 0x01,
.default_value = 0x03,
.flags = 0,
},
{
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "blue balance",
.minimum = 0x00,
.maximum = 0x1f,
.step = 0x01,
.default_value = 0x02,
.flags = 0,
},
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "brightness",
.minimum = 0x00,
.maximum = 0x1f,
.step = 0x01,
.default_value = 0x06,
.flags = 0,
},
},
.get_ctrl = &pas106b_get_ctrl,
.set_ctrl = &pas106b_set_ctrl,
.cropcap = {
.bounds = {
.left = 0,
.top = 0,
.width = 352,
.height = 288,
},
.defrect = {
.left = 0,
.top = 0,
.width = 352,
.height = 288,
},
},
.set_crop = &pas106b_set_crop,
.pix_format = {
.width = 352,
.height = 288,
.pixelformat = V4L2_PIX_FMT_SBGGR8,
.priv = 8, /* we use this field as 'bits per pixel' */
}
};
int sn9c102_probe_pas106b(struct sn9c102_device* cam)
{
int r0 = 0, r1 = 0, err = 0;
unsigned int pid = 0;
/* Minimal initialization to enable the I2C communication
NOTE: do NOT change the values! */
err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */
err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 48 MHz */
if (err)
return -EIO;
r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00);
r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01);
if (r0 < 0 || r1 < 0)
return -EIO;
pid = (r0 << 11) | ((r1 & 0xf0) >> 4);
if (pid != 0x007)
return -ENODEV;
sn9c102_attach_sensor(cam, &pas106b);
return 0;
}
This diff is collapsed.
/***************************************************************************
* Driver for TAS5110C1B image sensor connected to the SN9C10[12] PC *
* Camera Controllers *
* *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#include "sn9c102_sensor.h"
static struct sn9c102_sensor tas5110c1b;
static int tas5110c1b_init(struct sn9c102_device* cam)
{
int err = 0;
err += sn9c102_write_reg(cam, 0x01, 0x01);
err += sn9c102_write_reg(cam, 0x44, 0x01);
err += sn9c102_write_reg(cam, 0x00, 0x10);
err += sn9c102_write_reg(cam, 0x00, 0x11);
err += sn9c102_write_reg(cam, 0x00, 0x14);
err += sn9c102_write_reg(cam, 0x60, 0x17);
err += sn9c102_write_reg(cam, 0x06, 0x18);
err += sn9c102_write_reg(cam, 0xcb, 0x19);
return err;
}
static int tas5110c1b_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
struct sn9c102_sensor* s = &tas5110c1b;
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
return err;
}
static struct sn9c102_sensor tas5110c1b = {
.name = "TAS5110C1B",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
.init = &tas5110c1b_init,
.cropcap = {
.bounds = {
.left = 0,
.top = 0,
.width = 352,
.height = 288,
},
.defrect = {
.left = 0,
.top = 0,
.width = 352,
.height = 288,
},
},
.set_crop = &tas5110c1b_set_crop,
.pix_format = {
.width = 352,
.height = 288,
.pixelformat = V4L2_PIX_FMT_SBGGR8,
.priv = 8,
}
};
int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
{
/* This sensor has no identifiers, so let's attach it anyway */
sn9c102_attach_sensor(cam, &tas5110c1b);
/* At the moment, only devices whose PID is 0x6005 have this sensor */
if (tas5110c1b.usbdev->descriptor.idProduct != 0x6005)
return -ENODEV;
return 0;
}
/***************************************************************************
* Driver for TAS5130D1B image sensor connected to the SN9C10[12] PC *
* Camera Controllers *
* *
* Copyright (C) 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#include "sn9c102_sensor.h"
static struct sn9c102_sensor tas5130d1b;
static int tas5130d1b_init(struct sn9c102_device* cam)
{
int err = 0;
err += sn9c102_write_reg(cam, 0x01, 0x01);
err += sn9c102_write_reg(cam, 0x20, 0x17);
err += sn9c102_write_reg(cam, 0x04, 0x01);
err += sn9c102_write_reg(cam, 0x01, 0x10);
err += sn9c102_write_reg(cam, 0x00, 0x11);
err += sn9c102_write_reg(cam, 0x00, 0x14);
err += sn9c102_write_reg(cam, 0x60, 0x17);
err += sn9c102_write_reg(cam, 0x07, 0x18);
err += sn9c102_write_reg(cam, 0x33, 0x19);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x40,
0x47, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x02, 0x20,
0xa9, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0xc0,
0x49, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x02, 0x20,
0x6c, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0xc0,
0x08, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x20,
0x00, 0, 0);
err += sn9c102_write_reg(cam, 0x63, 0x19);
return err;
}
static int tas5130d1b_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
struct sn9c102_sensor* s = &tas5130d1b;
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
return err;
}
static struct sn9c102_sensor tas5130d1b = {
.name = "TAS5130D1B",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_3WIRES,
.init = &tas5130d1b_init,
.cropcap = {
.bounds = {
.left = 0,
.top = 0,
.width = 640,
.height = 480,
},
.defrect = {
.left = 0,
.top = 0,
.width = 640,
.height = 480,
},
},
.set_crop = &tas5130d1b_set_crop,
.pix_format = {
.width = 640,
.height = 480,
.pixelformat = V4L2_PIX_FMT_SBGGR8,
.priv = 8,
}
};
int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
{
/* This sensor has no identifiers, so let's attach it anyway */
sn9c102_attach_sensor(cam, &tas5130d1b);
/* At the moment, only devices whose PID is 0x6025 have this sensor */
if (tas5130d1b.usbdev->descriptor.idProduct != 0x6025)
return -ENODEV;
dev_info(tas5130d1b.dev, "TAS5130D1B detected, but the support for it "
"is disabled at the moment - needs further "
"testing -\n");
return -ENODEV;
}
This diff is collapsed.
......@@ -24,21 +24,26 @@
#include <linux/videodev.h>
#include <linux/usb.h>
#include <linux/i2c.h>
#include <linux/device.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/wait.h>
#include <linux/config.h>
#include <linux/param.h>
#include <linux/types.h>
#include <asm/semaphore.h>
#include <asm/types.h>
#include <asm/rwsem.h>
#include "w9968cf_externaldef.h"
#include <media/ovcamchip.h>
#include "w9968cf_vpp.h"
/****************************************************************************
* Default values *
****************************************************************************/
#define W9968CF_OVMOD_LOAD 1 /* automatic 'ovcamchip' module loading */
#define W9968CF_VPPMOD_LOAD 1 /* automatic 'w9968cf-vpp' module loading */
/* Comment/uncomment the following line to enable/disable debugging messages */
......@@ -95,8 +100,8 @@ static const struct w9968cf_format w9968cf_formatlist[] = {
#define W9968CF_FORCE_RGB 0 /* read RGB instead of BGR, yes=1/no=0 */
#define W9968CF_MAX_WIDTH 800 /* should be >= 640 */
#define W9968CF_MAX_HEIGHT 600 /* should be >= 480 */
#define W9968CF_MAX_WIDTH 800 /* Has effect if up-scaling is on */
#define W9968CF_MAX_HEIGHT 600 /* Has effect if up-scaling is on */
#define W9968CF_WIDTH 320 /* from 128 to 352, multiple of 16 */
#define W9968CF_HEIGHT 240 /* from 96 to 288, multiple of 16 */
......@@ -130,13 +135,11 @@ static const struct w9968cf_format w9968cf_formatlist[] = {
#define W9968CF_MODULE_NAME "V4L driver for W996[87]CF JPEG USB " \
"Dual Mode Camera Chip"
#define W9968CF_MODULE_VERSION "v1.25-basic"
#define W9968CF_MODULE_VERSION "1:1.32-basic"
#define W9968CF_MODULE_AUTHOR "(C) 2002-2004 Luca Risolia"
#define W9968CF_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define W9968CF_MODULE_LICENSE "GPL"
static u8 w9968cf_vppmod_present; /* status flag: yes=1, no=0 */
static const struct usb_device_id winbond_id_table[] = {
{
/* Creative Labs Video Blaster WebCam Go Plus */
......@@ -151,18 +154,19 @@ static const struct usb_device_id winbond_id_table[] = {
{ } /* terminating entry */
};
MODULE_DEVICE_TABLE(usb, winbond_id_table);
/* W996[87]CF camera models, internal ids: */
enum w9968cf_model_id {
W9968CF_MOD_GENERIC = 1, /* Generic W996[87]CF based device */
W9968CF_MOD_CLVBWGP = 11,/*Creative Labs Video Blaster WebCam Go Plus*/
W9968CF_MOD_ADPA5R = 21, /* Aroma Digi Pen ADG-5000 Refurbished */
W9986CF_MOD_AU = 31, /* AVerTV USB */
W9968CF_MOD_CLVBWG = 34, /* Creative Labs Video Blaster WebCam Go */
W9968CF_MOD_DLLDK = 37, /* Die Lebon LDC-D35A Digital Kamera */
W9968CF_MOD_ADPVDMA = 21, /* Aroma Digi Pen VGA Dual Mode ADG-5000 */
W9986CF_MOD_AAU = 31, /* AVerMedia AVerTV USB */
W9968CF_MOD_CLVBWG = 34, /* Creative Labs Video Blaster WebCam Go */
W9968CF_MOD_LL = 37, /* Lebon LDC-035A */
W9968CF_MOD_EEEMC = 40, /* Ezonics EZ-802 EZMega Cam */
W9968CF_MOD_OOE = 42, /* OmniVision OV8610-EDE */
W9968CF_MOD_ODPVDMPC = 43,/* OPCOM Digi Pen VGA Dual Mode Pen Camera */
W9968CF_MOD_PDPII = 46, /* Pretec Digi Pen-II */
W9968CF_MOD_PDP480 = 49, /* Pretec DigiPen-480 */
};
enum w9968cf_frame_status {
......@@ -173,9 +177,10 @@ enum w9968cf_frame_status {
};
struct w9968cf_frame_t {
#define W9968CF_HW_BUF_SIZE 640*480*2 /* buf.size of original frames */
void* buffer;
unsigned long size;
u32 length;
int number;
enum w9968cf_frame_status status;
struct w9968cf_frame_t* next;
u8 queued;
......@@ -189,12 +194,19 @@ enum w9968cf_vpp_flag {
VPP_UYVY_TO_RGBX = 0x08,
};
static struct list_head w9968cf_dev_list; /* head of V4L registered cameras list */
static LIST_HEAD(w9968cf_dev_list);
struct semaphore w9968cf_devlist_sem; /* semaphore for list traversal */
static struct w9968cf_vpp_t* w9968cf_vpp;
static DECLARE_MUTEX(w9968cf_vppmod_lock);
static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
static DECLARE_MUTEX(w9968cf_devlist_sem); /* semaphore for list traversal */
static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */
/* Main device driver structure */
struct w9968cf_device {
struct device dev; /* device structure */
enum w9968cf_model_id id; /* private device identifier */
struct video_device* v4ldev; /* -> V4L structure */
......@@ -207,10 +219,10 @@ struct w9968cf_device {
u16* data_buffer; /* -> data to send to the FSB */
struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS];
struct w9968cf_frame_t frame_tmp; /* temporary frame */
struct w9968cf_frame_t frame_tmp; /* temporary frame */
struct w9968cf_frame_t frame_vpp; /* helper frame.*/
struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */
struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS];
void* vpp_buffer; /*-> helper buf.for video post-processing routines */
u8 max_buffers, /* number of requested buffers */
force_palette, /* yes=1/no=0 */
......@@ -233,7 +245,7 @@ struct w9968cf_device {
hs_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*/
start_cropy; /* pixels from VS inactive edge to 1st cropped pixel*/
enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */
......@@ -246,13 +258,13 @@ struct w9968cf_device {
u8 sensor_initialized; /* flag: yes=1, no=0 */
/* Determined by CMOS sensor type: */
/* Determined by the image 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 */
monochrome; /* image sensor is (probably) monochrome */
u16 maxwidth, /* maximum width supported by the image sensor */
maxheight, /* maximum height supported by the image sensor */
minwidth, /* minimum width supported by the image sensor */
minheight; /* minimum height supported by the image sensor */
u8 auto_brt, /* auto brightness enabled flag */
auto_exp, /* auto exposure enabled flag */
backlight, /* backlight exposure algorithm flag */
......@@ -270,8 +282,9 @@ struct w9968cf_device {
fileop_sem; /* for read and ioctl */
spinlock_t urb_lock, /* for submit_urb() and unlink_urb() */
flist_lock; /* for requested frame list accesses */
char command[16]; /* name of the program holding the device */
wait_queue_head_t open, wait_queue;
char command[16]; /* name of the program holding the device */
};
......@@ -280,31 +293,47 @@ struct w9968cf_device {
****************************************************************************/
#undef DBG
#undef KDBG
#ifdef W9968CF_DEBUG
# define DBG(level, fmt, args...) \
{ \
if ( ((specific_debug) && (debug == (level))) || \
((!specific_debug) && (debug >= (level))) ) { \
if ((level) == 1) \
err(fmt, ## args); \
else if ((level) == 2 || (level) == 3) \
info(fmt, ## args); \
else if ((level) == 4) \
warn(fmt, ## args); \
else if ((level) >= 5) \
info("[%s:%d] " fmt, \
__FUNCTION__, __LINE__ , ## args); \
} \
/* For device specific debugging messages */
# define DBG(level, fmt, args...) \
{ \
if ( ((specific_debug) && (debug == (level))) || \
((!specific_debug) && (debug >= (level))) ) { \
if ((level) == 1) \
dev_err(&cam->dev, fmt "\n", ## args); \
else if ((level) == 2 || (level) == 3) \
dev_info(&cam->dev, fmt "\n", ## args); \
else if ((level) == 4) \
dev_warn(&cam->dev, fmt "\n", ## args); \
else if ((level) >= 5) \
dev_info(&cam->dev, "[%s:%d] " fmt "\n", \
__FUNCTION__, __LINE__ , ## args); \
} \
}
/* For generic kernel (not device specific) messages */
# define KDBG(level, fmt, args...) \
{ \
if ( ((specific_debug) && (debug == (level))) || \
((!specific_debug) && (debug >= (level))) ) { \
if ((level) >= 1 && (level) <= 4) \
pr_info("w9968cf: " fmt "\n", ## args); \
else if ((level) >= 5) \
pr_debug("w9968cf: [%s:%d] " fmt "\n", __FUNCTION__, \
__LINE__ , ## args); \
} \
}
#else
/* Not debugging: nothing */
# define DBG(level, fmt, args...) do {;} while(0);
# define KDBG(level, fmt, args...) do {;} while(0);
#endif
#undef PDBG
#define PDBG(fmt, args...) \
dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args);
#undef PDBGG
#define PDBG(fmt, args...) info("[%s:%d] "fmt, \
__PRETTY_FUNCTION__, __LINE__ , ## args);
#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
#endif /* _W9968CF_H_ */
/***************************************************************************
* Various definitions for compatibility with OVCAMCHIP external module. *
* This file is part of the W996[87]CF driver for Linux. *
* Interface for video post-processing functions for the W996[87]CF driver *
* for Linux. *
* *
* The definitions have been taken from the OVCAMCHIP module written by *
* Mark McClelland. *
* Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
......@@ -20,75 +19,25 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#ifndef _W9968CF_EXTERNALDEF_H_
#define _W9968CF_EXTERNALDEF_H_
#ifndef _W9968CF_VPP_H_
#define _W9968CF_VPP_H_
#include <linux/videodev.h>
#include <linux/i2c.h>
#include <asm/ioctl.h>
#include <linux/module.h>
#include <asm/types.h>
#ifndef I2C_DRIVERID_OVCAMCHIP
# define I2C_DRIVERID_OVCAMCHIP 0xf00f
#endif
struct w9968cf_vpp_t {
struct module* owner;
int (*check_headers)(const unsigned char*, const unsigned long);
int (*decode)(const char*, const unsigned long, const unsigned,
const unsigned, char*);
void (*swap_yuvbytes)(void*, unsigned long);
void (*uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8);
void (*scale_up)(u8*, u8*, u16, u16, u16, u16, u16);
/* Controls */
enum {
OVCAMCHIP_CID_CONT, /* Contrast */
OVCAMCHIP_CID_BRIGHT, /* Brightness */
OVCAMCHIP_CID_SAT, /* Saturation */
OVCAMCHIP_CID_HUE, /* Hue */
OVCAMCHIP_CID_EXP, /* Exposure */
OVCAMCHIP_CID_FREQ, /* Light frequency */
OVCAMCHIP_CID_BANDFILT, /* Banding filter */
OVCAMCHIP_CID_AUTOBRIGHT, /* Auto brightness */
OVCAMCHIP_CID_AUTOEXP, /* Auto exposure */
OVCAMCHIP_CID_BACKLIGHT, /* Back light compensation */
OVCAMCHIP_CID_MIRROR, /* Mirror horizontally */
u8 busy; /* read-only flag: module is/is not in use */
};
/* I2C addresses */
#define OV7xx0_SID (0x42 >> 1)
#define OV6xx0_SID (0xC0 >> 1)
extern int w9968cf_vppmod_register(struct w9968cf_vpp_t*);
extern int w9968cf_vppmod_deregister(struct w9968cf_vpp_t*);
/* Sensor types */
enum {
CC_UNKNOWN,
CC_OV76BE,
CC_OV7610,
CC_OV7620,
CC_OV7620AE,
CC_OV6620,
CC_OV6630,
CC_OV6630AE,
CC_OV6630AF,
};
/* API */
struct ovcamchip_control {
__u32 id;
__s32 value;
};
struct ovcamchip_window {
int x;
int y;
int width;
int height;
int format;
int quarter; /* Scale width and height down 2x */
/* This stuff will be removed eventually */
int clockdiv; /* Clock divisor setting */
};
/* Commands.
You must call OVCAMCHIP_CMD_INITIALIZE before any of other commands */
#define OVCAMCHIP_CMD_Q_SUBTYPE _IOR (0x88, 0x00, int)
#define OVCAMCHIP_CMD_INITIALIZE _IOW (0x88, 0x01, int)
#define OVCAMCHIP_CMD_S_CTRL _IOW (0x88, 0x02, struct ovcamchip_control)
#define OVCAMCHIP_CMD_G_CTRL _IOWR (0x88, 0x03, struct ovcamchip_control)
#define OVCAMCHIP_CMD_S_MODE _IOW (0x88, 0x04, struct ovcamchip_window)
#define OVCAMCHIP_MAX_CMD _IO (0x88, 0x3f)
#endif /* _W9968CF_EXTERNALDEF_H_ */
#endif /* _W9968CF_VPP_H_ */
......@@ -429,8 +429,9 @@ struct video_code
#define VID_HARDWARE_CPIA2 33
#define VID_HARDWARE_VICAM 34
#define VID_HARDWARE_SF16FMR2 35
#define VID_HARDWARE_W9968CF 36
#define VID_HARDWARE_W9968CF 36
#define VID_HARDWARE_SAA7114H 37
#define VID_HARDWARE_SN9C102 38
#endif /* __LINUX_VIDEODEV_H */
/*
......
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