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