📄 usbvideo.c
字号:
/* Calculate percentage wisely, remember integer limits */ assert(allPackets != 0); if (goodPackets < (((unsigned long)-1)/100)) percent = (100 * goodPackets) / allPackets; else percent = goodPackets / (allPackets / 100); info("Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%", allPackets, badPackets, percent); if (uvd->iso_packet_len > 0) { unsigned long allBytes, xferBytes; char multiplier = ' '; allBytes = allPackets * uvd->iso_packet_len; xferBytes = uvd->stats.data_count; assert(allBytes != 0); if (xferBytes < (((unsigned long)-1)/100)) percent = (100 * xferBytes) / allBytes; else percent = xferBytes / (allBytes / 100); /* Scale xferBytes for easy reading */ if (xferBytes > 10*1024) { xferBytes /= 1024; multiplier = 'K'; if (xferBytes > 10*1024) { xferBytes /= 1024; multiplier = 'M'; if (xferBytes > 10*1024) { xferBytes /= 1024; multiplier = 'G'; if (xferBytes > 10*1024) { xferBytes /= 1024; multiplier = 'T'; } } } } info("Transfer Statistics: Transferred=%lu%cB Usage=%lu%%", xferBytes, multiplier, percent); } }}/* * usbvideo_DrawLine() * * A standard implementation of Bresenham's line drawing algorithm. * This procedure is provided primarily for debugging or demo * purposes. */void usbvideo_DrawLine( usbvideo_frame_t *frame, int x1, int y1, int x2, int y2, unsigned char cr, unsigned char cg, unsigned char cb){ int i, dx, dy, np, d; int dinc1, dinc2, x, xinc1, xinc2, y, yinc1, yinc2; if ((dx = x2 - x1) < 0) dx = -dx; if ((dy = y2 - y1) < 0) dy = -dy; if (dx >= dy) { np = dx + 1; d = (2 * dy) - dx; dinc1 = dy << 1; dinc2 = (dy - dx) << 1; xinc1 = 1; xinc2 = 1; yinc1 = 0; yinc2 = 1; } else { np = dy + 1; d = (2 * dx) - dy; dinc1 = dx << 1; dinc2 = (dx - dy) << 1; xinc1 = 0; xinc2 = 1; yinc1 = 1; yinc2 = 1; } /* Make sure x and y move in the right directions */ if (x1 > x2) { xinc1 = -xinc1; xinc2 = -xinc2; } if (y1 > y2) { yinc1 = -yinc1; yinc2 = -yinc2; } for (i=0, x=x1, y=y1; i < np; i++) { if (frame->palette == VIDEO_PALETTE_RGB24) {/* TODO */ RGB24_PUTPIXEL(frame, x, y, cr, cg, cb); } if (d < 0) { d += dinc1; x += xinc1; y += yinc1; } else { d += dinc2; x += xinc2; y += yinc2; } }}/* * usbvideo_TestPattern() * * Procedure forms a test pattern (yellow grid on blue background). * * Parameters: * fullframe: if TRUE then entire frame is filled, otherwise the procedure * continues from the current scanline. * pmode 0: fill the frame with solid blue color (like on VCR or TV) * 1: Draw a colored grid * * History: * 01-Feb-2000 Created. */void usbvideo_TestPattern(uvd_t *uvd, int fullframe, int pmode){ static const char proc[] = "usbvideo_TestPattern"; usbvideo_frame_t *frame; int num_cell = 0; int scan_length = 0; static int num_pass = 0; if (uvd == NULL) { err("%s: uvd == NULL", proc); return; } if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) { err("%s: uvd->curframe=%d.", proc, uvd->curframe); return; } /* Grab the current frame */ frame = &uvd->frame[uvd->curframe]; /* Optionally start at the beginning */ if (fullframe) { frame->curline = 0; frame->seqRead_Length = 0; }#if 0 { /* For debugging purposes only */ char tmp[20]; usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request); 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);}/* * 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);}/* Debugging aid */void usbvideo_SayAndWait(const char *what){ wait_queue_head_t wq; init_waitqueue_head(&wq); info("Say: %s", what); interruptible_sleep_on_timeout (&wq, HZ*3); /* Timeout */}/* ******************************************************************** */static void usbvideo_ClientIncModCount(uvd_t *uvd){ static const char proc[] = "usbvideo_ClientIncModCount"; if (uvd == NULL) { err("%s: uvd == NULL", proc); return; } if (uvd->handle == NULL) { err("%s: uvd->handle == NULL", proc); return; } if (uvd->handle->md_module == NULL) { err("%s: uvd->handle->md_module == NULL", proc); return; } __MOD_INC_USE_COUNT(uvd->handle->md_module);}static void usbvideo_ClientDecModCount(uvd_t *uvd){ static const char proc[] = "usbvideo_ClientDecModCount"; if (uvd == NULL) { err("%s: uvd == NULL", proc); return; } if (uvd->handle == NULL) { err("%s: uvd->handle == NULL", proc); return; } if (uvd->handle->md_module == NULL) { err("%s: uvd->handle->md_module == NULL", proc); return; } __MOD_DEC_USE_COUNT(uvd->handle->md_module);}int usbvideo_register( usbvideo_t **pCams, const int num_cams, const int num_extra, const char *driverName, const usbvideo_cb_t *cbTbl, struct module *md ){ static const char proc[] = "usbvideo_register"; usbvideo_t *cams; int i, base_size; /* Check parameters for sanity */ if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) { err("%s: Illegal call", proc); return -EINVAL; } /* Check registration callback - must be set! */ if (cbTbl->probe == NULL) { err("%s: probe() is required!", proc); return -EINVAL; } base_size = num_cams * sizeof(uvd_t) + sizeof(usbvideo_t); cams = (usbvideo_t *) kmalloc(base_size, GFP_KERNEL); if (cams == NULL) { err("Failed to allocate %d. bytes for usbvideo_t", base_size); return -ENOMEM; } dbg("%s: Allocated $%p (%d. bytes) for %d. cameras", proc, 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 USES_PROC_FS /* * If both /proc fs callbacks are NULL then we assume that the driver * does not need procfs services at all. Leave them NULL. */ cams->uses_procfs = (cams->cb.procfs_read != NULL) || (cams->cb.procfs_write == NULL); if (cams->uses_procfs) { if (cams->cb.procfs_read == NULL) cams->cb.procfs_read = usbvideo_default_procfs_read_proc; if (cams->cb.procfs_write == NULL) cams->cb.procfs_write = usbvideo_default_procfs_write_proc; }#else /* !USES_PROC_FS */ /* Report a warning so that user knows why there is no /proc entries */ if ((cams->cb.procfs_read != NULL) || (cams->cb.procfs_write == NULL)) { dbg("%s: /proc fs support requested but not configured!", proc); }#endif cams->num_cameras = num_cams; cams->cam = (uvd_t *) &cams[1]; cams->md_module = md; if (cams->md_module == NULL) warn("%s: module == NULL!", proc); init_MUTEX(&cams->lock); /* to 1 == available */ for (i = 0; i < num_cams; i++) { uvd_t *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) { up->user_size = 0; err("%s: Failed to allocate user_data (%d. bytes)", proc, up->user_size); return -ENOMEM; } dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)", proc, 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;#if USES_PROC_FS if (cams->uses_procfs) { dbg("%s: Creating /proc filesystem entries.", proc); usbvideo_procfs_level1_create(cams); }#endif /* * 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; usb_register(&cams->usbdrv); return 0;}/* * 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(usbvideo_t **pCams){ static const char proc[] = "usbvideo_deregister"; usbvideo_t *cams; int i; if (pCams == NULL) { err("%s: pCams == NULL", proc); return; } cams = *pCams; if (cams == NULL) { err("%s: cams == NULL", proc); return; }#if USES_PROC_FS if (cams->uses_procfs) { dbg("%s: Deregistering filesystem entries.", proc); usbvideo_procfs_level1_destroy(cams); }#endif dbg("%s: Deregistering %s driver.", proc, cams->drvName); usb_deregister(&cams->usbdrv); dbg("%s: Deallocating cams=$%p (%d. cameras)", proc, cams, cams->num_cameras); for (i=0; i < cams->num_cameras; i++) { uvd_t *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.", proc, up->user_data, up->user_size); } else { dbg("%s: Freeing %d. $%p->user_data=$%p", proc, i, up, up->user_data); kfree(up->user_data); } } /* Whole array was allocated in one chunk */ dbg("%s: Freed %d uvd_t structures", proc, cams->num_cameras); kfree(cams); *pCams = NULL;}/* * 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. */void usbvideo_Disconnect(struct usb_device *dev, void *ptr){ static const char proc[] = "usbvideo_Disconnect"; uvd_t *uvd = (uvd_t *) ptr; int i; if ((dev == NULL) || (uvd == NULL)) { err("%s($%p,$%p): Illegal call.", proc, dev, ptr); return; } usbvideo_ClientIncModCount(uvd); if (uvd->debug > 0) info("%s(%p,%p.)", proc, dev, ptr); down(&uvd->lock); uvd->remove_pending = 1; /* Now all ISO data will be ignored */ /* At this time we ask to cancel outstanding URBs */ usbvideo_StopDataPump(uvd); for (i=0; i < USBVIDEO_NUMSBUF; i++) usb_free_urb(uvd->sbuf[i].urb); usb_dec_dev_use(uvd->dev); uvd->dev = NULL; /* USB device is no more */ if (uvd->user)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -