Commit f3d092b8 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (5304): Improve chip matching in v4l2_register

The chip matching in struct v4l2_register for VIDIOC_DBG_G/S_REGISTER 
was rather primitive. It could not be extended to other busses besides 
i2c and it lacked a way to.
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent d55c7aec
...@@ -633,7 +633,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, ...@@ -633,7 +633,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
{ {
struct v4l2_register *reg = arg; struct v4l2_register *reg = arg;
if (reg->i2c_id != I2C_DRIVERID_CX25840) if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
return -EINVAL; return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
......
...@@ -1389,7 +1389,7 @@ static int vidioc_g_register (struct file *file, void *fh, ...@@ -1389,7 +1389,7 @@ static int vidioc_g_register (struct file *file, void *fh,
{ {
struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
if (reg->i2c_id != 0) if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
return -EINVAL; return -EINVAL;
/* cx2388x has a 24-bit register space */ /* cx2388x has a 24-bit register space */
reg->val = cx_read(reg->reg&0xffffff); reg->val = cx_read(reg->reg&0xffffff);
...@@ -1401,7 +1401,7 @@ static int vidioc_s_register (struct file *file, void *fh, ...@@ -1401,7 +1401,7 @@ static int vidioc_s_register (struct file *file, void *fh,
{ {
struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
if (reg->i2c_id != 0) if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
return -EINVAL; return -EINVAL;
cx_write(reg->reg&0xffffff, reg->val); cx_write(reg->reg&0xffffff, reg->val);
return 0; return 0;
......
...@@ -3256,8 +3256,8 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw) ...@@ -3256,8 +3256,8 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
int pvr2_hdw_register_access(struct pvr2_hdw *hdw, int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
u32 chip_id, u64 reg_id, u32 match_type, u32 match_chip, u64 reg_id,
int setFl,u32 *val_ptr) int setFl,u64 *val_ptr)
{ {
#ifdef CONFIG_VIDEO_ADV_DEBUG #ifdef CONFIG_VIDEO_ADV_DEBUG
struct list_head *item; struct list_head *item;
...@@ -3268,13 +3268,16 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw, ...@@ -3268,13 +3268,16 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (!capable(CAP_SYS_ADMIN)) return -EPERM;
req.i2c_id = chip_id; req.match_type = match_type;
req.match_chip = match_chip;
req.reg = reg_id; req.reg = reg_id;
if (setFl) req.val = *val_ptr; if (setFl) req.val = *val_ptr;
mutex_lock(&hdw->i2c_list_lock); do { mutex_lock(&hdw->i2c_list_lock); do {
list_for_each(item,&hdw->i2c_clients) { list_for_each(item,&hdw->i2c_clients) {
cp = list_entry(item,struct pvr2_i2c_client,list); cp = list_entry(item,struct pvr2_i2c_client,list);
if (cp->client->driver->id != chip_id) continue; if (!v4l2_chip_match_i2c_client(cp->client, req.match_type, req.match_chip)) {
continue;
}
stat = pvr2_i2c_client_cmd( stat = pvr2_i2c_client_cmd(
cp,(setFl ? VIDIOC_DBG_S_REGISTER : cp,(setFl ? VIDIOC_DBG_S_REGISTER :
VIDIOC_DBG_G_REGISTER),&req); VIDIOC_DBG_G_REGISTER),&req);
......
...@@ -217,13 +217,14 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *, ...@@ -217,13 +217,14 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,
enum pvr2_v4l_type index,int); enum pvr2_v4l_type index,int);
/* Direct read/write access to chip's registers: /* Direct read/write access to chip's registers:
chip_id - unique id of chip (e.g. I2C_DRIVERD_xxxx) match_type - how to interpret match_chip (e.g. driver ID, i2c address)
match_chip - chip match value (e.g. I2C_DRIVERD_xxxx)
reg_id - register number to access reg_id - register number to access
setFl - true to set the register, false to read it setFl - true to set the register, false to read it
val_ptr - storage location for source / result. */ val_ptr - storage location for source / result. */
int pvr2_hdw_register_access(struct pvr2_hdw *, int pvr2_hdw_register_access(struct pvr2_hdw *,
u32 chip_id,u64 reg_id, u32 match_type, u32 match_chip,u64 reg_id,
int setFl,u32 *val_ptr); int setFl,u64 *val_ptr);
/* The following entry points are all lower level things you normally don't /* The following entry points are all lower level things you normally don't
want to worry about. */ want to worry about. */
......
...@@ -740,11 +740,11 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, ...@@ -740,11 +740,11 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_DBG_S_REGISTER: case VIDIOC_DBG_S_REGISTER:
case VIDIOC_DBG_G_REGISTER: case VIDIOC_DBG_G_REGISTER:
{ {
u32 val; u64 val;
struct v4l2_register *req = (struct v4l2_register *)arg; struct v4l2_register *req = (struct v4l2_register *)arg;
if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val; if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;
ret = pvr2_hdw_register_access( ret = pvr2_hdw_register_access(
hdw,req->i2c_id,req->reg, hdw,req->match_type,req->match_chip,req->reg,
cmd == VIDIOC_DBG_S_REGISTER,&val); cmd == VIDIOC_DBG_S_REGISTER,&val);
if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val; if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;
break; break;
......
...@@ -1425,7 +1425,7 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar ...@@ -1425,7 +1425,7 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
{ {
struct v4l2_register *reg = arg; struct v4l2_register *reg = arg;
if (reg->i2c_id != I2C_DRIVERID_SAA711X) if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
return -EINVAL; return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
......
...@@ -619,7 +619,7 @@ static int saa7127_command(struct i2c_client *client, ...@@ -619,7 +619,7 @@ static int saa7127_command(struct i2c_client *client,
{ {
struct v4l2_register *reg = arg; struct v4l2_register *reg = arg;
if (reg->i2c_id != I2C_DRIVERID_SAA7127) if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
return -EINVAL; return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
......
...@@ -955,7 +955,7 @@ static int tvp5150_command(struct i2c_client *c, ...@@ -955,7 +955,7 @@ static int tvp5150_command(struct i2c_client *c,
{ {
struct v4l2_register *reg = arg; struct v4l2_register *reg = arg;
if (reg->i2c_id != I2C_DRIVERID_TVP5150) if (!v4l2_chip_match_i2c_client(c, reg->match_type, reg->match_chip))
return -EINVAL; return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
......
...@@ -167,7 +167,7 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void * ...@@ -167,7 +167,7 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
{ {
struct v4l2_register *reg = arg; struct v4l2_register *reg = arg;
if (reg->i2c_id != I2C_DRIVERID_UPD64031A) if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
return -EINVAL; return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
......
...@@ -144,7 +144,7 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a ...@@ -144,7 +144,7 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a
{ {
struct v4l2_register *reg = arg; struct v4l2_register *reg = arg;
if (reg->i2c_id != I2C_DRIVERID_UPD64083) if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
return -EINVAL; return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
......
...@@ -521,7 +521,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, ...@@ -521,7 +521,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_register *reg = arg; struct v4l2_register *reg = arg;
int errCode; int errCode;
if (reg->i2c_id != 0) if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
return -EINVAL; return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
...@@ -540,7 +540,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, ...@@ -540,7 +540,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
PDEBUG(DBG_IOCTL, "VIDIOC_DBG_%c_REGISTER reg=0x%02X, value=0x%02X", PDEBUG(DBG_IOCTL, "VIDIOC_DBG_%c_REGISTER reg=0x%02X, value=0x%02X",
cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S', cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S',
(unsigned int)reg->reg, reg->val); (unsigned int)reg->reg, (unsigned int)reg->val);
return 0; return 0;
} }
#endif #endif
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/i2c.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -947,6 +948,32 @@ u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id) ...@@ -947,6 +948,32 @@ u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
return **ctrl_classes; return **ctrl_classes;
} }
int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 match_type, u32 match_chip)
{
switch (match_type) {
case V4L2_CHIP_MATCH_ALWAYS:
return 1;
case V4L2_CHIP_MATCH_I2C_DRIVER:
return (c != NULL && c->driver != NULL && c->driver->id == match_chip);
case V4L2_CHIP_MATCH_I2C_ADDR:
return (c != NULL && c->addr == match_chip);
default:
return 0;
}
}
int v4l2_chip_match_host(u32 match_type, u32 match_chip)
{
switch (match_type) {
case V4L2_CHIP_MATCH_ALWAYS:
return 1;
case V4L2_CHIP_MATCH_HOST:
return match_chip == 0;
default:
return 0;
}
}
/* ----------------------------------------------------------------- */ /* ----------------------------------------------------------------- */
EXPORT_SYMBOL(v4l2_norm_to_name); EXPORT_SYMBOL(v4l2_norm_to_name);
...@@ -970,6 +997,9 @@ EXPORT_SYMBOL(v4l2_ctrl_query_menu); ...@@ -970,6 +997,9 @@ EXPORT_SYMBOL(v4l2_ctrl_query_menu);
EXPORT_SYMBOL(v4l2_ctrl_query_fill); EXPORT_SYMBOL(v4l2_ctrl_query_fill);
EXPORT_SYMBOL(v4l2_ctrl_query_fill_std); EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
EXPORT_SYMBOL(v4l2_chip_match_host);
/* /*
* Local variables: * Local variables:
* c-basic-offset: 8 * c-basic-offset: 8
......
...@@ -1306,10 +1306,17 @@ struct v4l2_streamparm ...@@ -1306,10 +1306,17 @@ struct v4l2_streamparm
*/ */
/* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */ /* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */
#define V4L2_CHIP_MATCH_ALWAYS 0 /* Match always (match_chip is not used) */
#define V4L2_CHIP_MATCH_HOST 1 /* Match against chip ID on host (0 for the host) */
#define V4L2_CHIP_MATCH_I2C_DRIVER 2 /* Match against I2C driver ID */
#define V4L2_CHIP_MATCH_I2C_ADDR 3 /* Match against I2C 7-bit address */
struct v4l2_register { struct v4l2_register {
__u32 match_type; /* Match type */
__u32 match_chip; /* Match this chip, meaning determined by match_type */
__u64 reg; __u64 reg;
__u32 i2c_id; /* I2C driver ID of the I2C chip, or 0 for the host */ __u64 val;
__u32 val;
}; };
/* /*
......
...@@ -94,6 +94,14 @@ u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id); ...@@ -94,6 +94,14 @@ u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id);
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* Register/chip ident helper function */
struct i2c_client; /* forward reference */
int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 id_type, u32 chip_id);
int v4l2_chip_match_host(u32 id_type, u32 chip_id);
/* ------------------------------------------------------------------------- */
/* Internal ioctls */ /* Internal ioctls */
/* VIDIOC_INT_DECODE_VBI_LINE */ /* VIDIOC_INT_DECODE_VBI_LINE */
......
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