diff options
author | Michael Krufky <mkrufky@linuxtv.org> | 2008-09-06 10:44:53 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-10-12 07:37:01 -0400 |
commit | 89fd28545c7390eb6c63d3d9e6faac78942dd1a4 (patch) | |
tree | 50e79a8e6eb3cf2384b04e88f716fed4e93fd43c /drivers/media/common/tuners | |
parent | ffb412346bcebf143d0f43ab4c6a61c4270a9266 (diff) |
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>
Diffstat (limited to 'drivers/media/common/tuners')
-rw-r--r-- | drivers/media/common/tuners/xc5000.c | 87 |
1 files changed, 61 insertions, 26 deletions
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c index 50d42c8db4ea..1850f7b7d961 100644 --- a/drivers/media/common/tuners/xc5000.c +++ b/drivers/media/common/tuners/xc5000.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "dvb_frontend.h" | 30 | #include "dvb_frontend.h" |
31 | 31 | ||
32 | #include "xc5000.h" | 32 | #include "xc5000.h" |
33 | #include "tuner-i2c.h" | ||
33 | 34 | ||
34 | static int debug; | 35 | static int debug; |
35 | module_param(debug, int, 0644); | 36 | module_param(debug, int, 0644); |
@@ -39,6 +40,9 @@ static int xc5000_load_fw_on_attach; | |||
39 | module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644); | 40 | module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644); |
40 | MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization."); | 41 | MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization."); |
41 | 42 | ||
43 | static DEFINE_MUTEX(xc5000_list_mutex); | ||
44 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
45 | |||
42 | #define dprintk(level,fmt, arg...) if (debug >= level) \ | 46 | #define dprintk(level,fmt, arg...) if (debug >= level) \ |
43 | printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) | 47 | printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) |
44 | 48 | ||
@@ -47,7 +51,9 @@ MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization."); | |||
47 | 51 | ||
48 | struct xc5000_priv { | 52 | struct xc5000_priv { |
49 | struct xc5000_config *cfg; | 53 | struct xc5000_config *cfg; |
50 | struct i2c_adapter *i2c; | 54 | |
55 | struct tuner_i2c_props i2c_props; | ||
56 | struct list_head hybrid_tuner_instance_list; | ||
51 | 57 | ||
52 | u32 freq_hz; | 58 | u32 freq_hz; |
53 | u32 bandwidth; | 59 | u32 bandwidth; |
@@ -520,13 +526,13 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) | |||
520 | u8 buf[2] = { reg >> 8, reg & 0xff }; | 526 | u8 buf[2] = { reg >> 8, reg & 0xff }; |
521 | u8 bval[2] = { 0, 0 }; | 527 | u8 bval[2] = { 0, 0 }; |
522 | struct i2c_msg msg[2] = { | 528 | struct i2c_msg msg[2] = { |
523 | { .addr = priv->cfg->i2c_address, | 529 | { .addr = priv->i2c_props.addr, |
524 | .flags = 0, .buf = &buf[0], .len = 2 }, | 530 | .flags = 0, .buf = &buf[0], .len = 2 }, |
525 | { .addr = priv->cfg->i2c_address, | 531 | { .addr = priv->i2c_props.addr, |
526 | .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, | 532 | .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, |
527 | }; | 533 | }; |
528 | 534 | ||
529 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { | 535 | if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { |
530 | printk(KERN_WARNING "xc5000: I2C read failed\n"); | 536 | printk(KERN_WARNING "xc5000: I2C read failed\n"); |
531 | return -EREMOTEIO; | 537 | return -EREMOTEIO; |
532 | } | 538 | } |
@@ -537,10 +543,10 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) | |||
537 | 543 | ||
538 | static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len) | 544 | static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len) |
539 | { | 545 | { |
540 | struct i2c_msg msg = { .addr = priv->cfg->i2c_address, | 546 | struct i2c_msg msg = { .addr = priv->i2c_props.addr, |
541 | .flags = 0, .buf = buf, .len = len }; | 547 | .flags = 0, .buf = buf, .len = len }; |
542 | 548 | ||
543 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | 549 | if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { |
544 | printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", | 550 | printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", |
545 | (int)len); | 551 | (int)len); |
546 | return -EREMOTEIO; | 552 | return -EREMOTEIO; |
@@ -550,10 +556,10 @@ static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len) | |||
550 | 556 | ||
551 | static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len) | 557 | static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len) |
552 | { | 558 | { |
553 | struct i2c_msg msg = { .addr = priv->cfg->i2c_address, | 559 | struct i2c_msg msg = { .addr = priv->i2c_props.addr, |
554 | .flags = I2C_M_RD, .buf = buf, .len = len }; | 560 | .flags = I2C_M_RD, .buf = buf, .len = len }; |
555 | 561 | ||
556 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | 562 | if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { |
557 | printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len); | 563 | printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len); |
558 | return -EREMOTEIO; | 564 | return -EREMOTEIO; |
559 | } | 565 | } |
@@ -570,7 +576,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe) | |||
570 | printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", | 576 | printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", |
571 | XC5000_DEFAULT_FIRMWARE); | 577 | XC5000_DEFAULT_FIRMWARE); |
572 | 578 | ||
573 | ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev); | 579 | ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c_props.adap->dev); |
574 | if (ret) { | 580 | if (ret) { |
575 | printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); | 581 | printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); |
576 | ret = XC_RESULT_RESET_FAILURE; | 582 | ret = XC_RESULT_RESET_FAILURE; |
@@ -908,9 +914,19 @@ static int xc5000_init(struct dvb_frontend *fe) | |||
908 | 914 | ||
909 | static int xc5000_release(struct dvb_frontend *fe) | 915 | static int xc5000_release(struct dvb_frontend *fe) |
910 | { | 916 | { |
917 | struct xc5000_priv *priv = fe->tuner_priv; | ||
918 | |||
911 | dprintk(1, "%s()\n", __func__); | 919 | dprintk(1, "%s()\n", __func__); |
912 | kfree(fe->tuner_priv); | 920 | |
921 | mutex_lock(&xc5000_list_mutex); | ||
922 | |||
923 | if (priv) | ||
924 | hybrid_tuner_release_state(priv); | ||
925 | |||
926 | mutex_unlock(&xc5000_list_mutex); | ||
927 | |||
913 | fe->tuner_priv = NULL; | 928 | fe->tuner_priv = NULL; |
929 | |||
914 | return 0; | 930 | return 0; |
915 | } | 931 | } |
916 | 932 | ||
@@ -938,26 +954,41 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, | |||
938 | struct xc5000_config *cfg, void *devptr) | 954 | struct xc5000_config *cfg, void *devptr) |
939 | { | 955 | { |
940 | struct xc5000_priv *priv = NULL; | 956 | struct xc5000_priv *priv = NULL; |
957 | int instance; | ||
941 | u16 id = 0; | 958 | u16 id = 0; |
942 | 959 | ||
943 | dprintk(1, "%s()\n", __func__); | 960 | dprintk(1, "%s(%d-%04x)\n", __func__, |
961 | i2c ? i2c_adapter_id(i2c) : -1, | ||
962 | cfg ? cfg->i2c_address : -1); | ||
944 | 963 | ||
945 | priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL); | 964 | mutex_lock(&xc5000_list_mutex); |
946 | if (priv == NULL) | ||
947 | return NULL; | ||
948 | 965 | ||
949 | priv->cfg = cfg; | 966 | instance = hybrid_tuner_request_state(struct xc5000_priv, priv, |
950 | priv->bandwidth = BANDWIDTH_6_MHZ; | 967 | hybrid_tuner_instance_list, |
951 | priv->i2c = i2c; | 968 | i2c, cfg->i2c_address, "xc5000"); |
952 | priv->devptr = devptr; | 969 | switch (instance) { |
970 | case 0: | ||
971 | goto fail; | ||
972 | break; | ||
973 | case 1: | ||
974 | /* new tuner instance */ | ||
975 | priv->cfg = cfg; | ||
976 | priv->bandwidth = BANDWIDTH_6_MHZ; | ||
977 | priv->devptr = devptr; | ||
978 | |||
979 | fe->tuner_priv = priv; | ||
980 | break; | ||
981 | default: | ||
982 | /* existing tuner instance */ | ||
983 | fe->tuner_priv = priv; | ||
984 | break; | ||
985 | } | ||
953 | 986 | ||
954 | /* Check if firmware has been loaded. It is possible that another | 987 | /* Check if firmware has been loaded. It is possible that another |
955 | instance of the driver has loaded the firmware. | 988 | instance of the driver has loaded the firmware. |
956 | */ | 989 | */ |
957 | if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) { | 990 | if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) |
958 | kfree(priv); | 991 | goto fail; |
959 | return NULL; | ||
960 | } | ||
961 | 992 | ||
962 | switch(id) { | 993 | switch(id) { |
963 | case XC_PRODUCT_ID_FW_LOADED: | 994 | case XC_PRODUCT_ID_FW_LOADED: |
@@ -978,19 +1009,23 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, | |||
978 | printk(KERN_ERR | 1009 | printk(KERN_ERR |
979 | "xc5000: Device not found at addr 0x%02x (0x%x)\n", | 1010 | "xc5000: Device not found at addr 0x%02x (0x%x)\n", |
980 | cfg->i2c_address, id); | 1011 | cfg->i2c_address, id); |
981 | kfree(priv); | 1012 | goto fail; |
982 | return NULL; | ||
983 | } | 1013 | } |
984 | 1014 | ||
1015 | mutex_unlock(&xc5000_list_mutex); | ||
1016 | |||
985 | memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, | 1017 | memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, |
986 | sizeof(struct dvb_tuner_ops)); | 1018 | sizeof(struct dvb_tuner_ops)); |
987 | 1019 | ||
988 | fe->tuner_priv = priv; | ||
989 | |||
990 | if (xc5000_load_fw_on_attach) | 1020 | if (xc5000_load_fw_on_attach) |
991 | xc5000_init(fe); | 1021 | xc5000_init(fe); |
992 | 1022 | ||
993 | return fe; | 1023 | return fe; |
1024 | fail: | ||
1025 | mutex_unlock(&xc5000_list_mutex); | ||
1026 | |||
1027 | xc5000_release(fe); | ||
1028 | return NULL; | ||
994 | } | 1029 | } |
995 | EXPORT_SYMBOL(xc5000_attach); | 1030 | EXPORT_SYMBOL(xc5000_attach); |
996 | 1031 | ||