📄 bttv-driver.c
字号:
* PS: The manual is free for download in .pdf format from * www.brooktree.com - nicely done those folks. */ static inline void bt848_set_eogeo(struct bttv *btv, struct tvnorm *tvn, int odd, int width, int height){ u16 vscale, hscale; u32 xsf, sr; u16 hdelay; u8 crop, vtc; int inter = (height>tvn->sheight/2) ? 0 : 1; int off = odd ? 0x80 : 0x00; xsf = (width*tvn->scaledtwidth)/tvn->swidth; hscale = ((tvn->totalwidth*4096UL)/xsf-4096); hdelay = tvn->hdelayx1; hdelay = (hdelay*width)/tvn->swidth; hdelay &= 0x3fe; sr=((tvn->sheight>>inter)*512)/height-512; vscale=(0x10000UL-sr)&0x1fff; crop=((width>>8)&0x03)|((hdelay>>6)&0x0c)| ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0); vscale |= inter ? (BT848_VSCALE_INT<<8) : 0; if (combfilter) { /* Some people say interpolation looks bad ... */ vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); if (width < 769) btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); else btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); } else { vtc = 0; btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); } btwrite(vtc, BT848_E_VTC+off); btwrite(hscale>>8, BT848_E_HSCALE_HI+off); btwrite(hscale&0xff, BT848_E_HSCALE_LO+off); btaor((vscale>>8), 0xe0, BT848_E_VSCALE_HI+off); btwrite(vscale&0xff, BT848_E_VSCALE_LO+off); btwrite(width&0xff, BT848_E_HACTIVE_LO+off); btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off); btwrite(tvn->sheight&0xff, BT848_E_VACTIVE_LO+off); btwrite(tvn->vdelay&0xff, BT848_E_VDELAY_LO+off); btwrite(crop, BT848_E_CROP+off);}static void bt848_set_geo(struct bttv *btv, int no_irq_context){ u16 ewidth, eheight, owidth, oheight; u16 format, bswap; struct tvnorm *tvn; tvn=&tvnorms[btv->win.norm]; btwrite(tvn->adelay, BT848_ADELAY); btwrite(tvn->bdelay, BT848_BDELAY); btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM); btwrite(tvn->vbipack, BT848_VBI_PACK_SIZE); btwrite(1, BT848_VBI_PACK_DEL); btv->pll.pll_ofreq = tvn->Fsc; if (no_irq_context) set_pll(btv); btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0; if (0 == btv->risc_cap_odd && 0 == btv->risc_cap_even) { /* overlay only */ owidth = btv->win.width; oheight = btv->win.height; ewidth = btv->win.width; eheight = btv->win.height; format = btv->win.color_fmt; bswap = btv->fb_color_ctl; } else if (-1 != btv->gq_grab && 0 == btv->risc_cap_odd && !btv->win.interlace && btv->scr_on) { /* odd field -> overlay, even field -> capture */ owidth = btv->win.width; oheight = btv->win.height; ewidth = btv->gbuf[btv->gq_grab].width; eheight = btv->gbuf[btv->gq_grab].height; format = (btv->win.color_fmt & 0xf0) | (btv->gbuf[btv->gq_grab].fmt & 0x0f); bswap = btv->fb_color_ctl & 0x0a; } else { /* capture only */ owidth = btv->gbuf[btv->gq_grab].width; oheight = btv->gbuf[btv->gq_grab].height; ewidth = btv->gbuf[btv->gq_grab].width; eheight = btv->gbuf[btv->gq_grab].height; format = btv->gbuf[btv->gq_grab].fmt; bswap = 0; } /* program odd + even fields */ bt848_set_eogeo(btv, tvn, 1, owidth, oheight); bt848_set_eogeo(btv, tvn, 0, ewidth, eheight); btwrite(format, BT848_COLOR_FMT); btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);}static int bpp2fmt[4] = { BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 };static void bt848_set_winsize(struct bttv *btv){ unsigned short format; if (btv->picture.palette > 0 && btv->picture.palette <= VIDEO_PALETTE_YUV422) { /* format set by VIDIOCSPICT */ format = palette2fmt[btv->picture.palette]; } else { /* use default for the given color depth */ format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : bpp2fmt[(btv->win.bpp-1)&3]; } btv->win.color_fmt = format; if (bigendian && format == BT848_COLOR_FMT_RGB32) { btv->fb_color_ctl = BT848_COLOR_CTL_WSWAP_ODD | BT848_COLOR_CTL_WSWAP_EVEN | BT848_COLOR_CTL_BSWAP_ODD | BT848_COLOR_CTL_BSWAP_EVEN; } else if (bigendian && (format == BT848_COLOR_FMT_RGB16 || format == BT848_COLOR_FMT_RGB15)) { btv->fb_color_ctl = BT848_COLOR_CTL_BSWAP_ODD | BT848_COLOR_CTL_BSWAP_EVEN; } else { btv->fb_color_ctl = 0; } /* RGB8 seems to be a 9x5x5 GRB color cube starting at * color 16. Why the h... can't they even mention this in the * data sheet? [AC - because it's a standard format so I guess * it never occurred to them] * Enable dithering in this mode. */ if (format==BT848_COLOR_FMT_RGB8) btand(~BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); else btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); bt848_set_geo(btv,1);}/* * Grab into virtual memory. */static int vgrab(struct bttv *btv, struct video_mmap *mp){ unsigned int *ro, *re; unsigned int *vbuf; unsigned long flags; if(btv->fbuffer==NULL) { if(fbuffer_alloc(btv)) return -ENOBUFS; } if(mp->frame >= gbuffers || mp->frame < 0) return -EINVAL; if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED) return -EBUSY; if(mp->height < 32 || mp->width < 48) return -EINVAL; if (mp->format >= PALETTEFMT_MAX) return -EINVAL; if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2 > gbufsize) return -EINVAL; if(-1 == palette2fmt[mp->format]) return -EINVAL; /* * Ok load up the BT848 */ vbuf=(unsigned int *)(btv->fbuffer+gbufsize*mp->frame); ro=btv->gbuf[mp->frame].risc; re=ro+2048; make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format); if (bttv_debug) printk("bttv%d: cap vgrab: queue %d (%d:%dx%d)\n", btv->nr,mp->frame,mp->format,mp->width,mp->height); spin_lock_irqsave(&btv->s_lock, flags); btv->gbuf[mp->frame].stat = GBUFFER_GRABBING; btv->gbuf[mp->frame].fmt = palette2fmt[mp->format]; btv->gbuf[mp->frame].width = mp->width; btv->gbuf[mp->frame].height = mp->height; btv->gbuf[mp->frame].ro = virt_to_bus(ro); btv->gbuf[mp->frame].re = virt_to_bus(re);#if 1 if (mp->height <= tvnorms[btv->win.norm].sheight/2 && mp->format != VIDEO_PALETTE_RAW) btv->gbuf[mp->frame].ro = 0;#endif if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) { btv->gq_start = 1; btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); } btv->gqueue[btv->gq_in++] = mp->frame; btv->gq_in = btv->gq_in % MAX_GBUFFERS; btor(3, BT848_CAP_CTL); btor(3, BT848_GPIO_DMA_CTL); spin_unlock_irqrestore(&btv->s_lock, flags); return 0;}static long bttv_write(struct video_device *v, const char *buf, unsigned long count, int nonblock){ return -EINVAL;}static long bttv_read(struct video_device *v, char *buf, unsigned long count, int nonblock){ struct bttv *btv= (struct bttv *)v; int q,todo; DECLARE_WAITQUEUE(wait, current); /* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */ todo=count; while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) { if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q)) return -EFAULT; todo-=q; buf+=q; add_wait_queue(&btv->vbiq, &wait); current->state = TASK_INTERRUPTIBLE; if (todo && q==VBIBUF_SIZE-btv->vbip) { if(nonblock) { remove_wait_queue(&btv->vbiq, &wait); current->state = TASK_RUNNING; if(count==todo) return -EWOULDBLOCK; return count-todo; } schedule(); if(signal_pending(current)) { remove_wait_queue(&btv->vbiq, &wait); current->state = TASK_RUNNING; if(todo==count) return -EINTR; else return count-todo; } } remove_wait_queue(&btv->vbiq, &wait); current->state = TASK_RUNNING; } if (todo) { if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo)) return -EFAULT; btv->vbip+=todo; } return count;}static inline void burst(int on){ tvnorms[0].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0); tvnorms[0].hdelayx1 = 186 - (on?BURSTOFFSET :0); tvnorms[2].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0); tvnorms[2].hdelayx1 = 186 - (on?BURSTOFFSET :0);}/* * called from irq handler on fatal errors. Takes the grabber chip * offline, flag it needs a reinitialization (which can't be done * from irq context) and wake up all sleeping proccesses. They would * block forever else. We also need someone who actually does the * reinitialization from process context... */static void bt848_offline(struct bttv *btv){ int i; spin_lock(&btv->s_lock); /* cancel all outstanding grab requests */ btv->gq_in = 0; btv->gq_out = 0; btv->gq_grab = -1; for (i = 0; i < gbuffers; i++) if (btv->gbuf[i].stat == GBUFFER_GRABBING) btv->gbuf[i].stat = GBUFFER_ERROR; /* disable screen overlay and DMA */ btv->risc_cap_odd = 0; btv->risc_cap_even = 0; bt848_set_risc_jmps(btv,0); /* flag the chip needs a restart */ btv->needs_restart = 1; spin_unlock(&btv->s_lock); wake_up_interruptible(&btv->vbiq); wake_up_interruptible(&btv->capq);}static void bt848_restart(struct bttv *btv){ unsigned long irq_flags; if (bttv_verbose) printk("bttv%d: resetting chip\n",btv->nr); btwrite(0xfffffUL, BT848_INT_STAT); btand(~15, BT848_GPIO_DMA_CTL); btwrite(0, BT848_SRESET); btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD); /* enforce pll reprogramming */ btv->pll.pll_current = 0; set_pll(btv); spin_lock_irqsave(&btv->s_lock, irq_flags); btv->errors = 0; btv->needs_restart = 0; bt848_set_geo(btv,0); bt848_set_risc_jmps(btv,-1); spin_unlock_irqrestore(&btv->s_lock, irq_flags);}/* * Open a bttv card. Right now the flags stuff is just playing */static int bttv_open(struct video_device *dev, int flags){ struct bttv *btv = (struct bttv *)dev; int i,ret; ret = -EBUSY; if (bttv_debug) printk("bttv%d: open called\n",btv->nr); down(&btv->lock); if (btv->user) goto out_unlock; btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); ret = -ENOMEM; if (!btv->fbuffer) goto out_unlock; btv->gq_in = 0; btv->gq_out = 0; btv->gq_grab = -1; for (i = 0; i < gbuffers; i++) btv->gbuf[i].stat = GBUFFER_UNUSED; if (btv->needs_restart) bt848_restart(btv); burst(0); set_pll(btv); btv->user++; up(&btv->lock); return 0; out_unlock: up(&btv->lock); return ret;}static void bttv_close(struct video_device *dev){ struct bttv *btv=(struct bttv *)dev; unsigned long irq_flags; int need_wait; down(&btv->lock); btv->user--; spin_lock_irqsave(&btv->s_lock, irq_flags); need_wait = (-1 != btv->gq_grab); btv->gq_start = 0; btv->gq_in = 0; btv->gq_out = 0; btv->gq_grab = -1; btv->scr_on = 0; btv->risc_cap_odd = 0; btv->risc_cap_even = 0; bt848_set_risc_jmps(btv,-1); spin_unlock_irqrestore(&btv->s_lock, irq_flags); /* * A word of warning. At this point the chip * is still capturing because its FIFO hasn't emptied * and the DMA control operations are posted PCI * operations. */ btread(BT848_I2C); /* This fixes the PCI posting delay */ if (need_wait) { /* * This is sucky but right now I can't find a good way to * be sure its safe to free the buffer. We wait 5-6 fields * which is more than sufficient to be sure. */ current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(HZ/10); /* Wait 1/10th of a second */ } /* * We have allowed it to drain. */ if(btv->fbuffer) rvfree((void *) btv->fbuffer, gbuffers*gbufsize); btv->fbuffer=0; up(&btv->lock);}/***********************************//* ioctls and supporting functions *//***********************************/extern inline void bt848_bright(struct bttv *btv, uint bright){ btwrite(bright&0xff, BT848_BRIGHT);}extern inline void bt848_hue(struct bttv *btv, uint hue){ btwrite(hue&0xff, BT848_HUE);}extern inline void bt848_contrast(struct bttv *btv, uint cont){ unsigned int conthi; conthi=(cont>>6)&4; btwrite(cont&0xff, BT848_CONTRAST_LO); btaor(conthi, ~4, BT848_E_CONTROL); btaor(conthi, ~4, BT848_O_CONTROL);}extern inline void bt848_sat_u(struct bttv *btv, unsigned long data){ u32 datahi; datahi=(data>>7)&2; btwrite(data&0xff, BT848_SAT_U_LO); btaor(datahi, ~2, BT848_E_CONTROL); btaor(datahi, ~2, BT848_O_CONTROL);}static inline void bt848_sat_v(struct bttv *btv, unsigned long data){ u32 datahi; datahi=(data>>8)&1; btwrite(data&0xff, BT848_SAT_V_LO); btaor(datahi, ~1, BT848_E_CONTROL); btaor(datahi, ~1, BT848_O_CONTROL);}/* * ioctl routine */ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg){ struct bttv *btv=(struct bttv *)dev; unsigned long irq_flags; int i,ret = 0; if (bttv_debug > 1) printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd); switch (cmd) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -