📄 uvcvideo.c.svn-base
字号:
.v4l2 = V4L2_CID_PANTILT_RELATIVE, .name = "Pan/Tilt (relative)", .id = LXU_MOTOR_PANTILT_RELATIVE_CONTROL, .bit = 0, .size = 4, .type = V4L2_CTRL_TYPE_INTEGER, .unit = UVC_GUID_LOGITECH_MOTOR, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_DEF, }, { .v4l2 = V4L2_CID_PANTILT_RESET, .name = "Pan/Tilt (reset)", .id = LXU_MOTOR_PANTILT_RESET_CONTROL, .bit = 0, .size = 1, .type = V4L2_CTRL_TYPE_INTEGER, .unit = UVC_GUID_LOGITECH_MOTOR, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF, }, { .v4l2 = V4L2_CID_EXPOSURE_AUTO, .name = "Exposure, Auto", .id = CT_AE_MODE_CONTROL, .bit = 1, .size = 1, .type = V4L2_CTRL_TYPE_INTEGER, .unit = UVC_GUID_UVC_CAMERA, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_DEF | UVC_CONTROL_GET_RES, }, { .v4l2 = V4L2_CID_EXPOSURE_ABSOLUTE, .name = "Exposure (Absolute)", .id = CT_EXPOSURE_TIME_ABSOLUTE_CONTROL, .bit = 3, .size = 4, .type = V4L2_CTRL_TYPE_INTEGER, .unit = UVC_GUID_UVC_CAMERA, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF, }, { .v4l2 = V4L2_CID_WHITE_BALANCE_TEMPERATURE_AUTO, .name = "White Balance Temperature, Auto", .id = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, .bit = 12, .size = 1, .type = V4L2_CTRL_TYPE_BOOLEAN, .unit = UVC_GUID_UVC_PROCESSING, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_DEF, }, { .v4l2 = V4L2_CID_WHITE_BALANCE_TEMPERATURE, .name = "White Balance Temperature", .id = PU_WHITE_BALANCE_TEMPERATURE_CONTROL, .bit = 6, .size = 2, .type = V4L2_CTRL_TYPE_INTEGER, .unit = UVC_GUID_UVC_PROCESSING, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF, }};static struct uvc_format_desc uvc_fmts[] = { { .guid = UVC_GUID_FORMAT_YUY2, .fcc = V4L2_PIX_FMT_YUYV, }, { .guid = UVC_GUID_FORMAT_YUY2, .fcc = V4L2_PIX_FMT_YUYV, }, { .guid = UVC_GUID_FORMAT_NV12, .fcc = V4L2_PIX_FMT_NV12, },};static const __u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;/*#define PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d#define PU_DIGITAL_MULTIPLIER_CONTROL 0x0e#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f*//* ------------------------------------------------------------------------ * Debugging, printing and logging */#define UVC_TRACE_PROBE (1 << 0)#define UVC_TRACE_DESCR (1 << 1)#define UVC_TRACE_CONTROL (1 << 2)#define UVC_TRACE_FORMAT (1 << 3)#define UVC_TRACE_CAPTURE (1 << 4)#define UVC_TRACE_CALLS (1 << 5)#define UVC_TRACE_IOCTL (1 << 6)#define UVC_TRACE_FRAME (1 << 7)static unsigned int trace = 0;#define uvc_trace(flag, msg...) \ do { \ if (trace & flag) \ printk(KERN_DEBUG "uvcvideo: " msg); \ } while(0)#define uvc_printk(level, msg...) \ printk(level "uvcvideo: " msg)#if 0static void uvc_print_streaming_control(struct uvc_streaming_control *ctrl){ printk(KERN_DEBUG "bmHint: 0x%04x\n", ctrl->bmHint); printk(KERN_DEBUG "bFormatIndex: %3u\n", ctrl->bFormatIndex); printk(KERN_DEBUG "bFrameIndex: %3u\n", ctrl->bFrameIndex); printk(KERN_DEBUG "dwFrameInterval: %9u\n", ctrl->dwFrameInterval); printk(KERN_DEBUG "wKeyFrameRate: %5u\n", ctrl->wKeyFrameRate); printk(KERN_DEBUG "wPFrameRate: %5u\n", ctrl->wPFrameRate); printk(KERN_DEBUG "wCompQuality: %5u\n", ctrl->wCompQuality); printk(KERN_DEBUG "wCompWindowSize: %5u\n", ctrl->wCompWindowSize); printk(KERN_DEBUG "wDelay: %5u\n", ctrl->wDelay); printk(KERN_DEBUG "dwMaxVideoFrameSize: %9u\n", ctrl->dwMaxVideoFrameSize); printk(KERN_DEBUG "dwMaxPayloadTransferSize: %9u\n", ctrl->dwMaxPayloadTransferSize); printk(KERN_DEBUG "dwClockFrequency: %9u\n", ctrl->dwClockFrequency); printk(KERN_DEBUG "bmFramingInfo: 0x%02x\n", ctrl->bmFramingInfo); printk(KERN_DEBUG "bPreferedVersion: %3u\n", ctrl->bPreferedVersion); printk(KERN_DEBUG "bMinVersion: %3u\n", ctrl->bMinVersion); printk(KERN_DEBUG "bMaxVersion: %3u\n", ctrl->bMaxVersion);}#endif/* ------------------------------------------------------------------------ * Utility functions */static inline int uvc_get_bit(const __u8 *data, int bit){ return (data[bit >> 3] >> (bit & 7)) & 1;}static __s32 uvc_get_le_value(const __u8 *data, int size){ switch (size) { case 1: return data[0]; case 2: return le16_to_cpup((__le16*)data); case 4: return le32_to_cpup((__le32*)data); } return 0;}static void uvc_set_le_value(__s32 value, __u8 *data, int size){ switch (size) { case 1: data[0] = value; break; case 2: *(__le16*)&data[0] = cpu_to_le16(value); break; case 4: *(__le32*)&data[0] = cpu_to_le32(value); break; }}static struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, __u8 epaddr){ struct usb_host_endpoint *ep; unsigned int i; for (i = 0; i < alts->desc.bNumEndpoints; ++i) { ep = &alts->endpoint[i]; if (ep->desc.bEndpointAddress == epaddr) return ep; } return NULL;}static __u32 uvc_guid_to_fcc(const __u8 guid[16]){ unsigned int len = ARRAY_SIZE(uvc_fmts); unsigned int i; for (i = 0; i < len; ++i) { if (memcmp(guid, uvc_fmts[i].guid, 16) == 0) return uvc_fmts[i].fcc; } return -1;}static __u32 uvc_colorspace(const __u8 primaries){ static const __u8 colorprimaries[] = { 0, V4L2_COLORSPACE_SRGB, V4L2_COLORSPACE_470_SYSTEM_M, V4L2_COLORSPACE_470_SYSTEM_BG, V4L2_COLORSPACE_SMPTE170M, V4L2_COLORSPACE_SMPTE240M, }; if (primaries < ARRAY_SIZE(colorprimaries)) return colorprimaries[primaries]; return 0;}/* Simplify a fraction using a simple continued fraction decomposition. The * idea here is to convert fractions such as 333333/10000000 to 1/30 using * 32 bit arithmetic only. The algorithm is not perfect and relies upon two * arbitrary parameters to remove non-significative terms from the simple * continued fraction decomposition. Using 8 and 333 for n_terms and threshold * respectively seems to give nice results. */static void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator, unsigned int n_terms, unsigned int threshold){ uint32_t *an; uint32_t x, y, r; unsigned int i, n; an = kmalloc(n_terms * sizeof *an, GFP_KERNEL); if (an == NULL) return; /* Convert the fraction to a simple continued fraction. See * http://mathforum.org/dr.math/faq/faq.fractions.html * Stop if the current term is bigger than or equal to the given * threshold. */ memset(an, 0, sizeof an); x = *numerator; y = *denominator; for (n = 0; n < n_terms && y != 0; ++n) { an[n] = x / y; if (an[n] >= threshold) { if (n < 2) n++; break; } r = x - an[n] * y; x = y; y = r; } /* Expand the simple continued fraction back to an integer fraction. */ x = 0; y = 1; for (i = n; i > 0; --i) { r = y; y = an[i-1] * y + x; x = r; } *numerator = y; *denominator = x; kfree(an);}/* Convert a fraction to a frame interval in 100ns multiples. The idea here is * to compute numerator / denominator * 10000000 using 32 bit fixed point * arithmetic only. */static uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator){ uint32_t multiplier; /* Saturate the result if the operation would overflow. */ if (numerator/denominator >= ((uint32_t)-1)/10000000) return (uint32_t)-1; /* Divide both the denominator and the multiplier by two until * numerator * multiplier doesn't overflow. If anyone knows a better * algorithm please let me know. */ multiplier = 10000000; while (numerator > ((uint32_t)-1)/multiplier) { multiplier /= 2; denominator /= 2; } return denominator ? numerator * multiplier / denominator : 0;}/* ------------------------------------------------------------------------ * Terminal and unit management */static struct uvc_terminal *uvc_terminal(struct uvc_device *dev, int id){ struct list_head *p; list_for_each(p, &dev->terminals) { struct uvc_terminal *terminal; terminal = list_entry(p, struct uvc_terminal, list); if (terminal->id == id) return terminal; } return NULL;}static struct uvc_unit *uvc_unit_by_id(struct uvc_device *dev, int id){ struct list_head *p; list_for_each(p, &dev->units) { struct uvc_unit *unit; unit = list_entry(p, struct uvc_unit, list); if (unit->id == id) return unit; } return NULL;}static struct uvc_unit *uvc_unit_by_guid(struct uvc_device *dev, __u8 guid[16]){ struct list_head *p; list_for_each(p, &dev->units) { struct uvc_unit *unit; unit = list_entry(p, struct uvc_unit, list); if (unit->type == VC_EXTENSION_UNIT && memcmp(unit->extension.guidExtensionCode, guid, 16) == 0) return unit; } return NULL;}/* ------------------------------------------------------------------------ * Video buffers queue management. * * Video queues is initialized by uvc_queue_init(). The function performs * basic initialization of the uvc_video_queue struct and never fails. * * Video buffer allocation and freeing are performed by uvc_alloc_buffers and * uvc_free_buffers respectively. The former acquires the video queue lock, * while the later must be called with the lock held (so that allocation can * free previously allocated buffers). Trying to free buffers that are mapped * to user space will return -EBUSY. * * Video buffers are managed using two queues. However, unlike most USB video * drivers which use an in queue and an out queue, we use a main queue which * holds all queued buffers (both 'empty' and 'done' buffers), and an irq * queue which holds empty buffers. This design (copied from video-buf) * minimizes locking in interrupt, as only one queue is shared between * interrupt and user contexts. * * Use cases * --------- * * Unless stated otherwise, all operations which modify the irq buffers queue * are protected by the irq spinlock. * * 1. The user queues the buffers, starts streaming and dequeues a buffer. * * The buffers are added to the main and irq queues. Both operations are * protected by the queue lock, and the latert is protected by the irq * spinlock as well. * * The completion handler fetches a buffer from the irq queue and fills it * with video data. If no buffer is available (irq queue empty), the handler * returns immediately. * * When the buffer is full, the completion handler removes it from the irq * queue, marks it as ready (UVC_BUF_STATE_DONE) and wake its wait queue. * At that point, any process waiting on the buffer will be woken up. If a * process tries to dequeue a buffer after it has been marked ready, the * dequeing will succeed immediately. * * 2. Buffers are queued, user is waiting on a buffer and the device gets * disconnected. * * When the device is disconnected, the kernel calls the completion handler * with an appropriate status code. The handler marks all buffers in the * irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so * that any process waiting on a buffer gets woken up. * * Waking up up the first buffer on the irq list is not enough, as the * process waiting on the buffer might restart the dequeue operation * immediately. * *//* * Free the video buffers. * * This function must be called with the queue lock held. */static int uvc_free_buffers(struct uvc_video_queue *queue){ unsigned int i; for (i = 0; i < queue->count; ++i) { if (queue->buffer[i].vma_use_count != 0) return -EBUSY; } if (queue->count) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) unsigned long addr = (unsigned long)queue->mem; size_t size = queue->count * queue->buffer[0].size; while (size > 0) { ClearPageReserved(vmalloc_to_page((void*)addr)); addr += PAGE_SIZE; size -= PAGE_SIZE; }#endif vfree(queue->mem); queue->count = 0; } return 0;}/* * Allocate the video buffers. * * Pages are reserved to make sure they will not be swaped, as they will be * filled in URB completion handler. * * Buffers will be individually mapped, so they must all be page aligned. */static int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, unsigned int buflength){ unsigned int bufsize = PAGE_ALIGN(buflength); unsigned int i; void *mem = NULL; int ret; if (nbuffers > UVC_MAX_VIDEO_BUFFERS) nbuffers = UVC_MAX_VIDEO_BUFFERS; down(&queue->lock); if ((ret = uvc_free_buffers(queue)) < 0) goto done; /* Decrement the number of buffers until allocation succeeds. */ for (; nbuffers > 0; --nbuffers) { mem = vmalloc_32(nbuffers * bufsize); if (mem != NULL) break; } if (mem == NULL) { ret = -ENOMEM; goto done; } for (i = 0; i < nbuffers; ++i) { memset(&queue->buffer[i], 0, sizeof queue->buffer[i]); queue->buffer[i].size = bufsize; queue->buffer[i].buf.index = i; queue->buffer[i].buf.m.offset = i * bufsize; queue->buffer[i].buf.length = buflength; queue->buffer[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; queue->buffer[i].buf.sequence = 0; queue->buffer[i].buf.field = V4L2_FIELD_NONE; queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP; queue->buffer[i].buf.flags = 0; init_waitqueue_head(&queue->buffer[i].wait); } queue->mem = mem; queue->count = nbuffers;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -