|
@@ -413,10 +413,21 @@ uvc_function_disconnect(struct uvc_device *uvc)
|
|
|
* USB probe and disconnect
|
|
|
*/
|
|
|
|
|
|
+static ssize_t function_name_show(struct device *dev,
|
|
|
+ struct device_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ struct uvc_device *uvc = dev_get_drvdata(dev);
|
|
|
+
|
|
|
+ return sprintf(buf, "%s\n", uvc->func.fi->group.cg_item.ci_name);
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR_RO(function_name);
|
|
|
+
|
|
|
static int
|
|
|
uvc_register_video(struct uvc_device *uvc)
|
|
|
{
|
|
|
struct usb_composite_dev *cdev = uvc->func.config->cdev;
|
|
|
+ int ret;
|
|
|
|
|
|
/* TODO reference counting. */
|
|
|
uvc->vdev.v4l2_dev = &uvc->v4l2_dev;
|
|
@@ -429,7 +440,17 @@ uvc_register_video(struct uvc_device *uvc)
|
|
|
|
|
|
video_set_drvdata(&uvc->vdev, uvc);
|
|
|
|
|
|
- return video_register_device(&uvc->vdev, VFL_TYPE_GRABBER, -1);
|
|
|
+ ret = video_register_device(&uvc->vdev, VFL_TYPE_GRABBER, -1);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = device_create_file(&uvc->vdev.dev, &dev_attr_function_name);
|
|
|
+ if (ret < 0) {
|
|
|
+ video_unregister_device(&uvc->vdev);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
#define UVC_COPY_DESCRIPTOR(mem, dst, desc) \
|
|
@@ -867,6 +888,7 @@ static void uvc_unbind(struct usb_configuration *c, struct usb_function *f)
|
|
|
|
|
|
INFO(cdev, "%s\n", __func__);
|
|
|
|
|
|
+ device_remove_file(&uvc->vdev.dev, &dev_attr_function_name);
|
|
|
video_unregister_device(&uvc->vdev);
|
|
|
v4l2_device_unregister(&uvc->v4l2_dev);
|
|
|
|