FlexcopII Standby-Resume Patch
26. November 2013 01:40

Dieser Patch behebt das Problem für DVB Karten, welche mit dem FlexcopII Chip bestückt sind, dass nach einem Standby beim Resume die Karte nicht wieder funktioniert.
Der Patch stammt aus der Kernel-Mailingliste, wurde leider seit Jahren nicht in den Upstream eingebunden.
Handelt sich also nicht um Code vom Autor dieser Website, es waren jedoch ein paar Änderungen notwendig.

                    Index: drivers/media/common/b2c2/flexcop-common.h
===================================================================
--- drivers/media/common/b2c2/flexcop-common.h
+++ drivers/media/common/b2c2/flexcop-common.h
@@ -117,6 +117,9 @@ int flexcop_device_initialize(struct fle
 void flexcop_device_exit(struct flexcop_device *fc);
 void flexcop_reset_block_300(struct flexcop_device *fc);
 
+void flexcop_device_suspend(struct flexcop_device *fc);
+void flexcop_device_resume(struct flexcop_device *fc);
+
 /* from flexcop-dma.c */
 int flexcop_dma_allocate(struct pci_dev *pdev,
 		struct flexcop_dma *dma, u32 size);
Index: drivers/media/common/b2c2/flexcop.c
===================================================================
--- drivers/media/common/b2c2/flexcop.c
+++ drivers/media/common/b2c2/flexcop.c
@@ -292,6 +292,75 @@ void flexcop_device_exit(struct flexcop_
 }
 EXPORT_SYMBOL(flexcop_device_exit);
 
+void flexcop_device_suspend(struct flexcop_device *fc)
+{
+	/* flexcop_device_exit does only unregister objects
+	 * so just stop streaming here */
+	struct dvb_demux_feed *feed;
+
+	/* copied from flexcop_pci_irq_check_work */
+#if 1
+	info("stopping pid feeds");
+	spin_lock_irq(&fc->demux.lock);
+	list_for_each_entry(feed, &fc->demux.feed_list,
+			list_head) {
+		flexcop_pid_feed_control(fc, feed, 0);
+	}
+	spin_unlock_irq(&fc->demux.lock);
+#endif
+
+#if 1
+	/* make sure streaming is really off */
+	if (fc->stream_control)
+		fc->stream_control(fc, 0);
+#endif
+#if 0
+	fc->feedcount = 0;
+	fc->extra_feedcount = 0;
+	flexcop_reset_block_300(fc);
+	flexcop_hw_filter_init(fc);
+#endif
+}
+EXPORT_SYMBOL(flexcop_device_suspend);
+
+void flexcop_device_resume(struct flexcop_device *fc)
+{
+	/* copied from flexcop_device_initialize */
+	//struct dvb_demux_feed *feed;
+	flexcop_reset(fc);
+
+	flexcop_sram_init(fc);
+	flexcop_hw_filter_init(fc);
+	flexcop_smc_ctrl(fc, 0);
+
+	/* do the MAC address reading after initializing the dvb_adapter */
+	/* TODO: need not reread MAC address, but status was not saved */
+	if (fc->get_mac_addr(fc, 0) == 0) {
+		u8 *b = fc->dvb_adapter.proposed_mac;
+		info("MAC address = %pM", b);
+		flexcop_set_mac_filter(fc, b);
+		flexcop_mac_filter_ctrl(fc, 1);
+	} else
+		warn("reading of MAC address failed.\n");
+
+	/* TODO: Is it fine to start streaming here,
+	 * before DMA is re-initialized */
+
+	/* copied from flexcop_pci_irq_check_work */
+	info("restarting pid feeds");
+#if 0
+	spin_lock_irq(&fc->demux.lock);
+	list_for_each_entry(feed, &fc->demux.feed_list,
+			list_head) {
+		flexcop_pid_feed_control(fc, feed, 1);
+	}
+	spin_unlock_irq(&fc->demux.lock);
+#endif
+
+	flexcop_device_name(fc, "resume of", "complete");
+}
+EXPORT_SYMBOL(flexcop_device_resume);
+
 static int flexcop_module_init(void)
 {
 	info(DRIVER_NAME " loaded successfully");
Index: drivers/media/common/b2c2/flexcop-pci.c
===================================================================
--- drivers/media/pci/b2c2/flexcop-pci.c
+++ drivers/media/pci/b2c2/flexcop-pci.c
@@ -319,8 +319,6 @@ static int flexcop_pci_init(struct flexc
 	pci_read_config_byte(fc_pci->pdev, PCI_CLASS_REVISION, &card_rev);
 	info("card revision %x", card_rev);
 
-	if ((ret = pci_enable_device(fc_pci->pdev)) != 0)
-		return ret;
 	pci_set_master(fc_pci->pdev);
 
 	if ((ret = pci_request_regions(fc_pci->pdev, DRIVER_NAME)) != 0)
@@ -334,7 +332,6 @@ static int flexcop_pci_init(struct flexc
 		goto err_pci_release_regions;
 	}
 
-	pci_set_drvdata(fc_pci->pdev, fc_pci);
 	spin_lock_init(&fc_pci->irq_lock);
 	if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr,
 					IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0)
@@ -345,7 +342,6 @@ static int flexcop_pci_init(struct flexc
 
 err_pci_iounmap:
 	pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
-	pci_set_drvdata(fc_pci->pdev, NULL);
 err_pci_release_regions:
 	pci_release_regions(fc_pci->pdev);
 err_pci_disable_device:
@@ -358,9 +354,7 @@ static void flexcop_pci_exit(struct flex
 	if (fc_pci->init_state & FC_PCI_INIT) {
 		free_irq(fc_pci->pdev->irq, fc_pci);
 		pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
-		pci_set_drvdata(fc_pci->pdev, NULL);
 		pci_release_regions(fc_pci->pdev);
-		pci_disable_device(fc_pci->pdev);
 	}
 	fc_pci->init_state &= ~FC_PCI_INIT;
 }
@@ -399,6 +393,11 @@ static int flexcop_pci_probe(struct pci_
 
 	/* bus specific part */
 	fc_pci->pdev = pdev;
+	ret = pci_enable_device(pdev);
+	if (ret != 0)
+		goto err_kfree;
+
+	pci_set_drvdata(pdev, fc_pci);
 	if ((ret = flexcop_pci_init(fc_pci)) != 0)
 		goto err_kfree;
 
@@ -428,6 +427,7 @@ err_fc_exit:
 err_pci_exit:
 	flexcop_pci_exit(fc_pci);
 err_kfree:
+	pci_set_drvdata(pdev, NULL);
 	flexcop_device_kfree(fc);
 	return ret;
 }
@@ -445,9 +445,74 @@ static void flexcop_pci_remove(struct pc
 	flexcop_pci_dma_exit(fc_pci);
 	flexcop_device_exit(fc_pci->fc_dev);
 	flexcop_pci_exit(fc_pci);
+	pci_set_drvdata(pdev, NULL);
+	pci_disable_device(pdev);
 	flexcop_device_kfree(fc_pci->fc_dev);
 }
 
+#ifdef CONFIG_PM
+static int flexcop_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+	struct flexcop_pci *fc_pci = pci_get_drvdata(pdev);
+	struct flexcop_device *fc = fc_pci->fc_dev;
+
+	/* most parts are from flexcop_pci_remove */
+
+	if (irq_chk_intv > 0)
+		cancel_delayed_work(&fc_pci->irq_check_work);
+
+	flexcop_pci_dma_exit(fc_pci);
+	flexcop_device_suspend(fc);
+	flexcop_pci_exit(fc_pci);
+
+	pci_save_state(pdev);
+
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, mesg));
+
+	return 0;
+}
+
+static int flexcop_pci_resume(struct pci_dev *pdev)
+{
+	int ret;
+	struct flexcop_pci *fc_pci = pci_get_drvdata(pdev);
+	struct flexcop_device *fc = fc_pci->fc_dev;
+
+	/* restore power state 0 */
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	ret = pci_enable_device(pdev);
+	if (ret < 0) {
+		err("unable to enable device in resume\n");
+		return ret;
+	}
+
+	/* from flexcop_pci_probe */
+	ret = flexcop_pci_init(fc_pci);
+	if (ret < 0) {
+		err("could not allocate pci resources in resume\n");
+		return ret;
+	}
+
+	/* init flexcop */
+	flexcop_device_resume(fc); /* instead of flexcop_device_initialize */
+
+	/* init dma */
+	flexcop_pci_dma_init(fc_pci);
+
+	/* last step: restart watchdog */
+	if (irq_chk_intv > 0)
+		schedule_delayed_work(&fc_pci->irq_check_work,
+				msecs_to_jiffies(irq_chk_intv < 100 ?
+					100 :
+					irq_chk_intv));
+
+	return 0;
+}
+#endif
+
 static struct pci_device_id flexcop_pci_tbl[] = {
 	{ PCI_DEVICE(0x13d0, 0x2103) },
 	{ },
@@ -460,6 +525,10 @@ static struct pci_driver flexcop_pci_dri
 	.id_table = flexcop_pci_tbl,
 	.probe    = flexcop_pci_probe,
 	.remove   = flexcop_pci_remove,
+#ifdef CONFIG_PM
+	.suspend  = flexcop_pci_suspend,
+	.resume   = flexcop_pci_resume,
+#endif
 };
 
 static int __init flexcop_pci_module_init(void)

                    
        
Download