📄 vicam.c
字号:
}static intinitialize_camera(struct vicam_camera *cam){ const struct { u8 *data; u32 size; } firmware[] = { { .data = setup1, .size = sizeof(setup1) }, { .data = setup2, .size = sizeof(setup2) }, { .data = setup3, .size = sizeof(setup3) }, { .data = setup4, .size = sizeof(setup4) }, { .data = setup5, .size = sizeof(setup5) }, { .data = setup3, .size = sizeof(setup3) }, { .data = NULL, .size = 0 } }; int err, i; for (i = 0, err = 0; firmware[i].data && !err; i++) { memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size); err = send_control_msg(cam, 0xff, 0, 0, cam->cntrlbuf, firmware[i].size); } return err;}static intset_camera_power(struct vicam_camera *cam, int state){ int status; if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0) return status; if (state) { send_control_msg(cam, 0x55, 1, 0, NULL, 0); } return 0;}static intvicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg){ void __user *user_arg = (void __user *)arg; struct vicam_camera *cam = file->private_data; int retval = 0; if (!cam) return -ENODEV; switch (ioctlnr) { /* query capabilities */ case VIDIOCGCAP: { struct video_capability b; DBG("VIDIOCGCAP\n"); memset(&b, 0, sizeof(b)); strcpy(b.name, "ViCam-based Camera"); b.type = VID_TYPE_CAPTURE; b.channels = 1; b.audios = 0; b.maxwidth = 320; /* VIDEOSIZE_CIF */ b.maxheight = 240; b.minwidth = 320; /* VIDEOSIZE_48_48 */ b.minheight = 240; if (copy_to_user(user_arg, &b, sizeof(b))) retval = -EFAULT; break; } /* get/set video source - we are a camera and nothing else */ case VIDIOCGCHAN: { struct video_channel v; DBG("VIDIOCGCHAN\n"); if (copy_from_user(&v, user_arg, sizeof(v))) { retval = -EFAULT; break; } if (v.channel != 0) { retval = -EINVAL; break; } v.channel = 0; strcpy(v.name, "Camera"); v.tuners = 0; v.flags = 0; v.type = VIDEO_TYPE_CAMERA; v.norm = 0; if (copy_to_user(user_arg, &v, sizeof(v))) retval = -EFAULT; break; } case VIDIOCSCHAN: { int v; if (copy_from_user(&v, user_arg, sizeof(v))) retval = -EFAULT; DBG("VIDIOCSCHAN %d\n", v); if (retval == 0 && v != 0) retval = -EINVAL; break; } /* image properties */ case VIDIOCGPICT: { struct video_picture vp; DBG("VIDIOCGPICT\n"); memset(&vp, 0, sizeof (struct video_picture)); vp.brightness = cam->gain << 8; vp.depth = 24; vp.palette = VIDEO_PALETTE_RGB24; if (copy_to_user(user_arg, &vp, sizeof (struct video_picture))) retval = -EFAULT; break; } case VIDIOCSPICT: { struct video_picture vp; if (copy_from_user(&vp, user_arg, sizeof(vp))) { retval = -EFAULT; break; } DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth, vp.palette); cam->gain = vp.brightness >> 8; if (vp.depth != 24 || vp.palette != VIDEO_PALETTE_RGB24) retval = -EINVAL; break; } /* get/set capture window */ case VIDIOCGWIN: { struct video_window vw; vw.x = 0; vw.y = 0; vw.width = 320; vw.height = 240; vw.chromakey = 0; vw.flags = 0; vw.clips = NULL; vw.clipcount = 0; DBG("VIDIOCGWIN\n"); if (copy_to_user(user_arg, (void *)&vw, sizeof(vw))) retval = -EFAULT; // I'm not sure what the deal with a capture window is, it is very poorly described // in the doc. So I won't support it now. break; } case VIDIOCSWIN: { struct video_window vw; if (copy_from_user(&vw, user_arg, sizeof(vw))) { retval = -EFAULT; break; } DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height); if ( vw.width != 320 || vw.height != 240 ) retval = -EFAULT; break; } /* mmap interface */ case VIDIOCGMBUF: { struct video_mbuf vm; int i; DBG("VIDIOCGMBUF\n"); memset(&vm, 0, sizeof (vm)); vm.size = VICAM_MAX_FRAME_SIZE * VICAM_FRAMES; vm.frames = VICAM_FRAMES; for (i = 0; i < VICAM_FRAMES; i++) vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i; if (copy_to_user(user_arg, (void *)&vm, sizeof(vm))) retval = -EFAULT; break; } case VIDIOCMCAPTURE: { struct video_mmap vm; // int video_size; if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) { retval = -EFAULT; break; } DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format); if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 ) retval = -EINVAL; // in theory right here we'd start the image capturing // (fill in a bulk urb and submit it asynchronously) // // Instead we're going to do a total hack job for now and // retrieve the frame in VIDIOCSYNC break; } case VIDIOCSYNC: { int frame; if (copy_from_user((void *)&frame, user_arg, sizeof(int))) { retval = -EFAULT; break; } DBG("VIDIOCSYNC: %d\n", frame); read_frame(cam, frame); vicam_decode_color(cam->raw_image, cam->framebuf + frame * VICAM_MAX_FRAME_SIZE ); break; } /* pointless to implement overlay with this camera */ case VIDIOCCAPTURE: case VIDIOCGFBUF: case VIDIOCSFBUF: case VIDIOCKEY: retval = -EINVAL; break; /* tuner interface - we have none */ case VIDIOCGTUNER: case VIDIOCSTUNER: case VIDIOCGFREQ: case VIDIOCSFREQ: retval = -EINVAL; break; /* audio interface - we have none */ case VIDIOCGAUDIO: case VIDIOCSAUDIO: retval = -EINVAL; break; default: retval = -ENOIOCTLCMD; break; } return retval;}static intvicam_open(struct inode *inode, struct file *file){ struct video_device *dev = video_devdata(file); struct vicam_camera *cam = (struct vicam_camera *) dev->priv; DBG("open\n"); if (!cam) { printk(KERN_ERR "vicam video_device improperly initialized"); } /* the videodev_lock held above us protects us from * simultaneous opens...for now. we probably shouldn't * rely on this fact forever. */ if (cam->open_count > 0) { printk(KERN_INFO "vicam_open called on already opened camera"); return -EBUSY; } cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL); if (!cam->raw_image) { return -ENOMEM; } cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); if (!cam->framebuf) { kfree(cam->raw_image); return -ENOMEM; } cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!cam->cntrlbuf) { kfree(cam->raw_image); rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); return -ENOMEM; } // First upload firmware, then turn the camera on if (!cam->is_initialized) { initialize_camera(cam); cam->is_initialized = 1; } set_camera_power(cam, 1); cam->needsDummyRead = 1; cam->open_count++; file->private_data = cam; return 0;}static int vicam_close(struct inode *inode, struct file *file){ struct vicam_camera *cam = file->private_data; int open_count; struct usb_device *udev; DBG("close\n"); /* it's not the end of the world if * we fail to turn the camera off. */ set_camera_power(cam, 0); kfree(cam->raw_image); rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); kfree(cam->cntrlbuf); down(&cam->cam_lock); cam->open_count--; open_count = cam->open_count; udev = cam->udev; up(&cam->cam_lock); if (!open_count && !udev) { kfree(cam); } return 0;}static void vicam_decode_color(const u8 *data, u8 *rgb){ /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB * Copyright (C) 2002 Monroe Williams (monroe@pobox.com) */ int i, prevY, nextY; prevY = 512; nextY = 512; data += VICAM_HEADER_SIZE; for( i = 0; i < 240; i++, data += 512 ) { const int y = ( i * 242 ) / 240; int j, prevX, nextX; int Y, Cr, Cb; if ( y == 242 - 1 ) { nextY = -512; } prevX = 1; nextX = 1; for ( j = 0; j < 320; j++, rgb += 3 ) { const int x = ( j * 512 ) / 320; const u8 * const src = &data[x]; if ( x == 512 - 1 ) { nextX = -1; } Cr = ( src[prevX] - src[0] ) + ( src[nextX] - src[0] ); Cr /= 2; Cb = ( src[prevY] - src[prevX + prevY] ) + ( src[prevY] - src[nextX + prevY] ) + ( src[nextY] - src[prevX + nextY] ) + ( src[nextY] - src[nextX + nextY] ); Cb /= 4; Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 ); if ( i & 1 ) { int Ct = Cr; Cr = Cb; Cb = Ct; } if ( ( x ^ i ) & 1 ) { Cr = -Cr; Cb = -Cb; } rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) + 500 ) / 900, 0, 255 ); rgb[1] = clamp( ( ( Y - ( 392 * Cb ) - ( 813 * Cr ) ) + 500 ) / 1000, 0, 255 ); rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) + 500 ) / 1300, 0, 255 ); prevX = -1; } prevY = -512; }}static voidread_frame(struct vicam_camera *cam, int framenum){ unsigned char *request = cam->cntrlbuf; int realShutter; int n; int actual_length; if (cam->needsDummyRead) { cam->needsDummyRead = 0; read_frame(cam, framenum); } memset(request, 0, 16); request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain request[1] = 0; // 512x242 capture request[2] = 0x90; // the function of these two bytes request[3] = 0x07; // is not yet understood
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -