Commit 89fd2854 authored by Michael Krufky's avatar Michael Krufky Committed by Mauro Carvalho Chehab

V4L/DVB (8949): xc5000: allow multiple driver instances for the same hardware to share state

Convert xc5000 to use the hybrid_tuner_request_state and
hybrid_tuner_release_state macros to manage state sharing between
hybrid tuner instances.
Signed-off-by: default avatarMichael Krufky <mkrufky@linuxtv.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent ffb41234
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "dvb_frontend.h" #include "dvb_frontend.h"
#include "xc5000.h" #include "xc5000.h"
#include "tuner-i2c.h"
static int debug; static int debug;
module_param(debug, int, 0644); module_param(debug, int, 0644);
...@@ -39,6 +40,9 @@ static int xc5000_load_fw_on_attach; ...@@ -39,6 +40,9 @@ static int xc5000_load_fw_on_attach;
module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644); module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization."); MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
static DEFINE_MUTEX(xc5000_list_mutex);
static LIST_HEAD(hybrid_tuner_instance_list);
#define dprintk(level,fmt, arg...) if (debug >= level) \ #define dprintk(level,fmt, arg...) if (debug >= level) \
printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
...@@ -47,7 +51,9 @@ MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization."); ...@@ -47,7 +51,9 @@ MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
struct xc5000_priv { struct xc5000_priv {
struct xc5000_config *cfg; struct xc5000_config *cfg;
struct i2c_adapter *i2c;
struct tuner_i2c_props i2c_props;
struct list_head hybrid_tuner_instance_list;
u32 freq_hz; u32 freq_hz;
u32 bandwidth; u32 bandwidth;
...@@ -520,13 +526,13 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) ...@@ -520,13 +526,13 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
u8 buf[2] = { reg >> 8, reg & 0xff }; u8 buf[2] = { reg >> 8, reg & 0xff };
u8 bval[2] = { 0, 0 }; u8 bval[2] = { 0, 0 };
struct i2c_msg msg[2] = { struct i2c_msg msg[2] = {
{ .addr = priv->cfg->i2c_address, { .addr = priv->i2c_props.addr,
.flags = 0, .buf = &buf[0], .len = 2 }, .flags = 0, .buf = &buf[0], .len = 2 },
{ .addr = priv->cfg->i2c_address, { .addr = priv->i2c_props.addr,
.flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
}; };
if (i2c_transfer(priv->i2c, msg, 2) != 2) { if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
printk(KERN_WARNING "xc5000: I2C read failed\n"); printk(KERN_WARNING "xc5000: I2C read failed\n");
return -EREMOTEIO; return -EREMOTEIO;
} }
...@@ -537,10 +543,10 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) ...@@ -537,10 +543,10 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len) static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
{ {
struct i2c_msg msg = { .addr = priv->cfg->i2c_address, struct i2c_msg msg = { .addr = priv->i2c_props.addr,
.flags = 0, .buf = buf, .len = len }; .flags = 0, .buf = buf, .len = len };
if (i2c_transfer(priv->i2c, &msg, 1) != 1) { if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
(int)len); (int)len);
return -EREMOTEIO; return -EREMOTEIO;
...@@ -550,10 +556,10 @@ static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len) ...@@ -550,10 +556,10 @@ static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len) static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
{ {
struct i2c_msg msg = { .addr = priv->cfg->i2c_address, struct i2c_msg msg = { .addr = priv->i2c_props.addr,
.flags = I2C_M_RD, .buf = buf, .len = len }; .flags = I2C_M_RD, .buf = buf, .len = len };
if (i2c_transfer(priv->i2c, &msg, 1) != 1) { if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len); printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
return -EREMOTEIO; return -EREMOTEIO;
} }
...@@ -570,7 +576,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe) ...@@ -570,7 +576,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe)
printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
XC5000_DEFAULT_FIRMWARE); XC5000_DEFAULT_FIRMWARE);
ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev); ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c_props.adap->dev);
if (ret) { if (ret) {
printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
ret = XC_RESULT_RESET_FAILURE; ret = XC_RESULT_RESET_FAILURE;
...@@ -908,9 +914,19 @@ static int xc5000_init(struct dvb_frontend *fe) ...@@ -908,9 +914,19 @@ static int xc5000_init(struct dvb_frontend *fe)
static int xc5000_release(struct dvb_frontend *fe) static int xc5000_release(struct dvb_frontend *fe)
{ {
struct xc5000_priv *priv = fe->tuner_priv;
dprintk(1, "%s()\n", __func__); dprintk(1, "%s()\n", __func__);
kfree(fe->tuner_priv);
mutex_lock(&xc5000_list_mutex);
if (priv)
hybrid_tuner_release_state(priv);
mutex_unlock(&xc5000_list_mutex);
fe->tuner_priv = NULL; fe->tuner_priv = NULL;
return 0; return 0;
} }
...@@ -938,26 +954,41 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, ...@@ -938,26 +954,41 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct xc5000_config *cfg, void *devptr) struct xc5000_config *cfg, void *devptr)
{ {
struct xc5000_priv *priv = NULL; struct xc5000_priv *priv = NULL;
int instance;
u16 id = 0; u16 id = 0;
dprintk(1, "%s()\n", __func__); dprintk(1, "%s(%d-%04x)\n", __func__,
i2c ? i2c_adapter_id(i2c) : -1,
cfg ? cfg->i2c_address : -1);
priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL); mutex_lock(&xc5000_list_mutex);
if (priv == NULL)
return NULL;
priv->cfg = cfg; instance = hybrid_tuner_request_state(struct xc5000_priv, priv,
priv->bandwidth = BANDWIDTH_6_MHZ; hybrid_tuner_instance_list,
priv->i2c = i2c; i2c, cfg->i2c_address, "xc5000");
priv->devptr = devptr; switch (instance) {
case 0:
goto fail;
break;
case 1:
/* new tuner instance */
priv->cfg = cfg;
priv->bandwidth = BANDWIDTH_6_MHZ;
priv->devptr = devptr;
fe->tuner_priv = priv;
break;
default:
/* existing tuner instance */
fe->tuner_priv = priv;
break;
}
/* Check if firmware has been loaded. It is possible that another /* Check if firmware has been loaded. It is possible that another
instance of the driver has loaded the firmware. instance of the driver has loaded the firmware.
*/ */
if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) { if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
kfree(priv); goto fail;
return NULL;
}
switch(id) { switch(id) {
case XC_PRODUCT_ID_FW_LOADED: case XC_PRODUCT_ID_FW_LOADED:
...@@ -978,19 +1009,23 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, ...@@ -978,19 +1009,23 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
printk(KERN_ERR printk(KERN_ERR
"xc5000: Device not found at addr 0x%02x (0x%x)\n", "xc5000: Device not found at addr 0x%02x (0x%x)\n",
cfg->i2c_address, id); cfg->i2c_address, id);
kfree(priv); goto fail;
return NULL;
} }
mutex_unlock(&xc5000_list_mutex);
memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
sizeof(struct dvb_tuner_ops)); sizeof(struct dvb_tuner_ops));
fe->tuner_priv = priv;
if (xc5000_load_fw_on_attach) if (xc5000_load_fw_on_attach)
xc5000_init(fe); xc5000_init(fe);
return fe; return fe;
fail:
mutex_unlock(&xc5000_list_mutex);
xc5000_release(fe);
return NULL;
} }
EXPORT_SYMBOL(xc5000_attach); EXPORT_SYMBOL(xc5000_attach);
......
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