diff options
Diffstat (limited to 'linux/drivers/media/video')
-rw-r--r-- | linux/drivers/media/video/uvc/uvc_ctrl.c | 2 | ||||
-rw-r--r-- | linux/drivers/media/video/uvc/uvc_driver.c | 27 | ||||
-rw-r--r-- | linux/drivers/media/video/uvc/uvc_status.c | 16 | ||||
-rw-r--r-- | linux/drivers/media/video/uvc/uvc_v4l2.c | 12 | ||||
-rw-r--r-- | linux/drivers/media/video/uvc/uvc_video.c | 79 | ||||
-rw-r--r-- | linux/drivers/media/video/uvc/uvcvideo.h | 7 |
6 files changed, 74 insertions, 69 deletions
diff --git a/linux/drivers/media/video/uvc/uvc_ctrl.c b/linux/drivers/media/video/uvc/uvc_ctrl.c index f3f36f625..7774ce6b5 100644 --- a/linux/drivers/media/video/uvc/uvc_ctrl.c +++ b/linux/drivers/media/video/uvc/uvc_ctrl.c @@ -788,7 +788,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl); v4l2_ctrl->id = mapping->id; v4l2_ctrl->type = mapping->v4l2_type; - strncpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name); + strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name); v4l2_ctrl->flags = 0; if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR)) diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c index 401bb7c15..2a41eb418 100644 --- a/linux/drivers/media/video/uvc/uvc_driver.c +++ b/linux/drivers/media/video/uvc/uvc_driver.c @@ -314,7 +314,7 @@ static int uvc_parse_format(struct uvc_device *dev, fmtdesc = uvc_format_by_guid(&buffer[5]); if (fmtdesc != NULL) { - strncpy(format->name, fmtdesc->name, + strlcpy(format->name, fmtdesc->name, sizeof format->name); format->fcc = fmtdesc->fcc; } else { @@ -345,7 +345,7 @@ static int uvc_parse_format(struct uvc_device *dev, return -EINVAL; } - strncpy(format->name, "MJPEG", sizeof format->name); + strlcpy(format->name, "MJPEG", sizeof format->name); format->fcc = V4L2_PIX_FMT_MJPEG; format->flags = UVC_FMT_FLAG_COMPRESSED; format->bpp = 0; @@ -363,13 +363,13 @@ static int uvc_parse_format(struct uvc_device *dev, switch (buffer[8] & 0x7f) { case 0: - strncpy(format->name, "SD-DV", sizeof format->name); + strlcpy(format->name, "SD-DV", sizeof format->name); break; case 1: - strncpy(format->name, "SDL-DV", sizeof format->name); + strlcpy(format->name, "SDL-DV", sizeof format->name); break; case 2: - strncpy(format->name, "HD-DV", sizeof format->name); + strlcpy(format->name, "HD-DV", sizeof format->name); break; default: uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" @@ -379,7 +379,7 @@ static int uvc_parse_format(struct uvc_device *dev, return -EINVAL; } - strncat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz", + strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz", sizeof format->name); format->fcc = V4L2_PIX_FMT_DV; @@ -1526,7 +1526,7 @@ static int uvc_register_video(struct uvc_device *dev) vdev->minor = -1; vdev->fops = &uvc_fops; vdev->release = video_device_release; - strncpy(vdev->name, dev->name, sizeof vdev->name); + strlcpy(vdev->name, dev->name, sizeof vdev->name); /* Set the driver data before calling video_register_device, otherwise * uvc_v4l2_open might race us. @@ -1621,7 +1621,7 @@ static int uvc_probe(struct usb_interface *intf, dev->quirks = id->driver_info | uvc_quirks_param; if (udev->product != NULL) - strncpy(dev->name, udev->product, sizeof dev->name); + strlcpy(dev->name, udev->product, sizeof dev->name); else snprintf(dev->name, sizeof dev->name, "UVC Camera (%04x:%04x)", @@ -1835,6 +1835,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceSubClass = 1, .bInterfaceProtocol = 0 }, + /* Alcor Micro AU3820 (Future Boy PC USB Webcam) */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x058f, + .idProduct = 0x3820, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, /* Apple Built-In iSight */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -1881,7 +1890,7 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* Asus F9SG */ + /* Syntek (Asus F9SG) */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x174f, diff --git a/linux/drivers/media/video/uvc/uvc_status.c b/linux/drivers/media/video/uvc/uvc_status.c index 77a263463..4f4171fa8 100644 --- a/linux/drivers/media/video/uvc/uvc_status.c +++ b/linux/drivers/media/video/uvc/uvc_status.c @@ -28,26 +28,19 @@ #ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV static int uvc_input_init(struct uvc_device *dev) { - struct usb_device *udev = dev->udev; struct input_dev *input; - char *phys = NULL; int ret; input = input_allocate_device(); if (input == NULL) return -ENOMEM; - phys = kmalloc(6 + strlen(udev->bus->bus_name) + strlen(udev->devpath), - GFP_KERNEL); - if (phys == NULL) { - ret = -ENOMEM; - goto error; - } - sprintf(phys, "usb-%s-%s", udev->bus->bus_name, udev->devpath); + usb_make_path(dev->udev, dev->input_phys, sizeof(dev->input_phys)); + strlcat(dev->input_phys, "/button", sizeof(dev->input_phys)); input->name = dev->name; - input->phys = phys; - usb_to_input_id(udev, &input->id); + input->phys = dev->input_phys; + usb_to_input_id(dev->udev, &input->id); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) input->dev.parent = &dev->intf->dev; #else @@ -65,7 +58,6 @@ static int uvc_input_init(struct uvc_device *dev) error: input_free_device(input); - kfree(phys); return ret; } diff --git a/linux/drivers/media/video/uvc/uvc_v4l2.c b/linux/drivers/media/video/uvc/uvc_v4l2.c index f295d7169..9130349f4 100644 --- a/linux/drivers/media/video/uvc/uvc_v4l2.c +++ b/linux/drivers/media/video/uvc/uvc_v4l2.c @@ -55,7 +55,7 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video, return -EINVAL; menu_info = &mapping->menu_info[query_menu->index]; - strncpy(query_menu->name, menu_info->name, 32); + strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name); return 0; } @@ -492,9 +492,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_capability *cap = arg; memset(cap, 0, sizeof *cap); - strncpy(cap->driver, "uvcvideo", sizeof cap->driver); - strncpy(cap->card, vdev->name, 32); - strncpy(cap->bus_info, video->dev->udev->bus->bus_name, + strlcpy(cap->driver, "uvcvideo", sizeof cap->driver); + strlcpy(cap->card, vdev->name, sizeof cap->card); + strlcpy(cap->bus_info, video->dev->udev->bus->bus_name, sizeof cap->bus_info); cap->version = DRIVER_VERSION_NUMBER; if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -626,7 +626,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) memset(input, 0, sizeof *input); input->index = index; - strncpy(input->name, iterm->name, sizeof input->name); + strlcpy(input->name, iterm->name, sizeof input->name); if (UVC_ENTITY_TYPE(iterm) == ITT_CAMERA) input->type = V4L2_INPUT_TYPE_CAMERA; break; @@ -688,7 +688,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) fmt->flags = 0; if (format->flags & UVC_FMT_FLAG_COMPRESSED) fmt->flags |= V4L2_FMT_FLAG_COMPRESSED; - strncpy(fmt->description, format->name, + strlcpy(fmt->description, format->name, sizeof fmt->description); fmt->description[sizeof fmt->description - 1] = 0; fmt->pixelformat = format->fcc; diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index 999155fc2..04c791213 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -703,27 +703,47 @@ static void uvc_free_urb_buffers(struct uvc_video_device *video) * already allocated when resuming from suspend, in which case it will * return without touching the buffers. * - * Return 0 on success or -ENOMEM when out of memory. + * Limit the buffer size to UVC_MAX_PACKETS bulk/isochronous packets. If the + * system is too low on memory try successively smaller numbers of packets + * until allocation succeeds. + * + * Return the number of allocated packets on success or 0 when out of memory. */ static int uvc_alloc_urb_buffers(struct uvc_video_device *video, - unsigned int size) + unsigned int size, unsigned int psize, gfp_t gfp_flags) { + unsigned int npackets; unsigned int i; /* Buffers are already allocated, bail out. */ if (video->urb_size) return 0; - for (i = 0; i < UVC_URBS; ++i) { - video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev, - size, GFP_KERNEL, &video->urb_dma[i]); - if (video->urb_buffer[i] == NULL) { - uvc_free_urb_buffers(video); - return -ENOMEM; + /* Compute the number of packets. Bulk endpoints might transfer UVC + * payloads accross multiple URBs. + */ + npackets = DIV_ROUND_UP(size, psize); + if (npackets > UVC_MAX_PACKETS) + npackets = UVC_MAX_PACKETS; + + /* Retry allocations until one succeed. */ + for (; npackets > 1; npackets /= 2) { + for (i = 0; i < UVC_URBS; ++i) { + video->urb_buffer[i] = usb_buffer_alloc( + video->dev->udev, psize * npackets, + gfp_flags | __GFP_NOWARN, &video->urb_dma[i]); + if (!video->urb_buffer[i]) { + uvc_free_urb_buffers(video); + break; + } + } + + if (i == UVC_URBS) { + video->urb_size = psize * npackets; + return npackets; } } - video->urb_size = size; return 0; } @@ -757,29 +777,19 @@ static int uvc_init_video_isoc(struct uvc_video_device *video, { struct urb *urb; unsigned int npackets, i, j; - __u16 psize; - __u32 size; + u16 psize; + u32 size; - /* Compute the number of isochronous packets to allocate by dividing - * the maximum video frame size by the packet size. Limit the result - * to UVC_MAX_ISO_PACKETS. - */ psize = le16_to_cpu(ep->desc.wMaxPacketSize); psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); - size = video->streaming->ctrl.dwMaxVideoFrameSize; - if (size > UVC_MAX_FRAME_SIZE) - return -EINVAL; - npackets = DIV_ROUND_UP(size, psize); - if (npackets > UVC_MAX_ISO_PACKETS) - npackets = UVC_MAX_ISO_PACKETS; + npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags); + if (npackets == 0) + return -ENOMEM; size = npackets * psize; - if (uvc_alloc_urb_buffers(video, size) < 0) - return -ENOMEM; - for (i = 0; i < UVC_URBS; ++i) { urb = usb_alloc_urb(npackets, gfp_flags); if (urb == NULL) { @@ -818,25 +828,20 @@ static int uvc_init_video_bulk(struct uvc_video_device *video, struct usb_host_endpoint *ep, gfp_t gfp_flags) { struct urb *urb; - unsigned int pipe, i; - __u16 psize; - __u32 size; - - /* Compute the bulk URB size. Some devices set the maximum payload - * size to a value too high for memory-constrained devices. We must - * then transfer the payload accross multiple URBs. To be consistant - * with isochronous mode, allocate maximum UVC_MAX_ISO_PACKETS per bulk - * URB. - */ + unsigned int npackets, pipe, i; + u16 psize; + u32 size; + psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff; size = video->streaming->ctrl.dwMaxPayloadTransferSize; video->bulk.max_payload_size = size; - if (size > psize * UVC_MAX_ISO_PACKETS) - size = psize * UVC_MAX_ISO_PACKETS; - if (uvc_alloc_urb_buffers(video, size) < 0) + npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags); + if (npackets == 0) return -ENOMEM; + size = npackets * psize; + if (usb_endpoint_dir_in(&ep->desc)) pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress); diff --git a/linux/drivers/media/video/uvc/uvcvideo.h b/linux/drivers/media/video/uvc/uvcvideo.h index c9f4973ea..408b8b846 100644 --- a/linux/drivers/media/video/uvc/uvcvideo.h +++ b/linux/drivers/media/video/uvc/uvcvideo.h @@ -297,10 +297,8 @@ struct uvc_xu_control { /* Number of isochronous URBs. */ #define UVC_URBS 5 -/* Maximum number of packets per isochronous URB. */ -#define UVC_MAX_ISO_PACKETS 40 -/* Maximum frame size in bytes, for sanity checking. */ -#define UVC_MAX_FRAME_SIZE (16*1024*1024) +/* Maximum number of packets per URB. */ +#define UVC_MAX_PACKETS 32 /* Maximum number of video buffers. */ #define UVC_MAX_VIDEO_BUFFERS 32 /* Maximum status buffer size in bytes of interrupt URB. */ @@ -650,6 +648,7 @@ struct uvc_device { struct urb *int_urb; __u8 *status; struct input_dev *input; + char input_phys[64]; /* Video Streaming interfaces */ struct list_head streaming; |