/* interrupt handler */ static irqreturn_t interrupt_hw(int irq, void *dev_id) { struct saa7146_dev *dev = dev_id; u32 isr; u32 ack_isr; /* read out the interrupt status register */ ack_isr = isr = saa7146_read(dev, ISR); /* is this our interrupt? */ if ( 0 == isr ) { /* nope, some other device */ return IRQ_NONE; } if (dev->ext) { if (dev->ext->irq_mask & isr) { if (dev->ext->irq_func) dev->ext->irq_func(dev, &isr); isr &= ~dev->ext->irq_mask; } } if (0 != (isr & (MASK_27))) { DEB_INT(("irq: RPS0 (0x%08x).\n",isr)); if (dev->vv_data && dev->vv_callback) dev->vv_callback(dev,isr); isr &= ~MASK_27; } if (0 != (isr & (MASK_28))) { if (dev->vv_data && dev->vv_callback) dev->vv_callback(dev,isr); isr &= ~MASK_28; } if (0 != (isr & (MASK_16|MASK_17))) { SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); /* only wake up if we expect something */ if (0 != dev->i2c_op) { dev->i2c_op = 0; wake_up(&dev->i2c_wq); } else { u32 psr = saa7146_read(dev, PSR); u32 ssr = saa7146_read(dev, SSR); #ifdef CONFIG_DEBUG_PRINTK printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n", dev->name, isr, psr, ssr); #else ; #endif } isr &= ~(MASK_16|MASK_17); } if( 0 != isr ) { ERR(("warning: interrupt enabled, but not handled properly.(0x%08x)\n",isr)); ERR(("disabling interrupt source(s)!\n")); SAA7146_IER_DISABLE(dev,isr); } saa7146_write(dev, ISR, ack_isr); return IRQ_HANDLED; }
static irqreturn_t interrupt_hw(int irq, void *dev_id) { struct saa7146_dev *dev = dev_id; u32 isr; u32 ack_isr; ack_isr = isr = saa7146_read(dev, ISR); if ( 0 == isr ) { return IRQ_NONE; } if (dev->ext) { if (dev->ext->irq_mask & isr) { if (dev->ext->irq_func) dev->ext->irq_func(dev, &isr); isr &= ~dev->ext->irq_mask; } } if (0 != (isr & (MASK_27))) { DEB_INT("irq: RPS0 (0x%08x)\n", isr); if (dev->vv_data && dev->vv_callback) dev->vv_callback(dev,isr); isr &= ~MASK_27; } if (0 != (isr & (MASK_28))) { if (dev->vv_data && dev->vv_callback) dev->vv_callback(dev,isr); isr &= ~MASK_28; } if (0 != (isr & (MASK_16|MASK_17))) { SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); if (0 != dev->i2c_op) { dev->i2c_op = 0; wake_up(&dev->i2c_wq); } else { u32 psr = saa7146_read(dev, PSR); u32 ssr = saa7146_read(dev, SSR); pr_warn("%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n", dev->name, isr, psr, ssr); } isr &= ~(MASK_16|MASK_17); } if( 0 != isr ) { ERR("warning: interrupt enabled, but not handled properly.(0x%08x)\n", isr); ERR("disabling interrupt source(s)!\n"); SAA7146_IER_DISABLE(dev,isr); } saa7146_write(dev, ISR, ack_isr); return IRQ_HANDLED; }
static void vbi_stop(struct saa7146_fh *fh, struct file *file) { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; unsigned long flags; DEB_VBI("dev:%p, fh:%p\n", dev, fh); spin_lock_irqsave(&dev->slock,flags); /* disable rps1 */ saa7146_write(dev, MC1, MASK_29); /* disable rps1 irqs */ SAA7146_IER_DISABLE(dev, MASK_28); /* shut down dma 3 transfers */ saa7146_write(dev, MC1, MASK_20); if (vv->vbi_dmaq.curr) saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE); videobuf_queue_cancel(&fh->vbi_q); vv->vbi_streaming = NULL; del_timer(&vv->vbi_dmaq.timeout); del_timer(&vv->vbi_read_timeout); spin_unlock_irqrestore(&dev->slock, flags); }
static int stop_ts_capture(struct budget *budget) { dprintk(2, "budget: %p\n", budget); saa7146_write(budget->dev, MC1, MASK_20); // DMA3 off SAA7146_IER_DISABLE(budget->dev, MASK_10); return 0; }
static int video_end(struct saa7146_fh *fh, struct file *file) { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; struct saa7146_format *fmt = NULL; unsigned long flags; unsigned int resource; u32 dmas = 0; DEB_EE(("dev:%p, fh:%p\n",dev,fh)); if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { DEB_S(("not capturing.\n")); return 0; } if (vv->video_fh != fh) { DEB_S(("capturing, but in another open.\n")); return -EBUSY; } fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); /* we need to have a valid format set here */ BUG_ON(NULL == fmt); if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS; dmas = MASK_22 | MASK_21 | MASK_20; } else { resource = RESOURCE_DMA1_HPS; dmas = MASK_22; } spin_lock_irqsave(&dev->slock,flags); /* disable rps0 */ saa7146_write(dev, MC1, MASK_28); /* disable rps0 irqs */ SAA7146_IER_DISABLE(dev, MASK_27); /* shut down all used video dma transfers */ saa7146_write(dev, MC1, dmas); spin_unlock_irqrestore(&dev->slock, flags); vv->video_fh = NULL; vv->video_status = 0; saa7146_res_free(fh, resource); if (vv->ov_suspend != NULL) { saa7146_start_preview(vv->ov_suspend); vv->ov_suspend = NULL; } return 0; }
static int vbi_workaround(struct saa7146_dev *dev) { struct saa7146_vv *vv = dev->vv_data; u32 *cpu; dma_addr_t dma_addr; int count = 0; int i; DECLARE_WAITQUEUE(wait, current); DEB_VBI("dev:%p\n", dev); /* once again, a bug in the saa7146: the brs acquisition is buggy and especially the BXO-counter does not work as specified. there is this workaround, but please don't let me explain it. ;-) */ cpu = pci_alloc_consistent(dev->pci, 4096, &dma_addr); if (NULL == cpu) return -ENOMEM; /* setup some basic programming, just for the workaround */ saa7146_write(dev, BASE_EVEN3, dma_addr); saa7146_write(dev, BASE_ODD3, dma_addr+vbi_pixel_to_capture); saa7146_write(dev, PROT_ADDR3, dma_addr+4096); saa7146_write(dev, PITCH3, vbi_pixel_to_capture); saa7146_write(dev, BASE_PAGE3, 0x0); saa7146_write(dev, NUM_LINE_BYTE3, (2<<16)|((vbi_pixel_to_capture)<<0)); saa7146_write(dev, MC2, MASK_04|MASK_20); /* load brs-control register */ WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); /* BXO = 1h, BRS to outbound */ WRITE_RPS1(0xc000008c); /* wait for vbi_a or vbi_b*/ if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { DEB_D("...using port b\n"); WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B); WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B); /* WRITE_RPS1(CMD_PAUSE | MASK_09); */ } else { DEB_D("...using port a\n"); WRITE_RPS1(CMD_PAUSE | MASK_10); } /* upload brs */ WRITE_RPS1(CMD_UPLOAD | MASK_08); /* load brs-control register */ WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); /* BYO = 1, BXO = NQBIL (=1728 for PAL, for NTSC this is 858*2) - NumByte3 (=1440) = 288 */ WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19); /* wait for brs_done */ WRITE_RPS1(CMD_PAUSE | MASK_08); /* upload brs */ WRITE_RPS1(CMD_UPLOAD | MASK_08); /* load video-dma3 NumLines3 and NumBytes3 */ WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4)); /* dev->vbi_count*2 lines, 720 pixel (= 1440 Bytes) */ WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture)); /* load brs-control register */ WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); /* Set BRS right: note: this is an experimental value for BXO (=> PAL!) */ WRITE_RPS1((540 << 7) | (5 << 19)); // 5 == vbi_start /* wait for brs_done */ WRITE_RPS1(CMD_PAUSE | MASK_08); /* upload brs and video-dma3*/ WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04); /* load mc2 register: enable dma3 */ WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4)); WRITE_RPS1(MASK_20 | MASK_04); /* generate interrupt */ WRITE_RPS1(CMD_INTERRUPT); /* stop rps1 */ WRITE_RPS1(CMD_STOP); /* we have to do the workaround twice to be sure that everything is ok */ for(i = 0; i < 2; i++) { /* indicate to the irq handler that we do the workaround */ saa7146_write(dev, MC2, MASK_31|MASK_15); saa7146_write(dev, NUM_LINE_BYTE3, (1<<16)|(2<<0)); saa7146_write(dev, MC2, MASK_04|MASK_20); /* enable rps1 irqs */ SAA7146_IER_ENABLE(dev,MASK_28); /* prepare to wait to be woken up by the irq-handler */ add_wait_queue(&vv->vbi_wq, &wait); current->state = TASK_INTERRUPTIBLE; /* start rps1 to enable workaround */ saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); saa7146_write(dev, MC1, (MASK_13 | MASK_29)); schedule(); DEB_VBI("brs bug workaround %d/1\n", i); remove_wait_queue(&vv->vbi_wq, &wait); current->state = TASK_RUNNING; /* disable rps1 irqs */ SAA7146_IER_DISABLE(dev,MASK_28); /* stop video-dma3 */ saa7146_write(dev, MC1, MASK_20); if(signal_pending(current)) { DEB_VBI("aborted (rps:0x%08x)\n", saa7146_read(dev, RPS_ADDR1)); /* stop rps1 for sure */ saa7146_write(dev, MC1, MASK_29); pci_free_consistent(dev->pci, 4096, cpu, dma_addr); return -EINTR; } } pci_free_consistent(dev->pci, 4096, cpu, dma_addr); return 0; }
static int vbi_workaround(struct saa7146_dev *dev) { struct saa7146_vv *vv = dev->vv_data; u32 *cpu; dma_addr_t dma_addr; int count = 0; int i; DECLARE_WAITQUEUE(wait, current); DEB_VBI(("dev:%p\n",dev)); cpu = pci_alloc_consistent(dev->pci, 4096, &dma_addr); if (NULL == cpu) return -ENOMEM; saa7146_write(dev, BASE_EVEN3, dma_addr); saa7146_write(dev, BASE_ODD3, dma_addr+vbi_pixel_to_capture); saa7146_write(dev, PROT_ADDR3, dma_addr+4096); saa7146_write(dev, PITCH3, vbi_pixel_to_capture); saa7146_write(dev, BASE_PAGE3, 0x0); saa7146_write(dev, NUM_LINE_BYTE3, (2<<16)|((vbi_pixel_to_capture)<<0)); saa7146_write(dev, MC2, MASK_04|MASK_20); WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); WRITE_RPS1(0xc000008c); if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { DEB_D(("...using port b\n")); WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_E_FID_B); WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | CMD_O_FID_B); } else { DEB_D(("...using port a\n")); WRITE_RPS1(CMD_PAUSE | MASK_10); } WRITE_RPS1(CMD_UPLOAD | MASK_08); WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); WRITE_RPS1(((1728-(vbi_pixel_to_capture)) << 7) | MASK_19); WRITE_RPS1(CMD_PAUSE | MASK_08); WRITE_RPS1(CMD_UPLOAD | MASK_08); WRITE_RPS1(CMD_WR_REG | (1 << 8) | (NUM_LINE_BYTE3/4)); WRITE_RPS1((2 << 16) | (vbi_pixel_to_capture)); WRITE_RPS1(CMD_WR_REG | (1 << 8) | (BRS_CTRL/4)); WRITE_RPS1((540 << 7) | (5 << 19)); WRITE_RPS1(CMD_PAUSE | MASK_08); WRITE_RPS1(CMD_UPLOAD | MASK_08 | MASK_04); WRITE_RPS1(CMD_WR_REG | (1 << 8) | (MC1/4)); WRITE_RPS1(MASK_20 | MASK_04); WRITE_RPS1(CMD_INTERRUPT); WRITE_RPS1(CMD_STOP); for(i = 0; i < 2; i++) { saa7146_write(dev, MC2, MASK_31|MASK_15); saa7146_write(dev, NUM_LINE_BYTE3, (1<<16)|(2<<0)); saa7146_write(dev, MC2, MASK_04|MASK_20); SAA7146_IER_ENABLE(dev,MASK_28); add_wait_queue(&vv->vbi_wq, &wait); current->state = TASK_INTERRUPTIBLE; saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); saa7146_write(dev, MC1, (MASK_13 | MASK_29)); schedule(); DEB_VBI(("brs bug workaround %d/1.\n",i)); remove_wait_queue(&vv->vbi_wq, &wait); current->state = TASK_RUNNING; SAA7146_IER_DISABLE(dev,MASK_28); saa7146_write(dev, MC1, MASK_20); if(signal_pending(current)) { DEB_VBI(("aborted (rps:0x%08x).\n",saa7146_read(dev,RPS_ADDR1))); saa7146_write(dev, MC1, MASK_29); pci_free_consistent(dev->pci, 4096, cpu, dma_addr); return -EINTR; } } pci_free_consistent(dev->pci, 4096, cpu, dma_addr); return 0; }