📄 usbvideo.c
字号:
info("%s: In use, disconnect pending.", proc); else usbvideo_CameraRelease(uvd); up(&uvd->lock); info("USB camera disconnected."); usbvideo_ClientDecModCount(uvd);}/* * usbvideo_CameraRelease() * * This code does final release of uvd_t. This happens * after the device is disconnected -and- all clients * closed their files. * * History: * 27-Jan-2000 Created. */void usbvideo_CameraRelease(uvd_t *uvd){ static const char proc[] = "usbvideo_CameraRelease"; if (uvd == NULL) { err("%s: Illegal call", proc); return; } video_unregister_device(&uvd->vdev); if (uvd->debug > 0) info("%s: Video unregistered.", proc);#if USES_PROC_FS assert(uvd->handle != NULL); if (uvd->handle->uses_procfs) { dbg("%s: Removing /proc/%s/ filesystem entries.", proc, uvd->handle->drvName); usbvideo_procfs_level2_destroy(uvd); }#endif RingQueue_Free(&uvd->dp); if (VALID_CALLBACK(uvd, userFree)) GET_CALLBACK(uvd, userFree)(uvd); uvd->uvd_used = 0; /* This is atomic, no need to take mutex */}/* * usbvideo_find_struct() * * This code searches the array of preallocated (static) structures * and returns index of the first one that isn't in use. Returns -1 * if there are no free structures. * * History: * 27-Jan-2000 Created. */static int usbvideo_find_struct(usbvideo_t *cams){ int u, rv = -1; if (cams == NULL) { err("No usbvideo_t handle?"); return -1; } down(&cams->lock); for (u = 0; u < cams->num_cameras; u++) { uvd_t *uvd = &cams->cam[u]; if (!uvd->uvd_used) /* This one is free */ { uvd->uvd_used = 1; /* In use now */ init_MUTEX(&uvd->lock); /* to 1 == available */ uvd->dev = NULL; rv = u; break; } } up(&cams->lock); return rv;}uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams){ int i, devnum; uvd_t *uvd = NULL; if (cams == NULL) { err("No usbvideo_t handle?"); return NULL; } devnum = usbvideo_find_struct(cams); if (devnum == -1) { err("IBM USB camera driver: Too many devices!"); return NULL; } uvd = &cams->cam[devnum]; dbg("Device entry #%d. at $%p", devnum, uvd); /* Not relying upon caller we increase module counter ourselves */ usbvideo_ClientIncModCount(uvd); down(&uvd->lock); for (i=0; i < USBVIDEO_NUMSBUF; i++) { uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC); if (uvd->sbuf[i].urb == NULL) { err("usb_alloc_urb(%d.) failed.", FRAMES_PER_DESC); uvd->uvd_used = 0; uvd = NULL; goto allocate_done; } } uvd->user=0; uvd->remove_pending = 0; uvd->last_error = 0; RingQueue_Initialize(&uvd->dp); /* Initialize video device structure */ memset(&uvd->vdev, 0, sizeof(uvd->vdev)); i = sprintf(uvd->vdev.name, "%s USB Camera", cams->drvName); if (i >= sizeof(uvd->vdev.name)) { err("Wrote too much into uvd->vdev.name, expect trouble!"); } uvd->vdev.type = VID_TYPE_CAPTURE; uvd->vdev.hardware = VID_HARDWARE_CPIA; uvd->vdev.open = usbvideo_v4l_open; uvd->vdev.close = usbvideo_v4l_close; uvd->vdev.read = usbvideo_v4l_read; uvd->vdev.write = usbvideo_v4l_write; uvd->vdev.ioctl = usbvideo_v4l_ioctl; uvd->vdev.mmap = usbvideo_v4l_mmap; uvd->vdev.initialize = usbvideo_v4l_initialize; /* * The client is free to overwrite those because we * return control to the client's probe function right now. */allocate_done: up (&uvd->lock); usbvideo_ClientDecModCount(uvd); return uvd;}int usbvideo_RegisterVideoDevice(uvd_t *uvd){ static const char proc[] = "usbvideo_RegisterVideoDevice"; char tmp1[20], tmp2[20]; /* Buffers for printing */ if (uvd == NULL) { err("%s: Illegal call.", proc); return -EINVAL; } if (uvd->video_endp == 0) { info("%s: No video endpoint specified; data pump disabled.", proc); } if (uvd->paletteBits == 0) { err("%s: No palettes specified!", proc); return -EINVAL; } if (uvd->defaultPalette == 0) { info("%s: No default palette!", proc); } uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) * VIDEOSIZE_Y(uvd->canvas) * V4L_BYTES_PER_PIXEL; usbvideo_VideosizeToString(tmp1, sizeof(tmp1), uvd->videosize); usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas); if (uvd->debug > 0) { info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx", proc, uvd->iface, uvd->video_endp, uvd->paletteBits); } if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { err("%s: video_register_device failed", proc); return -EPIPE; } if (uvd->debug > 1) { info("%s: video_register_device() successful", proc); } if (uvd->dev == NULL) { err("%s: uvd->dev == NULL", proc); return -EINVAL; } info("%s on /dev/video%d: canvas=%s videosize=%s", (uvd->handle != NULL) ? uvd->handle->drvName : "???", uvd->vdev.minor, tmp2, tmp1);#if USES_PROC_FS assert(uvd->handle != NULL); if (uvd->handle->uses_procfs) { if (uvd->debug > 0) { info("%s: Creating /proc/video/%s/ filesystem entries.", proc, uvd->handle->drvName); } usbvideo_procfs_level2_create(uvd); }#endif usb_inc_dev_use(uvd->dev); return 0;}/* ******************************************************************** */int usbvideo_v4l_initialize(struct video_device *dev){ return 0;}long usbvideo_v4l_write(struct video_device *dev, const char *buf, unsigned long count, int noblock){ return -EINVAL;}int usbvideo_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size){ uvd_t *uvd = (uvd_t *) dev; unsigned long start = (unsigned long) adr; unsigned long page, pos; if (!CAMERA_IS_OPERATIONAL(uvd)) return -EFAULT; if (size > (((2 * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) return -EINVAL; pos = (unsigned long) uvd->fbuf; while (size > 0) { page = usbvideo_kvirt_to_pa(pos); if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; start += PAGE_SIZE; pos += PAGE_SIZE; if (size > PAGE_SIZE) size -= PAGE_SIZE; else size = 0; } return 0;}/* * usbvideo_v4l_open() * * This is part of Video 4 Linux API. The driver can be opened by one * client only (checks internal counter 'uvdser'). The procedure * then allocates buffers needed for video processing. * * History: * 22-Jan-2000 Rewrote, moved scratch buffer allocation here. Now the * camera is also initialized here (once per connect), at * expense of V4L client (it waits on open() call). * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). */int usbvideo_v4l_open(struct video_device *dev, int flags){ static const char proc[] = "usbvideo_v4l_open"; uvd_t *uvd = (uvd_t *) dev; const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len; int i, errCode = 0; if (uvd->debug > 1) info("%s($%p,$%08x", proc, dev, flags); usbvideo_ClientIncModCount(uvd); down(&uvd->lock); if (uvd->user) { err("%s: Someone tried to open an already opened device!", proc); errCode = -EBUSY; } else { /* Clear statistics */ memset(&uvd->stats, 0, sizeof(uvd->stats)); /* Clean pointers so we know if we allocated something */ for (i=0; i < USBVIDEO_NUMSBUF; i++) uvd->sbuf[i].data = NULL; /* Allocate memory for the frame buffers */ uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size; uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size); RingQueue_Allocate(&uvd->dp, 128*1024); /* FIXME #define */ if ((uvd->fbuf == NULL) || (!RingQueue_IsAllocated(&uvd->dp))) { err("%s: Failed to allocate fbuf or dp", proc); errCode = -ENOMEM; } else { /* Allocate all buffers */ for (i=0; i < USBVIDEO_NUMFRAMES; i++) { uvd->frame[i].frameState = FrameState_Unused; uvd->frame[i].data = uvd->fbuf + i*(uvd->max_frame_size); /* * Set default sizes in case IOCTL (VIDIOCMCAPTURE) * is not used (using read() instead). */ uvd->frame[i].canvas = uvd->canvas; uvd->frame[i].seqRead_Index = 0; } for (i=0; i < USBVIDEO_NUMSBUF; i++) { uvd->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL); if (uvd->sbuf[i].data == NULL) { errCode = -ENOMEM; break; } } } if (errCode != 0) { /* Have to free all that memory */ if (uvd->fbuf != NULL) { usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); uvd->fbuf = NULL; } RingQueue_Free(&uvd->dp); for (i=0; i < USBVIDEO_NUMSBUF; i++) { if (uvd->sbuf[i].data != NULL) { kfree (uvd->sbuf[i].data); uvd->sbuf[i].data = NULL; } } } } /* If so far no errors then we shall start the camera */ if (errCode == 0) { /* Start data pump if we have valid endpoint */ if (uvd->video_endp != 0) errCode = usbvideo_StartDataPump(uvd); if (errCode == 0) { if (VALID_CALLBACK(uvd, setupOnOpen)) { if (uvd->debug > 1) info("%s: setupOnOpen callback", proc); errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd); if (errCode < 0) { err("%s: setupOnOpen callback failed (%d.).", proc, errCode); } else if (uvd->debug > 1) { info("%s: setupOnOpen callback successful", proc); } } if (errCode == 0) { uvd->settingsAdjusted = 0; if (uvd->debug > 1) info("%s: Open succeeded.", proc); uvd->user++; } } } up(&uvd->lock); if (errCode != 0) usbvideo_ClientDecModCount(uvd); if (uvd->debug > 0) info("%s: Returning %d.", proc, errCode); return errCode;}/* * usbvideo_v4l_close() * * This is part of Video 4 Linux API. The procedure * stops streaming and deallocates all buffers that were earlier * allocated in usbvideo_v4l_open(). * * History: * 22-Jan-2000 Moved scratch buffer deallocation here. * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. * 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep. */void usbvideo_v4l_close(struct video_device *dev){ static const char proc[] = "usbvideo_v4l_close"; uvd_t *uvd = (uvd_t *)dev; int i; if (uvd->debug > 1) info("%s($%p)", proc, dev); down(&uvd->lock); usbvideo_StopDataPump(uvd); usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); uvd->fbuf = NULL; RingQueue_Free(&uvd->dp); for (i=0; i < USBVIDEO_NUMSBUF; i++) { kfree(uvd->sbuf[i].data); uvd->sbuf[i].data = NULL; }#if USBVIDEO_REPORT_STATS usbvideo_ReportStatistics(uvd);#endif uvd->user--; if (uvd->remove_pending) { if (uvd->debug > 0) info("usbvideo_v4l_close: Final disconnect."); usbvideo_CameraRelease(uvd); } up(&uvd->lock); usbvideo_ClientDecModCount(uvd); if (uvd->debug > 1) info("%s: Completed.", proc);}/* * usbvideo_v4l_ioctl() * * This is part of Video 4 Linux API. The procedure handles ioctl() calls. * * History: * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings. */int usbvideo_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg){ uvd_t *uvd = (uvd_t *)dev; if (!CAMERA_IS_OPERATIONAL(uvd)) return -EFAULT; switch (cmd) { case VIDIOCGCAP: { if (copy_to_user(arg, &uvd->vcap, sizeof(uvd->vcap))) return -EFAULT; return 0; } case VIDIOCGCHAN: { if (copy_to_user(arg, &uvd->vchan, sizeof(uvd->vchan))) return -EFAULT; return 0; } case VIDIOCSCHAN: { /* Not used but we return success */ int v; if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; return 0; } case VIDIOCGPICT: { if (copy_to_user(arg, &uvd->vpic, sizeof(uvd->vpic))) return -EFAULT; return 0; } case VIDIOCSPICT: { struct video_picture tmp; /* * Use temporary 'video_picture' structure to preserve our * own settings (such as color depth, palette) that we * aren't allowing everyone (V4L client) to change. */ if (copy_from_user(&tmp, arg, sizeof(tmp))) return -EFAULT; uvd->vpic.brightness = tmp.brightness; uvd->vpic.hue = tmp.hue; uvd->vpic.colour = tmp.colour; uvd->vpic.contrast = tmp.contrast; uvd->settingsAdjusted = 0; /* Will force new settings */ return 0; } case VIDIOCSWIN: { struct video_window vw; if (copy_from_user(&vw, arg, sizeof(vw))) return -EFAULT; if (vw.flags) return -EINVAL; if (vw.clipcount) return -EINVAL; if (vw.width != VIDEOSIZE_X(uvd->canvas)) return -EINVAL; if (vw.height != VIDEOSIZE_Y(uvd->canvas)) return -EINVAL; return 0; } case VIDIOCGWIN: { struct video_window vw; vw.x = 0; vw.y = 0; vw.width = VIDEOSIZE_X(uvd->canvas);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -