📄 zr36120.c
字号:
{ u16 Wt, Wa, Ht, Ha, HStart, VStart;};static struct tvnorm tvnorms[] = { /* PAL-BDGHI *//* { 864, 720, 625, 576, 131, 21 },*//*00*/ { 864, 768, 625, 576, 81, 17 }, /* NTSC *//*01*/ { 858, 720, 525, 480, 121, 10 }, /* SECAM *//*02*/ { 864, 720, 625, 576, 131, 21 }, /* BW50 *//*03*/ { 864, 720, 625, 576, 131, 21 }, /* BW60 *//*04*/ { 858, 720, 525, 480, 121, 10 }};#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))/* * Program the chip for a setup as described in the vidinfo struct. * * Side-effects: calculates vidXshift, vidInterlace, * vidHeight, vidWidth which are used in a later stage * to calculate the overlay mask * * This is an internal function, as such it does not check the * validity of the struct members... Spectaculair crashes will * follow /very/ quick when you're wrong and the chip right :) */staticvoid zoran_set_geo(struct zoran* ztv, struct vidinfo* i){ ulong top, bot; int stride; int winWidth, winHeight; int maxWidth, maxHeight, maxXOffset, maxYOffset; long vfec;DEBUG(printk(CARD_DEBUG "set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, busadr=%lx, overlay=%p)\n",CARD,i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->busadr,i->overlay)); /* * make sure the DMA transfers are inhibited during our * reprogramming of the chip */ zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); maxWidth = tvnorms[ztv->norm].Wa; maxHeight = tvnorms[ztv->norm].Ha/2; maxXOffset = tvnorms[ztv->norm].HStart; maxYOffset = tvnorms[ztv->norm].VStart; /* setup vfec register (keep ExtFl,TopField and VCLKPol settings) */ vfec = (zrread(ZORAN_VFEC) & (ZORAN_VFEC_EXTFL|ZORAN_VFEC_TOPFIELD|ZORAN_VFEC_VCLKPOL)) | (palette2fmt[i->format].mode & (ZORAN_VFEC_RGB|ZORAN_VFEC_ERRDIF|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24)); /* * Set top, bottom ptrs. Since these must be DWORD aligned, * possible adjust the x and the width of the window. * so the endposition stay the same. The vidXshift will make * sure we are not writing pixels before the requested x. */ ztv->vidXshift = 0; winWidth = i->w; if (winWidth < 0) winWidth = -winWidth; top = i->busadr + i->x*i->bpp + i->y*i->bpl; if (top & 3) { ztv->vidXshift = (top & 3) / i->bpp; winWidth += ztv->vidXshift; DEBUG(printk(KERN_DEBUG " window-x shifted %d pixels left\n",ztv->vidXshift)); top &= ~3; } /* * bottom points to next frame but in interleaved mode we want * to 'mix' the 2 frames to one capture, so 'bot' points to one * (physical) line below the top line. */ bot = top + i->bpl; zrwrite(top,ZORAN_VTOP); zrwrite(bot,ZORAN_VBOT); /* * Make sure the winWidth is DWORD aligned too, * thereby automaticly making sure the stride to the * next line is DWORD aligned too (as required by spec). */ if ((winWidth*i->bpp) & 3) {DEBUG(printk(KERN_DEBUG " window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3)); winWidth += (winWidth*i->bpp) & 3; } /* determine the DispMode and stride */ if (i->h >= 0 && i->h <= maxHeight) { /* single frame grab suffices for this height. */ vfec |= ZORAN_VFEC_DISPMOD; ztv->vidInterlace = 0; stride = i->bpl - (winWidth*i->bpp); winHeight = i->h; } else { /* interleaving needed for this height */ ztv->vidInterlace = 1; stride = i->bpl*2 - (winWidth*i->bpp); winHeight = i->h/2; } if (winHeight < 0) /* can happen for VBI! */ winHeight = -winHeight; /* safety net, sometimes bpl is too short??? */ if (stride<0) {DEBUG(printk(CARD_DEBUG "WARNING stride = %d\n",CARD,stride)); stride = 0; } zraor((winHeight<<12)|(winWidth<<0),~(ZORAN_VDC_VIDWINHT|ZORAN_VDC_VIDWINWID), ZORAN_VDC); zraor(stride<<16,~ZORAN_VSTR_DISPSTRIDE,ZORAN_VSTR); /* remember vidWidth, vidHeight for overlay calculations */ ztv->vidWidth = winWidth; ztv->vidHeight = winHeight;DEBUG(printk(KERN_DEBUG " top=%08lx, bottom=%08lx\n",top,bot));DEBUG(printk(KERN_DEBUG " winWidth=%d, winHeight=%d\n",winWidth,winHeight));DEBUG(printk(KERN_DEBUG " maxWidth=%d, maxHeight=%d\n",maxWidth,maxHeight));DEBUG(printk(KERN_DEBUG " stride=%d\n",stride)); /* * determine horizontal scales and crops */ if (i->w < 0) { int Hstart = 1; int Hend = Hstart + winWidth;DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Hstart, Hend)); zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH); } else { int Wa = maxWidth; int X = (winWidth*64+Wa-1)/Wa; int We = winWidth*64/X; int HorDcm = 64-X; int hcrop1 = 2*(Wa-We)/4; /* * BUGFIX: Juha Nurmela <junki@qn-lpr2-165.quicknet.inet.fi> * found the solution to the color phase shift. * See ChangeLog for the full explanation) */ int Hstart = (maxXOffset + hcrop1) | 1; int Hend = Hstart + We - 1;DEBUG(printk(KERN_DEBUG " X: scale=%d, start=%d, end=%d\n", HorDcm, Hstart, Hend)); zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH); vfec |= HorDcm<<14; if (HorDcm<16) vfec |= ZORAN_VFEC_HFILTER_1; /* no filter */ else if (HorDcm<32) vfec |= ZORAN_VFEC_HFILTER_3; /* 3 tap filter */ else if (HorDcm<48) vfec |= ZORAN_VFEC_HFILTER_4; /* 4 tap filter */ else vfec |= ZORAN_VFEC_HFILTER_5; /* 5 tap filter */ } /* * Determine vertical scales and crops * * when height is negative, we want to read starting at line 0 * One day someone might need access to these lines... */ if (i->h < 0) { int Vstart = 0; int Vend = Vstart + winHeight;DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Vstart, Vend)); zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV); } else { int Ha = maxHeight; int Y = (winHeight*64+Ha-1)/Ha; int He = winHeight*64/Y; int VerDcm = 64-Y; int vcrop1 = 2*(Ha-He)/4; int Vstart = maxYOffset + vcrop1; int Vend = Vstart + He - 1;DEBUG(printk(KERN_DEBUG " Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend)); zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV); vfec |= VerDcm<<8; }DEBUG(printk(KERN_DEBUG " F: format=%d(=%s)\n",i->format,palette2fmt[i->format].name)); /* setup the requested format */ zrwrite(vfec, ZORAN_VFEC);}staticvoid zoran_common_open(struct zoran* ztv, int flags){ UNUSED(flags); /* already opened? */ if (ztv->users++ != 0) return; /* unmute audio */ /* /what/ audio? */ ztv->state = 0; /* setup the encoder to the initial values */ ztv->picture.colour=254<<7; ztv->picture.brightness=128<<8; ztv->picture.hue=128<<8; ztv->picture.contrast=216<<7; i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture); /* default to the composite input since my camera is there */ zoran_muxsel(ztv, 0, VIDEO_MODE_PAL);}staticvoid zoran_common_close(struct zoran* ztv){ if (--ztv->users != 0) return; /* mute audio */ /* /what/ audio? */ /* stop the chip */ zoran_cap(ztv, 0);}/* * Open a zoran card. Right now the flags are just a hack */static int zoran_open(struct video_device *dev, int flags){ struct zoran *ztv = (struct zoran*)dev; struct vidinfo* item; char* pos; DEBUG(printk(CARD_DEBUG "open(dev,%d)\n",CARD,flags)); /********************************************* * We really should be doing lazy allocing... *********************************************/ /* allocate a frame buffer */ if (!ztv->fbuffer) ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE); if (!ztv->fbuffer) { /* could not get a buffer, bail out */ return -ENOBUFS; } /* at this time we _always_ have a framebuffer */ memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE); if (!ztv->overinfo.overlay) ztv->overinfo.overlay = (void*)kmalloc(1024*1024/8, GFP_KERNEL); if (!ztv->overinfo.overlay) { /* could not get an overlay buffer, bail out */ bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE); return -ENOBUFS; } /* at this time we _always_ have a overlay */ /* clear buffer status, and give them a DMAable address */ pos = ztv->fbuffer; for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) { item->status = FBUFFER_FREE; item->memadr = pos; item->busadr = virt_to_bus(pos); pos += ZORAN_MAX_FBUFFER; } /* do the common part of all open's */ zoran_common_open(ztv, flags); return 0;}staticvoid zoran_close(struct video_device* dev){ struct zoran *ztv = (struct zoran*)dev; DEBUG(printk(CARD_DEBUG "close(dev)\n",CARD)); /* driver specific closure */ clear_bit(STATE_OVERLAY, &ztv->state); zoran_common_close(ztv); /* * 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 */ /* free the allocated framebuffer */ if (ztv->fbuffer) bfree( ztv->fbuffer, ZORAN_MAX_FBUFSIZE ); ztv->fbuffer = 0; if (ztv->overinfo.overlay) kfree( ztv->overinfo.overlay ); ztv->overinfo.overlay = 0;}/* * This read function could be used reentrant in a SMP situation. * * This is made possible by the spinlock which is kept till we * found and marked a buffer for our own use. The lock must * be released as soon as possible to prevent lock contention. */staticlong zoran_read(struct video_device* dev, char* buf, unsigned long count, int nonblock){ struct zoran *ztv = (struct zoran*)dev; unsigned long max; struct vidinfo* unused = 0; struct vidinfo* done = 0; DEBUG(printk(CARD_DEBUG "zoran_read(%p,%ld,%d)\n",CARD,buf,count,nonblock)); /* find ourself a free or completed buffer */ for (;;) { struct vidinfo* item; write_lock_irq(&ztv->lock); for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) { if (!unused && item->status == FBUFFER_FREE) unused = item; if (!done && item->status == FBUFFER_DONE) done = item; } if (done || unused) break; /* no more free buffers, wait for them. */ write_unlock_irq(&ztv->lock); if (nonblock) return -EWOULDBLOCK; interruptible_sleep_on(&ztv->grabq); if (signal_pending(current)) return -EINTR; } /* Do we have 'ready' data? */ if (!done) { /* no? than this will take a while... */ if (nonblock) { write_unlock_irq(&ztv->lock); return -EWOULDBLOCK; } /* mark the unused buffer as wanted */ unused->status = FBUFFER_BUSY; unused->w = 320; unused->h = 240; unused->format = VIDEO_PALETTE_RGB24; unused->bpp = palette2fmt[unused->format].bpp; unused->bpl = unused->w * unused->bpp; unused->next = 0; { /* add to tail of queue */ struct vidinfo* oldframe = ztv->workqueue; if (!oldframe) ztv->workqueue = unused; else { while (oldframe->next) oldframe = oldframe->next; oldframe->next = unused; } } write_unlock_irq(&ztv->lock); /* tell the state machine we want it filled /NOW/ */ zoran_cap(ztv, 1); /* wait till this buffer gets grabbed */ while (unused->status == FBUFFER_BUSY) { interruptible_sleep_on(&ztv->grabq); /* see if a signal did it */ if (signal_pending(current)) return -EINTR; } done = unused; } else write_unlock_irq(&ztv->lock); /* Yes! we got data! */ max = done->bpl * done->h; if (count > max) count = max; if (copy_to_user((void*)buf, done->memadr, count)) count = -EFAULT; /* keep the engine running */ done->status = FBUFFER_FREE;// zoran_cap(ztv,1); /* tell listeners this buffer became free */ wake_up_interruptible(&ztv->grabq); /* goodbye */ DEBUG(printk(CARD_DEBUG "zoran_read() returns %lu\n",CARD,count)); return count;}staticlong zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock){ struct zoran *ztv = (struct zoran *)dev; UNUSED(ztv); UNUSED(dev); UNUSED(buf); UNUSED(count); UNUSED(nonblock); DEBUG(printk(CARD_DEBUG "zoran_write\n",CARD)); return -EINVAL;}#if LINUX_VERSION_CODE >= 0x020100staticunsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait){ struct zoran *ztv = (struct zoran *)dev; struct vidinfo* item; unsigned int mask = 0; poll_wait(file, &ztv->grabq, wait); for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) if (item->status == FBUFFER_DONE) { mask |= (POLLIN | POLLRDNORM); break; } DEBUG(printk(CARD_DEBUG "zoran_poll()=%x\n",CARD,mask)); return mask;}#endif/* append a new clipregion to the vector of video_clips */staticvoid new_clip(struct video_window* vw, struct video_clip* vcp, int x, int y, int w, int h){ vcp[vw->clipcount].x = x; vcp[vw->clipcount].y = y; vcp[vw->clipcount].width = w; vcp[vw->clipcount].height = h; vw->clipcount++;}staticint zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg){ struct zoran* ztv = (struct zoran*)dev; switch (cmd) { case VIDIOCGCAP: { struct video_capability c; DEBUG(printk(CARD_DEBUG "VIDIOCGCAP\n",CARD)); strcpy(c.name,ztv->video_dev.name); c.type = VID_TYPE_CAPTURE| VID_TYPE_OVERLAY| VID_TYPE_CLIPPING| VID_TYPE_FRAMERAM| VID_TYPE_SCALES; if (ztv->have_tuner) c.type |= VID_TYPE_TUNER; if (ztv->have_decoder) { c.channels = ztv->card->video_inputs; c.audios = ztv->card->audio_inputs; } else /* no decoder -> no channels */ c.channels = c.audios = 0; c.maxwidth = 768; c.maxheight = 576; c.minwidth = 32; c.minheight = 32; if (copy_to_user(arg,&c,sizeof(c))) return -EFAULT; break; } case VIDIOCGCHAN: { struct video_channel v; int mux; if (copy_from_user(&v, arg,sizeof(v))) return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDIOCGCHAN(%d)\n",CARD,v.channel)); v.flags=VIDEO_VC_AUDIO#ifdef VIDEO_VC_NORM |VIDEO_VC_NORM#endif ; v.tuners=0; v.type=VIDEO_TYPE_CAMERA;#ifdef I_EXPECT_POSSIBLE_NORMS_IN_THE_API v.norm=VIDEO_MODE_PAL| VIDEO_MODE_NTSC| VIDEO_MODE_SECAM;#else v.norm=VIDEO_MODE_PAL;#endif /* too many inputs? no decoder -> no channels */ if (!ztv->have_decoder || v.channel < 0 || v.channel >= ztv->card->video_inputs) return -EINVAL; /* now determine the name of the channel */ mux = ztv->card->video_mux[v.channel]; if (mux & IS_TUNER) { /* lets assume only one tuner, yes? */ strcpy(v.name,"Television"); v.type = VIDEO_TYPE_TV; if (ztv->have_tuner) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -