|
@@ -33,6 +33,7 @@
|
|
|
#include "cx23885.h"
|
|
|
#include "cimax2.h"
|
|
|
#include "cx23888-ir.h"
|
|
|
+#include "cx23885-ir.h"
|
|
|
|
|
|
MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
|
|
|
MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
|
|
@@ -1655,6 +1656,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
|
|
|
u32 ts1_status, ts1_mask;
|
|
|
u32 ts2_status, ts2_mask;
|
|
|
int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
|
|
|
+ bool ir_handled = false;
|
|
|
|
|
|
pci_status = cx_read(PCI_INT_STAT);
|
|
|
pci_mask = cx_read(PCI_INT_MSK);
|
|
@@ -1680,18 +1682,12 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
|
|
|
dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n",
|
|
|
ts2_status, ts2_mask, ts2_count);
|
|
|
|
|
|
- if ((pci_status & PCI_MSK_RISC_RD) ||
|
|
|
- (pci_status & PCI_MSK_RISC_WR) ||
|
|
|
- (pci_status & PCI_MSK_AL_RD) ||
|
|
|
- (pci_status & PCI_MSK_AL_WR) ||
|
|
|
- (pci_status & PCI_MSK_APB_DMA) ||
|
|
|
- (pci_status & PCI_MSK_VID_C) ||
|
|
|
- (pci_status & PCI_MSK_VID_B) ||
|
|
|
- (pci_status & PCI_MSK_VID_A) ||
|
|
|
- (pci_status & PCI_MSK_AUD_INT) ||
|
|
|
- (pci_status & PCI_MSK_AUD_EXT) ||
|
|
|
- (pci_status & PCI_MSK_GPIO0) ||
|
|
|
- (pci_status & PCI_MSK_GPIO1)) {
|
|
|
+ if (pci_status & (PCI_MSK_RISC_RD | PCI_MSK_RISC_WR |
|
|
|
+ PCI_MSK_AL_RD | PCI_MSK_AL_WR | PCI_MSK_APB_DMA |
|
|
|
+ PCI_MSK_VID_C | PCI_MSK_VID_B | PCI_MSK_VID_A |
|
|
|
+ PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT |
|
|
|
+ PCI_MSK_GPIO0 | PCI_MSK_GPIO1 |
|
|
|
+ PCI_MSK_IR)) {
|
|
|
|
|
|
if (pci_status & PCI_MSK_RISC_RD)
|
|
|
dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n",
|
|
@@ -1740,6 +1736,10 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
|
|
|
if (pci_status & PCI_MSK_GPIO1)
|
|
|
dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n",
|
|
|
PCI_MSK_GPIO1);
|
|
|
+
|
|
|
+ if (pci_status & PCI_MSK_IR)
|
|
|
+ dprintk(7, " (PCI_MSK_IR 0x%08x)\n",
|
|
|
+ PCI_MSK_IR);
|
|
|
}
|
|
|
|
|
|
if (cx23885_boards[dev->board].cimax > 0 &&
|
|
@@ -1770,12 +1770,48 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
|
|
|
if (vida_status)
|
|
|
handled += cx23885_video_irq(dev, vida_status);
|
|
|
|
|
|
+ if (pci_status & PCI_MSK_IR) {
|
|
|
+ v4l2_subdev_call(dev->sd_ir, ir, interrupt_service_routine,
|
|
|
+ pci_status, &ir_handled);
|
|
|
+ if (ir_handled)
|
|
|
+ handled++;
|
|
|
+ }
|
|
|
+
|
|
|
if (handled)
|
|
|
cx_write(PCI_INT_STAT, pci_status);
|
|
|
out:
|
|
|
return IRQ_RETVAL(handled);
|
|
|
}
|
|
|
|
|
|
+static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd,
|
|
|
+ unsigned int notification, void *arg)
|
|
|
+{
|
|
|
+ struct cx23885_dev *dev;
|
|
|
+
|
|
|
+ if (sd == NULL)
|
|
|
+ return;
|
|
|
+
|
|
|
+ dev = to_cx23885(sd->v4l2_dev);
|
|
|
+
|
|
|
+ switch (notification) {
|
|
|
+ case V4L2_SUBDEV_IR_RX_NOTIFY: /* Called in an IRQ context */
|
|
|
+ if (sd == dev->sd_ir)
|
|
|
+ cx23885_ir_rx_v4l2_dev_notify(sd, *(u32 *)arg);
|
|
|
+ break;
|
|
|
+ case V4L2_SUBDEV_IR_TX_NOTIFY: /* Called in an IRQ context */
|
|
|
+ if (sd == dev->sd_ir)
|
|
|
+ cx23885_ir_tx_v4l2_dev_notify(sd, *(u32 *)arg);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void cx23885_v4l2_dev_notify_init(struct cx23885_dev *dev)
|
|
|
+{
|
|
|
+ INIT_WORK(&dev->ir_rx_work, cx23885_ir_rx_work_handler);
|
|
|
+ INIT_WORK(&dev->ir_tx_work, cx23885_ir_tx_work_handler);
|
|
|
+ dev->v4l2_dev.notify = cx23885_v4l2_dev_notify;
|
|
|
+}
|
|
|
+
|
|
|
static inline int encoder_on_portb(struct cx23885_dev *dev)
|
|
|
{
|
|
|
return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER;
|
|
@@ -1872,6 +1908,9 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
|
|
|
if (err < 0)
|
|
|
goto fail_free;
|
|
|
|
|
|
+ /* Prepare to handle notifications from subdevices */
|
|
|
+ cx23885_v4l2_dev_notify_init(dev);
|
|
|
+
|
|
|
/* pci init */
|
|
|
dev->pci = pci_dev;
|
|
|
if (pci_enable_device(pci_dev)) {
|
|
@@ -1914,6 +1953,13 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * The CX2388[58] IR controller can start firing interrupts when
|
|
|
+ * enabled, so these have to take place after the cx23885_irq() handler
|
|
|
+ * is hooked up by the call to request_irq() above.
|
|
|
+ */
|
|
|
+ cx23885_ir_pci_int_enable(dev);
|
|
|
+
|
|
|
return 0;
|
|
|
|
|
|
fail_irq:
|
|
@@ -1930,9 +1976,9 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
|
|
|
struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
|
|
|
struct cx23885_dev *dev = to_cx23885(v4l2_dev);
|
|
|
|
|
|
- cx23885_shutdown(dev);
|
|
|
+ cx23885_ir_fini(dev);
|
|
|
|
|
|
- cx23888_ir_remove(dev);
|
|
|
+ cx23885_shutdown(dev);
|
|
|
|
|
|
pci_disable_device(pci_dev);
|
|
|
|