summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor M. Liplianin <liplianin@netup.ru>2009-02-26 03:40:41 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-03-30 12:43:00 -0300
commitd1498ffc474b18574ed2d5e4d9a33fd21eaaf3cf (patch)
treedc232b20b7bb1c1cd86191fa8c6072b1ccd7920f
parentac40d9e09825c62b77e8b11b3ed201f390550351 (diff)
downloadblackbird-op-linux-d1498ffc474b18574ed2d5e4d9a33fd21eaaf3cf.tar.gz
blackbird-op-linux-d1498ffc474b18574ed2d5e4d9a33fd21eaaf3cf.zip
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 <liplianin@netup.ru> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/dvb/dm1105/dm1105.c110
1 files changed, 60 insertions, 50 deletions
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index f48f73aff195..d9f55beb4890 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)
OpenPOWER on IntegriCloud