📄 cyberpro.c
字号:
if (w.x > dp->buf.width) w.x = dp->buf.width; if (w.y > dp->buf.height) w.y = dp->buf.height; if (w.width < dp->capt.width) w.width = dp->capt.width; if (w.height < dp->capt.height) w.height = dp->capt.height; if (w.x + w.width > dp->buf.width) w.width = dp->buf.width - w.x; if (w.y + w.height > dp->buf.height) w.height = dp->buf.height - w.y; /* * We've tried to make the values fit, but * they just won't. */ if (w.width < dp->capt.width || w.height < dp->capt.height) return -EINVAL; diff = dp->ovl->dst.x != w.x || dp->ovl->dst.y != w.y || dp->ovl->dst.width != w.width || dp->ovl->dst.height != w.height || dp->ovl->dst.chromakey != w.chromakey || dp->ovl->dst.flags != w.flags; if (!dp->win_set || diff) { dp->ovl->dst.x = w.x; dp->ovl->dst.y = w.y; dp->ovl->dst.width = w.width; dp->ovl->dst.height = w.height; dp->ovl->dst.chromakey = w.chromakey; dp->ovl->dst.flags = w.flags; if (dp->ovl_active) dp->ovl->ctl(dp, dp->ovl, 0); dp->ovl->set_win(dp, dp->ovl); if (dp->ovl_active) dp->ovl->ctl(dp, dp->ovl, 1); diff = w.flags & VIDEO_WINDOW_INTERLACE ? 1 : 0; if (!dp->win_set || dp->interlace != diff) { dp->interlace = diff; cyberpro_set_interlace(dp); } } dp->win_set = 1; return 0; } case VIDIOCSFBUF: /* set frame buffer info */ { struct video_buffer b; int ret; if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EPERM; if (dp->cap_active) return -EINVAL; if (copy_from_user(&b, arg, sizeof(b))) return -EFAULT; ret = cyberpro_set_buffer(dp, &b); if (ret == 0) { dp->buf_set = 1; dp->win_set = 0; } return ret; } case VIDIOCCAPTURE: { int on; if (get_user(on, (int *)arg)) return -EFAULT; if (( on && dp->ovl_active) || (!on && !dp->ovl_active)) return 0; if (on && (!dp->buf_set || !dp->win_set)) return -EINVAL; cyberpro_capture(dp, on); dp->cap_active = on; dp->ovl->ctl(dp, dp->ovl, on); dp->ovl_active = on; return 0; }#ifdef USE_MMAP case VIDIOCSYNC: { DECLARE_WAITQUEUE(wait, current); int buf; /* * The buffer must have been mmaped * for this call to work. */ if (!dp->mmaped) return -EINVAL; if (get_user(buf, (int *)arg)) return -EFAULT; if (buf < 0 || buf >= NR_FRAMES) return -EINVAL; switch (dp->frame[buf].status) { case FRAME_FREE: return -EINVAL; case FRAME_WAITING: case FRAME_GRABBING: add_wait_queue(&dp->frame_wait, &wait); while (1) { set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) break; if (dp->frame[buf].status == FRAME_DONE) break; schedule(); } set_current_state(TASK_RUNNING); remove_wait_queue(&dp->frame_wait, &wait); if (signal_pending(current)) return -EINTR; /*FALLTHROUGH*/ case FRAME_DONE: dp->frame[buf].status = FRAME_FREE; break; } return 0; } case VIDIOCMCAPTURE: { struct video_mmap vmap; /* * The buffer must have been mmaped * for this call to work. */ if (!dp->mmaped) return -EINVAL; if (copy_from_user(&vmap, arg, sizeof(vmap))) return -EFAULT; /* * We can only capture in our source format/size. */ if (vmap.frame >= NR_FRAMES || vmap.format != dp->stream_fmt || vmap.width != dp->capt.width || vmap.height != dp->capt.height) return -EINVAL; if (dp->frame[vmap.frame].status == FRAME_WAITING || dp->frame[vmap.frame].status == FRAME_GRABBING) return -EBUSY; dp->frame[vmap.frame].status = FRAME_WAITING; return 0; } case VIDIOCGMBUF: { struct video_mbuf vmb; unsigned int i; vmb.frames = NR_FRAMES; vmb.size = dp->frame_size * NR_FRAMES; for (i = 0; i < NR_FRAMES; i++) vmb.offsets[i] = dp->frame[i].offset; return copy_to_user(arg, &vmb, sizeof(vmb)) ? -EFAULT : 0; }#endif case VIDIOCSCAPTURE: { struct video_capture capt;#ifndef ALLOW_SCAPTURE_WHILE_CAP if (dp->cap_active) return -EINVAL;#endif if (copy_from_user(&capt, arg, sizeof(capt))) return -EFAULT; if (capt.x < 0 || capt.width < 0 || capt.y < 0 || capt.height < 0 || capt.x + capt.width > dp->cap.maxwidth || capt.y + capt.height > dp->cap.maxheight) return -EINVAL; /* * The capture width must be a multiple of 4 */ if (dp->capt.width & 3) return -EINVAL; dp->capt.x = capt.x; dp->capt.y = capt.y; dp->capt.width = capt.width; dp->capt.height = capt.height;#ifdef ALLOW_SCAPTURE_WHILE_CAP if (dp->ovl_active) dp->ovl->ctl(dp, dp->ovl, 0); if (dp->cap_active) cyberpro_capture(dp, 0);#endif cyberpro_capture_set_win(dp); /* * Update the overlay window information */ dp->ovl->src.width = capt.width; dp->ovl->src.height = capt.height; dp->ovl->set_src(dp, dp->ovl); if (dp->win_set) dp->ovl->set_win(dp, dp->ovl);#ifdef ALLOW_SCAPTURE_WHILE_CAP if (dp->cap_active) cyberpro_capture(dp, 1); if (dp->ovl_active) dp->ovl->ctl(dp, dp->ovl, 1);#endif return 0; } case VIDIOCGTUNER: /* no tuner */ case VIDIOCSTUNER: return -EINVAL; } return -EINVAL;}#ifdef USE_MMAPstatic intcyberpro_grabber_mmap(struct video_device *dev, const char *addr, unsigned long size){ struct cyberpro_vidinfo *dp = dev->priv; unsigned long vaddr = (unsigned long)addr; pgprot_t prot; int frame_idx, ret = -EINVAL;#if defined(__arm__) prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_USER | L_PTE_WRITE | L_PTE_DIRTY);#elif defined(__i386__) prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED); if (boot_cpu_data.x86 > 3) pgprot_val(prot) |= _PAGE_PCD;#else#error "Unsupported architecture"#endif /* * The mmap() request must have the correct size. */ if (size != NR_FRAMES * dp->frame_size) goto out; /* * If it's already mapped, don't re-do */ if (dp->mmaped) goto out; dp->mmaped = 1; /* * Map in each frame */ for (frame_idx = 0; frame_idx < NR_FRAMES; frame_idx++) { struct framebuf *frame; int pgidx; frame = dp->frame + frame_idx; ret = cyberpro_alloc_frame_buffer(dp, frame); /* * If an error occurs, we can be lazy and leave what we've * been able to do. Our release function will free any * allocated buffers, and do_mmap_pgoff() will zap any * inserted mappings. */ if (ret) goto out2; /* * Map in each page on a page by page basis. This is just * a little on the inefficient side, but it's only run once. */ for (pgidx = 0; pgidx < NR_PAGES; pgidx++) { unsigned long virt; virt = page_address(frame->pages[pgidx]); ret = remap_page_range(vaddr, virt_to_phys((void *)virt), PAGE_SIZE, prot); if (ret) goto out2; vaddr += PAGE_SIZE; } } out2: if (ret) dp->mmaped = 0; out: return ret;}#endifstatic int __init cyberpro_grabber_init_done(struct video_device *dev){ struct cyberpro_vidinfo *dp; struct cyberpro_info *info = dev->priv; int ret; dp = kmalloc(sizeof(*dp), GFP_KERNEL); if (!dp) return -ENOMEM; memset(dp, 0, sizeof(*dp)); dev->priv = dp; dp->info = *info; dp->dev = dev; dp->bus = &cyberpro_i2c_bus; dp->regs = info->regs; dp->irq = info->dev->irq; strcpy(dp->cap.name, dev->name); dp->cap.type = dev->type; dp->cap.channels = 1; dp->cap.audios = 0; dp->cap.minwidth = 32; dp->cap.maxwidth = 716; dp->cap.minheight = 32; dp->cap.maxheight = 576; dp->pic.brightness = 32768; dp->pic.hue = 32768; dp->pic.colour = 32768; dp->pic.contrast = 32768; dp->pic.whiteness = 0; dp->pic.depth = 8; dp->pic.palette = VIDEO_PALETTE_YUV422; /* dp->buf is setup by the user */ /* dp->cap_mem_offset setup by dp->buf */ dp->norm = VIDEO_MODE_AUTO; /* * The extended overlay window */ dp->ext.init = cyberpro_ext_init; dp->ext.set_src = cyberpro_ext_set_src; dp->ext.set_win = cyberpro_ext_set_win; dp->ext.ctl = cyberpro_ext_ctl; /* * The V2 overlay window */ dp->v2.init = cyberpro_v2_init; dp->v2.set_src = cyberpro_v2_set_src; dp->v2.set_win = cyberpro_v2_set_win; dp->v2.ctl = cyberpro_v2_ctl; /* * The X2 overlay window */ dp->x2.init = cyberpro_x2_init; dp->x2.set_src = cyberpro_x2_set_src; dp->x2.set_win = cyberpro_x2_set_win; dp->x2.ctl = cyberpro_x2_ctl; /* * Set the overlay window which we shall be using */ dp->ovl = &dp->ext; dp->cap_mode1 = EXT_CAP_MODE1_ALTFIFO; /* * Initialise hardware specific values. * - CCIR656 8bit mode (YUV422 data) * - Ignore Hgood signal * - Invert Odd/Even field signal */ dp->cap_mode1 |= EXT_CAP_MODE1_CCIR656 | EXT_CAP_MODE1_8BIT; dp->cap_mode2 = EXT_CAP_MODE2_FIXSONY | EXT_CAP_MODE2_DATEND | EXT_CAP_MODE2_CCIRINVOE; dp->stream_fmt = VIDEO_PALETTE_YUV422; init_waitqueue_head(&dp->vbl_wait); cyberpro_frames_init(dp); /* * wake up the decoder */ decoder_sleep(0); dp->bus->data = dp; strncpy(dp->bus->name, dev->name, sizeof(dp->bus->name)); pci_set_master(dp->info.dev); ret = i2c_register_bus(dp->bus); /* * If we successfully registered the bus, but didn't initialise * the decoder (because its driver is not present), request * that it is loaded. */ if (ret == 0 && !dp->decoder) request_module("saa7111"); /* * If that didn't work, then we're out of luck. */ if (ret == 0 && !dp->decoder) { i2c_unregister_bus(dp->bus); ret = -ENXIO; } if (ret) { kfree(dp); /* * put the decoder back to sleep */ decoder_sleep(1); } return ret;}static struct video_device cyberpro_grabber = { name: "", type: VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CHROMAKEY | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, hardware: 0, open: cyberpro_grabber_open, close: cyberpro_grabber_close, read: cyberpro_grabber_read, write: cyberpro_grabber_write, ioctl: cyberpro_grabber_ioctl,#ifdef USE_MMAP mmap: cyberpro_grabber_mmap,#endif initialize: cyberpro_grabber_init_done,};int init_cyber2000fb_viddev(void){ struct cyberpro_info info; if (!cyber2000fb_attach(&info, 0)) return -ENXIO; strncpy(cyberpro_grabber.name, info.dev_name, sizeof(cyberpro_grabber.name)); cyberpro_grabber.priv = &info; return video_register_device(&cyberpro_grabber, VFL_TYPE_GRABBER, -1);}/* * This can be cleaned up when the SAA7111 code is fixed. */#ifdef MODULEstatic int __init cyberpro_init(void){ disable_irq(35); return init_cyber2000fb_viddev();}static void __exit cyberpro_exit(void){ video_unregister_device(&cyberpro_grabber); kfree(cyberpro_grabber.priv); i2c_unregister_bus(&cyberpro_i2c_bus); /* * put the decoder back to sleep */ decoder_sleep(1); cyber2000fb_detach(0);}module_init(cyberpro_init);module_exit(cyberpro_exit);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -