aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorAntti Palosaari <crope@iki.fi>2011-11-12 20:33:30 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-11-24 14:46:47 -0500
commitff83bd82cb343d37b5ab8e402aaad9ef33d03f1e (patch)
tree780a63675c7c9ecb288a2b075d465e90f2d119da /drivers/media
parent1249a3a82d08d73ece65ae79e0553cd0f3407a15 (diff)
[media] af9015: limit I2C access to keep FW happy
AF9015 firmware does not like if it gets interrupted by I2C adapter request on some critical phases. During normal operation I2C adapter is used only 2nd demodulator and tuner on dual tuner devices. Override demodulator callbacks and use mutex for limit access to those "critical" paths to keep AF9015 happy. Signed-off-by: Antti Palosaari <crope@iki.fi> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.c97
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.h7
2 files changed, 104 insertions, 0 deletions
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index c6c275bac08..033aa8affd8 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -1093,9 +1093,80 @@ error:
1093 return ret; 1093 return ret;
1094} 1094}
1095 1095
1096/* override demod callbacks for resource locking */
1097static int af9015_af9013_set_frontend(struct dvb_frontend *fe,
1098 struct dvb_frontend_parameters *params)
1099{
1100 int ret;
1101 struct dvb_usb_adapter *adap = fe->dvb->priv;
1102 struct af9015_state *priv = adap->dev->priv;
1103
1104 if (mutex_lock_interruptible(&adap->dev->usb_mutex))
1105 return -EAGAIN;
1106
1107 ret = priv->set_frontend[adap->id](fe, params);
1108
1109 mutex_unlock(&adap->dev->usb_mutex);
1110
1111 return ret;
1112}
1113
1114/* override demod callbacks for resource locking */
1115static int af9015_af9013_read_status(struct dvb_frontend *fe,
1116 fe_status_t *status)
1117{
1118 int ret;
1119 struct dvb_usb_adapter *adap = fe->dvb->priv;
1120 struct af9015_state *priv = adap->dev->priv;
1121
1122 if (mutex_lock_interruptible(&adap->dev->usb_mutex))
1123 return -EAGAIN;
1124
1125 ret = priv->read_status[adap->id](fe, status);
1126
1127 mutex_unlock(&adap->dev->usb_mutex);
1128
1129 return ret;
1130}
1131
1132/* override demod callbacks for resource locking */
1133static int af9015_af9013_init(struct dvb_frontend *fe)
1134{
1135 int ret;
1136 struct dvb_usb_adapter *adap = fe->dvb->priv;
1137 struct af9015_state *priv = adap->dev->priv;
1138
1139 if (mutex_lock_interruptible(&adap->dev->usb_mutex))
1140 return -EAGAIN;
1141
1142 ret = priv->init[adap->id](fe);
1143
1144 mutex_unlock(&adap->dev->usb_mutex);
1145
1146 return ret;
1147}
1148
1149/* override demod callbacks for resource locking */
1150static int af9015_af9013_sleep(struct dvb_frontend *fe)
1151{
1152 int ret;
1153 struct dvb_usb_adapter *adap = fe->dvb->priv;
1154 struct af9015_state *priv = adap->dev->priv;
1155
1156 if (mutex_lock_interruptible(&adap->dev->usb_mutex))
1157 return -EAGAIN;
1158
1159 ret = priv->init[adap->id](fe);
1160
1161 mutex_unlock(&adap->dev->usb_mutex);
1162
1163 return ret;
1164}
1165
1096static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) 1166static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
1097{ 1167{
1098 int ret; 1168 int ret;
1169 struct af9015_state *state = adap->dev->priv;
1099 1170
1100 if (adap->id == 1) { 1171 if (adap->id == 1) {
1101 /* copy firmware to 2nd demodulator */ 1172 /* copy firmware to 2nd demodulator */
@@ -1116,6 +1187,32 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
1116 adap->fe_adap[0].fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], 1187 adap->fe_adap[0].fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
1117 &adap->dev->i2c_adap); 1188 &adap->dev->i2c_adap);
1118 1189
1190 /*
1191 * AF9015 firmware does not like if it gets interrupted by I2C adapter
1192 * request on some critical phases. During normal operation I2C adapter
1193 * is used only 2nd demodulator and tuner on dual tuner devices.
1194 * Override demodulator callbacks and use mutex for limit access to
1195 * those "critical" paths to keep AF9015 happy.
1196 * Note: we abuse unused usb_mutex here.
1197 */
1198 if (adap->fe_adap[0].fe) {
1199 state->set_frontend[adap->id] =
1200 adap->fe_adap[0].fe->ops.set_frontend;
1201 adap->fe_adap[0].fe->ops.set_frontend =
1202 af9015_af9013_set_frontend;
1203
1204 state->read_status[adap->id] =
1205 adap->fe_adap[0].fe->ops.read_status;
1206 adap->fe_adap[0].fe->ops.read_status =
1207 af9015_af9013_read_status;
1208
1209 state->init[adap->id] = adap->fe_adap[0].fe->ops.init;
1210 adap->fe_adap[0].fe->ops.init = af9015_af9013_init;
1211
1212 state->sleep[adap->id] = adap->fe_adap[0].fe->ops.sleep;
1213 adap->fe_adap[0].fe->ops.sleep = af9015_af9013_sleep;
1214 }
1215
1119 return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; 1216 return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
1120} 1217}
1121 1218
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
index 6252ea6c190..4a126177e10 100644
--- a/drivers/media/dvb/dvb-usb/af9015.h
+++ b/drivers/media/dvb/dvb-usb/af9015.h
@@ -102,6 +102,13 @@ struct af9015_state {
102 u8 rc_repeat; 102 u8 rc_repeat;
103 u32 rc_keycode; 103 u32 rc_keycode;
104 u8 rc_last[4]; 104 u8 rc_last[4];
105
106 /* for demod callback override */
107 int (*set_frontend[2]) (struct dvb_frontend *fe,
108 struct dvb_frontend_parameters *params);
109 int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status);
110 int (*init[2]) (struct dvb_frontend *fe);
111 int (*sleep[2]) (struct dvb_frontend *fe);
105}; 112};
106 113
107struct af9015_config { 114struct af9015_config {