📄 zr36120.c
字号:
clear_bit(STATE_VBI, &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 */ for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) { if (item->memadr) bfree(item->memadr, ZORAN_VBI_BUFSIZE); item->memadr = 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 vbi_read(struct video_device* dev, char* buf, unsigned long count, int nonblock){ struct zoran *ztv = (struct zoran*)dev->priv; unsigned long max; struct vidinfo* unused = 0; struct vidinfo* done = 0; DEBUG(printk(CARD_DEBUG "vbi_read(0x%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->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; 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->vbiq); 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->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->vbiq); /* 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; /* check if the user gave us enough room to write the data */ if (!access_ok(VERIFY_WRITE, buf, count)) { count = -EFAULT; goto out; } /* * Now transform/strip the data from YUV to Y-only * NB. Assume the Y is in the LSB of the YUV data. */ { unsigned char* optr = buf; unsigned char* eptr = buf+count; /* are we beeing accessed from an old driver? */ if (count == 2*19*2048) { /* * Extreme HACK, old VBI programs expect 2048 points * of data, and we only got 864 orso. Double each * datapoint and clear the rest of the line. * This way we have appear to have a * sample_frequency of 29.5 Mc. */ int x,y; unsigned char* iptr = done->memadr+1; for (y=done->h; optr<eptr && y<0; y++) { /* copy to doubled data to userland */ for (x=0; optr+1<eptr && x<-done->w; x++) { unsigned char a = iptr[x*2]; *optr++ = a; *optr++ = a; } /* and clear the rest of the line */ for (x*=2; optr<eptr && x<done->bpl; x++) *optr++ = 0; /* next line */ iptr += done->bpl; } } else { /* * Other (probably newer) programs asked * us what geometry we are using, and are * reading the correct size. */ int x,y; unsigned char* iptr = done->memadr+1; for (y=done->h; optr<eptr && y<0; y++) { /* copy to doubled data to userland */ for (x=0; optr<eptr && x<-done->w; x++) *optr++ = iptr[x*2]; /* and clear the rest of the line */ for (;optr<eptr && x<done->bpl; x++) *optr++ = 0; /* next line */ iptr += done->bpl; } } /* API compliance: * place the framenumber (half fieldnr) in the last long */ ((ulong*)eptr)[-1] = done->fieldnr/2; } /* keep the engine running */ done->status = FBUFFER_FREE; zoran_cap(ztv, 1); /* tell listeners this buffer just became free */ wake_up_interruptible(&ztv->vbiq); /* goodbye */out: DEBUG(printk(CARD_DEBUG "vbi_read() returns %lu\n",CARD,count)); return count;}#if LINUX_VERSION_CODE >= 0x020100staticunsigned int vbi_poll(struct video_device *dev, struct file *file, poll_table *wait){ struct zoran *ztv = (struct zoran*)dev->priv; struct vidinfo* item; unsigned int mask = 0; poll_wait(file, &ztv->vbiq, wait); for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) if (item->status == FBUFFER_DONE) { mask |= (POLLIN | POLLRDNORM); break; } DEBUG(printk(CARD_DEBUG "vbi_poll()=%x\n",CARD,mask)); return mask;}#endifstaticint vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg){ struct zoran* ztv = (struct zoran*)dev->priv; switch (cmd) { case VIDIOCGVBIFMT: { struct vbi_format f; DEBUG(printk(CARD_DEBUG "VIDIOCGVBIINFO\n",CARD)); f.sampling_rate = 14750000UL; f.samples_per_line = -ztv->readinfo[0].w; f.sample_format = VIDEO_PALETTE_RAW; f.start[0] = f.start[1] = ztv->readinfo[0].y; f.start[1] += 312; f.count[0] = f.count[1] = -ztv->readinfo[0].h; f.flags = VBI_INTERLACED; if (copy_to_user(arg,&f,sizeof(f))) return -EFAULT; break; } case VIDIOCSVBIFMT: { struct vbi_format f; int i; if (copy_from_user(&f, arg,sizeof(f))) return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDIOCSVBIINFO(%d,%d,%d,%d,%d,%d,%d,%x)\n",CARD,f.sampling_rate,f.samples_per_line,f.sample_format,f.start[0],f.start[1],f.count[0],f.count[1],f.flags)); /* lots of parameters are fixed... (PAL) */ if (f.sampling_rate != 14750000UL || f.samples_per_line > 864 || f.sample_format != VIDEO_PALETTE_RAW || f.start[0] < 0 || f.start[0] != f.start[1]-312 || f.count[0] != f.count[1] || f.start[0]+f.count[0] >= 288 || f.flags != VBI_INTERLACED) return -EINVAL; write_lock_irq(&ztv->lock); ztv->readinfo[0].y = f.start[0]; ztv->readinfo[0].w = -f.samples_per_line; ztv->readinfo[0].h = -f.count[0]; ztv->readinfo[0].bpl = f.samples_per_line*ztv->readinfo[0].bpp; for (i=1; i<ZORAN_VBI_BUFFERS; i++) ztv->readinfo[i] = ztv->readinfo[i]; write_unlock_irq(&ztv->lock); break; } default: return -ENOIOCTLCMD; } return 0;}static struct video_device vbi_template={ owner: THIS_MODULE, name: "UNSET", type: VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, hardware: VID_HARDWARE_ZR36120, open: vbi_open, close: vbi_close, read: vbi_read, write: zoran_write, poll: vbi_poll, ioctl: vbi_ioctl, minor: -1,};/* * Scan for a Zoran chip, request the irq and map the io memory */staticint __init find_zoran(void){ int result; struct zoran *ztv; struct pci_dev *dev = NULL; unsigned char revision; int zoran_num=0; while ((dev = pci_find_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev))) { /* Ok, a ZR36120/ZR36125 found! */ ztv = &zorans[zoran_num]; ztv->dev = dev; if (pci_enable_device(dev)) return -EIO; pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision); printk(KERN_INFO "zoran: Zoran %x (rev %d) ", dev->device, revision); printk("bus: %d, devfn: %d, irq: %d, ", dev->bus->number, dev->devfn, dev->irq); printk("memory: 0x%08lx.\n", ztv->zoran_adr); ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000); DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem)); result = request_irq(dev->irq, zoran_irq, SA_SHIRQ|SA_INTERRUPT,"zoran",(void *)ztv); if (result==-EINVAL) { iounmap(ztv->zoran_mem); printk(KERN_ERR "zoran: Bad irq number or handler\n"); return -EINVAL; } if (result==-EBUSY) printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",dev->irq); if (result < 0) { iounmap(ztv->zoran_mem); return result; } /* Enable bus-mastering */ pci_set_master(dev); zoran_num++; } if(zoran_num) printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num); return zoran_num;}staticint __init init_zoran(int card){ struct zoran *ztv = &zorans[card]; int i; /* if the given cardtype valid? */ if (cardtype[card]>=NRTVCARDS) { printk(KERN_INFO "invalid cardtype(%d) detected\n",cardtype[card]); return -1; } /* reset the zoran */ zrand(~ZORAN_PCI_SOFTRESET,ZORAN_PCI); udelay(10); zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI); udelay(10); /* zoran chip specific details */ ztv->card = tvcards+cardtype[card]; /* point to the selected card */ ztv->norm = 0; /* PAL */ ztv->tuner_freq = 0; /* videocard details */ ztv->swidth = 800; ztv->sheight = 600; ztv->depth = 16; /* State details */ ztv->fbuffer = 0; ztv->overinfo.kindof = FBUFFER_OVERLAY; ztv->overinfo.status = FBUFFER_FREE; ztv->overinfo.x = 0; ztv->overinfo.y = 0; ztv->overinfo.w = 768; /* 640 */ ztv->overinfo.h = 576; /* 480 */ ztv->overinfo.format = VIDEO_PALETTE_RGB565; ztv->overinfo.bpp = palette2fmt[ztv->overinfo.format].bpp; ztv->overinfo.bpl = ztv->overinfo.bpp*ztv->swidth; ztv->overinfo.busadr = 0; ztv->overinfo.memadr = 0; ztv->overinfo.overlay = 0; for (i=0; i<ZORAN_MAX_FBUFFERS; i++) { ztv->grabinfo[i] = ztv->overinfo; ztv->grabinfo[i].kindof = FBUFFER_GRAB; } init_waitqueue_head(&ztv->grabq); /* VBI details */ ztv->readinfo[0] = ztv->overinfo; ztv->readinfo[0].kindof = FBUFFER_VBI; ztv->readinfo[0].w = -864; ztv->readinfo[0].h = -38; ztv->readinfo[0].format = VIDEO_PALETTE_YUV422; ztv->readinfo[0].bpp = palette2fmt[ztv->readinfo[0].format].bpp; ztv->readinfo[0].bpl = 1024*ztv->readinfo[0].bpp; for (i=1; i<ZORAN_VBI_BUFFERS; i++) ztv->readinfo[i] = ztv->readinfo[0]; init_waitqueue_head(&ztv->vbiq); /* maintenance data */ ztv->have_decoder = 0; ztv->have_tuner = 0; ztv->tuner_type = 0; ztv->running = 0; ztv->users = 0; ztv->lock = RW_LOCK_UNLOCKED; ztv->workqueue = 0; ztv->fieldnr = 0; ztv->lastfieldnr = 0; if (triton1) zrand(~ZORAN_VDC_TRICOM, ZORAN_VDC); /* external FL determines TOP frame */ zror(ZORAN_VFEC_EXTFL, ZORAN_VFEC); /* set HSpol */ if (ztv->card->hsync_pos) zrwrite(ZORAN_VFEH_HSPOL, ZORAN_VFEH); /* set VSpol */ if (ztv->card->vsync_pos) zrwrite(ZORAN_VFEV_VSPOL, ZORAN_VFEV); /* Set the proper General Purpuse register bits */ /* implicit: no softreset, 0 waitstates */ zrwrite(ZORAN_PCI_SOFTRESET|(ztv->card->gpdir<<0),ZORAN_PCI); /* implicit: 3 duration and recovery PCI clocks on guest 0-3 */ zrwrite(ztv->card->gpval<<24,ZORAN_GUEST); /* clear interrupt status */ zrwrite(~0, ZORAN_ISR); /* * i2c template */ ztv->i2c = zoran_i2c_bus_template; sprintf(ztv->i2c.name,"zoran-%d",card); ztv->i2c.data = ztv; /* * Now add the template and register the device unit */ ztv->video_dev = zr36120_template; strcpy(ztv->video_dev.name, ztv->i2c.name); ztv->video_dev.priv = ztv; if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER, video_nr) < 0) return -1; ztv->vbi_dev = vbi_template; strcpy(ztv->vbi_dev.name, ztv->i2c.name); ztv->vbi_dev.priv = ztv; if (video_register_device(&ztv->vbi_dev, VFL_TYPE_VBI, vbi_nr) < 0) { video_unregister_device(&ztv->video_dev); return -1; } i2c_register_bus(&ztv->i2c); /* set interrupt mask - the PIN enable will be set later */ zrwrite(ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1|ZORAN_ICR_CODE, ZORAN_ICR); printk(KERN_INFO "%s: installed %s\n",ztv->i2c.name,ztv->card->name); return 0;}staticvoid release_zoran(int max){ struct zoran *ztv; int i; for (i=0;i<max; i++) { ztv = &zorans[i]; /* turn off all capturing, DMA and IRQs */ /* reset the zoran */ zrand(~ZORAN_PCI_SOFTRESET,ZORAN_PCI); udelay(10); zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI); udelay(10); /* first disable interrupts before unmapping the memory! */ zrwrite(0, ZORAN_ICR); zrwrite(0xffffffffUL,ZORAN_ISR); /* free it */ free_irq(ztv->dev->irq,ztv); /* unregister i2c_bus */ i2c_unregister_bus((&ztv->i2c)); /* unmap and free memory */ if (ztv->zoran_mem) iounmap(ztv->zoran_mem); video_unregister_device(&ztv->video_dev); video_unregister_device(&ztv->vbi_dev); }}void __exit zr36120_exit(void){ release_zoran(zoran_cards);}int __init zr36120_init(void){ int card; handle_chipset(); zoran_cards = find_zoran(); if (zoran_cards<0) /* no cards found, no need for a driver */ return -EIO; /* initialize Zorans */ for (card=0; card<zoran_cards; card++) { if (init_zoran(card)<0) { /* only release the zorans we have registered */ release_zoran(card); return -EIO; } } return 0;}module_init(zr36120_init);module_exit(zr36120_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -