Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f513a01b authored by Guenter Roeck's avatar Guenter Roeck Committed by Greg Kroah-Hartman
Browse files

media: uvcvideo: Handle errors from calls to usb_string



[ Upstream commit 4867bb590ae445bcfaa711a86b603c97e94574b3 ]

On a Webcam from Quanta, we see the following error.

usb 3-5: New USB device found, idVendor=0408, idProduct=30d2, bcdDevice= 0.03
usb 3-5: New USB device strings: Mfr=3, Product=1, SerialNumber=2
usb 3-5: Product: USB2.0 HD UVC WebCam
usb 3-5: Manufacturer: Quanta
usb 3-5: SerialNumber: 0x0001
...
uvcvideo: Found UVC 1.10 device USB2.0 HD UVC WebCam (0408:30d2)
uvcvideo: Failed to initialize entity for entity 5
uvcvideo: Failed to register entities (-22).

The Webcam reports an entity of type UVC_VC_EXTENSION_UNIT. It reports a
string index of '7' associated with that entity. The attempt to read that
string from the camera fails with error -32 (-EPIPE). usb_string() returns
that error, but it is ignored. As result, the entity name is empty. This
later causes v4l2_device_register_subdev() to return -EINVAL, and no
entities are registered as result.

While this appears to be a firmware problem with the camera, the kernel
should still handle the situation gracefully. To do that, check the return
value from usb_string(). If it reports an error, assign the entity's
default name.

Signed-off-by: default avatarGuenter Roeck <linux@roeck-us.net>
Reviewed-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 2914259f
Loading
Loading
Loading
Loading
+19 −29
Original line number Original line Diff line number Diff line
@@ -1033,10 +1033,8 @@ static int uvc_parse_vendor_control(struct uvc_device *dev,
					       + n;
					       + n;
		memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);
		memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);


		if (buffer[24+p+2*n] != 0)
		if (buffer[24+p+2*n] == 0 ||
			usb_string(udev, buffer[24+p+2*n], unit->name,
		    usb_string(udev, buffer[24+p+2*n], unit->name, sizeof(unit->name)) < 0)
				   sizeof(unit->name));
		else
			sprintf(unit->name, "Extension %u", buffer[3]);
			sprintf(unit->name, "Extension %u", buffer[3]);


		list_add_tail(&unit->list, &dev->entities);
		list_add_tail(&unit->list, &dev->entities);
@@ -1161,15 +1159,15 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
			memcpy(term->media.bmTransportModes, &buffer[10+n], p);
			memcpy(term->media.bmTransportModes, &buffer[10+n], p);
		}
		}


		if (buffer[7] != 0)
		if (buffer[7] == 0 ||
			usb_string(udev, buffer[7], term->name,
		    usb_string(udev, buffer[7], term->name, sizeof(term->name)) < 0) {
				   sizeof(term->name));
			if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA)
		else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA)
				sprintf(term->name, "Camera %u", buffer[3]);
				sprintf(term->name, "Camera %u", buffer[3]);
		else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT)
			if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT)
				sprintf(term->name, "Media %u", buffer[3]);
				sprintf(term->name, "Media %u", buffer[3]);
			else
			else
				sprintf(term->name, "Input %u", buffer[3]);
				sprintf(term->name, "Input %u", buffer[3]);
		}


		list_add_tail(&term->list, &dev->entities);
		list_add_tail(&term->list, &dev->entities);
		break;
		break;
@@ -1201,10 +1199,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev,


		memcpy(term->baSourceID, &buffer[7], 1);
		memcpy(term->baSourceID, &buffer[7], 1);


		if (buffer[8] != 0)
		if (buffer[8] == 0 ||
			usb_string(udev, buffer[8], term->name,
		    usb_string(udev, buffer[8], term->name, sizeof(term->name)) < 0)
				   sizeof(term->name));
		else
			sprintf(term->name, "Output %u", buffer[3]);
			sprintf(term->name, "Output %u", buffer[3]);


		list_add_tail(&term->list, &dev->entities);
		list_add_tail(&term->list, &dev->entities);
@@ -1226,10 +1222,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev,


		memcpy(unit->baSourceID, &buffer[5], p);
		memcpy(unit->baSourceID, &buffer[5], p);


		if (buffer[5+p] != 0)
		if (buffer[5+p] == 0 ||
			usb_string(udev, buffer[5+p], unit->name,
		    usb_string(udev, buffer[5+p], unit->name, sizeof(unit->name)) < 0)
				   sizeof(unit->name));
		else
			sprintf(unit->name, "Selector %u", buffer[3]);
			sprintf(unit->name, "Selector %u", buffer[3]);


		list_add_tail(&unit->list, &dev->entities);
		list_add_tail(&unit->list, &dev->entities);
@@ -1259,10 +1253,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
		if (dev->uvc_version >= 0x0110)
		if (dev->uvc_version >= 0x0110)
			unit->processing.bmVideoStandards = buffer[9+n];
			unit->processing.bmVideoStandards = buffer[9+n];


		if (buffer[8+n] != 0)
		if (buffer[8+n] == 0 ||
			usb_string(udev, buffer[8+n], unit->name,
		    usb_string(udev, buffer[8+n], unit->name, sizeof(unit->name)) < 0)
				   sizeof(unit->name));
		else
			sprintf(unit->name, "Processing %u", buffer[3]);
			sprintf(unit->name, "Processing %u", buffer[3]);


		list_add_tail(&unit->list, &dev->entities);
		list_add_tail(&unit->list, &dev->entities);
@@ -1290,10 +1282,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
		unit->extension.bmControls = (u8 *)unit + sizeof(*unit);
		unit->extension.bmControls = (u8 *)unit + sizeof(*unit);
		memcpy(unit->extension.bmControls, &buffer[23+p], n);
		memcpy(unit->extension.bmControls, &buffer[23+p], n);


		if (buffer[23+p+n] != 0)
		if (buffer[23+p+n] == 0 ||
			usb_string(udev, buffer[23+p+n], unit->name,
		    usb_string(udev, buffer[23+p+n], unit->name, sizeof(unit->name)) < 0)
				   sizeof(unit->name));
		else
			sprintf(unit->name, "Extension %u", buffer[3]);
			sprintf(unit->name, "Extension %u", buffer[3]);


		list_add_tail(&unit->list, &dev->entities);
		list_add_tail(&unit->list, &dev->entities);