📄 planb.c
字号:
/* Reset clip mask */ memset ((void *) pb->mask, 0xff, (pb->maxlines * ((PLANB_MAXPIXELS + 7) & ~7)) / 8); /* Add any clip rects */ for (i = 0; i < vw.clipcount; i++) { if (copy_from_user(&clip, vw.clips + i, sizeof(struct video_clip))) return -EFAULT; add_clip(pb, &clip); } /* restart overlay if it was running */ resume_overlay(pb); planb_unlock(pb); return 0; } case VIDIOCGWIN: { struct video_window vw; DBG("PlanB: IOCTL VIDIOCGWIN\n"); vw.x=pb->win.x; vw.y=pb->win.y; vw.width=pb->win.width; vw.height=pb->win.height; vw.chromakey=0; vw.flags=0; if(pb->win.interlace) vw.flags|=VIDEO_WINDOW_INTERLACE; if(copy_to_user(arg,&vw,sizeof(vw))) return -EFAULT; return 0; } case VIDIOCSYNC: { int i; gbuf_ptr gbuf; DBG("PlanB: IOCTL VIDIOCSYNC\n"); if(copy_from_user((void *)&i,arg,sizeof(int))) return -EFAULT; DBG("PlanB: sync to frame %d\n", i); if(i > (MAX_GBUFFERS - 1) || i < 0) return -EINVAL; gbuf = &pb->gbuf[i];chk_grab: switch (*gbuf->status) { case GBUFFER_UNUSED: return -EINVAL; case GBUFFER_GRABBING: DBG("PlanB: waiting for grab" " done (%d)\n", i); interruptible_sleep_on(&pb->capq); if(signal_pending(current)) return -EINTR; goto chk_grab; case GBUFFER_DONE: *gbuf->status = GBUFFER_UNUSED; break; } return 0; } case VIDIOCMCAPTURE: { struct video_mmap vm; int fr; DBG("PlanB: IOCTL VIDIOCMCAPTURE\n"); if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm))) return -EFAULT; fr = vm.frame; if(fr > (MAX_GBUFFERS - 1) || fr < 0) return -EINVAL; if (*pb->gbuf[fr].status != GBUFFER_UNUSED) return -EBUSY; return vgrab(pb, &vm); } case VIDIOCGMBUF: { int i; struct video_mbuf vm; DBG("PlanB: IOCTL VIDIOCGMBUF\n"); memset(&vm, 0 , sizeof(vm)); vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS; vm.frames = MAX_GBUFFERS; for(i = 0; i<MAX_GBUFFERS; i++) vm.offsets[i] = PLANB_MAX_FBUF * i; if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) return -EFAULT; return 0; } case VIDIOCGUNIT: { struct video_unit vu; DBG("PlanB: IOCTL VIDIOCGUNIT\n"); vu.video=pb->video_dev.minor; vu.vbi=pb->vbi_dev.minor; vu.radio=VIDEO_NO_UNIT; vu.audio=VIDEO_NO_UNIT; vu.teletext=VIDEO_NO_UNIT; if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) return -EFAULT; return 0; } case PLANBIOCGSAAREGS: { struct planb_saa_regs preg; DBG("PlanB: IOCTL PLANBIOCGSAAREGS\n"); if(copy_from_user(&preg, arg, sizeof(preg))) return -EFAULT; if(preg.addr >= SAA7196_NUMREGS) return -EINVAL; preg.val = saa_regs[pb->win.norm][preg.addr]; if(copy_to_user((void *)arg, (void *)&preg, sizeof(preg))) return -EFAULT; return 0; } case PLANBIOCSSAAREGS: { struct planb_saa_regs preg; DBG("PlanB: IOCTL PLANBIOCSSAAREGS\n"); if(copy_from_user(&preg, arg, sizeof(preg))) return -EFAULT; if(preg.addr >= SAA7196_NUMREGS) return -EINVAL; saa_set (preg.addr, preg.val, pb); return 0; } case PLANBIOCGSTAT: { struct planb_stat_regs pstat; DBG("PlanB: IOCTL PLANBIOCGSTAT\n"); pstat.ch1_stat = readl(&pb->planb_base->ch1.status); pstat.ch2_stat = readl(&pb->planb_base->ch2.status); pstat.ch1_cmdbase = (unsigned long)pb->vid_cbo.start; pstat.ch2_cmdbase = (unsigned long)pb->clip_cbo.start; pstat.ch1_cmdptr = readl(&pb->planb_base->ch1.cmdptr); pstat.ch2_cmdptr = readl(&pb->planb_base->ch2.cmdptr); pstat.saa_stat0 = saa_status(0, pb); pstat.saa_stat1 = saa_status(1, pb); if(copy_to_user((void *)arg, (void *)&pstat, sizeof(pstat))) return -EFAULT; return 0; } case PLANBIOCSMODE: { int v; DBG("PlanB: IOCTL PLANBIOCSMODE\n"); if(copy_from_user(&v, arg, sizeof(v))) return -EFAULT; switch(v) { case PLANB_TV_MODE: saa_set (SAA7196_STDC, (saa_regs[pb->win.norm][SAA7196_STDC] & 0x7f), pb); break; case PLANB_VTR_MODE: saa_set (SAA7196_STDC, (saa_regs[pb->win.norm][SAA7196_STDC] | 0x80), pb); break; default: return -EINVAL; break; } pb->win.mode = v; return 0; } case PLANBIOCGMODE: { int v=pb->win.mode; DBG("PlanB: IOCTL PLANBIOCGMODE\n"); if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; }#ifdef PLANB_GSCANLINE case PLANBG_GRAB_BPL: { int v=pb->gbytes_per_line; DBG("PlanB: IOCTL PLANBG_GRAB_BPL\n"); if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; }#endif /* PLANB_GSCANLINE *//* These serve only for debugging... */#ifdef DEBUG case PLANB_INTR_DEBUG: { int i; DBG("PlanB: IOCTL PLANB_INTR_DEBUG\n"); if(copy_from_user(&i, arg, sizeof(i))) return -EFAULT; /* avoid hang ups all together */ for (i = 0; i < MAX_GBUFFERS; i++) { if(*pb->gbuf[i].status == GBUFFER_GRABBING) { *pb->gbuf[i].status = GBUFFER_DONE; } } if(pb->grabbing) pb->grabbing--; wake_up_interruptible(&pb->capq); return 0; } case PLANB_INV_REGS: { int i; struct planb_any_regs any; DBG("PlanB: IOCTL PLANB_INV_REGS\n"); if(copy_from_user(&any, arg, sizeof(any))) return -EFAULT; if(any.offset < 0 || any.offset + any.bytes > 0x400) return -EINVAL; if(any.bytes > 128) return -EINVAL; for (i = 0; i < any.bytes; i++) { any.data[i] = readb((unsigned char *)pb->planb_base + any.offset + i); } if(copy_to_user(arg,&any,sizeof(any))) return -EFAULT; return 0; } case PLANBIOCGDBDMABUF: { struct planb_buf_regs buf; dbdma_cmd_ptr dc; int i; DBG("PlanB: IOCTL PLANBIOCGDBDMABUF\n"); if(copy_from_user(&buf, arg, sizeof(buf))) return -EFAULT; buf.end &= ~0xf; if( (buf.start < 0) || (buf.end < 0x10) || (buf.end < buf.start+0x10) || (buf.end > 2*pb->tab_size) ) return -EINVAL; printk ("PlanB DBDMA command buffer:\n"); for (i=(buf.start>>4); i<=(buf.end>>4); i++) { printk(" 0x%04x:", i<<4); dc = pb->vid_cbo.start + i; printk (" %04x %04x %08x %08x %04x %04x\n", dc->req_count, dc->command, dc->phy_addr, dc->cmd_dep, dc->res_count, dc->xfer_status); } return 0; }#endif /* DEBUG */ default: { DBG("PlanB: Unimplemented IOCTL: %d (0x%x)\n", cmd, cmd); return -ENOIOCTLCMD; } /* Some IOCTLs are currently unsupported on PlanB */ case VIDIOCGTUNER: { DBG("PlanB: IOCTL VIDIOCGTUNER\n"); goto unimplemented; } case VIDIOCSTUNER: { DBG("PlanB: IOCTL VIDIOCSTUNER\n"); goto unimplemented; } case VIDIOCSFREQ: { DBG("PlanB: IOCTL VIDIOCSFREQ\n"); goto unimplemented; } case VIDIOCGFREQ: { DBG("PlanB: IOCTL VIDIOCGFREQ\n"); goto unimplemented; } case VIDIOCKEY: { DBG("PlanB: IOCTL VIDIOCKEY\n"); goto unimplemented; } case VIDIOCSAUDIO: { DBG("PlanB: IOCTL VIDIOCSAUDIO\n"); goto unimplemented; } case VIDIOCGAUDIO: { DBG("PlanB: IOCTL VIDIOCGAUDIO\n"); goto unimplemented; }unimplemented: DBG(" Unimplemented\n"); return -ENOIOCTLCMD; } return 0;}static int planb_mmap(struct video_device *dev, const char *adr, unsigned long size){ struct planb *pb = (struct planb *)dev->priv; unsigned long start = (unsigned long)adr; int i; if (size > MAX_GBUFFERS * PLANB_MAX_FBUF) return -EINVAL; if (!pb->rawbuf) { int err; if((err=grabbuf_alloc(pb))) return err; } for (i = 0; i < pb->rawbuf_nchunks; i++) { if (remap_page_range(start, virt_to_phys((void *)pb->rawbuf[i]), PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; start += PAGE_SIZE; if (size <= PAGE_SIZE) break; size -= PAGE_SIZE; } return 0;}/********************************** * VBI device operation functions * **********************************/static long planb_vbi_read(struct video_device *dev, char *buf, unsigned long count, int nonblock){ struct planb *pb = (struct planb *)dev->priv; int q,todo; DECLARE_WAITQUEUE(wait, current);/* Dummy for now */ printk ("PlanB: VBI read %li bytes.\n", count); return (0); todo=count; while (todo && todo>(q=VBIBUF_SIZE-pb->vbip)) { if(copy_to_user((void *) buf, (void *) pb->vbibuf+pb->vbip, q)) return -EFAULT; todo-=q; buf+=q; add_wait_queue(&pb->vbiq, &wait); current->state = TASK_INTERRUPTIBLE; if (todo && q==VBIBUF_SIZE-pb->vbip) { if(nonblock) { remove_wait_queue(&pb->vbiq, &wait); current->state = TASK_RUNNING; if(count==todo) return -EWOULDBLOCK; return count-todo; } schedule(); if(signal_pending(current)) { remove_wait_queue(&pb->vbiq, &wait); current->state = TASK_RUNNING; if(todo==count) return -EINTR; else return count-todo; } } remove_wait_queue(&pb->vbiq, &wait); current->state = TASK_RUNNING; } if (todo) { if(copy_to_user((void *) buf, (void *) pb->vbibuf+pb->vbip, todo)) return -EFAULT; pb->vbip+=todo; } return count;}static unsigned int planb_vbi_poll(struct video_device *dev, struct file *file, poll_table *wait){ struct planb *pb = (struct planb *)dev->priv; unsigned int mask = 0; printk ("PlanB: VBI poll.\n"); poll_wait(file, &pb->vbiq, wait); if (pb->vbip < VBIBUF_SIZE) mask |= (POLLIN | POLLRDNORM); return mask;}static int planb_vbi_open(struct video_device *dev, int flags){ struct planb *pb = (struct planb *)dev->priv; int err; /* first open on the driver? */ if(pb->vid_user + pb->vbi_user == 0) { if((err = planb_prepare_open(pb)) != 0) return err; } /* first open on the vbi device? */ if(pb->vbi_user == 1) { if((err = planb_prepare_vbi(pb)) != 0) return err; } ++pb->vbi_user; DBG("PlanB: VBI open\n"); MOD_INC_USE_COUNT; return 0; }static void planb_vbi_close(struct video_device *dev){ struct planb *pb = (struct planb *)dev->priv; /* last close on vbi device? */ if(--pb->vbi_user == 0) { planb_close_vbi(pb); } /* last close on any planb device? */ if(pb->vid_user + pb->vbi_user == 0) { planb_prepare_close(pb); } DBG("PlanB: VBI close\n"); MOD_DEC_USE_COUNT; return;}static int planb_vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg){ switch (cmd) { /* This is only for alevt */ case BTTV_VBISIZE: DBG("PlanB: IOCTL BTTV_VBISIZE.\n"); return VBIBUF_SIZE; default: DBG("PlanB: Unimplemented
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -