📄 planb.c
字号:
case PLANBIOCGSTAT: { struct planb_stat_regs pstat; DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n"); pstat.ch1_stat = in_le32(&pb->planb_base->ch1.status); pstat.ch2_stat = in_le32(&pb->planb_base->ch2.status); pstat.saa_stat0 = saa_status(0, pb); pstat.saa_stat1 = saa_status(1, pb); if(copy_to_user((void *)arg, (void *)&pstat, sizeof(pstat))) return -EFAULT; return 0; } case PLANBIOCSMODE: { int v; DEBUG("PlanB: IOCTL PLANBIOCSMODE\n"); if(copy_from_user(&v, arg, sizeof(v))) return -EFAULT; switch(v) { case PLANB_TV_MODE: saa_set (SAA7196_STDC, (saa_regs[pb->win.norm][SAA7196_STDC] & 0x7f), pb); break; case PLANB_VTR_MODE: saa_set (SAA7196_STDC, (saa_regs[pb->win.norm][SAA7196_STDC] | 0x80), pb); break; default: return -EINVAL; break; } pb->win.mode = v; return 0; } case PLANBIOCGMODE: { int v=pb->win.mode; DEBUG("PlanB: IOCTL PLANBIOCGMODE\n"); if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; }#ifdef PLANB_GSCANLINE case PLANBG_GRAB_BPL: { int v=pb->gbytes_per_line; DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n"); if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; }#endif /* PLANB_GSCANLINE */ case PLANB_INTR_DEBUG: { int i; DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n"); if(copy_from_user(&i, arg, sizeof(i))) return -EFAULT; /* avoid hang ups all together */ for (i = 0; i < MAX_GBUFFERS; i++) { if(pb->frame_stat[i] == GBUFFER_GRABBING) { pb->frame_stat[i] = GBUFFER_DONE; } } if(pb->grabbing) pb->grabbing--; wake_up_interruptible(&pb->capq); return 0; } case PLANB_INV_REGS: { int i; struct planb_any_regs any; DEBUG("PlanB: IOCTL PLANB_INV_REGS\n"); if(copy_from_user(&any, arg, sizeof(any))) return -EFAULT; if(any.offset < 0 || any.offset + any.bytes > 0x400) return -EINVAL; if(any.bytes > 128) return -EINVAL; for (i = 0; i < any.bytes; i++) { any.data[i] = in_8((unsigned char *)pb->planb_base + any.offset + i); } if(copy_to_user(arg,&any,sizeof(any))) return -EFAULT; return 0; } default: { DEBUG("PlanB: Unimplemented IOCTL\n"); return -ENOIOCTLCMD; } /* Some IOCTLs are currently unsupported on PlanB */ case VIDIOCGTUNER: { DEBUG("PlanB: IOCTL VIDIOCGTUNER\n"); goto unimplemented; } case VIDIOCSTUNER: { DEBUG("PlanB: IOCTL VIDIOCSTUNER\n"); goto unimplemented; } case VIDIOCSFREQ: { DEBUG("PlanB: IOCTL VIDIOCSFREQ\n"); goto unimplemented; } case VIDIOCGFREQ: { DEBUG("PlanB: IOCTL VIDIOCGFREQ\n"); goto unimplemented; } case VIDIOCKEY: { DEBUG("PlanB: IOCTL VIDIOCKEY\n"); goto unimplemented; } case VIDIOCSAUDIO: { DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n"); goto unimplemented; } case VIDIOCGAUDIO: { DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n"); goto unimplemented; }unimplemented: DEBUG(" Unimplemented\n"); return -ENOIOCTLCMD; } return 0;}static int planb_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size){ int i; struct planb *pb = (struct planb *)dev; unsigned long start = (unsigned long)adr; if (size > MAX_GBUFFERS * PLANB_MAX_FBUF) return -EINVAL; if (!pb->rawbuf) { int err; if((err=grabbuf_alloc(pb))) return err; } for (i = 0; i < pb->rawbuf_size; i++) { unsigned long pfn; pfn = virt_to_phys((void *)pb->rawbuf[i]) >> PAGE_SHIFT; if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; start += PAGE_SIZE; if (size <= PAGE_SIZE) break; size -= PAGE_SIZE; } return 0;}static struct video_device planb_template={ .owner = THIS_MODULE, .name = PLANB_DEVICE_NAME, .type = VID_TYPE_OVERLAY, .hardware = VID_HARDWARE_PLANB, .open = planb_open, .close = planb_close, .read = planb_read, .write = planb_write, .ioctl = planb_ioctl, .mmap = planb_mmap, /* mmap? */};static int init_planb(struct planb *pb){ unsigned char saa_rev; int i, result; memset ((void *) &pb->win, 0, sizeof (struct planb_window)); /* Simple sanity check */ if(def_norm >= NUM_SUPPORTED_NORM || def_norm < 0) { printk(KERN_ERR "PlanB: Option(s) invalid\n"); return -2; } pb->win.norm = def_norm; pb->win.mode = PLANB_TV_MODE; /* TV mode */ pb->win.interlace=1; pb->win.x=0; pb->win.y=0; pb->win.width=768; /* 640 */ pb->win.height=576; /* 480 */ pb->maxlines=576;#if 0 btv->win.cropwidth=768; /* 640 */ btv->win.cropheight=576; /* 480 */ btv->win.cropx=0; btv->win.cropy=0;#endif pb->win.pad=0; pb->win.bpp=4; pb->win.depth=32; pb->win.color_fmt=PLANB_COLOUR32; pb->win.bpl=1024*pb->win.bpp; pb->win.swidth=1024; pb->win.sheight=768;#ifdef PLANB_GSCANLINE if((pb->gbytes_per_line = PLANB_MAXPIXELS * 4) > PAGE_SIZE || (pb->gbytes_per_line <= 0)) return -3; else { /* page align pb->gbytes_per_line for DMA purpose */ for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);) i>>=1; pb->gbytes_per_line = i; }#endif pb->tab_size = PLANB_MAXLINES + 40; pb->suspend = 0; init_MUTEX(&pb->lock); pb->ch1_cmd = 0; pb->ch2_cmd = 0; pb->mask = 0; pb->priv_space = 0; pb->offset = 0; pb->user = 0; pb->overlay = 0; init_waitqueue_head(&pb->suspendq); pb->cmd_buff_inited = 0; pb->frame_buffer_phys = 0; /* Reset DMA controllers */ planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); saa_rev = (saa_status(0, pb) & 0xf0) >> 4; printk(KERN_INFO "PlanB: SAA7196 video processor rev. %d\n", saa_rev); /* Initialize the SAA registers in memory and on chip */ saa_init_regs (pb); /* clear interrupt mask */ pb->intr_mask = PLANB_CLR_IRQ; result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb); if (result < 0) { if (result==-EINVAL) printk(KERN_ERR "PlanB: Bad irq number (%d) " "or handler\n", (int)pb->irq); else if (result==-EBUSY) printk(KERN_ERR "PlanB: I don't know why, " "but IRQ %d is busy\n", (int)pb->irq); return result; } disable_irq(pb->irq); /* Now add the template and register the device unit. */ memcpy(&pb->video_dev,&planb_template,sizeof(planb_template)); pb->picture.brightness=0x90<<8; pb->picture.contrast = 0x70 << 8; pb->picture.colour = 0x70<<8; pb->picture.hue = 0x8000; pb->picture.whiteness = 0; pb->picture.depth = pb->win.depth; pb->frame_stat=NULL; init_waitqueue_head(&pb->capq); for(i=0; i<MAX_GBUFFERS; i++) { pb->gbuf_idx[i] = PLANB_MAX_FBUF * i / PAGE_SIZE; pb->gwidth[i]=0; pb->gheight[i]=0; pb->gfmt[i]=0; pb->cap_cmd[i]=NULL;#ifndef PLANB_GSCANLINE pb->l_fr_addr_idx[i] = MAX_GBUFFERS * (PLANB_MAX_FBUF / PAGE_SIZE + 1) + MAX_LNUM * i; pb->lsize[i] = 0; pb->lnum[i] = 0;#endif } pb->rawbuf=NULL; pb->grabbing=0; /* enable interrupts */ out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); pb->intr_mask = PLANB_FRM_IRQ; enable_irq(pb->irq); if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER, video_nr)<0) return -1; return 0;}/* * Scan for a PlanB controller, request the irq and map the io memory */static int find_planb(void){ struct planb *pb; struct device_node *planb_devices; unsigned char dev_fn, confreg, bus; unsigned int old_base, new_base; unsigned int irq; struct pci_dev *pdev; int rc; if (_machine != _MACH_Pmac) return 0; planb_devices = find_devices("planb"); if (planb_devices == 0) { planb_num=0; printk(KERN_WARNING "PlanB: no device found!\n"); return planb_num; } if (planb_devices->next != NULL) printk(KERN_ERR "Warning: only using first PlanB device!\n"); pb = &planbs[0]; planb_num = 1; if (planb_devices->n_addrs != 1) { printk (KERN_WARNING "PlanB: expecting 1 address for planb " "(got %d)", planb_devices->n_addrs); return 0; } if (planb_devices->n_intrs == 0) { printk(KERN_WARNING "PlanB: no intrs for device %s\n", planb_devices->full_name); return 0; } else { irq = planb_devices->intrs[0].line; } /* Initialize PlanB's PCI registers */ /* There is a bug with the way OF assigns addresses to the devices behind the chaos bridge. control needs only 0x1000 of space, but decodes only the upper 16 bits. It therefore occupies a full 64K. OF assigns the planb controller memory within this space; so we need to change that here in order to access planb. */ /* We remap to 0xf1000000 in hope that nobody uses it ! */ bus = (planb_devices->addrs[0].space >> 16) & 0xff; dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff; confreg = planb_devices->addrs[0].space & 0xff; old_base = planb_devices->addrs[0].address; new_base = 0xf1000000; DEBUG("PlanB: Found on bus %d, dev %d, func %d, " "membase 0x%x (base reg. 0x%x)\n", bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg); pdev = pci_find_slot (bus, dev_fn); if (!pdev) { printk(KERN_ERR "planb: cannot find slot\n"); goto err_out; } /* Enable response in memory space, bus mastering, use memory write and invalidate */ rc = pci_enable_device(pdev); if (rc) { printk(KERN_ERR "planb: cannot enable PCI device %s\n", pci_name(pdev)); goto err_out; } rc = pci_set_mwi(pdev); if (rc) { printk(KERN_ERR "planb: cannot enable MWI on PCI device %s\n", pci_name(pdev)); goto err_out_disable; } pci_set_master(pdev); /* Set the new base address */ pci_write_config_dword (pdev, confreg, new_base); planb_regs = (volatile struct planb_registers *) ioremap (new_base, 0x400); pb->planb_base = planb_regs; pb->planb_base_phys = (struct planb_registers *)new_base; pb->irq = irq; return planb_num;err_out_disable: pci_disable_device(pdev);err_out: /* FIXME handle error */ /* comment moved from pci_find_slot, above */ return 0;}static void release_planb(void){ int i; struct planb *pb; for (i=0;i<planb_num; i++) { pb=&planbs[i]; /* stop and flash DMAs unconditionally */ planb_dbdma_stop(&pb->planb_base->ch2); planb_dbdma_stop(&pb->planb_base->ch1); /* clear and free interrupts */ pb->intr_mask = PLANB_CLR_IRQ; out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ); free_irq(pb->irq, pb); /* make sure all allocated memory are freed */ planb_prepare_close(pb); printk(KERN_INFO "PlanB: unregistering with v4l\n"); video_unregister_device(&pb->video_dev); /* note that iounmap() does nothing on the PPC right now */ iounmap ((void *)pb->planb_base); }}static int __init init_planbs(void){ int i; if (find_planb()<=0) return -EIO; for (i=0; i<planb_num; i++) { if (init_planb(&planbs[i])<0) { printk(KERN_ERR "PlanB: error registering device %d" " with v4l\n", i); release_planb(); return -EIO; } printk(KERN_INFO "PlanB: registered device %d with v4l\n", i); } return 0;}static void __exit exit_planbs(void){ release_planb();}module_init(init_planbs);module_exit(exit_planbs);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -