static int __init webcam_init(void)
{
return usb_composite_probe(&webcam_driver, webcam_bind);
}
static void __exit
webcam_cleanup(void)
{
usb_composite_unregister(&webcam_driver);
}
通过usb_composite_probe()函数将usb_composite_driver结构体和webcam_bind绑定在一起。
进入usb_composite_probe看一看,将驱动功能和参数传递下去
struct usb_gadget_driver {
char *function;
enum usb_device_speed max_speed;
void (*unbind)(struct usb_gadget *);
int (*setup)(struct usb_gadget *,
const struct usb_ctrlrequest *);
void (*disconnect)(struct usb_gadget *);
void (*suspend)(struct usb_gadget *);
void (*resume)(struct usb_gadget *);
/* FIXME support safe rmmod */
struct device_driver driver;
};
int usb_composite_probe(struct usb_composite_driver *driver,
int (*bind)(struct usb_composite_dev *cdev))
{
if (!driver || !driver->dev || !bind || composite) //判断
return -EINVAL;
if (!driver->name)
driver->name = "composite";
if (!driver->iProduct)
driver->iProduct = driver->name;
composite_driver.function = (char *) driver->name; //接口功能名字
composite_driver.driver.name = driver->name; //驱动名字
composite_driver.max_speed =
min_t(u8, composite_driver.max_speed, driver->max_speed);
composite = driver; //绑定复合驱动结构体
composite_gadget_bind = bind; //
return usb_gadget_probe_driver(&composite_driver, composite_bind);
}
return usb_gadget_probe_driver(&composite_driver, composite_bind)。 调用composite.c中的函数,该代码一般不用修改。
回到usb_composite_probe(&webcam_driver, webcam_bind);webcam_driver必须被填充
static struct usb_composite_driver webcam_driver = {
.name = "drive_name",
.dev = &webcam_device_descriptor,
.strings = webcam_device_strings,
.max_speed = USB_SPEED_HIGH,
.unbind = webcam_unbind,
};
struct usb_composite_driver {
const char *name; //驱动名字
const char *iProduct; //厂商自定义
const char *iManufacturer; //厂商自定义
const struct usb_device_descriptor *dev; //最重要的设备描述符
struct usb_gadget_strings **strings; //绑定语言和camera的名字
enum usb_device_speed max_speed;
unsigned needs_serial:1;
int (*unbind)(struct usb_composite_dev *);
void (*disconnect)(struct usb_composite_dev *);
/* global suspend hooks */
void (*suspend)(struct usb_composite_dev *);
void (*resume)(struct usb_composite_dev *);
};
看向webcam_bind()函数,usb_add_config()由composite.c提供,我们负责填充里面的参数。usb_composite_dev *cdev先不理会。
if ((ret = usb_add_config(cdev, &webcam_config_driver,
webcam_config_bind)) < 0)
看向usb_configuration webcam_config_driver配置,
struct usb_configuration {
const char *label; //usb版本:USB2.0 USB3.0
struct usb_gadget_strings **strings;
const struct usb_descriptor_header **descriptors;
/* REVISIT: bind() functions can be marked __init, which
* makes trouble for section mismatch analysis. See if
* we can't restructure things to avoid mismatching...
*/
/* configuration management: unbind/setup */
void (*unbind)(struct usb_configuration *);
int (*setup)(struct usb_configuration *,
const struct usb_ctrlrequest *);
/* fields in the config descriptor */
u8 bConfigurationValue;
u8 iConfiguration;
u8 bmAttributes;
u8 bMaxPower;
struct usb_composite_dev *cdev;
/* private: */
/* internals */
struct list_head list;
struct list_head functions;
u8 next_interface_id;
unsigned superspeed:1;
unsigned highspeed:1;
unsigned fullspeed:1;
struct usb_function *interface[MAX_CONFIG_INTERFACES];
};
/* from config descriptor bmAttributes */
#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */
#define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */
#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */
#define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */
看向webcam_config_bind中的uvc_bind_config(c, uvc_control_cls, uvc_fs_streaming_cls,
uvc_hs_streaming_cls); 调用到f_uvc.c中进行UVC控制类和UVC视频类的绑定。
UVC控制类
static const struct uvc_descriptor_header * const uvc_control_cls[] = {
(const struct uvc_descriptor_header *) &uvc_control_header,
(const struct uvc_descriptor_header *) &uvc_camera_terminal,
(const struct uvc_descriptor_header *) &uvc_processing,
(const struct uvc_descriptor_header *) &uvc_xu_extdesc,
(const struct uvc_descriptor_header *) &uvc_output_terminal,
NULL,
};
uvc_control_header 控制接口?不确定
uvc_control_header = {
.bLength = UVC_DT_HEADER_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = UVC_VC_HEADER, //video control header
.bcdUVC = cpu_to_le16(0x0150), //UVC的版本
.wTotalLength = cpu_to_le16(0x0050), /* 描述符长度*/
.dwClockFrequency = cpu_to_le32(48000000), //时钟
.bInCollection = 1, /* dynamic */
.baInterfaceNr[0] = 1, /* dynamic */
};
uvc_camera_terminal,CT描述符。相机需要支持什命令就需要在这里添加对应的功能。
static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
.bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = UVC_VC_INPUT_TERMINAL,//视频类特定的VC接口描述子类型
.bTerminalID = UVC_ENTITY_ID_INPUT_TERMINAL,
.wTerminalType = cpu_to_le16(UVC_ITT_CAMERA),
.bAssocTerminal = 0,
.iTerminal = 0,
.wObjectiveFocalLengthMin = cpu_to_le16(0),
.wObjectiveFocalLengthMax = cpu_to_le16(0),
.wOcularFocalLength = cpu_to_le16(0),
.bControlSize = 3,//对照UVC协议的CT控制
.bmControls[0] = 0x00,
.bmControls[1] = 0x00,
.bmControls[2] = 0x00,
.wObjectiveFocalLengthMin = cpu_to_le16(0),
.wObjectiveFocalLengthMax = cpu_to_le16(0),
.wOcularFocalLength = cpu_to_le16(0),
.bControlSize = 3,
.bmControls[0] = 0x00,
.bmControls[1] = 0x00,
.bmControls[2] = 0x00,
};
static struct uvc_processing_unit_descriptor uvc_processing = {
.bLength = UVC_DT_PROCESSING_UNIT_SIZE(2),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = UVC_VC_PROCESSING_UNIT,
.bUnitID = UVC_ENTITY_ID_PROCESSING_UNIT,
.bSourceID = UVC_ENTITY_ID_INPUT_TERMINAL,
.wMaxMultiplier = cpu_to_le16(0x4000),
.bControlSize = 2,
.bmControls[0] = 0xff, // PU的控制选项
.bmControls[1] = 0xff, //
.bmVideoStandards = 0 //UVC 1.0 no support
};
uvc_processing。PU描述符,亮度与对比度之类功能添加,具体看UVC协议。
uvc_output_terminal_descriptor uvc_output_terminal端点描述符。bSourceID意为与其他单元的连接,如CT单元、PU单元。
static const struct uvc_output_terminal_descriptor uvc_output_terminal = {
.bLength = UVC_DT_OUTPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL,
.bTerminalID = UVC_ENTITY_ID_OUTPUT_TERMINAL,
.wTerminalType = cpu_to_le16(0x0101),
.bAssocTerminal = 0,
.bSourceID = UVC_ENTITY_ID_XU_H264,//UVC_ENTITY_ID_PROCESSING_UNIT,
.iTerminal = 0,
};