===================================================================
@@ -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);
===================================================================
@@ -292,6 +292,59 @@ 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 */
+ 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);
+}
+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");
+ 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);
+
+ flexcop_device_name(fc, "resume of", "complete");
+}
+EXPORT_SYMBOL(flexcop_device_resume);
+
static int flexcop_module_init(void)
{
info(DRIVER_NAME " loaded successfully");
===================================================================
@@ -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,65 @@ 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)
+{
+ 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);
+
+ pci_enable_device(pdev);
+
+ /* from flexcop_pci_probe */
+ flexcop_pci_init(fc_pci);
+
+ /* 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 +516,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)