📄 bttv.c
字号:
*(ro++)=BT848_RISC_JUMP; *(ro++)=btv->bus_vbi_even; *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16); *(re++)=btv->bus_vbi_odd; return 0;} static int make_vrisctab(struct bttv *btv, unsigned int *ro, unsigned int *re, unsigned int *vbuf, unsigned short width, unsigned short height, unsigned short palette){ unsigned long line; unsigned long bpl; /* bytes per line */ unsigned long bl; unsigned long todo; unsigned int **rp; int inter; unsigned long vadr=(unsigned long) vbuf; if (palette==VIDEO_PALETTE_RAW) return make_rawrisctab(btv, ro, re, vbuf); if (palette>=VIDEO_PALETTE_PLANAR) return make_prisctab(btv, ro, re, vbuf, width, height, palette); inter = (height>btv->win.cropheight/2) ? 1 : 0; bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0; *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0; for (line=0; line < (height<<(1^inter)); line++) { if (inter) rp= (line&1) ? &re : &ro; else rp= (line>=height) ? &re : &ro; bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr); if (bpl<=bl) { *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL| BT848_RISC_EOL|bpl; *((*rp)++)=kvirt_to_bus(vadr); vadr+=bpl; } else { todo=bpl; *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL|bl; *((*rp)++)=kvirt_to_bus(vadr); vadr+=bl; todo-=bl; while (todo>PAGE_SIZE) { *((*rp)++)=BT848_RISC_WRITE|PAGE_SIZE; *((*rp)++)=kvirt_to_bus(vadr); vadr+=PAGE_SIZE; todo-=PAGE_SIZE; } *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_EOL|todo; *((*rp)++)=kvirt_to_bus(vadr); vadr+=todo; } } *(ro++)=BT848_RISC_JUMP; *(ro++)=btv->bus_vbi_even; *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16); *(re++)=btv->bus_vbi_odd; return 0;}static unsigned char lmaskt[8] = { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80};static unsigned char rmaskt[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int h){ unsigned char lmask, rmask, *p; int W, l, r; int i; /* bitmap is fixed width, 128 bytes (1024 pixels represented) */ if (x<0) { w+=x; x=0; } if (y<0) { h+=y; y=0; } if (w < 0 || h < 0) /* catch bad clips */ return; /* out of range data should just fall through */ if (y+h>=625) h=625-y; if (x+w>=1024) w=1024-x; l=x>>3; r=(x+w)>>3; W=r-l-1; lmask=lmaskt[x&7]; rmask=rmaskt[(x+w)&7]; p=clipmap+128*y+l; if (W>0) { for (i=0; i<h; i++, p+=128) { *p|=lmask; memset(p+1, 0xff, W); p[W+1]|=rmask; } } else if (!W) { for (i=0; i<h; i++, p+=128) { p[0]|=lmask; p[1]|=rmask; } } else { for (i=0; i<h; i++, p+=128) p[0]|=lmask&rmask; } }static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr){ int i, line, x, y, bpl, width, height, inter; unsigned int bpp, dx, sx, **rp, *ro, *re, flags, len; unsigned long adr; unsigned char *clipmap, cbit, lastbit, outofmem; inter=(btv->win.interlace&1)^1; bpp=btv->win.bpp; if (bpp==15) /* handle 15bpp as 16bpp in calculations */ bpp++; bpl=btv->win.bpl; ro=btv->risc_odd; re=btv->risc_even; if((width=btv->win.width)>1023) width = 1023; /* sanity check */ if((height=btv->win.height)>625) height = 625; /* sanity check */ adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl; if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { /* can't clip, don't generate any risc code */ *(ro++)=BT848_RISC_JUMP; *(ro++)=btv->bus_vbi_even; *(re++)=BT848_RISC_JUMP; *(re++)=btv->bus_vbi_odd; } if (ncr < 0) { /* bitmap was pased */ memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE); } else { /* convert rectangular clips to a bitmap */ memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */ for (i=0; i<ncr; i++) clip_draw_rectangle(clipmap, cr[i].x, cr[i].y, cr[i].width, cr[i].height); } /* clip against viewing window AND screen so we do not have to rely on the user program */ clip_draw_rectangle(clipmap,(btv->win.x+width>btv->win.swidth) ? (btv->win.swidth-btv->win.x) : width, 0, 1024, 768); clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? (btv->win.sheight-btv->win.y) : height,1024,768); if (btv->win.x<0) clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); if (btv->win.y<0) clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0; *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0; /* translate bitmap to risc code */ for (line=outofmem=0; line < (height<<inter) && !outofmem; line++) { y = line>>inter; rp= (line&1) ? &re : &ro; lastbit=(clipmap[y<<7]&1); for(x=dx=1,sx=0; x<=width && !outofmem; x++) { cbit = (clipmap[(y<<7)+(x>>3)] & (1<<(x&7))); if (x < width && !lastbit == !cbit) dx++; else { /* generate the dma controller code */ len = dx * bpp; flags = ((bpp==4) ? BT848_RISC_BYTE3 : 0); flags |= ((!sx) ? BT848_RISC_SOL : 0); flags |= ((sx + dx == width) ? BT848_RISC_EOL : 0); if (!lastbit) { *((*rp)++)=BT848_RISC_WRITE|flags|len; *((*rp)++)=adr + bpp * sx; } else *((*rp)++)=BT848_RISC_SKIP|flags|len; lastbit=cbit; sx += dx; dx = 1; if (ro - btv->risc_odd > RISCMEM_LEN/2 - 16) outofmem++; if (re - btv->risc_even > RISCMEM_LEN/2 - 16) outofmem++; } } if ((!inter)||(line&1)) adr+=bpl; } vfree(clipmap); /* outofmem flag relies on the following code to discard extra data */ *(ro++)=BT848_RISC_JUMP; *(ro++)=btv->bus_vbi_even; *(re++)=BT848_RISC_JUMP; *(re++)=btv->bus_vbi_odd;}/* set geometry for even/odd frames just if you are wondering: handling of even and odd frames will be separated, e.g. for grabbing the even ones as RGB into videomem and the others as YUV in main memory for compressing and sending to the video conferencing partner.*/static inline void bt848_set_eogeo(struct bttv *btv, int odd, u8 vtc, u16 hscale, u16 vscale, u16 hactive, u16 vactive, u16 hdelay, u16 vdelay, u8 crop){ int off = odd ? 0x80 : 0x00; 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(hactive&0xff, BT848_E_HACTIVE_LO+off); btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off); btwrite(vactive&0xff, BT848_E_VACTIVE_LO+off); btwrite(vdelay&0xff, BT848_E_VDELAY_LO+off); btwrite(crop, BT848_E_CROP+off);}static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt){ u16 vscale, hscale; u32 xsf, sr; u16 hdelay, vdelay; u16 hactive, vactive; u16 inter; u8 crop, vtc; struct tvnorm *tvn; if (!width || !height) return; tvn=&tvnorms[btv->win.norm]; btv->win.cropheight=tvn->sheight; btv->win.cropwidth=tvn->swidth;/* if (btv->win.cropwidth>tvn->cropwidth) btv->win.cropwidth=tvn->cropwidth; if (btv->win.cropheight>tvn->cropheight) btv->win.cropheight=tvn->cropheight; if (width>btv->win.cropwidth) width=btv->win.cropwidth; if (height>btv->win.cropheight) height=btv->win.cropheight;*/ 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; set_pll(btv); btwrite(fmt, BT848_COLOR_FMT); hactive=width; vtc=0; /* Some people say interpolation looks bad ... */ /* vtc = (hactive < 193) ? 2 : ((hactive < 385) ? 1 : 0); */ btv->win.interlace = (height>btv->win.cropheight/2) ? 1 : 0; inter=(btv->win.interlace&1)^1; vdelay=btv->win.cropy+tvn->vdelay; xsf = (hactive*tvn->scaledtwidth)/btv->win.cropwidth; hscale = ((tvn->totalwidth*4096UL)/xsf-4096); hdelay=tvn->hdelayx1+btv->win.cropx; hdelay=(hdelay*hactive)/btv->win.cropwidth; hdelay&=0x3fe; sr=((btv->win.cropheight>>inter)*512)/height-512; vscale=(0x10000UL-sr)&0x1fff; vactive=btv->win.cropheight; crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)| ((vactive>>4)&0x30)|((vdelay>>2)&0xc0); vscale|= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0; bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, vactive, hdelay, vdelay, crop); bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive, hdelay, vdelay, crop);}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; btv->win.color_fmt = format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : bpp2fmt[(btv->win.bpp-1)&3]; /* 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, btv->win.width, btv->win.height, format);}/* * Set TSA5522 synthesizer frequency in 1/16 Mhz steps */static void set_freq(struct bttv *btv, unsigned short freq){ int fixme = freq; /* XXX */ /* mute */ if (btv->have_msp3400) i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, MSP_SWITCH_MUTE,0); /* switch channel */ if (btv->have_tuner) { if (btv->radio) { i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER, TUNER_SET_RADIOFREQ,&fixme); } else { i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER, TUNER_SET_TVFREQ,&fixme); } } if (btv->have_msp3400) { if (btv->radio) { i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, MSP_SET_RADIO,0); } else { i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, MSP_SET_TVNORM,&(btv->win.norm)); i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, MSP_NEWCHANNEL,0); } }}/* * Grab into virtual memory. * Currently only does double buffering. Do we need more? */static int vgrab(struct bttv *btv, struct video_mmap *mp){ unsigned int *ro, *re; unsigned int *vbuf; if(btv->fbuffer==NULL) { if(fbuffer_alloc(btv)) return -ENOBUFS; } if(btv->grabbing >= MAX_GBUFFERS) return -ENOBUFS; /* * No grabbing past the end of the buffer! */ if(mp->frame>1 || mp->frame <0) return -EINVAL; if(mp->height <0 || mp->width <0) return -EINVAL; /* This doesn磘 work like this for NTSC anyway. So, better check the total image size ...*//* if(mp->height>576 || mp->width>768+BURSTOFFSET) return -EINVAL;*/ if (mp->format >= PALETTEFMT_MAX) return -EINVAL; if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2 > BTTV_MAX_FBUF) return -EINVAL; if(-1 == palette2fmt[mp->format]) return -EINVAL; /* * FIXME: Check the format of the grab here. This is probably * also less restrictive than the normal overlay grabs. Stuff * like QCIF has meaning as a capture. */ /* * Ok load up the BT848 */ vbuf=(unsigned int *)(btv->fbuffer+BTTV_MAX_FBUF*mp->frame);/* if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)) return -EAGAIN;*/ ro=btv->grisc+(((btv->grabcount++)&1) ? 4096 :0); re=ro+2048; make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format); /* bt848_set_risc_jmps(btv); */ btv->frame_stat[mp->frame] = GBUFFER_GRABBING; if (btv->grabbing) { btv->gfmt_next=palette2fmt[mp->format]; btv->gwidth_next=mp->width; btv->gheight_next=mp->height; btv->gro_next=virt_to_bus(ro); btv->gre_next=virt_to_bus(re); btv->grf_next=mp->frame; } else { btv->gfmt=palette2fmt[mp->format]; btv->gwidth=mp->width; btv->gheight=mp->height; btv->gro=virt_to_bus(ro); btv->gre=virt_to_bus(re); btv->grf=mp->frame; } if (!(btv->grabbing++)) { if(mp->format>=VIDEO_PALETTE_COMPONENT) { btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI); btor(BT848_VSCALE_COMB, BT848_O_VSCALE_HI); } btv->risc_jmp[12]=BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ; } btor(3, BT848_CAP_CTL); btor(3, BT848_GPIO_DMA_CTL); /* interruptible_sleep_on(&btv->capq); */ 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; /* 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; cli(); if (todo && q==VBIBUF_SIZE-btv->vbip) { if(nonblock) { sti(); if(count==todo) return -EWOULDBLOCK; return count-todo;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -