📄 usbvideo.c
字号:
info("testpattern: frame=%s", tmp); }#endif /* Form every scan line */ for (; frame->curline < VIDEOSIZE_Y(frame->request); frame->curline++) { int i; unsigned char *f = frame->data + (VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL * frame->curline); for (i=0; i < VIDEOSIZE_X(frame->request); i++) { unsigned char cb=0x80; unsigned char cg = 0; unsigned char cr = 0; if (pmode == 1) { if (frame->curline % 32 == 0) cb = 0, cg = cr = 0xFF; else if (i % 32 == 0) { if (frame->curline % 32 == 1) num_cell++; cb = 0, cg = cr = 0xFF; } else { cb = ((num_cell*7) + num_pass) & 0xFF; cg = ((num_cell*5) + num_pass*2) & 0xFF; cr = ((num_cell*3) + num_pass*3) & 0xFF; } } else { /* Just the blue screen */ } *f++ = cb; *f++ = cg; *f++ = cr; scan_length += 3; } } frame->frameState = FrameState_Done; frame->seqRead_Length += scan_length; ++num_pass; /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */ usbvideo_OverlayStats(uvd, frame);}EXPORT_SYMBOL(usbvideo_TestPattern);#ifdef DEBUG/* * usbvideo_HexDump() * * A debugging tool. Prints hex dumps. * * History: * 29-Jul-2000 Added printing of offsets. */void usbvideo_HexDump(const unsigned char *data, int len){ const int bytes_per_line = 32; char tmp[128]; /* 32*3 + 5 */ int i, k; for (i=k=0; len > 0; i++, len--) { if (i > 0 && ((i % bytes_per_line) == 0)) { printk("%s\n", tmp); k=0; } if ((i % bytes_per_line) == 0) k += sprintf(&tmp[k], "%04x: ", i); k += sprintf(&tmp[k], "%02x ", data[i]); } if (k > 0) printk("%s\n", tmp);}EXPORT_SYMBOL(usbvideo_HexDump);#endif/* ******************************************************************** *//* XXX: this piece of crap really wants some error handling.. */static void usbvideo_ClientIncModCount(struct uvd *uvd){ if (uvd == NULL) { err("%s: uvd == NULL", __FUNCTION__); return; } if (uvd->handle == NULL) { err("%s: uvd->handle == NULL", __FUNCTION__); return; } if (uvd->handle->md_module == NULL) { err("%s: uvd->handle->md_module == NULL", __FUNCTION__); return; } if (!try_module_get(uvd->handle->md_module)) { err("%s: try_module_get() == 0", __FUNCTION__); return; }}static void usbvideo_ClientDecModCount(struct uvd *uvd){ if (uvd == NULL) { err("%s: uvd == NULL", __FUNCTION__); return; } if (uvd->handle == NULL) { err("%s: uvd->handle == NULL", __FUNCTION__); return; } if (uvd->handle->md_module == NULL) { err("%s: uvd->handle->md_module == NULL", __FUNCTION__); return; } module_put(uvd->handle->md_module);}int usbvideo_register( struct usbvideo **pCams, const int num_cams, const int num_extra, const char *driverName, const struct usbvideo_cb *cbTbl, struct module *md, const struct usb_device_id *id_table){ struct usbvideo *cams; int i, base_size, result; /* Check parameters for sanity */ if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) { err("%s: Illegal call", __FUNCTION__); return -EINVAL; } /* Check registration callback - must be set! */ if (cbTbl->probe == NULL) { err("%s: probe() is required!", __FUNCTION__); return -EINVAL; } base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo); cams = (struct usbvideo *) kmalloc(base_size, GFP_KERNEL); if (cams == NULL) { err("Failed to allocate %d. bytes for usbvideo struct", base_size); return -ENOMEM; } dbg("%s: Allocated $%p (%d. bytes) for %d. cameras", __FUNCTION__, cams, base_size, num_cams); memset(cams, 0, base_size); /* Copy callbacks, apply defaults for those that are not set */ memmove(&cams->cb, cbTbl, sizeof(cams->cb)); if (cams->cb.getFrame == NULL) cams->cb.getFrame = usbvideo_GetFrame; if (cams->cb.disconnect == NULL) cams->cb.disconnect = usbvideo_Disconnect; if (cams->cb.startDataPump == NULL) cams->cb.startDataPump = usbvideo_StartDataPump; if (cams->cb.stopDataPump == NULL) cams->cb.stopDataPump = usbvideo_StopDataPump; cams->num_cameras = num_cams; cams->cam = (struct uvd *) &cams[1]; cams->md_module = md; if (cams->md_module == NULL) warn("%s: module == NULL!", __FUNCTION__); init_MUTEX(&cams->lock); /* to 1 == available */ for (i = 0; i < num_cams; i++) { struct uvd *up = &cams->cam[i]; up->handle = cams; /* Allocate user_data separately because of kmalloc's limits */ if (num_extra > 0) { up->user_size = num_cams * num_extra; up->user_data = (char *) kmalloc(up->user_size, GFP_KERNEL); if (up->user_data == NULL) { err("%s: Failed to allocate user_data (%d. bytes)", __FUNCTION__, up->user_size); while (i) { up = &cams->cam[--i]; kfree(up->user_data); } kfree(cams); return -ENOMEM; } dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)", __FUNCTION__, i, up->user_data, up->user_size); } } /* * Register ourselves with USB stack. */ strcpy(cams->drvName, (driverName != NULL) ? driverName : "Unknown"); cams->usbdrv.name = cams->drvName; cams->usbdrv.probe = cams->cb.probe; cams->usbdrv.disconnect = cams->cb.disconnect; cams->usbdrv.id_table = id_table; /* * Update global handle to usbvideo. This is very important * because probe() can be called before usb_register() returns. * If the handle is not yet updated then the probe() will fail. */ *pCams = cams; result = usb_register(&cams->usbdrv); if (result) { for (i = 0; i < num_cams; i++) { struct uvd *up = &cams->cam[i]; kfree(up->user_data); } kfree(cams); } return result;}EXPORT_SYMBOL(usbvideo_register);/* * usbvideo_Deregister() * * Procedure frees all usbvideo and user data structures. Be warned that * if you had some dynamically allocated components in ->user field then * you should free them before calling here. */void usbvideo_Deregister(struct usbvideo **pCams){ struct usbvideo *cams; int i; if (pCams == NULL) { err("%s: pCams == NULL", __FUNCTION__); return; } cams = *pCams; if (cams == NULL) { err("%s: cams == NULL", __FUNCTION__); return; } dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName); usb_deregister(&cams->usbdrv); dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras); for (i=0; i < cams->num_cameras; i++) { struct uvd *up = &cams->cam[i]; int warning = 0; if (up->user_data != NULL) { if (up->user_size <= 0) ++warning; } else { if (up->user_size > 0) ++warning; } if (warning) { err("%s: Warning: user_data=$%p user_size=%d.", __FUNCTION__, up->user_data, up->user_size); } else { dbg("%s: Freeing %d. $%p->user_data=$%p", __FUNCTION__, i, up, up->user_data); kfree(up->user_data); } } /* Whole array was allocated in one chunk */ dbg("%s: Freed %d uvd structures", __FUNCTION__, cams->num_cameras); kfree(cams); *pCams = NULL;}EXPORT_SYMBOL(usbvideo_Deregister);/* * usbvideo_Disconnect() * * This procedure stops all driver activity. Deallocation of * the interface-private structure (pointed by 'ptr') is done now * (if we don't have any open files) or later, when those files * are closed. After that driver should be removable. * * This code handles surprise removal. The uvd->user is a counter which * increments on open() and decrements on close(). If we see here that * this counter is not 0 then we have a client who still has us opened. * We set uvd->remove_pending flag as early as possible, and after that * all access to the camera will gracefully fail. These failures should * prompt client to (eventually) close the video device, and then - in * usbvideo_v4l_close() - we decrement uvd->uvd_used and usage counter. * * History: * 22-Jan-2000 Added polling of MOD_IN_USE to delay removal until all users gone. * 27-Jan-2000 Reworked to allow pending disconnects; see xxx_close() * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). * 19-Oct-2000 Moved to usbvideo module. */static void usbvideo_Disconnect(struct usb_interface *intf){ struct uvd *uvd = usb_get_intfdata (intf); int i; if (uvd == NULL) { err("%s($%p): Illegal call.", __FUNCTION__, intf); return; } usb_set_intfdata (intf, NULL); usbvideo_ClientIncModCount(uvd); if (uvd->debug > 0) info("%s(%p.)", __FUNCTION__, intf); down(&uvd->lock); uvd->remove_pending = 1; /* Now all ISO data will be ignored */ /* At this time we ask to cancel outstanding URBs */ GET_CALLBACK(uvd, stopDataPump)(uvd); for (i=0; i < USBVIDEO_NUMSBUF; i++) usb_free_urb(uvd->sbuf[i].urb); usb_put_dev(uvd->dev); uvd->dev = NULL; /* USB device is no more */ video_unregister_device(&uvd->vdev); if (uvd->debug > 0) info("%s: Video unregistered.", __FUNCTION__); if (uvd->user) info("%s: In use, disconnect pending.", __FUNCTION__); else usbvideo_CameraRelease(uvd); up(&uvd->lock); info("USB camera disconnected."); usbvideo_ClientDecModCount(uvd);}/* * usbvideo_CameraRelease() * * This code does final release of uvd. This happens * after the device is disconnected -and- all clients * closed their files. * * History: * 27-Jan-2000 Created. */static void usbvideo_CameraRelease(struct uvd *uvd){ if (uvd == NULL) { err("%s: Illegal call", __FUNCTION__); return; } 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(struct usbvideo *cams){ int u, rv = -1; if (cams == NULL) { err("No usbvideo handle?"); return -1; } down(&cams->lock); for (u = 0; u < cams->num_cameras; u++) { struct uvd *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;}static struct file_operations usbvideo_fops = { .owner = THIS_MODULE, .open = usbvideo_v4l_open, .release =usbvideo_v4l_close, .read = usbvideo_v4l_read, .mmap = usbvideo_v4l_mmap, .ioctl = usbvideo_v4l_ioctl, .llseek = no_llseek,};static struct video_device usbvideo_template = { .owner = THIS_MODULE, .type = VID_TYPE_CAPTURE, .hardware = VID_HARDWARE_CPIA, .fops = &usbvideo_fops,};struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams){ int i, devnum; struct uvd *uvd = NULL; if (cams == NULL) { err("No usbvideo 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, GFP_KERNEL); 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 */ uvd->vdev = usbvideo_template; sprintf(uvd->vdev.name, "%.20s USB Camera", cams->drvName); /* * 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;}EXPORT_SYMBOL(usbvideo_AllocateDevice);int usbvideo_RegisterVideoDevice(struct uvd *uvd){ char tmp1[20], tmp2[20]; /* Buffers for printing */ if (uvd == NULL) { err("%s: Illegal call.", __FUNCTION__); return -EINVAL; } if (uvd->video_endp == 0) { info("%s: No video endpoint specified; data pump disabled.", __FUNCTION__); } if (uvd->paletteBits == 0) { err("%s: No palettes specified!", __FUNCTION__); return -EINVAL; } if (uvd->defaultPalette == 0) { info("%s: No default palette!", __FUNCTION__); } 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", __FUNCTION__, 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", __FUNCTION__); return -EPIPE; } if (uvd->debug > 1) { info("%s: video_register_device() successful", __FUNCTION__); } if (uvd->dev == NULL) { err("%s: uvd->dev == NULL", __FUNCTION__); return -EINVAL; } info("%s on /dev/video%d: canvas=%s videosize=%s", (uvd->handle != NULL) ? uvd->handle->drvName : "???", uvd->vdev.minor, tmp2, tmp1); usb_get_dev(uvd->dev); return 0;}EXPORT_SYMBOL(usbvideo_RegisterVideoDevice);/* ******************************************************************** */static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma){ struct uvd *uvd = file->private_data; unsigned long start = vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start; unsigned long page, pos; if (!CAMERA_IS_OPERATIONAL(uvd)) return -EFAULT; if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) return -EINVAL; pos = (unsigned long) uvd->fbuf; while (size > 0) { page = vmalloc_to_pfn((void *)pos); if (remap_pfn_range(vma, 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -