swarm_saa7114h.c
来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 1,696 行 · 第 1/3 页
C
1,696 行
out64(M_DMA_L2CA, MAC2_DMARX0_CSR(R_MAC_DMA_CONFIG1)); out64(d->ff.descrtab_phys, MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_BASE)); /* Enable interrupts and DMA */ out64(M_MAC_INT_EOP_COUNT<<S_MAC_RX_CH0, MAC2_CSR(R_MAC_INT_MASK)); out64(M_MAC_RXDMA_EN0 | M_MAC_BYP_RX_ENABLE, MAC2_CSR(R_MAC_ENABLE)); return 0;}/* ----------------------------------------------------------------------- * v4linux helpers - color conversion, etc (taken from cpia.c) * ----------------------------------------------------------------------- */#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)static void yuvconvert_inplace(uint8_t *data, uint32_t in_uyvy, int out_fmt, int mmap){ int y, u, v, r, g, b, y1; uint8_t *src, *dst; if (out_fmt == VIDEO_PALETTE_RGB24) { src = (uint8_t *)((int)data + in_uyvy); dst = (uint8_t *)((int)data + in_uyvy + (in_uyvy >> 1)); DBG(DBG_CONVERT, printk(KERN_DEBUG "inplace: %p %p %p\n", data, src, dst)); while (src > data) { if ((int)(src-data) < 4) break; //printk("freaky %p %p\n", src, data); y1 = (*(--src) - 16) * 76310; v = *(--src) - 128; y = (*(--src) - 16) * 76310; u = *(--src) - 128; r = 104635 * v; g = -25690 * u + -53294 * v; b = 132278 * u; /* XXXKW what on earth is up with mmap? */ if (mmap) { *(--dst) = LIMIT(r+y1); *(--dst) = LIMIT(g+y1); *(--dst) = LIMIT(b+y1); *(--dst) = LIMIT(r+y); *(--dst) = LIMIT(g+y); *(--dst) = LIMIT(b+y); } else { *(--dst) = LIMIT(b+y1); *(--dst) = LIMIT(g+y1); *(--dst) = LIMIT(r+y1); *(--dst) = LIMIT(b+y); *(--dst) = LIMIT(g+y); *(--dst) = LIMIT(r+y); } } }}static int saa7114h_get_cparams(struct saa7114h *decoder){ /* XXX check for error code */ decoder->bright = saa7114h_reg_read(decoder, SAA_BRIGHTNESS); decoder->contrast = saa7114h_reg_read(decoder, SAA_CONTRAST); decoder->sat = saa7114h_reg_read(decoder, SAA_SATURATION); decoder->hue = saa7114h_reg_read(decoder, SAA_HUE); decoder->vp.brightness = (uint16_t)decoder->bright << 8; decoder->vp.contrast = (uint16_t)decoder->contrast << 9; decoder->vp.colour = decoder->sat << 9; decoder->vp.hue = ((int16_t)decoder->hue + 128) << 8; return 0;}static int saa7114h_set_cparams(struct saa7114h *decoder){ decoder->bright = decoder->vp.brightness >> 8; decoder->contrast = decoder->vp.contrast >> 9; decoder->sat = decoder->vp.colour >> 9; decoder->hue = (uint8_t)((int8_t)(decoder->vp.hue >> 8) - 128); return (saa7114h_reg_write(decoder, SAA_BRIGHTNESS, decoder->bright) || saa7114h_reg_write(decoder, SAA_CONTRAST, decoder->contrast) || saa7114h_reg_write(decoder, SAA_SATURATION, decoder->sat) || saa7114h_reg_write(decoder, SAA_HUE, decoder->hue));}/* ----------------------------------------------------------------------- * Custom IOCTL support * ----------------------------------------------------------------------- */unsigned char eav[625][2];static int grab_frame(struct saa7114h *d, void *user_buf, int print_eav){ int cur_idx = 0; int to_go = 625; int delta; int i, len, eav_val, sav_val; int started = 0; uint8_t *buf; fifo_descr_t *cur_d; int swptr = d->ff.next_descr - d->ff.descrtab; int hwptr; DBG(DBG_CALL, printk(IF_NAME ": grabbing frame\n")); /* Check for Macrovision -- if it's on, DMA won't happen */ if (saa7114h_reg_read(d, DECODER_STATUS) & 0x2) return -EACCES; out64(d->ff.ringsz, MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT)); do { hwptr = (unsigned) (((in64(MAC2_DMARX0_CSR(R_MAC_DMA_CUR_DSCRADDR)) & M_DMA_CURDSCR_ADDR) - d->ff.descrtab_phys) / sizeof(fifo_descr_t)); delta = (hwptr + d->ff.ringsz - swptr) % d->ff.ringsz; if (delta == 0) {#if 0 uint64_t val = in64(MAC2_DMARX0_CSR(R_MAC_STATUS)); printk("mac status: %08x%08x\n", (u32)(val >> 32), (u32)(val&0xffffffff));#endif } for (i=0; i<delta; i++) { cur_d = d->ff.next_descr; if (++d->ff.next_descr == d->ff.descrtab_end) d->ff.next_descr = d->ff.descrtab; if (!(cur_d->descr_a & M_DMA_ETHRX_SOP)) { printk("bogus RX\n"); continue; } cur_d->descr_a &= ~M_DMA_ETHRX_SOP; len = G_DMA_DSCRB_PKT_SIZE(cur_d->descr_b); buf = (uint8_t *)__va(cur_d->descr_a & M_DMA_DSCRA_A_ADDR); if (len != (d->vw.width*RAW_PER_PIXEL)+RAW_LINE_PAD) { printk("funny size %d\n", len); continue; } eav_val = buf[1]; sav_val = buf[5]; if (eav_val == 0xf1) { /* end of field 2, V-blank */ if (started) { started = 0; delta = to_go = 0; /* just let DMA finish in background */ } else { started = 1; } } if (started) { eav[cur_idx][0] = eav_val; eav[cur_idx++][1] = sav_val; if (copy_to_user(user_buf, &buf[6], 1440)) return -EFAULT; user_buf += 1440; } } swptr = hwptr; if (delta) { if (started) to_go -= delta; if (delta > to_go) delta = to_go; out64(delta, MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT)); } } while (to_go); if (print_eav) { for (i=0; i<cur_idx; i++) { printk("%3d: %02x | %02x\n", i, eav[i][0], eav[i][1]); } } return cur_idx;}/* ----------------------------------------------------------------------- * Interrupt handler * ----------------------------------------------------------------------- */unsigned long int_count = 0;static void saa7114h_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct saa7114h *d = dev_id; uint64_t status_val; fifo_descr_t *cur_d; int i, delta, len; uint8_t *buf, eav_val; int swptr = d->ff.next_descr - d->ff.descrtab; int hwptr; status_val = in64(MAC2_CSR(R_MAC_STATUS)); /* Process finished decsriptors */ hwptr = (unsigned) (((in64(MAC2_DMARX0_CSR(R_MAC_DMA_CUR_DSCRADDR)) & M_DMA_CURDSCR_ADDR) - d->ff.descrtab_phys) / sizeof(fifo_descr_t)); delta = (hwptr + d->ff.ringsz - swptr) % d->ff.ringsz; if (!delta) { if (status_val & M_MAC_INT_EOP_SEEN<<S_MAC_RX_CH0) { /* Must have wrapped since the last interrupt */ delta = d->ff.ringsz; } else { /* XXXKW why would this happen? */ return; } } for (i=0; i<delta; i++) { cur_d = d->ff.next_descr; if (++d->ff.next_descr == d->ff.descrtab_end) d->ff.next_descr = d->ff.descrtab; if (!(cur_d->descr_a & M_DMA_ETHRX_SOP)) { printk(KERN_DEBUG "bogus RX\n"); continue; } cur_d->descr_a &= ~M_DMA_ETHRX_SOP; if (!d->dma_enable) continue; len = G_DMA_DSCRB_PKT_SIZE(cur_d->descr_b); buf = (uint8_t *)__va(cur_d->descr_a & M_DMA_DSCRA_A_ADDR); if (len != (d->vw.width*RAW_PER_PIXEL)+RAW_LINE_PAD) { printk(KERN_DEBUG "funny size %d\n", len);// continue; } len -= RAW_LINE_PAD; eav_val = buf[1]; DBG(DBG_FRAMING_LOUD, printk(KERN_DEBUG "eav: %02x len: %d\n", eav_val, len)); if (eav_val == 0xf1) { /* end of field 2, V-blank: start-of-frame */ switch (d->frame[d->hwframe].state) { case FRAME_UNUSED: DBG(DBG_FRAMING, printk(KERN_ERR "capture to unused frame %d\n", d->hwframe)); break; case FRAME_READY: DBG(DBG_FRAMING, printk(KERN_DEBUG "frame started %d\n", d->hwframe)); /* start this frame (skip eav/sav) */ memcpy(d->frame[d->hwframe].pos, &buf[6], len);#if DMA_DEINTERLACE if (!d->interlaced) memcpy(d->frame[d->hwframe].pos-len, &buf[6], len); d->frame[d->hwframe].pos += len*2;#else d->frame[d->hwframe].pos += len;#endif d->frame[d->hwframe].state = FRAME_GRABBING; /* XXXKW check pos overflow */ break; case FRAME_GRABBING: /* kick over to new frame */ d->frame[d->hwframe].size = d->frame[d->hwframe].pos - d->frame[d->hwframe].data; d->frame[d->hwframe].state = FRAME_DONE; DBG(DBG_FRAMING, printk(KERN_DEBUG "frame finished %d\n", d->frame[d->hwframe].size)); /* wake up a waiting reader */ DBG(DBG_IO, printk(KERN_DEBUG "wakeup\n")); wake_up(&d->frame[d->hwframe].read_wait); d->hwframe = (d->hwframe + 1) % NUM_FRAME; if (d->frame[d->hwframe].state == FRAME_READY) { /* start this frame */ DBG(DBG_FRAMING, printk(KERN_DEBUG "frame bumped %d\n", d->hwframe)); memcpy(d->frame[d->hwframe].pos, &buf[6], len);#if DMA_DEINTERLACE if (!d->interlaced) memcpy(d->frame[d->hwframe].pos-len, &buf[6], len); d->frame[d->hwframe].pos += len*2;#else d->frame[d->hwframe].pos += len;#endif d->frame[d->hwframe].state = FRAME_GRABBING; } else { /* drop on the floor, note that we've stopped DMA'ing */ DBG(DBG_FRAMING, printk(KERN_DEBUG "frame capture halted\n")); d->dma_enable = 0; } break; case FRAME_DONE: /* drop on the floor (must be waiting for sw) */ DBG(DBG_FRAMING, printk(KERN_DEBUG "frame capture halted\n")); d->dma_enable = 0; break; } } else { switch (d->frame[d->hwframe].state) { case FRAME_UNUSED: DBG(DBG_FRAMING, printk(KERN_ERR "capture to unused frame %d\n", d->hwframe)); break; case FRAME_READY: /* drop on the floor (must have dropped something) */ DBG(DBG_FRAMING_LOUD, printk(KERN_DEBUG "missed SOF\n")); break; case FRAME_DONE: /* drop on the floor (must be waiting for sw) */ DBG(DBG_FRAMING, printk(KERN_DEBUG "frame overflow\n")); d->dma_enable = 0; break; case FRAME_GRABBING:#if DMA_DEINTERLACE if (eav_val == 0xb6) { d->frame[d->hwframe].pos = d->frame[d->hwframe].data; } memcpy(d->frame[d->hwframe].pos, &buf[6], len); if (!d->interlaced) memcpy(d->frame[d->hwframe].pos-len, &buf[6], len); d->frame[d->hwframe].pos += len*2;#else memcpy(d->frame[d->hwframe].pos, &buf[6], len); d->frame[d->hwframe].pos += len;#endif /* XXXKW check pos overflow */ break; } } } if (d->dma_enable) { out64(delta, MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT)); DBG(DBG_DESCR, printk(KERN_DEBUG IF_NAME ": interrupt adds %d -> %d descrs\n", delta, (int)in64(MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT)))); }}/* ----------------------------------------------------------------------- * /dev/video interface * ----------------------------------------------------------------------- */static int saa7114h_open(struct video_device *vd, int nb){ struct saa7114h *d = vd->priv; uint32_t status; if (!d || d->opened) return -EBUSY; d->opened = 1; DBG(DBG_CALL, printk(KERN_DEBUG IF_NAME ": open\n")); /* XXKW Should check this periodically!? */ status = saa7114h_reg_read(d, DECODER_STATUS); d->interlaced = ((status & 0x80) != 0);#if !NULL_DMA if (d->dma_enable) { printk(IF_NAME ": open found DMA on?!\n");#if LAZY_READ }#else } else { int descr; d->dma_enable = 1; DBG(DBG_DESCR, printk(IF_NAME ": open enabling DMA\n")); /* Force capture to start into frame buffer 0 */ descr = in64(MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT)); DBG(DBG_DESCR, printk(IF_NAME ": open adds %d -> %d descrs\n", d->ff.ringsz-desc, descr)); out64(d->ff.ringsz-descr, MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT)); }#endif#endif return 0;}static void saa7114h_release(struct video_device *vd){ struct saa7114h *d = vd->priv; DBG(DBG_CALL, printk(KERN_DEBUG IF_NAME ": release\n")); d->opened = 0; d->dma_enable = 0; /* XXXKW do a clean drain of outstanding DMAs? toss leftover buffer contents to avoid stale pictures? */ return;}static long saa7114h_read(struct video_device *vd, char *buf, unsigned long count, int noblock){ struct saa7114h *d = vd->priv; int descr, status; if (!d) return -ENODEV; /* XXKW Should check this periodically!? */ status = saa7114h_reg_read(d, DECODER_STATUS);// d->interlaced = ((status & 0x80) != 0); #if !NULL_DMA#if LAZY_READ if (!d->dma_enable) { DBG(DBG_DESCR, printk(KERN_DEBUG IF_NAME ": enabling DMA\n")); /* Give the buffer to the DMA engine (force ptr reset) */ d->swframe = d->hwframe; d->frame[d->swframe].state = FRAME_READY;#if DMA_DEINTERLACE d->frame[d->swframe].pos = d->frame[d->swframe].data+d->vw.width*RAW_PER_PIXEL;#else d->frame[d->swframe].pos = d->frame[d->swframe].data;#endif /* Fire up the DMA engine again if it stopped */ d->dma_enable = 1; descr = in64(MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT)); out64(d->ff.ringsz-descr, MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT)); }#endif#endif /* XXXKW mmap/read mixture could break the swframe sequence */ if (d->frame[d->swframe].state != FRAME_DONE) { if (noblock) return -EAGAIN; else { DBG(DBG_IO, printk(KERN_DEBUG IF_NAME ": sleeping for frame\n")); interruptible_sleep_on(&d->frame[d->swframe].read_wait); DBG(DBG_IO, printk(KERN_DEBUG IF_NAME ": awakened\n")); if (signal_pending(current)) return -ERESTARTSYS; } } if (count < d->frame[d->swframe].size) return -EFAULT; count = d->frame[d->swframe].size; yuvconvert_inplace(d->frame[d->swframe].data, d->frame[d->swframe].size, d->vp.palette, 0); copy_to_user(buf, d->frame[d->swframe].data, d->frame[d->swframe].size); d->swframe = (d->swframe + 1) % NUM_FRAME; /* XXXKW doesn't do format conversion!!! */#if !NULL_DMA#if !LAZY_READ /* XXXKW Fire up the DMA engine again if it stopped ??? */ if (!d->dma_enable) { DBG(DBG_DESCR, printk(KERN_DEBUG IF_NAME ": enabling DMA\n")); /* Fire up the DMA engine again if it stopped */ d->dma_enable = 1; descr = in64(MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT)); out64(d->ff.ringsz-descr, MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT)); }#endif#endif return count;}static int saa7114h_ioctl(struct video_device *vd, unsigned int cmd, void *arg){ struct saa7114h *d = vd->priv; int val, reg, retval = 0; if (!d) return -ENODEV; switch (cmd) { case VIDIOCGCHAN: { struct video_channel v; if (copy_from_user(&v, arg, sizeof(v))) { retval = -EFAULT; break; } if (v.channel != 0) { retval = -EINVAL; break; } v.channel = 0; strcpy(v.name, "Camera"); v.tuners = 0; v.flags = 0; v.type = VIDEO_TYPE_CAMERA; v.norm = 0; if (copy_to_user(arg, &v, sizeof(v))) retval = -EFAULT; break; } case VIDIOCSCHAN: { int v; if (copy_from_user(&v, arg, sizeof(v))) retval = -EFAULT; if (retval == 0 && v != 0) retval = -EINVAL; break; } case VIDIOCGCAP: { struct video_capability b; strcpy(b.name, "Philips SAA7114H Decoder"); b.type = VID_TYPE_CAPTURE /* | VID_TYPE_TELETEXT */ | VID_TYPE_SCALES; b.channels = 1; b.audios = 0; b.maxwidth = MAX_HORIZ; b.maxheight = MAX_VERT; /* XXXKW find real values */ b.minwidth = 48; b.minheight = 48; if (copy_to_user(arg, &b, sizeof(b))) retval = -EFAULT; break; } /* image properties */ case VIDIOCGPICT: if (copy_to_user(arg, &d->vp, sizeof(struct video_picture))) retval = -EFAULT; break; case VIDIOCSPICT: { struct video_picture vp; /* copy_from_user */ if (copy_from_user(&vp, arg, sizeof(vp))) { retval = -EFAULT; break; } down(&d->param_lock); /* brightness, colour, contrast need not check 0-65535 */ memcpy( &d->vp, &vp, sizeof(vp) ); /* update cam->params.colourParams */ saa7114h_set_cparams(d); up(&d->param_lock); break; } /* get/set capture window */ case VIDIOCGWIN: if (copy_to_user(arg, &d->vw, sizeof(struct video_window)))
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?