📄 planb.c
字号:
leftover1 = 0; pagei = gbuf->idx; if(nlines <= 1) goto skip; do { int j; base = virt_to_bus(pb->rawbuf[pagei]); nlpp = (PAGE_SIZE - leftover1) / count / stepsize; if(leftover1 >= count) { tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, base + leftover1 - count, jump); i += stepsize; } for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++) tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, base + count * (j * stepsize + 1) + leftover1, jump); if(i < nlines) { int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1; if(lov0 == 0) leftover1 = 0; else { if(lov0 > count) { pb->l_to_addr[fr][gbuf->lnum] = pb->rawbuf[pagei] + count * (nlpp * stepsize + 1) + leftover1; pb->l_to_next_idx[fr][gbuf->lnum] = pagei + 1; pb->l_to_next_size[fr][gbuf->lnum] = count * stepsize - lov0; tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, virt_to_bus(pb->rawbuf[gbuf->l_fr_addr_idx + gbuf->lnum]), jump); if(++gbuf->lnum > MAX_LNUM) { /* FIXME: error condition! */ gbuf->lnum--; } i += stepsize; } leftover1 = count * stepsize - lov0; } } pagei++; } while(i < nlines);skip: tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); c1 = jump_addr;#endif /* PLANB_GSCANLINE */cmd_tab_data_end: tab_cmd_store(c1++, (unsigned)(&pb->planb_base_bus->intr_stat), (fr << 9) | PLANB_FRM_IRQ | PLANB_GEN_IRQ); /* stop it */ tab_cmd_dbdma(c1, DBDMA_STOP, 0); eieio(); return c1;}static void planb_irq(int irq, void *dev_id, struct pt_regs * regs){ unsigned int stat, astat; struct planb *pb = (struct planb *)dev_id; IDBG("PlanB: planb_irq()\n"); /* get/clear interrupt status bits */ eieio(); stat = readl(&pb->planb_base->intr_stat); astat = stat & pb->intr_mask; writel(PLANB_FRM_IRQ & ~astat & stat & ~PLANB_GEN_IRQ, &pb->planb_base->intr_stat); IDBG("PlanB: stat = %X, astat = %X\n", stat, astat); if(astat & PLANB_FRM_IRQ) { unsigned int fr = stat >> 9; gbuf_ptr gbuf = &pb->gbuf[fr];#ifndef PLANB_GSCANLINE int i;#endif IDBG("PlanB: PLANB_FRM_IRQ\n"); pb->gcount++; IDBG("PlanB: grab %d: fr = %d, gcount = %d\n", pb->grabbing, fr, pb->gcount);#ifndef PLANB_GSCANLINE /* Now that the buffer is full, copy those lines that fell * on a page boundary from the spare buffers back to where * they belong. */ IDBG("PlanB: %d * %d bytes are being copied over\n", gbuf->lnum, gbuf->lsize); for(i = 0; i < gbuf->lnum; i++) { int first = gbuf->lsize - pb->l_to_next_size[fr][i]; memcpy(pb->l_to_addr[fr][i], pb->rawbuf[gbuf->l_fr_addr_idx + i], first); memcpy(pb->rawbuf[pb->l_to_next_idx[fr][i]], pb->rawbuf[gbuf->l_fr_addr_idx + i] + first, pb->l_to_next_size[fr][i]); }#endif *gbuf->status = GBUFFER_DONE; pb->grabbing--; wake_up_interruptible(&pb->capq); return; } /* incorrect interrupts? */ pb->intr_mask = PLANB_CLR_IRQ; writel(PLANB_CLR_IRQ, &pb->planb_base->intr_stat); printk(KERN_ERR "PlanB: IRQ lockup, cleared interrupts" " unconditionally\n");}/******************************* * Device Operations functions * *******************************/static int planb_open(struct video_device *dev, int mode){ struct planb *pb = (struct planb *)dev->priv; int err; /* first open on driver? */ if(pb->vid_user + pb->vbi_user == 0) { if((err = planb_prepare_open(pb)) != 0) return err; } /* first open on video dev? */ if(pb->vid_user == 0) { if((err = planb_prepare_video(pb)) != 0) return err; } pb->vid_user++; DBG("PlanB: device opened\n"); MOD_INC_USE_COUNT; return 0; }static void planb_close(struct video_device *dev){ struct planb *pb = (struct planb *)dev->priv; planb_lock(pb); /* last close? then stop everything... */ if(--pb->vid_user == 0) { if(pb->overlay) { planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); pb->overlay = 0; } planb_close_video(pb); } /* last open on PlanB hardware? */ if(pb->vid_user + pb->vbi_user == 0) planb_prepare_close(pb); planb_unlock(pb); DBG("PlanB: device closed\n"); MOD_DEC_USE_COUNT; return;}static long planb_read(struct video_device *v, char *buf, unsigned long count, int nonblock){ DBG("planb: read request\n"); return -EINVAL;}static long planb_write(struct video_device *v, const char *buf, unsigned long count, int nonblock){ DBG("planb: write request\n"); return -EINVAL;}static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg){ struct planb *pb=(struct planb *)dev->priv; switch (cmd) { case VIDIOCGCAP: { struct video_capability b; DBG("PlanB: IOCTL VIDIOCGCAP\n"); strcpy (b.name, pb->video_dev.name); b.type = VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_CAPTURE; b.channels = 2; /* composite & svhs */ b.audios = 0; b.maxwidth = PLANB_MAXPIXELS; b.maxheight = PLANB_MAXLINES; b.minwidth = 32; /* wild guess */ b.minheight = 32; if (copy_to_user(arg,&b,sizeof(b))) return -EFAULT; return 0; } case VIDIOCSFBUF: { struct video_buffer v; unsigned int fmt; DBG("PlanB: IOCTL VIDIOCSFBUF\n"); if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) return -EPERM; if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; planb_lock(pb); switch(v.depth) { /* xawtv only asks for 8 bit in static grey, but * there is no way to know what it really means.. */ case 8: fmt = VIDEO_PALETTE_GREY; break; case 15: fmt = VIDEO_PALETTE_RGB555; break; case 32: fmt = VIDEO_PALETTE_RGB32; break; /* We don't deliver these two... */ case 16: case 24: default: planb_unlock(pb); return -EINVAL; } if (palette2fmt[fmt].bpp * v.width > v.bytesperline) { planb_unlock(pb); return -EINVAL; } pb->win.bpp = palette2fmt[fmt].bpp; pb->win.color_fmt = fmt; pb->fb.phys = (unsigned long) v.base; pb->win.sheight = v.height; pb->win.swidth = v.width; pb->picture.depth = pb->win.depth = v.depth; pb->win.bpl = pb->win.bpp * pb->win.swidth; pb->win.pad = v.bytesperline - pb->win.bpl; DBG("PlanB: Display at %p is %d by %d, bytedepth %d," " bpl %d (+ %d)\n", v.base, v.width,v.height, pb->win.bpp, pb->win.bpl, pb->win.pad); pb->cmd_buff_inited = 0; if(pb->overlay) { suspend_overlay(pb); fill_cmd_buff(pb); resume_overlay(pb); } planb_unlock(pb); return 0; } case VIDIOCGFBUF: { struct video_buffer v; DBG("PlanB: IOCTL VIDIOCGFBUF\n"); v.base = (void *)pb->fb.phys; v.height = pb->win.sheight; v.width = pb->win.swidth; v.depth = pb->win.depth; v.bytesperline = pb->win.bpl + pb->win.pad; if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; return 0; } case VIDIOCCAPTURE: { int i; if(copy_from_user(&i, arg, sizeof(i))) return -EFAULT; if(i==0) { DBG("PlanB: IOCTL VIDIOCCAPTURE Stop\n"); if (!(pb->overlay)) return 0; planb_lock(pb); pb->overlay = 0; overlay_stop(pb); planb_unlock(pb); } else { DBG("PlanB: IOCTL VIDIOCCAPTURE Start\n"); if (pb->fb.phys == 0 || pb->win.width == 0 || pb->win.height == 0) return -EINVAL; if (pb->overlay) return 0; planb_lock(pb); pb->overlay = 1; if(!(pb->cmd_buff_inited)) fill_cmd_buff(pb); overlay_start(pb); planb_unlock(pb); } return 0; } case VIDIOCGCHAN: { struct video_channel v; DBG("PlanB: IOCTL VIDIOCGCHAN\n"); if(copy_from_user(&v, arg,sizeof(v))) return -EFAULT; v.flags = 0; v.tuners = 0; v.type = VIDEO_TYPE_CAMERA; v.norm = pb->win.norm; switch(v.channel) { case 0: strcpy(v.name,"Composite"); break; case 1: strcpy(v.name,"SVHS"); break; default: return -EINVAL; break; } if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; } case VIDIOCSCHAN: { struct video_channel v; DBG("PlanB: IOCTL VIDIOCSCHAN\n"); if(copy_from_user(&v, arg, sizeof(v))) return -EFAULT; if (v.norm != pb->win.norm) { int i, maxlines; switch (v.norm) { case VIDEO_MODE_PAL: case VIDEO_MODE_SECAM: maxlines = PLANB_MAXLINES; break; case VIDEO_MODE_NTSC: maxlines = PLANB_NTSC_MAXLINES; break; default: DBG(" invalid norm %d.\n", v.norm); return -EINVAL; break; } planb_lock(pb); /* empty the grabbing queue */ while(pb->grabbing) interruptible_sleep_on(&pb->capq); pb->maxlines = maxlines; pb->win.norm = v.norm; /* Stop overlay if running */ suspend_overlay(pb); for(i = 0; i < MAX_GBUFFERS; i++) pb->gbuf[i].norm_switch = 1; /* I know it's an overkill, but.... */ fill_cmd_buff(pb); /* ok, now init it accordingly */ saa_init_regs (pb); /* restart overlay if it was running */ resume_overlay(pb); planb_unlock(pb); } switch(v.channel) { case 0: /* Composite */ saa_set (SAA7196_IOCC, ((saa_regs[pb->win.norm][SAA7196_IOCC] & ~7) | 3), pb); break; case 1: /* SVHS */ saa_set (SAA7196_IOCC, ((saa_regs[pb->win.norm][SAA7196_IOCC] & ~7) | 4), pb); break; default: DBG(" invalid channel %d.\n", v.channel); return -EINVAL; break; } return 0; } case VIDIOCGPICT: { struct video_picture vp = pb->picture; DBG("PlanB: IOCTL VIDIOCGPICT\n"); vp.palette = pb->win.color_fmt; if(copy_to_user(arg,&vp,sizeof(vp))) return -EFAULT; return 0; } case VIDIOCSPICT: { struct video_picture vp; DBG("PlanB: IOCTL VIDIOCSPICT\n"); if(copy_from_user(&vp,arg,sizeof(vp))) return -EFAULT; pb->picture = vp; /* Should we do sanity checks here? */ planb_lock(pb); saa_set (SAA7196_BRIG, (unsigned char) ((pb->picture.brightness) >> 8), pb); saa_set (SAA7196_HUEC, (unsigned char) ((pb->picture.hue) >> 8) ^ 0x80, pb); saa_set (SAA7196_CSAT, (unsigned char) ((pb->picture.colour) >> 9), pb); saa_set (SAA7196_CONT, (unsigned char) ((pb->picture.contrast) >> 9), pb); planb_unlock(pb); return 0; } case VIDIOCSWIN: { struct video_window vw; struct video_clip clip; int i; DBG("PlanB: IOCTL VIDIOCSWIN\n"); if(copy_from_user(&vw,arg,sizeof(vw))) return -EFAULT; planb_lock(pb); /* Stop overlay if running */ suspend_overlay(pb); pb->win.interlace = (vw.height > pb->maxlines/2)? 1: 0; if (pb->win.x != vw.x || pb->win.y != vw.y || pb->win.width != vw.width || pb->win.height != vw.height || !pb->cmd_buff_inited) { pb->win.x = vw.x; pb->win.y = vw.y; pb->win.width = vw.width; pb->win.height = vw.height; fill_cmd_buff(pb); } DBG("PlanB: Window at (%d,%d) size %dx%d\n", vw.x, vw.y, vw.width, vw.height);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -