📄 qcamvc.c
字号:
printk("QuickCam VC:8bpc bigbuffer read, len=%d, ",sizeof(buffer)); for (i=1 ; i < BIGBUFFER_SIZE ; i+=2) { if (a != *(bigbuffer + i)) { printk (" 0x%02x ", *(bigbuffer + i)); a=*(bigbuffer + i);} } printk("\n"); //buffer[0]=0x00; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0e, buffer, 1); //buffer[0]=0x00; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_SET_MISC, buffer, 1); //buffer[0]=0x78; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0f, buffer, 1); //buffer[0]=0x00; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_SET_MISC, buffer, 1); //buffer[0]=0x58; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0f, buffer, 1); //qcamvc_set_brightness(qcamvc, qcamvc->brightness); //qcamvc_set_exposure(qcamvc, qcamvc->exposure); //buffer[0]=0x11; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0a, buffer, 1); //buffer[0]=0x11; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0a, buffer, 1); qcamvc_set_topmost_row (qcamvc, firstrow[qcamvc->res]); qcamvc_set_leftmost_column (qcamvc, firstcolumn[qcamvc->res]); qcamvc_set_bottommost_row (qcamvc, lastrow[qcamvc->res]); qcamvc_set_rightmost_column(qcamvc, lastcolumn[qcamvc->res]); buffer[0] = mulfactor[qcamvc->res]; qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, 0x0a, buffer, 1); printk("h\n"); kfree(bigbuffer); return 0;}static int qcamvc_camera_init(struct qcamvc *qcamvc){ FIRST_ROW; LAST_ROW; FIRST_COL; LAST_COL; MUL_FACTOR; ISO_LEN; int ret=-1; switch(qcamvc->bpc) { case bpc6: { ret = bpc6_init(qcamvc); break; } case bpc8: { ret = bpc8_init(qcamvc); break; } } qcamvc->packet_len = iso_len[qcamvc->bpc][qcamvc->res]; qcamvc->height = lastrow[qcamvc->res] - firstrow[qcamvc->res]; qcamvc->width = lastcolumn[qcamvc->res] - firstcolumn[qcamvc->res]; if (!(mulfactor[qcamvc->res] & 0x02)) { qcamvc->height*=2; qcamvc->width*=2; } qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, QCAM_VC_GET_FRAME, NULL, 0); qcamvc->streaming=1; qcamvc->hue_calc=0;#ifdef DBG_CAM printk("QuickCam VC:Init at %dx%d\n", qcamvc->width, qcamvc->height);#endif return ret;}static void bpc6_parse(struct qcamvc *qcamvc, unsigned char *inbuf, unsigned char *outbuf, size_t count){ size_t i,q; unsigned char *temp=kmalloc(qcamvc->width*qcamvc->height, GFP_KERNEL); for( i = q = 0 ; i < qcamvc->width * qcamvc->height; i+=4,q+=3 ) { if ((q + 2) < qcamvc->packet_len) *(temp+i+3) = *((inbuf+2) + q + 2) & 0xfc; if ((q + 2) < qcamvc->packet_len) *(temp+i+2) = (((*((inbuf+2) + q + 1) >> 4) & 0x0f)|((*((inbuf+2)+ q + 2) <<4) & 0x30))<<2; if ((q + 1) < qcamvc->packet_len) *(temp+i+1) = (((*((inbuf+2) + q)>>6)&0x03)|((*((inbuf+2)+ q + 1)&0x0f)<<2))<<2; if (q < qcamvc->packet_len) *(temp+i+0) = (*((inbuf+2) + q)&0x3f)<<2; } codec(qcamvc, temp, outbuf); kfree(temp);}static void bpc8_parse(struct qcamvc *qcamvc, unsigned char *inbuf, unsigned char *outbuf, size_t count){ unsigned char *temp=kmalloc(qcamvc->width*qcamvc->height, GFP_KERNEL); memcpy(outbuf, inbuf, qcamvc->packet_len); kfree(temp);}static void qcamvc_parse(struct qcamvc *qcamvc, unsigned char *inbuf, unsigned char *outbuf, size_t count){ switch(qcamvc->bpc) { case bpc6: { bpc6_parse(qcamvc, inbuf, outbuf, count); break; } case bpc8: { bpc8_parse(qcamvc, inbuf, outbuf, count); break; } }}static int qcamvc_set_res(struct qcamvc *qcamvc, int res){ if (res == qcamvc->res) return -1; qcamvc->res = res; qcamvc_camera_init(qcamvc); return qcamvc->res;}/**************************************************************************** * * /proc interface * ***************************************************************************/#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)static struct proc_dir_entry *qcamvc_proc_entry = NULL;extern struct proc_dir_entry *video_proc_entry;#define YES_NO(x) ((x) ? "yes" : "no")/****************************************************************************/static int qcamvc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ char *out = page; int len; struct qcamvc *qcamvc = data; // Stay under PAGE_SIZE or bad things will happen :( out+=sprintf(out, "driver_version : %s\n", QCAMVCVERSION); out+=sprintf(out, "model : %s\n", qcamvc->vcap.name); out+=sprintf(out, "max resolution : %dx%d\n", qcamvc->vcap.maxwidth, qcamvc->vcap.maxheight); out+=sprintf(out, "min resolution : %dx%d\n\n", qcamvc->vcap.minwidth, qcamvc->vcap.minheight); out+=sprintf(out, "Settings\n"); out+=sprintf(out, "resolution : %dx%d\n", qcamvc->width, qcamvc->height); out+=sprintf(out, "bit per component: %d\n", (qcamvc->bpc==bpc6)? 6 : 8); out+=sprintf(out, "brightness : %d\n", qcamvc->brightness); out+=sprintf(out, "exposure : %d\n", (int)qcamvc->exposure); out+=sprintf(out, "red hue : %d\n", (int)qcamvc->red_hue); out+=sprintf(out, "blue hue : %d\n", (int)qcamvc->blue_hue); out+=sprintf(out, "santrast : %d\n", (int)qcamvc->santrast); out+=sprintf(out, "\n"); len = out - page; len -= off; if (len < count) { *eof = 1; if (len <= 0) return 0; } else len = count; *start = page + off; return len; }/****************************************************************************/static int qcamvc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data){ return -EINVAL;}/*************************************************************************** This routine is called when a quickcam is registered*/static void create_proc_qcamvc (struct qcamvc *qcamvc){ char name[7]; struct proc_dir_entry *ent; printk("Quickcam VC: Creating a camera entry in proc quickcam.\n"); printk("Quickcam dev struct in create_proc_qcamvc %p\n",qcamvc); if (!qcamvc_proc_entry || !qcamvc) return; sprintf (name, "video%d", qcamvc->vdev.minor); ent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, qcamvc_proc_entry); if (!ent) return; ent->data = qcamvc; ent->read_proc = qcamvc_read_proc; ent->write_proc = qcamvc_write_proc; qcamvc->proc_entry = ent;}/*************************************************************************** This routine is called when a quickcam is unregistered */static void destroy_proc_qcamvc (struct qcamvc *qcamvc){ /* One to much, just to be sure :) */ char name[9]; printk("Quickcam VC: Destroying a camera entry in proc quickcam.\n"); if (!qcamvc || !qcamvc->proc_entry) return; sprintf(name, "video%d", qcamvc->vdev.minor); remove_proc_entry(name, qcamvc_proc_entry); qcamvc->proc_entry = NULL;}/*************************************************************************** This routine is called when the driver is placed in memory* by an insmod.*/static void proc_qcamvc_create(void){ printk("QuickCam VC: Making a quickcam directory in /proc.\n"); if (video_proc_entry == NULL) { printk("/proc/video/ doesn't exist"); return; } qcamvc_proc_entry=create_proc_entry("qcamvc", S_IFDIR, video_proc_entry); if (qcamvc_proc_entry) qcamvc_proc_entry->owner = THIS_MODULE; else printk("Unable to initialize /proc/video/qcamvc");}/*************************************************************************** This routine is called when the driver is removed from memory* by an rmmod command.*/static void proc_quickcam_destroy(void){ printk("Quickcam VC: Destroying a quickcam directory in /proc.\n"); if (qcamvc_proc_entry == NULL) return; remove_proc_entry("qcamvc", video_proc_entry);}#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS *//****************************************************************************/static int qcamvc_init_done(struct video_device *dev){ #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) create_proc_qcamvc(dev->priv); printk("qcamvc dev struct in qcamvc_init_done %p\n",dev); #endif return 0;}/*****************************************************************************//* *//* Video 4 Linux *//* *//* *//*****************************************************************************/static long qcamvc_vread(struct video_device *dev, char *buf, unsigned long count, int noblock){ struct qcamvc *qcamvc = dev->priv; unsigned char *tempbuf = kmalloc(qcamvc->packet_len, GFP_KERNEL); if (down_interruptible(&qcamvc->busy)) return -EINTR; if (!buf) { up(&qcamvc->busy); return -EINVAL; } if (!count) { up(&qcamvc->busy); return 0; } if (!qcamvc->ops) { up(&qcamvc->busy); return -ENODEV; }#ifdef DBG_CAM printk("USB QuickCam quickcam_read count=%ld\n",count);#endif qcamvc->ops->qcamvc_stream_read(qcamvc->lowlevel_data, tempbuf, qcamvc->packet_len); qcamvc_parse(qcamvc, tempbuf, buf, count); kfree(tempbuf); up(&qcamvc->busy); return count;}static long qcamvc_vwrite(struct video_device *dev, const char *buf, unsigned long count, int noblock){ struct qcamvc *qcamvc = dev->priv; if (down_interruptible(&qcamvc->busy)) return -EINTR; up(&qcamvc->busy); return -EINVAL;}#ifdef USE_MMAPstatic int qcamvc_vmmap(struct video_device *dev, const char *adr, unsigned long size){ unsigned long start = (unsigned long) adr; unsigned long page, pos; int retval; struct qcamvc *qcamvc = dev->priv; if (down_interruptible(&qcamvc->busy)) return -EINTR; 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))#endifstatic 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -