Merge tag 'media/v5.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[linux-2.6-block.git] / drivers / media / usb / pvrusb2 / pvrusb2-dvb.c
index d8874a952418f663aa6d1e8ed059c331dab445bb..6954584526a326f43572332a30a6b37d9066c0c8 100644 (file)
@@ -334,26 +334,19 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
                goto done;
        }
 
-       if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) {
-
-               if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) {
+       if (dvb_props->frontend_attach(adap) == 0 && adap->fe[0]) {
+               if (dvb_register_frontend(&adap->dvb_adap, adap->fe[0])) {
                        pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                                   "frontend registration failed!");
-                       dvb_frontend_detach(adap->fe);
-                       adap->fe = NULL;
                        ret = -ENODEV;
-                       goto done;
+                       goto fail_frontend0;
                }
+               if (adap->fe[0]->ops.analog_ops.standby)
+                       adap->fe[0]->ops.analog_ops.standby(adap->fe[0]);
 
-               if (dvb_props->tuner_attach)
-                       dvb_props->tuner_attach(adap);
-
-               if (adap->fe->ops.analog_ops.standby)
-                       adap->fe->ops.analog_ops.standby(adap->fe);
-
-               /* Ensure all frontends negotiate bus access */
-               adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl;
-
+               pvr2_trace(PVR2_TRACE_INFO, "transferring fe[%d] ts_bus_ctrl() to pvr2_dvb_bus_ctrl()",
+                          adap->fe[0]->id);
+               adap->fe[0]->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl;
        } else {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "no frontend was attached!");
@@ -361,17 +354,74 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
                return ret;
        }
 
- done:
+       if (dvb_props->tuner_attach && dvb_props->tuner_attach(adap)) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS, "tuner attach failed");
+               ret = -ENODEV;
+               goto fail_tuner;
+       }
+
+       if (adap->fe[1]) {
+               adap->fe[1]->id = 1;
+               adap->fe[1]->tuner_priv = adap->fe[0]->tuner_priv;
+               memcpy(&adap->fe[1]->ops.tuner_ops,
+                      &adap->fe[0]->ops.tuner_ops,
+                      sizeof(struct dvb_tuner_ops));
+
+               if (dvb_register_frontend(&adap->dvb_adap, adap->fe[1])) {
+                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                                  "frontend registration failed!");
+                       ret = -ENODEV;
+                       goto fail_frontend1;
+               }
+               /* MFE lock */
+               adap->dvb_adap.mfe_shared = 1;
+
+               if (adap->fe[1]->ops.analog_ops.standby)
+                       adap->fe[1]->ops.analog_ops.standby(adap->fe[1]);
+
+               pvr2_trace(PVR2_TRACE_INFO, "transferring fe[%d] ts_bus_ctrl() to pvr2_dvb_bus_ctrl()",
+                          adap->fe[1]->id);
+               adap->fe[1]->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl;
+       }
+done:
        pvr2_channel_limit_inputs(&adap->channel, 0);
        return ret;
+
+fail_frontend1:
+       dvb_frontend_detach(adap->fe[1]);
+       adap->fe[1] = NULL;
+fail_tuner:
+       dvb_unregister_frontend(adap->fe[0]);
+fail_frontend0:
+       dvb_frontend_detach(adap->fe[0]);
+       adap->fe[0] = NULL;
+       dvb_module_release(adap->i2c_client_tuner);
+       dvb_module_release(adap->i2c_client_demod[1]);
+       dvb_module_release(adap->i2c_client_demod[0]);
+
+       return ret;
 }
 
 static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap)
 {
-       if (adap->fe != NULL) {
-               dvb_unregister_frontend(adap->fe);
-               dvb_frontend_detach(adap->fe);
+       if (adap->fe[1]) {
+               dvb_unregister_frontend(adap->fe[1]);
+               dvb_frontend_detach(adap->fe[1]);
+               adap->fe[1] = NULL;
+       }
+       if (adap->fe[0]) {
+               dvb_unregister_frontend(adap->fe[0]);
+               dvb_frontend_detach(adap->fe[0]);
+               adap->fe[0] = NULL;
        }
+
+       dvb_module_release(adap->i2c_client_tuner);
+       adap->i2c_client_tuner = NULL;
+       dvb_module_release(adap->i2c_client_demod[1]);
+       adap->i2c_client_demod[1] = NULL;
+       dvb_module_release(adap->i2c_client_demod[0]);
+       adap->i2c_client_demod[0] = NULL;
+
        return 0;
 }