📄 patch-linux-2.4.22-qcamvc-1.0.6
字号:
++ if (!qcamvc->frame_buf) {+ if ((retval = allocate_frame_buf(qcamvc))) {+ return 0;+ }+ }+ + pos = (unsigned long)(qcamvc->frame_buf);+ while (size > 0) {+ page = kvirt_to_pa(pos);+ if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {+ up(&qcamvc->busy);+ return -EAGAIN;+ }+ start += PAGE_SIZE;+ pos += PAGE_SIZE;+ if (size > PAGE_SIZE)+ size -= PAGE_SIZE;+ else+ size = 0;+ }+ up(&qcamvc->busy);+ return 0;+ +}+/**********************************************************************+ *+ * Memory management+ *+ * This is a shameless copy from the USB-cpia driver (linux kernel+ * version 2.3.29 or so, I have no idea what this code actually does ;).+ * Actually it seems to be a copy of a shameless copy of the bttv-driver.+ * Or that is a copy of a shameless copy of ... (To the powers: is there+ * no generic kernel-function to do this sort of stuff?)+ *+ * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says+ * there will be one, but apparentely not yet - jerdfelt+ *+ **********************************************************************/++/* Given PGD from the address space's page table, return the kernel+ * virtual mapping of the physical memory mapped at ADR.+ */+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)+{+ unsigned long ret = 0UL;+ pmd_t *pmd;+ pte_t *ptep, pte;+ + if (!pgd_none(*pgd)) {+ pmd = pmd_offset(pgd, adr);+ if (!pmd_none(*pmd)) {+ ptep = pte_offset(pmd, adr);+ pte = *ptep;+ if (pte_present(pte)) {+ ret = (unsigned long) page_address(pte_page(pte));+ ret |= (adr & (PAGE_SIZE-1));+ }+ }+ }+ return ret;+}++#if LINUX_VERSION_CODE < 0x020400+#define virt_to_page(kaddr) (MAP_NR(kaddr))+#endif++static void *rvmalloc(unsigned long size)+{+ void *mem;+ unsigned long adr, page;+ size += (PAGE_SIZE - 1);+ size &= ~(PAGE_SIZE - 1);++ mem = vmalloc_32(size);+ if (!mem)+ return NULL;++ memset(mem, 0, size);+ adr = (unsigned long) mem;+ while (size > 0) {+ page = kvirt_to_pa(adr);+ mem_map_reserve(virt_to_page(__va(page)));+ adr += PAGE_SIZE;+ if (size > PAGE_SIZE)+ size -= PAGE_SIZE;+ else+ size = 0;+ }++ return mem;+}++static void rvfree(void *mem, unsigned long size)+{+ unsigned long adr, page;+ if (!mem)+ return;+ + size += (PAGE_SIZE - 1);+ size &= ~(PAGE_SIZE - 1);+ + adr = (unsigned long) mem;+ while (size > 0) {+ page = kvirt_to_pa(adr);+ mem_map_unreserve(virt_to_page(__va(page)));+ adr += PAGE_SIZE;+ if (size > PAGE_SIZE)+ size -= PAGE_SIZE;+ else+ size = 0;+ }+ vfree(mem);+}++static int allocate_frame_buf(struct qcamvc *qcamvc)+{+ int i;+ qcamvc->frame_buf = rvmalloc(QUICKCAM_NUMFRAMES * QUICKCAM_MAX_SIZE);+ if (!qcamvc->frame_buf)+ return -ENOBUFS;+ + for (i = 0; i < QUICKCAM_NUMFRAMES; i++)+ qcamvc->frame[i].data = qcamvc->frame_buf + i * QUICKCAM_MAX_SIZE;+ + return 0;+}++static int free_frame_buf(struct qcamvc *qcamvc)+{+ int i;+ + rvfree(qcamvc->frame_buf, QUICKCAM_NUMFRAMES * QUICKCAM_MAX_SIZE);+ qcamvc->frame_buf = 0;+ for (i=0; i < QUICKCAM_NUMFRAMES; i++)+ qcamvc->frame[i].data = NULL;+ return 0;+}++static void inline free_frames(struct qcamvc_frame frame[QUICKCAM_NUMFRAMES])+{+ int i;++ for (i=0; i < QUICKCAM_NUMFRAMES; i++)+ frame[i].state = FRAME_UNUSED;+ return;+}++/* Here we want the physical address of the memory.+ * This is used when initializing the contents of the+ * area and marking the pages as reserved.+ */+static inline unsigned long kvirt_to_pa(unsigned long adr)+{+ unsigned long va, kva, ret;+ + va = VMALLOC_VMADDR(adr);+ kva = uvirt_to_kva(pgd_offset_k(va), va);+ ret = __pa(kva);+ return ret;+}++#endif /* USE_MMAP */++static int qcamvc_vioctl(struct video_device *dev, unsigned int cmd, void *arg)+{+ struct qcamvc *qcamvc = dev->priv;++ if (down_interruptible(&qcamvc->busy))+ return -EINTR;+++ switch(cmd)+ {+ + /* Return capability */+ case VIDIOCGCAP:+ {+ if (copy_to_user(arg, &qcamvc->vcap, sizeof(struct video_capability)))+ {+ up(&qcamvc->busy);+ return -EFAULT;+ }+ up(&qcamvc->busy);+ return 0;+ }+ + /* Video channel ioctl */+ case VIDIOCGCHAN:+ {+ if (copy_to_user(arg, &qcamvc->vchan, sizeof(struct video_channel)))+ {+ up(&qcamvc->busy);+ return -EFAULT;+ }+ up(&qcamvc->busy);+ return 0;+ }+ + case VIDIOCSCHAN:+ {+ int v;+ if(copy_from_user(&v, arg,sizeof(int)))+ {+ up(&qcamvc->busy);+ return -EFAULT;+ }+ if(v!=0)+ {+ up(&qcamvc->busy);+ return -EINVAL;+ }+ up(&qcamvc->busy);+ return 0;+ }+ + /* Video picture ioctl */+ case VIDIOCGPICT:+ {+ if (copy_to_user(arg, &qcamvc->vpic, sizeof(struct video_picture)))+ {+ up(&qcamvc->busy);+ return -EFAULT;+ }+ up(&qcamvc->busy); + return 0;+ }+ + case VIDIOCSPICT:+ {+ struct video_picture p;+ + if(copy_from_user(&p, arg, sizeof(struct video_picture)))+ {+ up(&qcamvc->busy);+ return -EFAULT;+ }+ + if (p.depth != 24 || p.palette != VIDEO_PALETTE_RGB24)+ {+ up(&qcamvc->busy);+ return -EINVAL;+ }+ + if (p.brightness >> 8 != qcamvc->brightness)+ {+ qcamvc->brightness = p.brightness >> 8;+ qcamvc_set_brightness(qcamvc,qcamvc->brightness);+ }+ + if (p.whiteness >> 8 != qcamvc->exposure)+ {+ qcamvc->exposure = p.whiteness >> 8;+ qcamvc_set_exposure(qcamvc,qcamvc->exposure);+ }+ + if (p.contrast != qcamvc->vpic.contrast)+ {+ qcamvc->blue_hue = p.contrast >> 8;+ qcamvc->hue_calc=0;+ }++ if (p.hue != qcamvc->vpic.hue)+ {+ qcamvc->red_hue = p.hue >> 8;+ qcamvc->hue_calc=0;+ }++ if (p.colour != qcamvc->vpic.colour)+ {+ qcamvc->santrast = p.colour >> 8;+ qcamvc->hue_calc=0;+ }+ + qcamvc->vpic = p;++ up(&qcamvc->busy);+ return 0;+ }+ + /* Capture window ioctl */+ case VIDIOCSWIN:+ {+ struct video_window vw;+ int res = qcamvc->res;+ + if(copy_from_user(&vw, arg,sizeof(struct video_window)))+ {+ up(&qcamvc->busy);+ return -EFAULT;+ }+ + if(vw.flags)+ {+ printk("1\n");+ up(&qcamvc->busy);+ return -EINVAL;+ }+ + if(vw.clipcount)+ {+ printk("2\n");+ up(&qcamvc->busy);+ return -EINVAL;+ }+ + if(vw.height<MIN_HEIGHT || vw.height>MAX_HEIGHT)+ {+ printk("Want to set %dx%d 3\n",vw.width, vw.height);+ up(&qcamvc->busy);+ return -EINVAL;+ }+ + if(vw.width<MIN_WIDTH || vw.width>MAX_WIDTH)+ {+ printk("Want to set %dx%d 4\n",vw.width, vw.height);+ up(&qcamvc->busy);+ return -EINVAL;+ }++ if(vw.width>=160 && vw.height>=120)+ {+ res=R160x120;+ }+ if(vw.width>=176 && vw.height>=144)+ {+ res=R176x144;+ }+ if(vw.width>=320 && vw.height>=240)+ {+ res=R320x240;+ }+ if(vw.width>=352 && vw.height>=288)+ {+ res=R352x288;+ }+ qcamvc_set_res(qcamvc, res);+ up(&qcamvc->busy);+ return 0;+ }+ + case VIDIOCGWIN:+ {+ struct video_window vw;+ + memset(&vw, 0, sizeof(struct video_window));+ vw.width = qcamvc->width;+ vw.height = qcamvc->height;+ vw.flags = 0;+ + if(copy_to_user(arg, &vw, sizeof(struct video_window)))+ {+ up(&qcamvc->busy);+ return -EFAULT;+ }+ up(&qcamvc->busy);+ return 0;+ }+#ifdef USE_MMAP + /* mmap interface */+ case VIDIOCGMBUF:+ {+ struct video_mbuf vm;+ int i;+ + memset(&vm, 0, sizeof(struct video_mbuf));+ vm.size = qcamvc->width * qcamvc->height *+ 3 * QUICKCAM_NUMFRAMES;+ vm.frames = QUICKCAM_NUMFRAMES;+ + for (i = 0; i < QUICKCAM_NUMFRAMES ; i++)+ vm.offsets[i] = qcamvc->width * qcamvc->height *+ 3 * i;+ + if (copy_to_user((void *)arg, (void *)&vm, sizeof(struct video_mbuf)))+ {+ up(&qcamvc->busy);+ return -EFAULT;+ }+ up(&qcamvc->busy);+ return 0;+ }+ + case VIDIOCSYNC:+ {+ int frame;+ + if (copy_from_user((void *)&frame, arg, sizeof(int)))+ {+ up(&qcamvc->busy);+ return -EFAULT;+ }+ + if (frame<0 || frame >= QUICKCAM_NUMFRAMES )+ {+ up(&qcamvc->busy);+ return -EINVAL;+ }+ + switch (qcamvc->frame[frame].state) + {+ case FRAME_UNUSED:+ case FRAME_READY:+ case FRAME_GRABBING:+ {+ printk("sync to unused frame %d\n", frame);+ up(&qcamvc->busy);+ return -EINVAL;+ }+ + case FRAME_DONE:+ qcamvc->frame[frame].state = FRAME_UNUSED;+ }+ up(&qcamvc->busy);+ return 0;+ }+ + case VIDIOCMCAPTURE:+ {+ struct video_mmap vm;+ + if (copy_from_user((void *)&vm, (void *)arg, sizeof(struct video_mmap)))+ {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -