📄 cyberpro.c
字号:
/* 8-bit capture */ xstart *= 2; xend *= 2; } xstart -= 1; xend -= 1; ystart = 18 + dp->capt.y; yend = ystart + dp->capt.height / 2; cyberpro_grphw16(CAP_X_START, xstart, dp); cyberpro_grphw16(CAP_X_END, xend + 1, dp); cyberpro_grphw16(CAP_Y_START, ystart, dp); cyberpro_grphw16(CAP_Y_END, yend + 2, dp); /* * This should take account of capt.decimation */ cyberpro_grphw16(CAP_DDA_X_INIT, 0x0800, dp); cyberpro_grphw16(CAP_DDA_X_INC, 0x1000, dp); cyberpro_grphw16(CAP_DDA_Y_INIT, 0x0800, dp); cyberpro_grphw16(CAP_DDA_Y_INC, 0x1000, dp); cyberpro_grphw8(CAP_PITCH, dp->capt.width >> 2, dp);}static void cyberpro_set_interlace(struct cyberpro_vidinfo *dp){ /* * set interlace mode */ if (dp->interlace) { dp->vfac3 |= VFAC_CTL3_CAP_INTERLACE; dp->cap_miscctl &= ~CAP_CTL_MISC_ODDEVEN; dp->ovl->src.height = dp->capt.height; } else { dp->vfac3 &= ~VFAC_CTL3_CAP_INTERLACE; dp->cap_miscctl |= CAP_CTL_MISC_ODDEVEN; dp->ovl->src.height = dp->capt.height / 2; } cyberpro_grphw8(VFAC_CTL3, dp->vfac3, dp); cyberpro_grphw8(CAP_CTL_MISC, dp->cap_miscctl, dp); dp->ovl->set_src(dp, dp->ovl); if (dp->win_set) dp->ovl->set_win(dp, dp->ovl);}/* * Calculate and set the address of the capture buffer. Note we * also update the extended memory buffer for the overlay window. * * base: phys base address of display * width: pixel width of display * height: height of display * depth: depth of display (8/16/24) * bytesperline: number of bytes on a line * * We place the capture buffer 16K after the screen. */static intcyberpro_set_buffer(struct cyberpro_vidinfo *dp, struct video_buffer *b){ unsigned long screensize, maxbufsz; if (b->height <= 0 || b->width <= 0 || b->bytesperline <= 0) return -EINVAL; maxbufsz = dp->cap.maxwidth * dp->cap.maxheight * 2; screensize = b->height * b->bytesperline + 16384; if ((screensize + maxbufsz) >= dp->info.fb_size) return -EINVAL; dp->buf.base = b->base; dp->buf.width = b->width; dp->buf.height = b->height; dp->buf.depth = b->depth; dp->buf.bytesperline = b->bytesperline; dp->cap_mem_offset = screensize >> 2; cyberpro_grphw24(CAP_MEM_START, dp->cap_mem_offset, dp); /* * Setup the overlay source information. */ dp->ovl->src.offset = dp->cap_mem_offset; dp->ovl->set_src(dp, dp->ovl); return 0;}static void cyberpro_hw_init(struct cyberpro_vidinfo *dp){ unsigned char old; /* * Enable access to bus-master registers */ dp->info.enable_extregs(dp->info.info); dp->vfac1 = VFAC_CTL1_PHILIPS | VFAC_CTL1_FREEZE_CAPTURE | VFAC_CTL1_FREEZE_CAPTURE_SYNC; dp->vfac3 = VFAC_CTL3_CAP_IRQ; dp->cap_miscctl = CAP_CTL_MISC_DISPUSED | CAP_CTL_MISC_SYNCTZOR | CAP_CTL_MISC_SYNCTZHIGH; /* * Setup bus-master mode */ cyberpro_grphw8(BM_CTRL1, 0x88, dp); cyberpro_grphw8(PCI_BM_CTL, PCI_BM_CTL_ENABLE, dp); cyberpro_grphw8(BM_CTRL0, 0x44, dp); cyberpro_grphw8(BM_CTRL1, 0x84, dp); cyberpro_grphw24(CAP_MEM_START, 0, dp); cyberpro_grphw8(VFAC_CTL1, dp->vfac1, dp); cyberpro_grphw8(VFAC_CTL3, dp->vfac3, dp); cyberpro_grphw8(VFAC_CTL2, 0, dp); cyberpro_grphw8(REG_BANK, REG_BANK_Y, dp); cyberpro_grphw8(EXT_TV_CTL, 0x80, dp); cyberpro_grphw8(EXT_CAP_CTL1, 0x3f, dp); /* disable PIP */ cyberpro_grphw8(EXT_CAP_CTL2, 0xc0 | EXT_CAP_CTL2_ODDFRAMEIRQ, dp); /* * Configure capture mode to match the * external video processor format */ cyberpro_grphw8(EXT_CAP_MODE1, dp->cap_mode1, dp); cyberpro_grphw8(EXT_CAP_MODE2, dp->cap_mode2, dp); /* setup overlay */ cyberpro_grphw16(EXT_FIFO_CTL, 0x1010, dp);// cyberpro_grphw16(EXT_FIFO_CTL, 0x1b0f, dp); /* * Always reset the capture parameters on each open. */ dp->capt.x = 0; dp->capt.y = 0; dp->capt.width = dp->cap.maxwidth; dp->capt.height = dp->cap.maxheight; dp->capt.decimation = 0; dp->capt.flags = 0; cyberpro_capture_set_win(dp); /* * Enable VAFC */ old = cyberpro_grphr8(EXT_LATCH1, dp); cyberpro_grphw8(EXT_LATCH1, old | EXT_LATCH1_VAFC_EN, dp); /* * Enable capture (we hope that VSYNC=1) */ dp->vfac1 |= VFAC_CTL1_CAPTURE; cyberpro_grphw8(VFAC_CTL1, dp->vfac1, dp); /* * The overlay source format is always the * same as the capture stream format. */ dp->ovl->src.width = dp->capt.width; dp->ovl->src.height = dp->capt.height; dp->ovl->src.format = dp->stream_fmt; /* * Initialise the overlay windows */ dp->ext.init(dp, &dp->ext); dp->v2.init(dp, &dp->v2); dp->x2.init(dp, &dp->x2);}static void cyberpro_deinit(struct cyberpro_vidinfo *dp){ unsigned char old; /* * Stop any bus-master activity */ cyberpro_writew(0, BM_CONTROL, dp); /* * Shut down overlay */ if (dp->ovl_active) dp->ovl->ctl(dp, dp->ovl, 0); dp->ovl_active = 0; /* * Shut down capture */ if (dp->cap_active) cyberpro_capture(dp, 0); dp->cap_active = 0; /* * Disable all capture */ cyberpro_grphw8(VFAC_CTL1, 0, dp); /* * Disable VAFC */ old = cyberpro_grphr8(EXT_LATCH1, dp); cyberpro_grphw8(EXT_LATCH1, old & ~EXT_LATCH1_VAFC_EN, dp); /* * Disable interrupt (this allows it to float) */ dp->vfac3 &= ~VFAC_CTL3_CAP_IRQ; cyberpro_grphw8(VFAC_CTL3, dp->vfac3, dp); /* * Switch off bus-master mode */ cyberpro_grphw8(PCI_BM_CTL, 0, dp); /* * Disable access to bus-master registers */ dp->info.disable_extregs(dp->info.info);}static int cyberpro_grabber_open(struct video_device *dev, int flags){ struct cyberpro_vidinfo *dp = dev->priv; int ret, one = 1; MOD_INC_USE_COUNT; ret = -EBUSY; if (flags || dp->users) goto out; dp->users += 1; if (dp->users == 1) { ret = request_irq(dp->irq, cyberpro_interrupt, SA_SHIRQ, dp->info.dev_name, dp); if (ret) { dp->users -= 1; goto out; } /* * Initialise the VGA chip */ cyberpro_hw_init(dp); /* * Enable the IRQ. This allows the IRQ to work as expected * even if the IRQ line is missing the pull-up resistor. */ enable_irq(dp->irq); i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &one); } ret = 0;out: if (ret) MOD_DEC_USE_COUNT; return ret;}static void cyberpro_grabber_close(struct video_device *dev){ struct cyberpro_vidinfo *dp = dev->priv; if (dp->users == 1) { int zero = 0; /* * Disable the IRQ. This prevents problems with missing * pull-up resistors on the PCI interrupt line. */ disable_irq(dp->irq); cyberpro_frames_free(dp); /* * Turn off the SAA7111 decoder */ i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER, DECODER_ENABLE_OUTPUT, &zero); /* * Disable grabber */ cyberpro_deinit(dp); free_irq(dp->irq, dp); } dp->users -= 1; MOD_DEC_USE_COUNT;}/* * Our general plan here is: * 1. Set the CyberPro to perform a BM-DMA of one frame to this memory * 2. Copy the frame to the userspace * * However, BM-DMA seems to be unreliable at the moment, especially on * rev. 4 NetWinders. */static longcyberpro_grabber_read(struct video_device *dev, char *buf, unsigned long count, int noblock){ struct cyberpro_vidinfo *dp = dev->priv; int ret = -EINVAL;#ifdef USE_MMIO unsigned long maxbufsz = dp->capt.width * dp->capt.height * 2; char *disp = dp->info.fb + (dp->cap_mem_offset << 2); /* * If the buffer is mmap()'d, we shouldn't be using read() */ if (dp->mmaped) return -EINVAL; if (count > maxbufsz) count = maxbufsz; if (dp->cap_active) cyberpro_capture(dp, 0); else cyberpro_capture_one(dp); ret = (int)count; if (copy_to_user(buf, disp, count)) ret = -EFAULT; /* * unfreeze capture */ if (dp->cap_active) cyberpro_capture(dp, 1);#endif return ret;}/* * We don't support writing to the grabber * (In theory, we could allow writing to a separate region of VGA memory, * and display this using the second overlay window. This would allow us * to do video conferencing for example). */static longcyberpro_grabber_write(struct video_device *dev, const char *buf, unsigned long count, int noblock){ return -EINVAL;}static intcyberpro_grabber_ioctl(struct video_device *dev, unsigned int cmd, void *arg){ struct cyberpro_vidinfo *dp = dev->priv; switch (cmd) { case VIDIOCGCAP: return copy_to_user(arg, &dp->cap, sizeof(dp->cap)) ? -EFAULT : 0; case VIDIOCGCHAN: { struct video_channel chan; chan.channel = 0; strcpy(chan.name, "Composite"); chan.tuners = 0; chan.flags = 0; chan.type = VIDEO_TYPE_CAMERA; chan.norm = dp->norm; return copy_to_user(arg, &chan, sizeof(chan)) ? -EFAULT : 0; } case VIDIOCGPICT: return copy_to_user(arg, &dp->pic, sizeof(dp->pic)) ? -EINVAL : 0; case VIDIOCGWIN: { struct video_window win; win.x = dp->ovl->dst.x; win.y = dp->ovl->dst.y; win.width = dp->ovl->dst.width; win.height = dp->ovl->dst.height; win.chromakey = dp->ovl->dst.chromakey; win.flags = VIDEO_WINDOW_CHROMAKEY | (dp->interlace ? VIDEO_WINDOW_INTERLACE : 0); win.clips = NULL; win.clipcount = 0; return copy_to_user(arg, &win, sizeof(win)) ? -EINVAL : 0; } case VIDIOCGFBUF: return copy_to_user(arg, &dp->buf, sizeof(dp->buf)) ? -EINVAL : 0; case VIDIOCGUNIT: { struct video_unit unit; unit.video = dev->minor; unit.vbi = VIDEO_NO_UNIT; unit.radio = VIDEO_NO_UNIT; unit.audio = VIDEO_NO_UNIT; unit.teletext = VIDEO_NO_UNIT; return copy_to_user(arg, &unit, sizeof(unit)) ? -EINVAL : 0; } case VIDIOCGCAPTURE: return copy_to_user(arg, &dp->capt, sizeof(dp->capt)) ? -EFAULT : 0; case VIDIOCSCHAN: { struct video_decoder_capability vdc; struct video_channel v; int ok; if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; if (v.channel != 0) return -EINVAL; i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &vdc); switch (v.norm) { case VIDEO_MODE_PAL: ok = vdc.flags & VIDEO_DECODER_PAL; break; case VIDEO_MODE_NTSC: ok = vdc.flags & VIDEO_DECODER_NTSC; break; case VIDEO_MODE_AUTO: ok = vdc.flags & VIDEO_DECODER_AUTO; break; default: ok = 0; } if (!ok) return -EINVAL; dp->norm = v.norm; i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &v.norm); return 0; } case VIDIOCSPICT: { struct video_picture p; if (copy_from_user(&p, arg, sizeof(p))) return -EFAULT; if (p.palette != dp->stream_fmt || p.depth != 8) return -EINVAL; dp->pic = p; /* p.depth sets the capture depth */ /* p.palette sets the capture palette */ i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p); return 0; } case VIDIOCSWIN: /* set the size & position of the overlay window */ { struct video_window w; int diff; if (!dp->buf_set) return -EINVAL; if (copy_from_user(&w, arg, sizeof(w))) return -EFAULT; if (w.clipcount) return -EINVAL; /* * Bound the overlay window by the size of the screen */ if (w.x < 0) w.x = 0; if (w.y < 0) w.y = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -