V4L/DVB (10743): dm1105: not demuxing from interrupt context.
authorIgor M. Liplianin <liplianin@netup.ru>
Thu, 26 Feb 2009 06:40:41 +0000 (03:40 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 30 Mar 2009 15:43:00 +0000 (12:43 -0300)
The driver already has DMA buffer organized like ringbuffer,
so it is easy to switch to a work queue.
Length of ringbuffer can easily be increased, if someone need it.

Signed-off-by: Igor M. Liplianin <liplianin@netup.ru>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/dm1105/dm1105.c

index f48f73a..d9f55be 100644 (file)
@@ -220,10 +220,14 @@ struct dm1105dvb {
        /* i2c */
        struct i2c_adapter i2c_adap;
 
+       /* irq */
+       struct work_struct work;
+
        /* dma */
        dma_addr_t dma_addr;
        unsigned char *ts_buf;
        u32 wrp;
+       u32 nextwrp;
        u32 buffer_size;
        unsigned int    PacketErrorCount;
        unsigned int dmarst;
@@ -415,6 +419,9 @@ static void dm1105_emit_key(unsigned long parm)
        u8 data;
        u16 keycode;
 
+       if (ir_debug)
+               printk(KERN_INFO "%s: received byte 0x%04x\n", __func__, ircom);
+
        data = (ircom >> 8) & 0x7f;
 
        input_event(ir->input_dev, EV_MSC, MSC_RAW, (0x0000f8 << 16) | data);
@@ -431,14 +438,45 @@ static void dm1105_emit_key(unsigned long parm)
 
 }
 
+/* work handler */
+static void dm1105_dmx_buffer(struct work_struct *work)
+{
+       struct dm1105dvb *dm1105dvb =
+                               container_of(work, struct dm1105dvb, work);
+       unsigned int nbpackets;
+       u32 oldwrp = dm1105dvb->wrp;
+       u32 nextwrp = dm1105dvb->nextwrp;
+
+       if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
+                       (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
+                       (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
+               dm1105dvb->PacketErrorCount++;
+               /* bad packet found */
+               if ((dm1105dvb->PacketErrorCount >= 2) &&
+                               (dm1105dvb->dmarst == 0)) {
+                       outb(1, dm_io_mem(DM1105_RST));
+                       dm1105dvb->wrp = 0;
+                       dm1105dvb->PacketErrorCount = 0;
+                       dm1105dvb->dmarst = 0;
+                       return;
+               }
+       }
+
+       if (nextwrp < oldwrp) {
+               memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size,
+                                               dm1105dvb->ts_buf, nextwrp);
+               nbpackets = ((dm1105dvb->buffer_size - oldwrp) + nextwrp) / 188;
+       } else
+               nbpackets = (nextwrp - oldwrp) / 188;
+
+       dm1105dvb->wrp = nextwrp;
+       dvb_dmx_swfilter_packets(&dm1105dvb->demux,
+                                       &dm1105dvb->ts_buf[oldwrp], nbpackets);
+}
+
 static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
 {
        struct dm1105dvb *dm1105dvb = dev_id;
-       unsigned int piece;
-       unsigned int nbpackets;
-       u32 command;
-       u32 nextwrp;
-       u32 oldwrp;
 
        /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
        unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS));
@@ -447,48 +485,17 @@ static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
        switch (intsts) {
        case INTSTS_TSIRQ:
        case (INTSTS_TSIRQ | INTSTS_IR):
-               nextwrp = inl(dm_io_mem(DM1105_WRP)) -
-                       inl(dm_io_mem(DM1105_STADR)) ;
-               oldwrp = dm1105dvb->wrp;
-               spin_lock(&dm1105dvb->lock);
-               if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
-                               (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
-                               (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
-                       dm1105dvb->PacketErrorCount++;
-                       /* bad packet found */
-                       if ((dm1105dvb->PacketErrorCount >= 2) &&
-                                       (dm1105dvb->dmarst == 0)) {
-                               outb(1, dm_io_mem(DM1105_RST));
-                               dm1105dvb->wrp = 0;
-                               dm1105dvb->PacketErrorCount = 0;
-                               dm1105dvb->dmarst = 0;
-                               spin_unlock(&dm1105dvb->lock);
-                               return IRQ_HANDLED;
-                       }
-               }
-               if (nextwrp < oldwrp) {
-                       piece = dm1105dvb->buffer_size - oldwrp;
-                       memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size, dm1105dvb->ts_buf, nextwrp);
-                       nbpackets = (piece + nextwrp)/188;
-               } else  {
-                       nbpackets = (nextwrp - oldwrp)/188;
-               }
-               dvb_dmx_swfilter_packets(&dm1105dvb->demux, &dm1105dvb->ts_buf[oldwrp], nbpackets);
-               dm1105dvb->wrp = nextwrp;
-               spin_unlock(&dm1105dvb->lock);
+               dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) -
+                                       inl(dm_io_mem(DM1105_STADR));
+               schedule_work(&dm1105dvb->work);
                break;
        case INTSTS_IR:
-               command = inl(dm_io_mem(DM1105_IRCODE));
-               if (ir_debug)
-                       printk("dm1105: received byte 0x%04x\n", command);
-
-               dm1105dvb->ir.ir_command = command;
+               dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE));
                tasklet_schedule(&dm1105dvb->ir.ir_tasklet);
                break;
        }
-       return IRQ_HANDLED;
-
 
+       return IRQ_HANDLED;
 }
 
 /* register with input layer */
@@ -710,7 +717,7 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
 
        dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);
        if (!dm1105dvb)
-               goto out;
+               return -ENOMEM;
 
        dm1105dvb->pdev = pdev;
        dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;
@@ -740,13 +747,9 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
        spin_lock_init(&dm1105dvb->lock);
        pci_set_drvdata(pdev, dm1105dvb);
 
-       ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, DRIVER_NAME, dm1105dvb);
-       if (ret < 0)
-               goto err_pci_iounmap;
-
        ret = dm1105dvb_hw_init(dm1105dvb);
        if (ret < 0)
-               goto err_free_irq;
+               goto err_pci_iounmap;
 
        /* i2c */
        i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb);
@@ -813,8 +816,15 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
 
        dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx);
        dm1105_ir_init(dm1105dvb);
-out:
-       return ret;
+
+       INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer);
+
+       ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED,
+                                               DRIVER_NAME, dm1105dvb);
+       if (ret < 0)
+               goto err_free_irq;
+
+       return 0;
 
 err_disconnect_frontend:
        dmx->disconnect_frontend(dmx);
@@ -843,7 +853,7 @@ err_pci_disable_device:
 err_kfree:
        pci_set_drvdata(pdev, NULL);
        kfree(dm1105dvb);
-       goto out;
+       return ret;
 }
 
 static void __devexit dm1105_remove(struct pci_dev *pdev)