📄 qcamvc.c
字号:
qcamvc->hue = val; err=0; } else if (MATCH("colour") && (val <= 255)) { qcamvc->saturation = val; err=0; } else if (MATCH("bpc")) { if ((val == 6) || (val == 8)) { qcamvc->bpc = val; qcamvc_camera_init(qcamvc); err=0; } else { printk("Invalid Range: bpc can only be 6 or 8\n"); } } else if (MATCH("flipbgr")) { if (val == 0 || val == 1) { qcamvc->flip_bgr = val; err = 0; } else { printk("Invalid setting: flipbgr can only be 0 or 1\n"); } } else if (MATCH("compression"))// && (val <= 255)) { qcamvc->compression=val; qcamvc_camera_init(qcamvc); err=0; } else if (MATCH("sensitivity") && (val <= 255)) { qcamvc->light_sens=val; qcamvc_set_light_sensitivity(qcamvc,qcamvc->light_sens); err=0; } if (!err) printk("Set: %s=%i\n", name, val); else printk("Couldn't Set: %s=%i\n", name, val);#undef MATCH up(&qcamvc->busy_lock);}/* copied from zoran_procfs */static int qcamvc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data){ char *string, *sp; char *line, *ldelim, *varname, *svar, *tdelim; struct qcamvc_data* qcamvc = (struct qcamvc_data*) data; string = sp = vmalloc(count + 1); if (!string) { printk("write_proc: can not allocate memory\n"); return -ENOMEM; } if (copy_from_user(string, buffer, count)) { vfree (string); return -EFAULT; } string[count] = 0; ldelim = " \t\n"; tdelim = "="; line = strpbrk(sp, ldelim); while (line) { *line = 0; svar = strpbrk(sp, tdelim); if (svar) { *svar = 0; varname = sp; svar++; setparam(qcamvc, varname, svar); } sp = line + 1; line = strpbrk(sp, ldelim); } vfree(string); return count;}static void create_proc_qcamvc_cam(struct qcamvc_data *qcamvc){ char name[8]; struct proc_dir_entry *ent; if (!qcamvc_proc_root || !qcamvc) return; printk(KERN_INFO "QuickCam VC: Creating a camera entry in /proc/qcamvc\n"); //printk("QuickCam VC: QuickCam dev struct in create_proc_qcamvc %p\n",qcamvc); sprintf(name, "video%d", qcamvc->vdev->minor); ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, qcamvc_proc_root); if (!ent) { printk(KERN_ERR "QuickCam VC: couldn't create /proc/qcamvc/%s\n", name); return; } ent->data = qcamvc; ent->read_proc = qcamvc_read_proc; ent->write_proc = qcamvc_write_proc; ent->size = 0; qcamvc->proc_entry = ent;}static void destroy_proc_qcamvc_cam(struct qcamvc_data *qcamvc){ char name[8]; if (!qcamvc || !qcamvc->proc_entry) return; sprintf(name, "video%d", qcamvc->vdev->minor); remove_proc_entry(name, qcamvc_proc_root); qcamvc->proc_entry = NULL;}static void proc_qcamvc_create(void){ qcamvc_proc_root = create_proc_entry("qcamvc", S_IFDIR, 0); if (qcamvc_proc_root) qcamvc_proc_root->owner = THIS_MODULE; else LOG("Unable to initialise /proc/qcamvc\n");}static void __exit proc_qcamvc_destroy(void){ remove_proc_entry("qcamvc", 0);}#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS *//*****************************************************************************//* *//* Video 4 Linux *//* *//*****************************************************************************/static int qcamvc_vopen(struct inode *inode, struct file *file){ struct video_device *dev = video_devdata(file); struct qcamvc_data *qcamvc = (struct qcamvc_data *)dev->priv;#ifdef DBG_CAM printk("QuickCam qcamvc_vopen:\n");#endif if (!qcamvc) { printk("Internal error, qcamvc_data not found!\n"); return -ENODEV; } if (qcamvc->open_count > 0) { printk("Camera already open\n"); return -EBUSY; } if (!try_module_get(qcamvc->ops->owner)) { printk("qcamvc_vopen: try_module_get() FAILED\n"); return -ENODEV; } /* Init the frame buffers to nothing */ qcamvc->curframe = 0; qcamvc->frame_count = 0; qcamvc->frame_waiting = 0; free_frame_buf(qcamvc); if (qcamvc->ops->qcamvc_open(qcamvc->lowlevel_data)) return -ENODEV; /* if the camera hasn't already been initialised, do it now */ if (!qcamvc->camera_init) { if (qcamvc_camera_init(qcamvc) == -1) return -ENODEV; } /* Set ownership of /proc/qcamvc/videoX to current user */ if(qcamvc->proc_entry) qcamvc->proc_entry->uid = current->uid; file->private_data = dev; qcamvc->open_count++; return 0;}static int qcamvc_vrelease(struct inode *inode, struct file *file){ struct video_device *dev = video_devdata(file); struct qcamvc_data *qcamvc = (struct qcamvc_data *)dev->priv; if (qcamvc->ops) { /* Return ownership of /proc/qcamvc/videoX to root */ if(qcamvc->proc_entry) qcamvc->proc_entry->uid = 0; qcamvc->ops->qcamvc_close(qcamvc->lowlevel_data); put_cam(qcamvc->ops); } if (--qcamvc->open_count == 0) { free_frame_buf(qcamvc); free_raw_frame(qcamvc); if (!qcamvc->ops) kfree(qcamvc); } file->private_data = NULL; return 0;}static ssize_t qcamvc_vread(struct file *file, char *data, size_t count, loff_t *ppos){ if (!file) return -EINVAL; struct video_device *dev = file->private_data; struct qcamvc_data *qcamvc = dev->priv; char *tmpbuf; if (!qcamvc || !data || !count) return -EINVAL; if ( ((qcamvc->colordepth / 8) * qcamvc->width * qcamvc->height) > count ) { printk("QuickCam VC: Image buffer (%ld) too small for bit count (%d bites, %d bytes required). Forcing to 24bit.\n", count, qcamvc->colordepth, (qcamvc->colordepth / 8) * qcamvc->width * qcamvc->height); /* force it to 24. If it still fails next time, there's not much we can do about it. */ qcamvc->colordepth = 24; qcamvc->pixelformat = V4L2_PIX_FMT_RGB24; return -EFAULT; } if (down_interruptible(&qcamvc->busy_lock)) return -EINTR; /* grab a raw frame from the camera */ if (send_grab_image(qcamvc, 1)) { up(&qcamvc->busy_lock); return 0; } count = get_raw_frame(qcamvc); if (count < 0) { /* error or no data from camera? */ up(&qcamvc->busy_lock); return 0; } /* convert the raw CMYG image to something usable */ count = qcamvc->colordepth / 8 * qcamvc->width * qcamvc->height; tmpbuf = vmalloc(count); if (!tmpbuf) { printk("QCamVC: Could not allocate %ld bytes\n", count); count = -ENOMEM; } else { qcamvc_parse(qcamvc, tmpbuf); if (copy_to_user(data, tmpbuf, count)) count = -EFAULT; vfree(tmpbuf); } up(&qcamvc->busy_lock); return count;}static int qcamvc_vmmap(struct file *file, struct vm_area_struct *vma){ struct video_device *dev = file->private_data; unsigned long start = vma->vm_start; unsigned long size = vma->vm_end - vma->vm_start; unsigned long page, pos; struct qcamvc_data *cam = dev->priv; int retval; if (!cam || !cam->ops) return -ENODEV; if (size > QCAMVC_NUMFRAMES*MAX_FRAME_SIZE) return -EINVAL; if (!cam || !cam->ops) return -ENODEV; if (down_interruptible(&cam->busy_lock)) return -EINTR; if ( (retval = allocate_frame_buf(cam)) ) { up(&cam->busy_lock); return retval; } pos = (unsigned long)(cam->frame_buf); while (size > 0) { page = kvirt_to_pa(pos); if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { up(&cam->busy_lock); return -EAGAIN; } start += PAGE_SIZE; pos += PAGE_SIZE; if (size > PAGE_SIZE) size -= PAGE_SIZE; else size = 0; } DBG("qcamvc_mmap: %ld\n", size); up(&cam->busy_lock); return 0;}static int qcamvc_vioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return video_usercopy(inode, file, cmd, arg, qcamvc_do_ioctl);}static int qcamvc_querycap(struct qcamvc_data *qcamvc, struct v4l2_capability *cap){ memset(cap, 0, sizeof(*cap)); strcpy(cap->driver,"qcamvc"); strlcpy(cap->card,qcamvc->camtypedesc,sizeof(cap->card)); cap->version = QCAMVC_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; return 0;}static int qcamvc_enum_fmt(struct v4l2_fmtdesc *f){ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; switch(f->index) { case 0: f->pixelformat = V4L2_PIX_FMT_RGB24; strcpy(f->description, "RGB 8-8-8"); break; case 1: f->pixelformat = V4L2_PIX_FMT_BGR24; strcpy(f->description, "BGRA 8-8-8"); break; case 2: f->pixelformat = V4L2_PIX_FMT_RGB32; strcpy(f->description, "RGBA 8-8-8-8"); break; case 3: f->pixelformat = V4L2_PIX_FMT_BGR32; strcpy(f->description, "BGR 8-8-8-8"); break; case 4: f->pixelformat = V4L2_PIX_FMT_RGB555; strcpy(f->description, "RGB 5-5-5"); break; case 5: f->pixelformat = V4L2_PIX_FMT_RGB565; strcpy(f->description, "RGB 5-6-5"); break; case 6: f->pixelformat = V4L2_PIX_FMT_GREY; strcpy(f->description, "Greyscale"); break; case 7: f->pixelformat = V4L2_PIX_FMT_YUYV; strcpy(f->description, "YUV 4:2:2 (YUYV)"); break; case 8: f->pixelformat = V4L2_PIX_FMT_UYVY; strcpy(f->description, "YUV 4:2:2 (UYVY)"); break; default: return -EINVAL; } f->flags = 0; return 0;}static int qcamvc_try_fmt(struct v4l2_format *f){ int depth; int width; int height; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || (f->fmt.pix.field != V4L2_FIELD_INTERLACED && f->fmt.pix.field != V4L2_FIELD_ANY)) return -EINVAL; depth = mode_depth(f->fmt.pix.pixelformat); if (!depth) return -EINVAL; width = f->fmt.pix.width; height = f->fmt.pix.height; make_valid_res(&width, &height); f->fmt.pix.width = width; f->fmt.pix.height = height; f->fmt.pix.field = V4L2_FIELD_INTERLACED; f->fmt.pix.bytesperline = f->fmt.pix.width * depth / 8; f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; f->fmt.pix.colorspace = mode_colorspace(f->fmt.pix.pixelformat); return 0;}static int qcamvc_s_fmt(struct qcamvc_data *qcamvc, struct v4l2_format *f){ int depth; int newbpc; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || (f->fmt.pix.field != V4L2_FIELD_INTERLACED && f->fmt.pix.field != V4L2_FIELD_ANY)) return -EINVAL; printk("Setting format to %dx%d %c%c%c%c\n", f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat, f->fmt.pix.pixelformat >> 8, f->fmt.pix.pixelformat >> 16, f->fmt.pix.pixelformat >> 24); depth = mode_depth(f->fmt.pix.pixelformat); if (!depth) return -EINVAL; newbpc = mode_bpc(f->fmt.pix.pixelformat); if (newbpc != qcamvc->bpc) { if (down_interruptible(&qcamvc->busy_lock)) return -EBUSY; } qcamvc_set_res(qcamvc, f->fmt.pix.width, f->fmt.pix.height); qcamvc->colordepth = depth; qcamvc->pixelformat = f->fmt.pix.pixelformat; f->fmt.pix.width = qcamvc->width; f->fmt.pix.height = qcamvc->height; f->fmt.pix.field = V4L2_FIELD_INTERLACED; f->fmt.pix.bytesperline = f->fmt.pix.width * depth / 8; f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; f->fmt.pix.colorspace = mode_colorspace(f->fmt.pix.pixelformat); if (newbpc != qcamvc->bpc) { qcamvc->bpc = newbpc; qcamvc_camera_init(qcamvc); up(&qcamvc->busy_lock); } return 0;}static int qcamvc_g_fmt(struct qcamvc_data *qcamvc, struct v4l2_format *f){ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; f->fmt.pix.width = qcamvc->width; f->fmt.pix.height = qcamvc->height; f->fmt.pix.pixelformat = qcamvc->pixelformat; f->fmt.pix.field = V4L2_FIELD_INTERLACED; f->fmt.pix.bytesperline = f->fmt.pix.width * qcamvc->colordepth / 8; f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; f->fmt.pix.colorspace = mode_colorspace(f->fmt.pix.pixelformat); f->fmt.pix.priv = 0; return 0;}static int qcamvc_cropcap(struct qcamvc_data *qcamvc, struct v4l2_cropcap *cap){ if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; memset(cap, 0, sizeof(*cap)); cap->bounds.left = 0; cap->bounds.top = 0; cap->bounds.width = qcamvc->width; cap->bounds.height = qcamvc->height; cap->defrect.left = 0; cap->defrect.top = 0; cap->defrect.width = qcamvc->width; cap->defrect.height = qcamvc->height; cap->pixelaspect.numerator = 1; cap->pixelaspect.denominator = 1; return 0;}#define IGNORE_IOCTL(x) case x: printk("QCamVC: Ignoring " #x "\n"); return -EINVAL;#define NOACTION_IOCTL(x) case x: printk("QCamVC: No action taken for " #x "\n"); return 0;static int qcamvc_enuminput(struct v4l2_input *pin){ if (pin->index != 0) return -EINVAL; strcpy(pin->name, "Camera"); pin->type = V4L2_INPUT_TYPE_CAMERA; pin->audioset = 0; pin->tuner = 0; pin->std = 0; pin->status = 0; memset(pin->reserved, 0, sizeof(pin->reserved)); return 0;}static int qcamvc_queryctrl(struct v4l2_queryctrl *qc){ switch (qc->id) { case V4L2_CID_BRIGHTNESS: strcpy(qc->name, "Brightness"); qc->type = V4L2_CTRL_TYPE_INTEGER; qc->maximum = 256 << 8; qc->default_value = 175 << 8; qc->step = 256; break; case V4L2_CID_WHITENESS: strcpy(qc->name, "Exposure"); qc->type = V4L2_CTRL_TYPE_INTEGER; qc->maximum = 255 << 8; qc->default_value = 57 << 8; qc->step = 256; break; case V4L2_CID_CONTRAST: strcpy(qc->name, "Contrast"); qc->type = V4L2_CTRL_TYPE_INTEGER; qc->maximum = 255 << 8; qc->default_value = 128 << 8; qc->step = 256; break; case V4L2_CID_SATURATION: strcpy(qc->name, "Saturation"); qc->type = V4L2_CTRL_TYPE_INTEGER; qc->maximum = 255 << 8; qc->default_value = 128 << 8; qc->step = 256; break; case V4L2_CID_HUE: strcpy(qc->name, "Hue"); qc->type = V4L2_CTRL_TYPE_INTEGER; qc->maximum = 255 << 8; qc->default_value = 128 << 8; qc->step = 256; break; case V4L2_CID_DO_WHITE_BALANCE: strcpy(qc->name, "Auto Brightness"); qc->type = V4L2_CTRL_TYPE_BOOLEAN; qc->maximum = 1; qc->default_value = 0; qc->step = 1; break; default: return -EINVAL; } qc->minimum = 0; qc->flags = 0; memset(qc->reserved, 0, sizeof(qc->reserved)); return 0;}static int qcamvc_s_ctrl(struct qcamvc_data *qcamvc, struct v4l2_control *c){ __u16 value = c->value; /* Works around a bug in V4L1-V4L2 conversion */ switch (c->id)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -