dm1105: not demuxing from interrupt context

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I read in mailing list about design error in dm1105.So I am designer.DMA buffer in the driver itself organized like ringbufferand not difficult to bind it to tasklet or work queue.I choose work queue, because it is like trend :)The code tested by me on quite fast computer and it works as usual.I think, on slow computer difference must be noticeable.The patch is preliminary.Anyone can criticize.
diff -r 359d95e1d541 -r f22da8d6a83c linux/drivers/media/dvb/dm1105/dm1105.c--- a/linux/drivers/media/dvb/dm1105/dm1105.c   Wed Feb 18 09:49:37 2009 -0300+++ b/linux/drivers/media/dvb/dm1105/dm1105.c   Thu Feb 19 04:38:32 2009 +0200@@ -220,10 +220,14 @@        /* 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;@@ -418,6 +422,9 @@        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);@@ -434,6 +441,50 @@  } +/* work handler */+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)+static void dm1105_dmx_buffer(void *_dm1105dvb)+#else+static void dm1105_dmx_buffer(struct work_struct *work)+#endif+{+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)+       struct dm1105dvb *dm1105dvb = _dm1105dvb;+#else+       struct dm1105dvb *dm1105dvb =+                               container_of(work, struct dm1105dvb, work);+#endif+       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);+}+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) static irqreturn_t dm1105dvb_irq(int irq, void *dev_id, struct pt_regs *regs) #else@@ -441,11 +492,6 @@ #endif {        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));@@ -454,48 +500,17 @@        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;-- }  /* register with input layer */@@ -717,7 +732,7 @@         dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);        if (!dm1105dvb)-               goto out;+               return -ENOMEM;         dm1105dvb->pdev = pdev;        dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;@@ -747,13 +762,9 @@        spin_lock_init(&dm1105dvb->lock);        pci_set_drvdata(pdev, dm1105dvb); -       ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, DRIVER_NAME, dm1105dvb);+       ret = dm1105dvb_hw_init(dm1105dvb);        if (ret < 0)                goto err_pci_iounmap;--       ret = dm1105dvb_hw_init(dm1105dvb);-       if (ret < 0)-               goto err_free_irq;         /* i2c */        i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb);@@ -820,8 +831,19 @@         dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx);        dm1105_ir_init(dm1105dvb);-out:-       return ret;++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)+       INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer, dm1105dvb);+#else+       INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer);+#endif++       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);@@ -850,7 +872,7 @@ err_kfree:        pci_set_drvdata(pdev, NULL);        kfree(dm1105dvb);-       goto out;+       return ret; }  static void __devexit dm1105_remove(struct pci_dev *pdev)ÿôèº{.nÇ+?·?®?­?+%?Ëÿ±éݶ¥?wÿº{.nÇ+?·¥?{±þg??¯â?Ø^n?r¡ö¦zË?ëh?¨è­Ú&£ûàz¿äz¹Þ?ú+?Ê+zf£¢·h??§~?­?Ûiÿÿï?êÿ?êçz_è®æj:+v?¨þ)ߣøm


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux