mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 22:56:27 +08:00
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: Michael Krufky <mkrufky@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
ffb412346b
commit
89fd28545c
@ -30,6 +30,7 @@
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
#include "xc5000.h"
|
||||
#include "tuner-i2c.h"
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
@ -39,6 +40,9 @@ static int xc5000_load_fw_on_attach;
|
||||
module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
|
||||
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) \
|
||||
printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
|
||||
|
||||
@ -47,7 +51,9 @@ MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
|
||||
|
||||
struct xc5000_priv {
|
||||
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 bandwidth;
|
||||
@ -520,13 +526,13 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
|
||||
u8 buf[2] = { reg >> 8, reg & 0xff };
|
||||
u8 bval[2] = { 0, 0 };
|
||||
struct i2c_msg msg[2] = {
|
||||
{ .addr = priv->cfg->i2c_address,
|
||||
{ .addr = priv->i2c_props.addr,
|
||||
.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 },
|
||||
};
|
||||
|
||||
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");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
|
||||
struct i2c_msg msg = { .addr = priv->i2c_props.addr,
|
||||
.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",
|
||||
(int)len);
|
||||
return -EREMOTEIO;
|
||||
@ -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)
|
||||
{
|
||||
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 };
|
||||
|
||||
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);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
@ -570,7 +576,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe)
|
||||
printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
|
||||
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) {
|
||||
printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
|
||||
ret = XC_RESULT_RESET_FAILURE;
|
||||
@ -908,9 +914,19 @@ static int xc5000_init(struct dvb_frontend *fe)
|
||||
|
||||
static int xc5000_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct xc5000_priv *priv = fe->tuner_priv;
|
||||
|
||||
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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -938,26 +954,41 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
|
||||
struct xc5000_config *cfg, void *devptr)
|
||||
{
|
||||
struct xc5000_priv *priv = NULL;
|
||||
int instance;
|
||||
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);
|
||||
if (priv == NULL)
|
||||
return NULL;
|
||||
mutex_lock(&xc5000_list_mutex);
|
||||
|
||||
priv->cfg = cfg;
|
||||
priv->bandwidth = BANDWIDTH_6_MHZ;
|
||||
priv->i2c = i2c;
|
||||
priv->devptr = devptr;
|
||||
instance = hybrid_tuner_request_state(struct xc5000_priv, priv,
|
||||
hybrid_tuner_instance_list,
|
||||
i2c, cfg->i2c_address, "xc5000");
|
||||
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
|
||||
instance of the driver has loaded the firmware.
|
||||
*/
|
||||
if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) {
|
||||
kfree(priv);
|
||||
return NULL;
|
||||
}
|
||||
if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
|
||||
goto fail;
|
||||
|
||||
switch(id) {
|
||||
case XC_PRODUCT_ID_FW_LOADED:
|
||||
@ -978,19 +1009,23 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
|
||||
printk(KERN_ERR
|
||||
"xc5000: Device not found at addr 0x%02x (0x%x)\n",
|
||||
cfg->i2c_address, id);
|
||||
kfree(priv);
|
||||
return NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mutex_unlock(&xc5000_list_mutex);
|
||||
|
||||
memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
|
||||
sizeof(struct dvb_tuner_ops));
|
||||
|
||||
fe->tuner_priv = priv;
|
||||
|
||||
if (xc5000_load_fw_on_attach)
|
||||
xc5000_init(fe);
|
||||
|
||||
return fe;
|
||||
fail:
|
||||
mutex_unlock(&xc5000_list_mutex);
|
||||
|
||||
xc5000_release(fe);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(xc5000_attach);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user