The patch number 8949 was added via Michael Krufky <[EMAIL PROTECTED]> to http://linuxtv.org/hg/v4l-dvb master development tree.
Kernel patches in this development tree may be modified to be backward compatible with older kernels. Compatibility modifications will be removed before inclusion into the mainstream Kernel If anyone has any objections, please let us know by sending a message to: [EMAIL PROTECTED] ------ From: Michael Krufky <[EMAIL PROTECTED]> 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. Priority: normal Signed-off-by: Michael Krufky <[EMAIL PROTECTED]> --- linux/drivers/media/common/tuners/xc5000.c | 93 ++++++++++++++------- 1 file changed, 64 insertions(+), 29 deletions(-) diff -r 6ac538c97b72 -r 9b8c420376d9 linux/drivers/media/common/tuners/xc5000.c --- a/linux/drivers/media/common/tuners/xc5000.c Sat Sep 06 09:52:30 2008 -0400 +++ b/linux/drivers/media/common/tuners/xc5000.c Sat Sep 06 10:44:53 2008 -0400 @@ -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 @@ module_param_named(init_fw, xc5000_load_ 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 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; @@ -539,13 +545,13 @@ static int xc5000_readreg(struct xc5000_ 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; } @@ -556,10 +562,10 @@ static int xc5000_readreg(struct xc5000_ 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; @@ -569,10 +575,10 @@ static int xc5000_writeregs(struct xc500 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; } @@ -589,7 +595,7 @@ static int xc5000_fwupload(struct dvb_fr 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; @@ -927,9 +933,19 @@ static int xc5000_init(struct dvb_fronte 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; } @@ -957,26 +973,41 @@ struct dvb_frontend *xc5000_attach(struc struct xc5000_config *cfg, void *devptr) { struct xc5000_priv *priv = NULL; + int instance; u16 id = 0; - dprintk(1, "%s()\n", __func__); - - priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->i2c = i2c; - priv->devptr = devptr; + dprintk(1, "%s(%d-%04x)\n", __func__, + i2c ? i2c_adapter_id(i2c) : -1, + cfg ? cfg->i2c_address : -1); + + mutex_lock(&xc5000_list_mutex); + + 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: @@ -997,19 +1028,23 @@ struct dvb_frontend *xc5000_attach(struc 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); --- Patch is available at: http://linuxtv.org/hg/v4l-dvb/rev/9b8c420376d98e63652d18e5e73bb27632bbf32a _______________________________________________ linuxtv-commits mailing list linuxtv-commits@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits