aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorIgor M. Liplianin <liplianin@netup.ru>2009-02-26 01:40:41 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-03-30 11:43:00 -0400
commitd1498ffc474b18574ed2d5e4d9a33fd21eaaf3cf (patch)
treedc232b20b7bb1c1cd86191fa8c6072b1ccd7920f /drivers
parentac40d9e09825c62b77e8b11b3ed201f390550351 (diff)
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>
Diffstat (limited to 'drivers')
-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 {
220 /* i2c */ 220 /* i2c */
221 struct i2c_adapter i2c_adap; 221 struct i2c_adapter i2c_adap;
222 222
223 /* irq */
224 struct work_struct work;
225
223 /* dma */ 226 /* dma */
224 dma_addr_t dma_addr; 227 dma_addr_t dma_addr;
225 unsigned char *ts_buf; 228 unsigned char *ts_buf;
226 u32 wrp; 229 u32 wrp;
230 u32 nextwrp;
227 u32 buffer_size; 231 u32 buffer_size;
228 unsigned int PacketErrorCount; 232 unsigned int PacketErrorCount;
229 unsigned int dmarst; 233 unsigned int dmarst;
@@ -415,6 +419,9 @@ static void dm1105_emit_key(unsigned long parm)
415 u8 data; 419 u8 data;
416 u16 keycode; 420 u16 keycode;
417 421
422 if (ir_debug)
423 printk(KERN_INFO "%s: received byte 0x%04x\n", __func__, ircom);
424
418 data = (ircom >> 8) & 0x7f; 425 data = (ircom >> 8) & 0x7f;
419 426
420 input_event(ir->input_dev, EV_MSC, MSC_RAW, (0x0000f8 << 16) | data); 427 input_event(ir->input_dev, EV_MSC, MSC_RAW, (0x0000f8 << 16) | data);
@@ -431,14 +438,45 @@ static void dm1105_emit_key(unsigned long parm)
431 438
432} 439}
433 440
441/* work handler */
442static void dm1105_dmx_buffer(struct work_struct *work)
443{
444 struct dm1105dvb *dm1105dvb =
445 container_of(work, struct dm1105dvb, work);
446 unsigned int nbpackets;
447 u32 oldwrp = dm1105dvb->wrp;
448 u32 nextwrp = dm1105dvb->nextwrp;
449
450 if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
451 (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
452 (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
453 dm1105dvb->PacketErrorCount++;
454 /* bad packet found */
455 if ((dm1105dvb->PacketErrorCount >= 2) &&
456 (dm1105dvb->dmarst == 0)) {
457 outb(1, dm_io_mem(DM1105_RST));
458 dm1105dvb->wrp = 0;
459 dm1105dvb->PacketErrorCount = 0;
460 dm1105dvb->dmarst = 0;
461 return;
462 }
463 }
464
465 if (nextwrp < oldwrp) {
466 memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size,
467 dm1105dvb->ts_buf, nextwrp);
468 nbpackets = ((dm1105dvb->buffer_size - oldwrp) + nextwrp) / 188;
469 } else
470 nbpackets = (nextwrp - oldwrp) / 188;
471
472 dm1105dvb->wrp = nextwrp;
473 dvb_dmx_swfilter_packets(&dm1105dvb->demux,
474 &dm1105dvb->ts_buf[oldwrp], nbpackets);
475}
476
434static irqreturn_t dm1105dvb_irq(int irq, void *dev_id) 477static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
435{ 478{
436 struct dm1105dvb *dm1105dvb = dev_id; 479 struct dm1105dvb *dm1105dvb = dev_id;
437 unsigned int piece;
438 unsigned int nbpackets;
439 u32 command;
440 u32 nextwrp;
441 u32 oldwrp;
442 480
443 /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */ 481 /* Read-Write INSTS Ack's Interrupt for DM1105 chip 16.03.2008 */
444 unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS)); 482 unsigned int intsts = inb(dm_io_mem(DM1105_INTSTS));
@@ -447,48 +485,17 @@ static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
447 switch (intsts) { 485 switch (intsts) {
448 case INTSTS_TSIRQ: 486 case INTSTS_TSIRQ:
449 case (INTSTS_TSIRQ | INTSTS_IR): 487 case (INTSTS_TSIRQ | INTSTS_IR):
450 nextwrp = inl(dm_io_mem(DM1105_WRP)) - 488 dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) -
451 inl(dm_io_mem(DM1105_STADR)) ; 489 inl(dm_io_mem(DM1105_STADR));
452 oldwrp = dm1105dvb->wrp; 490 schedule_work(&dm1105dvb->work);
453 spin_lock(&dm1105dvb->lock);
454 if (!((dm1105dvb->ts_buf[oldwrp] == 0x47) &&
455 (dm1105dvb->ts_buf[oldwrp + 188] == 0x47) &&
456 (dm1105dvb->ts_buf[oldwrp + 188 * 2] == 0x47))) {
457 dm1105dvb->PacketErrorCount++;
458 /* bad packet found */
459 if ((dm1105dvb->PacketErrorCount >= 2) &&
460 (dm1105dvb->dmarst == 0)) {
461 outb(1, dm_io_mem(DM1105_RST));
462 dm1105dvb->wrp = 0;
463 dm1105dvb->PacketErrorCount = 0;
464 dm1105dvb->dmarst = 0;
465 spin_unlock(&dm1105dvb->lock);
466 return IRQ_HANDLED;
467 }
468 }
469 if (nextwrp < oldwrp) {
470 piece = dm1105dvb->buffer_size - oldwrp;
471 memcpy(dm1105dvb->ts_buf + dm1105dvb->buffer_size, dm1105dvb->ts_buf, nextwrp);
472 nbpackets = (piece + nextwrp)/188;
473 } else {
474 nbpackets = (nextwrp - oldwrp)/188;
475 }
476 dvb_dmx_swfilter_packets(&dm1105dvb->demux, &dm1105dvb->ts_buf[oldwrp], nbpackets);
477 dm1105dvb->wrp = nextwrp;
478 spin_unlock(&dm1105dvb->lock);
479 break; 491 break;
480 case INTSTS_IR: 492 case INTSTS_IR:
481 command = inl(dm_io_mem(DM1105_IRCODE)); 493 dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE));
482 if (ir_debug)
483 printk("dm1105: received byte 0x%04x\n", command);
484
485 dm1105dvb->ir.ir_command = command;
486 tasklet_schedule(&dm1105dvb->ir.ir_tasklet); 494 tasklet_schedule(&dm1105dvb->ir.ir_tasklet);
487 break; 495 break;
488 } 496 }
489 return IRQ_HANDLED;
490
491 497
498 return IRQ_HANDLED;
492} 499}
493 500
494/* register with input layer */ 501/* register with input layer */
@@ -710,7 +717,7 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
710 717
711 dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL); 718 dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);
712 if (!dm1105dvb) 719 if (!dm1105dvb)
713 goto out; 720 return -ENOMEM;
714 721
715 dm1105dvb->pdev = pdev; 722 dm1105dvb->pdev = pdev;
716 dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES; 723 dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;
@@ -740,13 +747,9 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
740 spin_lock_init(&dm1105dvb->lock); 747 spin_lock_init(&dm1105dvb->lock);
741 pci_set_drvdata(pdev, dm1105dvb); 748 pci_set_drvdata(pdev, dm1105dvb);
742 749
743 ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED, DRIVER_NAME, dm1105dvb);
744 if (ret < 0)
745 goto err_pci_iounmap;
746
747 ret = dm1105dvb_hw_init(dm1105dvb); 750 ret = dm1105dvb_hw_init(dm1105dvb);
748 if (ret < 0) 751 if (ret < 0)
749 goto err_free_irq; 752 goto err_pci_iounmap;
750 753
751 /* i2c */ 754 /* i2c */
752 i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb); 755 i2c_set_adapdata(&dm1105dvb->i2c_adap, dm1105dvb);
@@ -813,8 +816,15 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
813 816
814 dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx); 817 dvb_net_init(dvb_adapter, &dm1105dvb->dvbnet, dmx);
815 dm1105_ir_init(dm1105dvb); 818 dm1105_ir_init(dm1105dvb);
816out: 819
817 return ret; 820 INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer);
821
822 ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED,
823 DRIVER_NAME, dm1105dvb);
824 if (ret < 0)
825 goto err_free_irq;
826
827 return 0;
818 828
819err_disconnect_frontend: 829err_disconnect_frontend:
820 dmx->disconnect_frontend(dmx); 830 dmx->disconnect_frontend(dmx);
@@ -843,7 +853,7 @@ err_pci_disable_device:
843err_kfree: 853err_kfree:
844 pci_set_drvdata(pdev, NULL); 854 pci_set_drvdata(pdev, NULL);
845 kfree(dm1105dvb); 855 kfree(dm1105dvb);
846 goto out; 856 return ret;
847} 857}
848 858
849static void __devexit dm1105_remove(struct pci_dev *pdev) 859static void __devexit dm1105_remove(struct pci_dev *pdev)