diff options
author | Igor M. Liplianin <liplianin@netup.ru> | 2009-02-26 01:40:41 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-30 11:43:00 -0400 |
commit | d1498ffc474b18574ed2d5e4d9a33fd21eaaf3cf (patch) | |
tree | dc232b20b7bb1c1cd86191fa8c6072b1ccd7920f /drivers/media/dvb/dm1105/dm1105.c | |
parent | ac40d9e09825c62b77e8b11b3ed201f390550351 (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/media/dvb/dm1105/dm1105.c')
-rw-r--r-- | drivers/media/dvb/dm1105/dm1105.c | 110 |
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 */ | ||
442 | static 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 | |||
434 | static irqreturn_t dm1105dvb_irq(int irq, void *dev_id) | 477 | static 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); |
816 | out: | 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 | ||
819 | err_disconnect_frontend: | 829 | err_disconnect_frontend: |
820 | dmx->disconnect_frontend(dmx); | 830 | dmx->disconnect_frontend(dmx); |
@@ -843,7 +853,7 @@ err_pci_disable_device: | |||
843 | err_kfree: | 853 | err_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 | ||
849 | static void __devexit dm1105_remove(struct pci_dev *pdev) | 859 | static void __devexit dm1105_remove(struct pci_dev *pdev) |