📄 qcamvc.c
字号:
{ case V4L2_CID_BRIGHTNESS: if (value > 255 << 8) return -ERANGE; if (down_interruptible(&qcamvc->busy_lock)) return -EBUSY; qcamvc->brightness = value >> 8; qcamvc_set_brightness(qcamvc, qcamvc->brightness); up(&qcamvc->busy_lock); return 0; case V4L2_CID_WHITENESS: if (value > 255 << 8) return -ERANGE; if (down_interruptible(&qcamvc->busy_lock)) return -EBUSY; qcamvc->exposure = value >> 8; qcamvc_set_exposure(qcamvc, qcamvc->exposure); up(&qcamvc->busy_lock); return 0; case V4L2_CID_CONTRAST: if (value > 255 << 8) return -ERANGE; qcamvc->contrast = value >> 8; qcamvc->gamma_done = 0; return 0; case V4L2_CID_SATURATION: if (value > 255 << 8) return -ERANGE; qcamvc->saturation = value >> 8; return 0; case V4L2_CID_HUE: if (value > 255 << 8) return -ERANGE; qcamvc->hue = value >> 8; return 0; case V4L2_CID_DO_WHITE_BALANCE: return 0; } return -EINVAL;}static int qcamvc_g_ctrl(struct qcamvc_data *qcamvc, struct v4l2_control *c){ switch (c->id) { case V4L2_CID_BRIGHTNESS: c->value = qcamvc->brightness << 8; break; case V4L2_CID_WHITENESS: c->value = qcamvc->exposure << 8; break; case V4L2_CID_CONTRAST: c->value = qcamvc->contrast << 8; break; case V4L2_CID_SATURATION: c->value = qcamvc->saturation << 8; break; case V4L2_CID_HUE: c->value = qcamvc->hue << 8; break; case V4L2_CID_DO_WHITE_BALANCE: c->value = 0; break; default: return -EINVAL; } return 0;}static int qcamvc_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg){ struct video_device *dev = file->private_data; struct qcamvc_data *qcamvc = dev->priv; int retval = 0; if (!qcamvc || !qcamvc->ops) return -ENODEV; if ((cmd & 0xff00) == 0x7600) { /* V4L version 1 - call the compatibility routine */ retval = v4l_compat_translate_ioctl(inode, file, cmd, arg, qcamvc_do_ioctl); if (retval >= 0) { // Fix things that v4l_compat can't handle switch (cmd) { case VIDIOCGPICT: ((struct video_picture *)arg)->depth = mode_depth(qcamvc->pixelformat); break; case VIDIOCGCAP: { struct video_capability *cap = (struct video_capability *) arg; cap->minwidth = MIN_WIDTH; cap->minheight = MIN_HEIGHT; } break; } } return retval; } switch(cmd) {#if 0 /* mmap interface for V4L1 - kept here in case we need to implement it * for V4L2, although we shouldn't do so unless an app requires it. * This implementation seems somewhat hackish since it still causes the * caller to sleep, which the mmap interface should not do. */ case VIDIOCGMBUF: { struct video_mbuf *vm = arg; int i; DBG("VIDIOCGMBUF\n"); memset(vm, 0, sizeof(*vm)); vm->size = QCAMVC_NUMFRAMES*MAX_FRAME_SIZE; vm->frames = QCAMVC_NUMFRAMES; for (i = 0; i < QCAMVC_NUMFRAMES; i++) vm->offsets[i] = MAX_FRAME_SIZE * i; break; } case VIDIOCMCAPTURE: { struct video_mmap *vm = arg;//printk("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame, vm->width, vm->height); if (vm->frame<0||vm->frame>=QCAMVC_NUMFRAMES) { retval = -EINVAL; break; } switch(vm->format) { case V4L2_PIX_FMT_GREY: qcamvc->vpic.depth=8; break; /* case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: qcamvc->vpic.depth = 16; break;*/ case V4L2_PIX_FMT_RGB24: qcamvc->vpic.depth = 24; break; case V4L2_PIX_FMT_RGB32: qcamvc->vpic.depth = 32; break; default: retval = -EINVAL; break; } if (retval) break; qcamvc->vpic.palette = vm->format; if (res_changed(qcamvc, vm->width, vm->height)) {printk("size changing\n"); //memset(&qcamvc->vc, 0, sizeof(qcamvc->vc)); qcamvc_set_res(qcamvc, vm->width, vm->height); } retval = capture_frame(qcamvc, vm->frame); break; } case VIDIOCSYNC: { int *frame = arg; if (*frame<0 || *frame >= QCAMVC_NUMFRAMES ) { retval = -EINVAL; break; } switch (qcamvc->frame[*frame].state) { case FRAME_GRABBING: { /* parse the frame now */ if (capture_frame(qcamvc, *frame)) retval = -EINVAL; qcamvc->frame[*frame].state = FRAME_READY; break; } case FRAME_READY: case FRAME_UNUSED: { printk("QuickCam VC: Sync to unused frame\n"); retval = -EINVAL; break; } case FRAME_DONE: /* if the frame has already been captured & parsed, just mark it as ready */ qcamvc->frame[*frame].state = FRAME_READY; break; default: retval = -EINVAL; break; } break; }#endif /* *** v4l2 *** ************************************************ */ case VIDIOC_QUERYCAP: return qcamvc_querycap(qcamvc, (struct v4l2_capability *) arg); case VIDIOC_S_FMT: return qcamvc_s_fmt(qcamvc, (struct v4l2_format *) arg); case VIDIOC_G_FMT: return qcamvc_g_fmt(qcamvc, (struct v4l2_format *) arg); case VIDIOC_ENUM_FMT: return qcamvc_enum_fmt((struct v4l2_fmtdesc *) arg); case VIDIOC_TRY_FMT: return qcamvc_try_fmt((struct v4l2_format *) arg); case VIDIOC_CROPCAP: return qcamvc_cropcap(qcamvc, (struct v4l2_cropcap *) arg); case VIDIOC_ENUMINPUT: return qcamvc_enuminput((struct v4l2_input *) arg); case VIDIOC_G_INPUT: *(int *) arg = 0; return 0; case VIDIOC_S_INPUT: if (*(int *) arg != 0) return -EINVAL; return 0; case VIDIOC_QUERYCTRL: return qcamvc_queryctrl((struct v4l2_queryctrl *) arg); case VIDIOC_S_CTRL: return qcamvc_s_ctrl(qcamvc, (struct v4l2_control *) arg); case VIDIOC_G_CTRL: return qcamvc_g_ctrl(qcamvc, (struct v4l2_control *) arg); case VIDIOC_G_STD: /* Should return -EINVAL but SANE fails if we do */ case VIDIOC_QUERYSTD: /* for broken apps - ideally we should return -EINVAL */ *(v4l2_std_id *) arg = 0; return 0; /* This relates to both memory mapping and user pointers. Implementing user * pointers may be a reasonable thing to do if an application needs it */ IGNORE_IOCTL(VIDIOC_REQBUFS) NOACTION_IOCTL(VIDIOC_STREAMOFF) NOACTION_IOCTL(VIDIOC_STREAMON) IGNORE_IOCTL(VIDIOC_QBUF) IGNORE_IOCTL(VIDIOC_DQBUF) /* This relates to memory mapping. It is probably not a good idea to implement * the mmap interface unless an application is found that requires them - memory * mapping is * required to allocate DMA-able memory for the buffers (that is, * kalloc memory * rather than vmalloc memory), which is a scarce resource and * highly prone to * failure with blocks the size of the ones we would be * allocating. All this for little to no performance improvement in our case * since we need to translate the pixels to something the app will understand * anyway. */ IGNORE_IOCTL(VIDIOC_QUERYBUF) /* These are miscellaneous features we shouldn't need to implement */ IGNORE_IOCTL(VIDIOC_QUERYMENU) IGNORE_IOCTL(VIDIOC_G_CROP) IGNORE_IOCTL(VIDIOC_S_CROP) IGNORE_IOCTL(VIDIOC_G_JPEGCOMP) /*These should never apply to this device */ IGNORE_IOCTL(VIDIOC_OVERLAY) IGNORE_IOCTL(VIDIOC_G_FBUF) IGNORE_IOCTL(VIDIOC_S_FBUF) IGNORE_IOCTL(VIDIOC_ENUMSTD) IGNORE_IOCTL(VIDIOC_S_STD) IGNORE_IOCTL(VIDIOC_G_PARM) IGNORE_IOCTL(VIDIOC_S_PARM) case VIDIOC_G_TUNER: case VIDIOC_S_TUNER: case VIDIOC_G_AUDIO: case VIDIOC_S_AUDIO: case VIDIOC_G_OUTPUT: case VIDIOC_S_OUTPUT: case VIDIOC_ENUMOUTPUT: case VIDIOC_G_AUDOUT: case VIDIOC_S_AUDOUT: case VIDIOC_G_MODULATOR: case VIDIOC_S_MODULATOR: case VIDIOC_G_FREQUENCY: case VIDIOC_S_FREQUENCY: /* These can never apply and so are ignored without * any notification. */ return -EINVAL; default: printk("QuickCam VC: Unknown IOCTL cmd: %X\n", cmd); retval = -ENOIOCTLCMD; break; } return retval;}/***************************************************************************** QuickCam Init*****************************************************************************/static int qcamvc_camera_init(struct qcamvc_data *qcamvc){ if (!qcamvc) return -1; long i; unsigned char *bigbuffer; unsigned char bitmask; memset(&qcamvc->misc_reg, 0, sizeof(qcamvc->misc_reg)); bigbuffer=kmalloc(BIGBUFFER_SIZE, GFP_KERNEL); if (bigbuffer==NULL) { printk("QuickCam VC: Init bigbuffer kmalloc error.\n"); return -1; } qcamvc->camera_init = 1; /* setup a 128KB bit mask for 6bit/8bit per component */ bitmask = 0xFF << qcamvc->bpc; for(i=0; i<BIGBUFFER_SIZE ; i+=2) { *(bigbuffer + i) = (unsigned char )(i >> 11); *(bigbuffer + i + 1) = bitmask; } get_camera_model(qcamvc); set_register(qcamvc, QCAM_VC_SET_BRIGHTNESS, 0x38); set_register(qcamvc, QCAM_VC_SET_BRIGHTNESS, 0x78); /* clear config bit & disable video streaming */ set_register(qcamvc, QCAM_VC_SET_MISC, 0x00); /* clear 0x0e address (whatever this address actually does?) */ set_register(qcamvc, 0x0E, 0x00); /* write 128KB of 6bit/8bit mask */ set_registers(qcamvc, QCAM_VC_GET_FRAME, bigbuffer, BIGBUFFER_SIZE); /* set address 0x0e to 0x01 */ set_register(qcamvc, 0x0E, 0x01); /* this might have somthing to do with setting the amount of compression - don't know how though. */ set_register(qcamvc, QCAM_VC_SET_BRIGHTNESS, 0x78); set_register(qcamvc, QCAM_VC_SET_BRIGHTNESS, 0x78); set_register(qcamvc, QCAM_VC_SET_BRIGHTNESS, 0x58); /* set brightness & exposure - probably not needed here */ qcamvc_set_brightness(qcamvc, qcamvc->brightness); qcamvc_set_exposure(qcamvc, qcamvc->exposure); /* set config bit. (whatever this bit actually does?) */ set_register(qcamvc, QCAM_VC_SET_MISC, 0x01); /* set CCD columns & rows */ qcamvc_set_ccd_area(qcamvc); /* set brightness & exposure */ qcamvc_set_brightness(qcamvc, qcamvc->brightness); qcamvc_set_exposure(qcamvc, qcamvc->exposure); /* set the Light Sensitivity (no gain/no attenuation = 128 ) */ qcamvc_set_light_sensitivity(qcamvc, qcamvc->light_sens); /* set Misc options & re-enable video streaming now */ qcamvc->misc_reg.config = 1; qcamvc->misc_reg.multiplier = (qcamvc->ccd_area.multiplier ? 0 : 1); qcamvc->misc_reg.compression = (qcamvc->compression ? 1 : 0); qcamvc->misc_reg.video_enable = 1; set_registers(qcamvc, QCAM_VC_SET_MISC, (unsigned char*)&qcamvc->misc_reg, 1); /* send a get frame to clear the previous resolution */ set_register(qcamvc, QCAM_VC_GET_FRAME, 0xFF); /* done with init */ kfree(bigbuffer); return 0;}/*****************************************************************************//* *//* QuickCam Video Camera layer *//* *//*****************************************************************************/static int qcamvc_initialise(struct qcamvc_data *qcamvc, char *camtype){ strcpy(qcamvc->camtypedesc, camtype); /* defaults */ qcamvc->camera_model = 0; qcamvc->camera_type = 0; qcamvc->width = 352; qcamvc->height = 288; qcamvc->bpc = 8; qcamvc->compression = 0; //FIXME: on/off - don't know how to set amount of compression. qcamvc->light_sens = 128; qcamvc->brightness = 175; qcamvc->exposure = 57; qcamvc->gamma_done = 0; qcamvc->hue = 128; qcamvc->saturation = 128; qcamvc->contrast = 128; qcamvc->pixelformat = V4L2_PIX_FMT_RGB24; qcamvc->colordepth = 24; qcamvc->flip_bgr = 0; qcamvc->transfer_rate = 0; qcamvc->curframe = 0; qcamvc->frame_count = 0; qcamvc->frame_waiting = 0; qcamvc->raw_frame = NULL; qcamvc->frame_buf = NULL; free_frame_buf(qcamvc); qcamvc->proc_entry = NULL; qcamvc->open_count = 0; qcamvc->camera_init = 0; qcamvc->vdev = video_device_alloc(); if (qcamvc->vdev == NULL) { printk(KERN_ERR "QuickCam VC: video_device_alloc() returned NULL!"); return -1; } *qcamvc->vdev = qcamvc_template; strcpy(qcamvc->vdev->name, qcamvc->camtypedesc); qcamvc->vdev->minor = -1; qcamvc->vdev->dev = NULL; qcamvc->vdev->release = video_device_release; qcamvc->vdev->priv = qcamvc; return 0;}struct qcamvc_data *qcamvc_register_camera(struct qcamvc_camera_ops *ops, void *lowlevel, char *camtype){ struct qcamvc_data *qcamvc; if ((qcamvc = kmalloc(sizeof(struct qcamvc_data), GFP_KERNEL)) == NULL) { printk(KERN_ERR "QuickCam VC: Error allocating memory in qcamvc_register_camera\n"); return NULL; } memset(qcamvc, 0, sizeof(struct qcamvc_data)); qcamvc->ops = ops; qcamvc->lowlevel_data = lowlevel; init_MUTEX(&qcamvc->busy_lock); if (qcamvc_initialise(qcamvc, camtype) < 0) { kfree(qcamvc); return NULL; } if (video_register_device(qcamvc->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { kfree(qcamvc); printk(KERN_ERR "QuickCam VC: video_register_device failed.\n"); return NULL; }#ifdef CONFIG_PROC_FS create_proc_qcamvc_cam(qcamvc);#endif if (!qcamvc->ops->qcamvc_open(qcamvc->lowlevel_data)) { qcamvc_camera_init(qcamvc); qcamvc->ops->qcamvc_close(qcamvc->lowlevel_data); } return qcamvc;}void qcamvc_unregister_camera(struct qcamvc_data *qcamvc){#ifdef CONFIG_PROC_FS printk(KERN_INFO "QuickCam VC: destroying /proc/qcamvc/video%d\n", qcamvc->vdev->minor); destroy_proc_qcamvc_cam(qcamvc);#endif printk(KERN_INFO "QuickCam VC: unregistering video...\n"); if (qcamvc->vdev) { if (-1 != qcamvc->vdev->minor) video_unregister_device(qcamvc->vdev); else video_device_release(qcamvc->vdev); qcamvc->vdev = NULL; } if (qcamvc->open_count) { put_cam(qcamvc->ops); printk(KERN_INFO "QuickCam VC: camera open -- setting ops to NULL\n"); qcamvc->ops = NULL; } free_raw_frame(qcamvc); if (!qcamvc->open_count) { printk(KERN_INFO "QuickCam VC: freeing camera\n"); kfree(qcamvc); }}/*****************************************************************************//* *//* QuickCam Video Camera layer *//* Module subs *//* *//*****************************************************************************/static int __init qcamvc_driver_init(void){ printk("QuickCam VC: (C) 2001 by De Marchi Daniele, <demarchidaniele@libero.it>\n"); printk("QuickCam VC: v4l level driver version %s registered.\n",QCAMVCVERSION);#ifdef CONFIG_PROC_FS proc_qcamvc_create();#endif #ifdef CONFIG_KMOD#ifdef CONFIG_VIDEO_QCAMVC_PP_MODULE request_module("qcamvc_pp");#endif#ifdef CONFIG_VIDEO_QCAMVC_USB_MODULE request_module("qcamvc_usb");#endif#endif /* CONFIG_KMOD */ #ifdef CONFIG_VIDEO_QCAMVC_PP qcamvc_pp_init();#endif#ifdef CONFIG_VIDEO_QCAMVC_USB qcamvc_usb_init();#endif return 0;}static void __exit qcamvc_driver_exit(void){#ifdef CONFIG_PROC_FS proc_qcamvc_destroy();#endif printk(KERN_INFO "QuickCam VC: v4l driver unregistered\n");}module_init(qcamvc_driver_init);module_exit(qcamvc_driver_exit);/* Exported symbols for modules. */EXPORT_SYMBOL(qcamvc_register_camera);EXPORT_SYMBOL(qcamvc_unregister_camera);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -