+ int handled = 0;
+
+ if (status & (1<<18)) {
+ cx88_ir_irq(core);
+ handled++;
+ }
+ if (!handled)
+ cx88_print_irqbits(core->name, "irq pci",
+ cx88_pci_irqs, status,
+ core->pci_irqmask);
+ return handled;
+}
+
+void cx88_wakeup(struct cx88_core *core,
+ struct cx88_dmaqueue *q, u32 count)
+{
+ struct cx88_buffer *buf;
+ int bc;
+
+ for (bc = 0;; bc++) {
+ if (list_empty(&q->active))
+ break;
+ buf = list_entry(q->active.next,
+ struct cx88_buffer, vb.queue);
+ /* count comes from the hw and is is 16bit wide --
+ * this trick handles wrap-arounds correctly for
+ * up to 32767 buffers in flight... */
+ if ((s16) (count - buf->count) < 0)
+ break;
+ do_gettimeofday(&buf->vb.ts);
+ dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
+ count, buf->count);
+ buf->vb.state = STATE_DONE;
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+ }
+ if (list_empty(&q->active)) {
+ del_timer(&q->timeout);
+ } else {
+ mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ }
+ if (bc != 1)
+ printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
+}
+
+void cx88_shutdown(struct cx88_core *core)
+{
+ /* disable RISC controller + IRQs */
+ cx_write(MO_DEV_CNTRL2, 0);
+
+ /* stop dma transfers */
+ cx_write(MO_VID_DMACNTRL, 0x0);
+ cx_write(MO_AUD_DMACNTRL, 0x0);
+ cx_write(MO_TS_DMACNTRL, 0x0);
+ cx_write(MO_VIP_DMACNTRL, 0x0);
+ cx_write(MO_GPHST_DMACNTRL, 0x0);
+
+ /* stop interrupts */
+ cx_write(MO_PCI_INTMSK, 0x0);
+ cx_write(MO_VID_INTMSK, 0x0);
+ cx_write(MO_AUD_INTMSK, 0x0);
+ cx_write(MO_TS_INTMSK, 0x0);
+ cx_write(MO_VIP_INTMSK, 0x0);
+ cx_write(MO_GPHST_INTMSK, 0x0);
+
+ /* stop capturing */
+ cx_write(VID_CAPTURE_CONTROL, 0);
+}
+
+int cx88_reset(struct cx88_core *core)
+{
+ dprintk(1,"%s\n",__FUNCTION__);
+ cx88_shutdown(core);
+
+ /* clear irq status */
+ cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
+ cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
+ cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
+
+ /* wait a bit */
+ msleep(100);
+
+ /* init sram */
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], 720*4, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH22], 128, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH23], 128, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH24], 128, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0);
+
+ /* misc init ... */
+ cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable
+ (1 << 12) | // agc gain
+ (1 << 11) | // adaptibe agc
+ (0 << 10) | // chroma agc
+ (0 << 9) | // ckillen
+ (7)));
+
+ /* setup image format */
+ cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000);
+
+ /* setup FIFO Threshholds */
+ cx_write(MO_PDMA_STHRSH, 0x0807);
+ cx_write(MO_PDMA_DTHRSH, 0x0807);
+
+ /* fixes flashing of image */
+ cx_write(MO_AGC_SYNC_TIP1, 0x0380000F);
+ cx_write(MO_AGC_BACK_VBI, 0x00E00555);
+
+ cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int
+ cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int
+ cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int
+
+ /* Reset on-board parts */
+ cx_write(MO_SRST_IO, 0);
+ msleep(10);
+ cx_write(MO_SRST_IO, 1);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
+{
+ return (norm->id & V4L2_STD_625_50) ? 922 : 754;
+}
+
+static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
+{
+ return (norm->id & V4L2_STD_625_50) ? 186 : 135;
+}
+
+static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
+{
+ return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
+}
+
+static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
+{
+ static const unsigned int ntsc = 28636360;
+ static const unsigned int pal = 35468950;
+ static const unsigned int palm = 28604892;
+
+ if (norm->id & V4L2_STD_PAL_M)
+ return palm;
+
+ return (norm->id & V4L2_STD_625_50) ? pal : ntsc;
+}
+
+static unsigned int inline norm_notchfilter(struct cx88_tvnorm *norm)
+{
+ return (norm->id & V4L2_STD_625_50)
+ ? HLNotchFilter135PAL
+ : HLNotchFilter135NTSC;
+}
+
+static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
+{
+ /* Should always be Line Draw Time / (4*FSC) */
+
+ if (norm->id & V4L2_STD_PAL_M)
+ return 909;
+
+ return (norm->id & V4L2_STD_625_50) ? 1135 : 910;
+}
+
+static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
+{
+ return (norm->id & V4L2_STD_625_50) ? 511 : 400;
+}
+
+int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
+ enum v4l2_field field)
+{
+ unsigned int swidth = norm_swidth(core->tvnorm);
+ unsigned int sheight = norm_maxh(core->tvnorm);
+ u32 value;
+
+ dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
+ V4L2_FIELD_HAS_TOP(field) ? "T" : "",
+ V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
+ core->tvnorm->name);
+ if (!V4L2_FIELD_HAS_BOTH(field))
+ height *= 2;
+
+ // recalc H delay and scale registers
+ value = (width * norm_hdelay(core->tvnorm)) / swidth;
+ value &= 0x3fe;
+ cx_write(MO_HDELAY_EVEN, value);
+ cx_write(MO_HDELAY_ODD, value);
+ dprintk(1,"set_scale: hdelay 0x%04x\n", value);
+
+ value = (swidth * 4096 / width) - 4096;
+ cx_write(MO_HSCALE_EVEN, value);
+ cx_write(MO_HSCALE_ODD, value);
+ dprintk(1,"set_scale: hscale 0x%04x\n", value);
+
+ cx_write(MO_HACTIVE_EVEN, width);
+ cx_write(MO_HACTIVE_ODD, width);
+ dprintk(1,"set_scale: hactive 0x%04x\n", width);
+
+ // recalc V scale Register (delay is constant)
+ cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm));
+ cx_write(MO_VDELAY_ODD, norm_vdelay(core->tvnorm));
+ dprintk(1,"set_scale: vdelay 0x%04x\n", norm_vdelay(core->tvnorm));
+
+ value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;
+ cx_write(MO_VSCALE_EVEN, value);
+ cx_write(MO_VSCALE_ODD, value);
+ dprintk(1,"set_scale: vscale 0x%04x\n", value);
+
+ cx_write(MO_VACTIVE_EVEN, sheight);
+ cx_write(MO_VACTIVE_ODD, sheight);
+ dprintk(1,"set_scale: vactive 0x%04x\n", sheight);
+
+ // setup filters
+ value = 0;
+ value |= (1 << 19); // CFILT (default)
+ if (core->tvnorm->id & V4L2_STD_SECAM) {
+ value |= (1 << 15);
+ value |= (1 << 16);
+ }
+ if (INPUT(core->input)->type == CX88_VMUX_SVIDEO)
+ value |= (1 << 13) | (1 << 5);
+ if (V4L2_FIELD_INTERLACED == field)
+ value |= (1 << 3); // VINT (interlaced vertical scaling)
+ if (width < 385)
+ value |= (1 << 0); // 3-tap interpolation
+ if (width < 193)
+ value |= (1 << 1); // 5-tap interpolation
+ if (nocomb)
+ value |= (3 << 5); // disable comb filter
+
+ cx_write(MO_FILTER_EVEN, value);
+ cx_write(MO_FILTER_ODD, value);
+ dprintk(1,"set_scale: filter 0x%04x\n", value);