From d1498ffc474b18574ed2d5e4d9a33fd21eaaf3cf Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Thu, 26 Feb 2009 03:40:41 -0300 Subject: [PATCH] V4L/DVB (10743): dm1105: not demuxing from interrupt context. 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 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dm1105/dm1105.c | 110 ++++++++++++++++-------------- 1 file changed, 60 insertions(+), 50 deletions(-) diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index f48f73aff19..d9f55beb489 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -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) -- 2.41.1