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

[PATCH] USB: SN9C10[12] driver update

Changes:

- Delete the correct entry in the outgoing queue during DQBUF
- Implement correct image downscaling selection through VIDIOC_S_[CROP|FTM]
- Replace darkness controls with brightness (simple swapping) for PAS106B and
  PAS202BCB
- Implement gain control for TAS5110C1B and TAS5130D1B
- Add a note to the documentation about correct image downscaling selection
Signed-off-by: default avatarLuca Risolia <luca.risolia@studio.unibo.it>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 2cf52a8b
...@@ -14,10 +14,10 @@ Index ...@@ -14,10 +14,10 @@ Index
4. Module dependencies 4. Module dependencies
5. Module loading 5. Module loading
6. Module parameters 6. Module parameters
7. Device control through "sysfs" 7. Optional device control through "sysfs"
8. Supported devices 8. Supported devices
9. How to add support for new image sensors 9. How to add support for new image sensors
10. Note for V4L2 developers 10. Notes for V4L2 application developers
11. Contact information 11. Contact information
12. Credits 12. Credits
...@@ -148,8 +148,8 @@ Default: 2 ...@@ -148,8 +148,8 @@ Default: 2
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
7. Device control through "sysfs" 7. Optional device control through "sysfs"
================================= ==========================================
It is possible to read and write both the SN9C10[12] and the image sensor It is possible to read and write both the SN9C10[12] and the image sensor
registers by using the "sysfs" filesystem interface. registers by using the "sysfs" filesystem interface.
...@@ -206,7 +206,7 @@ Vendor ID Product ID ...@@ -206,7 +206,7 @@ Vendor ID Product ID
0xc45 0x6029 0xc45 0x6029
0xc45 0x602a 0xc45 0x602a
0xc45 0x602c 0xc45 0x602c
0xc45 0x8001 0xc45 0x6030
The list above does NOT imply that all those devices work with this driver: up The list above does NOT imply that all those devices work with this driver: up
until now only the ones that mount the following image sensors are supported. until now only the ones that mount the following image sensors are supported.
...@@ -242,19 +242,27 @@ At the moment, not yet supported image sensors are: HV7131[D|E1] (VGA), ...@@ -242,19 +242,27 @@ At the moment, not yet supported image sensors are: HV7131[D|E1] (VGA),
MI03 (VGA), OV7620 (VGA). MI03 (VGA), OV7620 (VGA).
10. Note for V4L2 developers 10. Notes for V4L2 application developers
============================ =========================================
This driver follows the V4L2 API specifications. In particular, it enforces two This driver follows the V4L2 API specifications. In particular, it enforces two
rules: rules:
1) Exactly one I/O method, either "mmap" or "read", is associated with each - 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 file descriptor. Once it is selected, the application must close and reopen the
device to switch to the other I/O method. device to switch to the other I/O method;
2) Previously mapped buffer memory must always be unmapped before calling any - 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, of the "VIDIOC_S_CROP", "VIDIOC_TRY_FMT" and "VIDIOC_S_FMT" ioctl's. The same
the same number of buffers as before will be allocated again to match the size number of buffers as before will be allocated again to match the size of the
of the new video frames, so you have to map them again before any I/O attempts. new video frames, so you have to map them again before any I/O attempts.
Consistently with the hardware limits, this driver also supports image
downscaling with arbitrary scaling factors from 1, 2 and 4 in both directions.
However the V4L2 API specifications don't correctly define how the scaling
factor can be choosen arbitrarily by the "negotiation" of the "source" and
"target" rectangles. To work around this flaw, we have added the convention
that, during the negotiation, whenever the "VIDIOC_S_CROP" ioctl is issued, the
scaling factor is restored to 1.
11. Contact information 11. Contact information
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define SN9C102_DEBUG #define SN9C102_DEBUG
#define SN9C102_DEBUG_LEVEL 2 #define SN9C102_DEBUG_LEVEL 2
#define SN9C102_MAX_DEVICES 64 #define SN9C102_MAX_DEVICES 64
#define SN9C102_PRESERVE_IMGSCALE 0
#define SN9C102_MAX_FRAMES 32 #define SN9C102_MAX_FRAMES 32
#define SN9C102_URBS 2 #define SN9C102_URBS 2
#define SN9C102_ISO_PACKETS 7 #define SN9C102_ISO_PACKETS 7
...@@ -52,8 +53,8 @@ ...@@ -52,8 +53,8 @@
#define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia" #define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE "GPL" #define SN9C102_MODULE_LICENSE "GPL"
#define SN9C102_MODULE_VERSION "1:1.07" #define SN9C102_MODULE_VERSION "1:1.08"
#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 7) #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 8)
SN9C102_ID_TABLE; SN9C102_ID_TABLE;
SN9C102_SENSOR_TABLE; SN9C102_SENSOR_TABLE;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/compiler.h>
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/stat.h> #include <linux/stat.h>
...@@ -1731,13 +1732,15 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp, ...@@ -1731,13 +1732,15 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
rect->width &= ~15L; rect->width &= ~15L;
rect->height &= ~15L; rect->height &= ~15L;
{ /* calculate the actual scaling factor */ if (SN9C102_PRESERVE_IMGSCALE) {
/* Calculate the actual scaling factor */
u32 a, b; u32 a, b;
a = rect->width * rect->height; a = rect->width * rect->height;
b = pix_format->width * pix_format->height; b = pix_format->width * pix_format->height;
scale = b ? (u8)((a / b) < 4 ? 1 : scale = b ? (u8)((a / b) < 4 ? 1 :
((a / b) < 16 ? 2 : 4)) : 1; ((a / b) < 16 ? 2 : 4)) : 1;
} } else
scale = 1;
if (cam->stream == STREAM_ON) { if (cam->stream == STREAM_ON) {
cam->stream = STREAM_INTERRUPT; cam->stream = STREAM_INTERRUPT;
...@@ -2111,7 +2114,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp, ...@@ -2111,7 +2114,7 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
spin_lock_irqsave(&cam->queue_lock, lock_flags); spin_lock_irqsave(&cam->queue_lock, lock_flags);
f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, f = list_entry(cam->outqueue.next, struct sn9c102_frame_t,
frame); frame);
list_del(&cam->outqueue); list_del(cam->outqueue.next);
spin_unlock_irqrestore(&cam->queue_lock, lock_flags); spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
f->state = F_UNUSED; f->state = F_UNUSED;
......
...@@ -109,7 +109,7 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam, ...@@ -109,7 +109,7 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam,
err += sn9c102_i2c_write(cam, 0x0e, ctrl->value & 0x1f); err += sn9c102_i2c_write(cam, 0x0e, ctrl->value & 0x1f);
break; break;
case V4L2_CID_BRIGHTNESS: case V4L2_CID_BRIGHTNESS:
err += sn9c102_i2c_write(cam, 0x0d, ctrl->value & 0x1f); err += sn9c102_i2c_write(cam, 0x0d, 0x1f-(ctrl->value & 0x1f));
break; break;
case V4L2_CID_CONTRAST: case V4L2_CID_CONTRAST:
err += sn9c102_i2c_write(cam, 0x0f, ctrl->value & 0x03); err += sn9c102_i2c_write(cam, 0x0f, ctrl->value & 0x03);
...@@ -180,11 +180,11 @@ static struct sn9c102_sensor pas106b = { ...@@ -180,11 +180,11 @@ static struct sn9c102_sensor pas106b = {
{ {
.id = V4L2_CID_BRIGHTNESS, .id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER, .type = V4L2_CTRL_TYPE_INTEGER,
.name = "darkness", .name = "brightness",
.minimum = 0x00, .minimum = 0x00,
.maximum = 0x1f, .maximum = 0x1f,
.step = 0x01, .step = 0x01,
.default_value = 0x00, .default_value = 0x1f,
.flags = 0, .flags = 0,
}, },
{ {
......
...@@ -104,7 +104,7 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam, ...@@ -104,7 +104,7 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
err += sn9c102_i2c_write(cam, 0x10, ctrl->value & 0x1f); err += sn9c102_i2c_write(cam, 0x10, ctrl->value & 0x1f);
break; break;
case V4L2_CID_BRIGHTNESS: case V4L2_CID_BRIGHTNESS:
err += sn9c102_i2c_write(cam, 0x06, ctrl->value & 0x0f); err += sn9c102_i2c_write(cam, 0x06, 0x0f-(ctrl->value & 0x0f));
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -173,11 +173,11 @@ static struct sn9c102_sensor pas202bcb = { ...@@ -173,11 +173,11 @@ static struct sn9c102_sensor pas202bcb = {
{ {
.id = V4L2_CID_BRIGHTNESS, .id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER, .type = V4L2_CTRL_TYPE_INTEGER,
.name = "darkness", .name = "brightness",
.minimum = 0x00, .minimum = 0x00,
.maximum = 0x0f, .maximum = 0x0f,
.step = 0x01, .step = 0x01,
.default_value = 0x00, .default_value = 0x0f,
.flags = 0, .flags = 0,
}, },
}, },
......
...@@ -27,7 +27,6 @@ static struct sn9c102_sensor tas5110c1b; ...@@ -27,7 +27,6 @@ static struct sn9c102_sensor tas5110c1b;
static int tas5110c1b_init(struct sn9c102_device* cam) static int tas5110c1b_init(struct sn9c102_device* cam)
{ {
const u8 DARKNESS = 0xb7;
int err = 0; int err = 0;
err += sn9c102_write_reg(cam, 0x01, 0x01); err += sn9c102_write_reg(cam, 0x01, 0x01);
...@@ -41,13 +40,26 @@ static int tas5110c1b_init(struct sn9c102_device* cam) ...@@ -41,13 +40,26 @@ static int tas5110c1b_init(struct sn9c102_device* cam)
err += sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, 0x00, 0xc0, err += sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, 0x00, 0xc0,
0x80, 0, 0); 0x80, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, 0x02, 0x20,
DARKNESS, 0, 0);
return err; return err;
} }
static int tas5110c1b_set_ctrl(struct sn9c102_device* cam,
const struct v4l2_control* ctrl)
{
switch (ctrl->id) {
case V4L2_CID_GAIN:
return sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11,
0x02, 0x20,
0xff - (ctrl->value & 0xff),
0, 0);
default:
return -EINVAL;
}
}
static int tas5110c1b_set_crop(struct sn9c102_device* cam, static int tas5110c1b_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect) const struct v4l2_rect* rect)
{ {
...@@ -74,6 +86,19 @@ static struct sn9c102_sensor tas5110c1b = { ...@@ -74,6 +86,19 @@ static struct sn9c102_sensor tas5110c1b = {
.frequency = SN9C102_I2C_100KHZ, .frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_3WIRES, .interface = SN9C102_I2C_3WIRES,
.init = &tas5110c1b_init, .init = &tas5110c1b_init,
.qctrl = {
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "global gain",
.minimum = 0x00,
.maximum = 0xff,
.step = 0x01,
.default_value = 0x48,
.flags = 0,
},
},
.set_ctrl = &tas5110c1b_set_ctrl,
.cropcap = { .cropcap = {
.bounds = { .bounds = {
.left = 0, .left = 0,
......
...@@ -27,7 +27,6 @@ static struct sn9c102_sensor tas5130d1b; ...@@ -27,7 +27,6 @@ static struct sn9c102_sensor tas5130d1b;
static int tas5130d1b_init(struct sn9c102_device* cam) static int tas5130d1b_init(struct sn9c102_device* cam)
{ {
const u8 DARKNESS = 0xff, CONTRAST = 0xb0, GAIN = 0x08;
int err = 0; int err = 0;
err += sn9c102_write_reg(cam, 0x01, 0x01); err += sn9c102_write_reg(cam, 0x01, 0x01);
...@@ -39,19 +38,28 @@ static int tas5130d1b_init(struct sn9c102_device* cam) ...@@ -39,19 +38,28 @@ static int tas5130d1b_init(struct sn9c102_device* cam)
err += sn9c102_write_reg(cam, 0x60, 0x17); err += sn9c102_write_reg(cam, 0x60, 0x17);
err += sn9c102_write_reg(cam, 0x07, 0x18); err += sn9c102_write_reg(cam, 0x07, 0x18);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x80,
0x00, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0xc0,
GAIN, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x40, err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x40,
CONTRAST, 0, 0); 0x47, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x02, 0x20,
DARKNESS, 0, 0);
return err; return err;
} }
static int tas5130d1b_set_ctrl(struct sn9c102_device* cam,
const struct v4l2_control* ctrl)
{
switch (ctrl->id) {
case V4L2_CID_GAIN:
return sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11,
0x02, 0x20,
0xff - (ctrl->value & 0xff),
0, 0);
default:
return -EINVAL;
}
}
static int tas5130d1b_set_crop(struct sn9c102_device* cam, static int tas5130d1b_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect) const struct v4l2_rect* rect)
{ {
...@@ -78,6 +86,19 @@ static struct sn9c102_sensor tas5130d1b = { ...@@ -78,6 +86,19 @@ static struct sn9c102_sensor tas5130d1b = {
.frequency = SN9C102_I2C_100KHZ, .frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_3WIRES, .interface = SN9C102_I2C_3WIRES,
.init = &tas5130d1b_init, .init = &tas5130d1b_init,
.qctrl = {
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "global gain",
.minimum = 0x00,
.maximum = 0xff,
.step = 0x01,
.default_value = 0x00,
.flags = 0,
},
},
.set_ctrl = &tas5130d1b_set_ctrl,
.cropcap = { .cropcap = {
.bounds = { .bounds = {
.left = 0, .left = 0,
......
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