Skip to content

Commit

Permalink
V4L/DVB (10743): dm1105: not demuxing from interrupt context.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Igor M. Liplianin authored and Mauro Carvalho Chehab committed Mar 30, 2009
1 parent ac40d9e commit d1498ff
Showing 1 changed file with 60 additions and 50 deletions.
110 changes: 60 additions & 50 deletions drivers/media/dvb/dm1105/dm1105.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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));
Expand All @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -843,7 +853,7 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
err_kfree:
pci_set_drvdata(pdev, NULL);
kfree(dm1105dvb);
goto out;
return ret;
}

static void __devexit dm1105_remove(struct pci_dev *pdev)
Expand Down

0 comments on commit d1498ff

Please sign in to comment.