接着上一篇UVC摄像头(1)
composite_gadget_bind(cdev);
我们绑定它的函数是这个
webcam_bind(struct usb_composite_dev *cdev)
{
int ret;
/* Allocate string descriptor numbers ... note that string contents
* can be overridden by the composite_dev glue.
*/
if ((ret = usb_string_id(cdev)) < 0)
goto error;
webcam_strings[STRING_MANUFACTURER_IDX].id = ret;
webcam_device_descriptor.iManufacturer = ret;
webcam_device_descriptor.idVendor = cpu_to_le16(g_vendor_id);
webcam_device_descriptor.idProduct = cpu_to_le16(g_product_id);
webcam_device_descriptor.bcdDevice = cpu_to_le16(g_device_bcd);
if ((ret = usb_string_id(cdev)) < 0)
goto error;
webcam_strings[STRING_PRODUCT_IDX].id = ret;
webcam_device_descriptor.iProduct = ret;
if ((ret = usb_string_id(cdev)) < 0)
goto error;
webcam_strings[STRING_DESCRIPTION_IDX].id = ret;
webcam_config_driver.iConfiguration = ret;
/* Register our configuration. */
if ((ret = usb_add_config(cdev, &webcam_config_driver,
webcam_config_bind)) < 0)
goto error;
INFO(cdev, "Webcam Video Gadget, VID:%04x, PID:%04x, BCD:%04x\n", g_vendor_id, g_product_id, g_device_bcd);
return 0;
error:
webcam_unbind(cdev);
return ret;
}
填充了webcam_strings、webcam_device_descriptor、webcam_config_driver结构体;之后是重点:usb_add_config
int usb_add_config(struct usb_composite_dev *cdev,
struct usb_configuration *config,
int (*bind)(struct usb_configuration *))
{
int status = -EINVAL;
struct usb_configuration *c;
DBG(cdev, "adding config #%u '%s'/%p\n",
config->bConfigurationValue,
config->label, config);
if (!config->bConfigurationValue || !bind)
goto done;
/* Prevent duplicate configuration identifiers */
list_for_each_entry(c, &cdev->configs, list) {
if (c->bConfigurationValue == config->bConfigurationValue) {
status = -EBUSY;
goto done;
}
}
config->cdev = cdev;
list_add_tail(&config->list, &cdev->configs);
INIT_LIST_HEAD(&config->functions);
config->next_interface_id = 0;
memset(config->interface, 0, sizeof(config->interface));
status = bind(config);
if (status < 0) {
list_del(&config->list);
config->cdev = NULL;
} else {
unsigned i;
DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
config->bConfigurationValue, config,
config->superspeed ? " super" : "",
config->highspeed ? " high" : "",
config->fullspeed
? (gadget_is_dualspeed(cdev->gadget)
? " full"
: " full/low")
: "");
for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {
struct usb_function *f = config->interface[i];
if (!f)
continue;
DBG(cdev, " interface %d = %s/%p\n",
i, f->name, f);
}
}
/* set_alt(), or next bind(), sets up
* ep->driver_data as needed.
*/
usb_ep_autoconfig_reset(cdev->gadget);
done:
if (status)
DBG(cdev, "added config '%s'/%u --> %d\n", config->label,
config->bConfigurationValue, status);
return status;
}
形参cdev内有usb_gadget结构体,所以个人认为UVC描述符参数设置这部分还是属于UDC层。
主要设置流程:usb_add_config->webcam_config_bind->uvc_bind_config->usb_add_function->uvc_function_bind
最后一个函数很关键,其他都是套路
uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct uvc_device *uvc = to_uvc(f);
struct usb_ep *ep;
int ret = -EINVAL;
INFO(cdev, "uvc_function_bind\n");
#if 0
/* Allocate endpoints. */
ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
if (!ep) {
INFO(cdev, "Unable to allocate control EP\n");
goto error;
}
uvc->control_ep = ep;
ep->driver_data = uvc;
#endif
ep = usb_ep_autoconfig(cdev->gadget, &uvc_streaming_ep);
if (!ep) {
INFO(cdev, "Unable to allocate streaming EP\n");
goto error;
}
uvc->video.ep = ep;
ep->driver_data = uvc;
/* Allocate interface IDs. */
if ((ret = usb_interface_id(c, f)) < 0)
goto error;
uvc_iad.bFirstInterface = ret;
uvc_control_intf.bInterfaceNumber = ret;
uvc->control_intf = ret;
if ((ret = usb_interface_id(c, f)) < 0)
goto error;
uvc_streaming_intf_alt0.bInterfaceNumber = ret;
uvc_streaming_intf_alt1.bInterfaceNumber = ret;
uvc->streaming_intf = ret;
/* Copy descriptors. */
f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
/* Preallocate control endpoint request. */
uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL);
if (uvc->control_req == NULL || uvc->control_buf == NULL) {
ret = -ENOMEM;
goto error;
}
uvc->control_req->buf = uvc->control_buf;
uvc->control_req->complete = uvc_function_ep0_complete;
uvc->control_req->context = uvc;
/* Avoid letting this gadget enumerate until the userspace server is
* active.
*/
if ((ret = usb_function_deactivate(f)) < 0)
goto error;
/* Initialise video. */
ret = uvc_video_init(&uvc->video);
if (ret < 0)
goto error;
/* Register a V4L2 device. */
ret = uvc_register_video(uvc);
if (ret < 0) {
printk(KERN_INFO "Unable to register video device\n");
goto error;
}
return 0;
error:
if (uvc->vdev)
video_device_release(uvc->vdev);
if (uvc->control_ep)
uvc->control_ep->driver_data = NULL;
if (uvc->video.ep)
uvc->video.ep->driver_data = NULL;
if (uvc->control_req) {
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
kfree(uvc->control_buf);
}
kfree(f->descriptors);
kfree(f->hs_descriptors);
kfree(f->ss_descriptors);
return ret;
}
这里面
1.Allocate interface IDs分配接口ID
2. Copy descriptors填充USB设备描述符,非常重要
3. Preallocate control endpoint request不去鸟他
4. Avoid letting this gadget enumerate until the userspace server is active不去鸟他
5. Initialise video初始化
6. Register a V4L2 device注册V4L2设备,重要
UVC描述符参数设置
需要的资料:UVC 1.5 Class specification.pdf
uvc_function_bind中复制描述符方法
uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
{
struct uvc_input_header_descriptor *uvc_streaming_header;
struct uvc_header_descriptor *uvc_control_header;
const struct uvc_descriptor_header * const *uvc_streaming_cls;
const struct usb_descriptor_header * const *uvc_streaming_std;
const struct usb_descriptor_header * const *src;
struct usb_descriptor_header **dst;
struct usb_descriptor_header **hdr;
unsigned int control_size;
unsigned int streaming_size;
unsigned int n_desc;
unsigned int bytes;
void *mem;
uvc_streaming_cls = (speed == USB_SPEED_FULL)
? uvc->desc.fs_streaming : uvc->desc.hs_streaming;
uvc_streaming_std = (speed == USB_SPEED_FULL)
? uvc_fs_streaming : uvc_hs_streaming;
/* Descriptors layout
*
* uvc_iad
* uvc_control_intf
* Class-specific UVC control descriptors
* uvc_control_ep
* uvc_control_cs_ep
* uvc_streaming_intf_alt0
* Class-specific UVC streaming descriptors
* uvc_{fs|hs}_streaming
*/
/* Count descriptors and compute their size. */
control_size = 0;
streaming_size = 0;
bytes = uvc_iad.bLength + uvc_control_intf.bLength
/*+ uvc_control_ep.bLength + uvc_control_cs_ep.bLength*/
+ uvc_streaming_intf_alt0.bLength;
n_desc = 3;
for (src = (const struct usb_descriptor_header**)uvc->desc.control; *src; ++src) {
control_size += (*src)->bLength;
bytes += (*src)->bLength;
n_desc++;
}
for (src = (const struct usb_descriptor_header**)uvc_streaming_cls; *src; ++src) {
streaming_size += (*src)->bLength;
bytes += (*src)->bLength;
n_desc++;
}
for (src = uvc_streaming_std; *src; ++src) {
bytes += (*src)->bLength;
n_desc++;
}
mem = kmalloc((n_desc + 1) * sizeof(*src) + bytes, GFP_KERNEL);
if (mem == NULL)
return NULL;
hdr = mem;
dst = mem;
mem += (n_desc + 1) * sizeof(*src);
/* Copy the descriptors. */
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_iad);
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_intf);
uvc_control_header = mem;
UVC_COPY_DESCRIPTORS(mem, dst,
(const struct usb_descriptor_header**)uvc->desc.control);
uvc_control_header->wTotalLength = cpu_to_le16(control_size);
uvc_control_header->bInCollection = 1;
uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
//UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep);
//UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep);
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0);
uvc_streaming_header = mem;
UVC_COPY_DESCRIPTORS(mem, dst,
(const struct usb_descriptor_header**)uvc_streaming_cls);
uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size);
uvc_streaming_header->bEndpointAddress = uvc_streaming_ep.bEndpointAddress;
UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std);
*dst = NULL;
return hdr;
}
复制了这些
* uvc_iad
* uvc_control_intf
* Class-specific UVC control descriptors
* uvc_control_ep
* uvc_control_cs_ep
* uvc_streaming_intf_alt0
* Class-specific UVC streaming descriptors
* uvc_{fs|hs}_streaming
1.uvc_iad
见pdf表-Standard Video Interface Collection IAD,由于有些参数都是缺省值,所以这里以及以下的说明只圈重点,
bInterfaceCount:一般设置为2,包括控制(VC)流(VS)
2.uvc_control_intf
Standard VC Interface Descriptor
这个是表1的VC
.bInterfaceNumber:设置为0
3.uvc_control_ep
Standard VC Interrupt Endpoint Descriptor
4.uvc_control_cs_ep
Class-specific VC Interrupt Endpoint Descriptor
5.uvc_streaming_intf_alt0
Standard VC Interface Descriptor
同2.只不过这个是VS,所以
.bInterfaceNumber:设置为1
6.uvc_{fs|hs}_streaming
文中用的是uvc_streaming_cls,记录了
1. Class-specific VS Interface Input Header Descriptor
2. 具体格式描述符,比如Uncompressed Payload - 3.1.1. Uncompressed Video Format Descriptor
3. Color Matching Descriptor
可能一定要按照这个顺序排在uvc_streaming_cls中
DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 4);
static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 4) uvc_input_header = {
.bLength = UVC_DT_INPUT_HEADER_SIZE(1, 4),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = UVC_VS_INPUT_HEADER,
.bNumFormats = 4,
.wTotalLength = 0, /* dynamic */
.bEndpointAddress = 0, /* dynamic */
.bmInfo = 0,
.bTerminalLink = 3,
.bStillCaptureMethod = 0,
.bTriggerSupport = 0,
.bTriggerUsage = 0,
.bControlSize = 1,
#if ENABLE_YUYV==1
.bmaControls[INDEX_YUYV - 1][0] = 0,
#endif
#if ENABLE_YV12==1
.bmaControls[INDEX_YV12 - 1][0] = 0,
#endif
#if ENABLE_MJPG==1
.bmaControls[INDEX_MJPG - 1][0] = 4,
#endif
#if ENABLE_H264==1
.bmaControls[INDEX_H264 - 1][0] = 4,
#endif
};
#if ENABLE_YUYV==1
这里设置了4个格式,bNumFormats=4;bmaControls是控制参数,大小4
结束
参考资料:
https://blog.csdn.net/lizuobin2/article/details/53149583
https://blog.csdn.net/go_str/article/details/80844175
https://blog.csdn.net/qingkongyeyue/article/details/52396933