上个小patch吧...
关于昨天的usb枚举失败(获取配置描述符失败)
简要描述下:
1. 我的gadget配置成了usb3.2版本, (设置成1.0, 2.0也遇到一些问题, 暂表不论)
Protocols Supported:
USB 1.1: no
USB 2.0: no
USB 3.0: yes
2. 根据usb3协议, 相比usb1, usb2, 有些特殊且必要的描述符信息....
直接贴log...
[ 8825.746380] get desc for USB_DT_CONFIG
[ 8825.754287] buf:
[ 8825.756108] 0x9 0x2 0x1f 0x0 0x1 0x1 0x0 0xc0 0x1 // 0x2: 配置描述符, 后续跟接口, 端点等描述符信息, 故总长度是0x1f
[ 8825.760892] 0x9 0x4 0x0 0x0 0x1 0xff 0x0 0x0 0xfb // 0x4: 接口描述符, 总长度0x9
[ 8825.765684] 0x7 0x5 0x1 0x2 0x40 0x0 0x0 0x6 0x30 // 0x5: 端点描述符, 总长度0x7; 0x30: 端点伙伴(companion)描述符...
[ 8825.770466] 0x0 0x0 0x0 0x0
是的, 之前一直配置失败的原因是缺少了SuperSpeed Endpoint Companion描述信息, 即超速设备端点伙伴描述符...
usb3.0版本即super speed端点必须含有这个描述符, 且跟随在端点描述符后面...
果然不仔细看协议文档, 光调试代码, 很难找到缺少了什么...
anaway... 可以继续往下走了...
马上又遇到下一个问题,
[ 8825.787376] setup request: 6, desc_type: 0xf, w_lenght:255
[ 8825.792853] get desc for USB_DT_BOS
对的, 继续添加BOS描述符信息...
什么是BOS... (Binary Device Object Store)
看了内容, 这玩意是扩展设备描述符的, Device Type是0xf。
可以添加设备级的一些能力描述, 即device-level capability extensions。
如usb2/3的LPM能力啥的, 即Link Power Management, 链路电路管理。具体又有相应的协议....
ok, 不管了, 上代码, 枚举成功。
#include
#include /* min() */
#include
#include
#include
#include
MODULE_LICENSE("GPL");
MODULE_AUTHOR("River");
#define USB_BUFSIZE 256
struct g_loop_dev {
struct usb_gadget *gadget; // gadget device
struct usb_request *req; // for ep0 request
struct usb_ep *out_ep; // TBD: for ep out transfer
// struct cdev cdev; // TBD: char dev
};
#define STR_ID_MANUFACTURER 25
#define STR_ID_PRODUCT 42
#define STR_ID_SERIAL 101
#define STR_ID_LOOPBACK 251
/* my specific vid&pid */
#define DRIVER_VENDOR_NUM 0x1234
#define DRIVER_PRODUCT_NUM 0x5678
// #define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
// #define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
static struct usb_device_descriptor device_desc = {
.bLength = sizeof (device_desc),
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = __constant_cpu_to_le16(0x0320),
// .bcdUSB = __constant_cpu_to_le16(0x0201),
.bDeviceClass = USB_CLASS_VENDOR_SPEC,
.bMaxPacketSize0 = 9,
.idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
.idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
.iManufacturer = STR_ID_MANUFACTURER,
.iProduct = STR_ID_PRODUCT,
.iSerialNumber = STR_ID_SERIAL,
.bNumConfigurations = 1,
};
static struct usb_config_descriptor g_loop_config = {
.bLength = sizeof g_loop_config,
.bDescriptorType = USB_DT_CONFIG,
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
.bMaxPower = 1, /* self-powered */
};
/* interface descriptor */
static struct usb_interface_descriptor g_loop_interface = {
.bLength = sizeof(g_loop_interface),
.bDescriptorType = USB_DT_INTERFACE,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.iInterface = STR_ID_LOOPBACK,
};
/* endpoint descriptor */
static struct usb_endpoint_descriptor fs_sink_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType= USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT, // for pc host, it is out ep.
.bmAttributes = USB_ENDPOINT_XFER_BULK,
// .wMaxPacketSize = __constant_cpu_to_le16(1024),
};
static struct usb_ss_ep_comp_descriptor ss_fs_sink_comp_desc = {
.bLength = sizeof(ss_fs_sink_comp_desc),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
.bMaxBurst = 0,
.bmAttributes = 0,
.wBytesPerInterval = 0,
};
/* function/interface description... */
static const struct usb_descriptor_header *fs_g_loop_function[] = {
(struct usb_descriptor_header *) &g_loop_interface,
(struct usb_descriptor_header *) &fs_sink_desc,
(struct usb_descriptor_header *) &ss_fs_sink_comp_desc,
NULL,
};
static struct usb_string strings[] = {
{STR_ID_MANUFACTURER, "river run", },
{STR_ID_PRODUCT, "river loop", },
{STR_ID_SERIAL, "1234567890", },
{STR_ID_LOOPBACK, "loop in to out", },
{ },
};
static struct usb_gadget_strings string_table = {
.language = 0x0409, /* en-us */
.strings = strings,
};
static void g_loop_setup_complete(struct usb_ep *ep,
struct usb_request *req) {
printk(KERN_INFO "g_loop_setup complete --> %d, %d, %d\n",
req->status, req->actual, req->length);
return;
}
static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
{
kfree(req->buf);
usb_ep_free_request(ep, req);
}
static int g_loop_dev_prepare(struct g_loop_dev *dev) {
struct usb_gadget *gadget = dev->gadget;
int ret;
/* reset ep autoconfig state */
usb_ep_autoconfig_reset(gadget);
/* config & prepare an endpoint */
dev->out_ep = usb_ep_autoconfig(gadget, &fs_sink_desc);
if (!dev->out_ep) {
printk(KERN_ERR "usb_ep_autoconfig failed\n");
ret = - ENOMEM;
goto config_fail;
}
printk(KERN_INFO "ep_desc = %p\n", dev->out_ep->desc);
printk(KERN_INFO "fs_sink_desc = %p\n", &fs_sink_desc);
printk(KERN_INFO "ep->addr = %d\n", dev->out_ep->address);
printk(KERN_INFO "ep->claimed = %d\n", dev->out_ep->claimed);
printk(KERN_INFO "ep->enabled = %d\n", dev->out_ep->enabled);
printk(KERN_INFO "usb_ep_autoconfig succeed\n");
/* preallocate control response and buffer */
dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
if (!dev->req) {
ret = -ENOMEM;
goto ep_fail;
}
dev->req->buf = kmalloc(USB_BUFSIZE, GFP_KERNEL);
if (!dev->req->buf)
goto malloc_fail;
dev->req->complete = g_loop_setup_complete;
dev->req->context = dev;
gadget->ep0->driver_data = dev;
usb_gadget_set_selfpowered(gadget);
return 0;
malloc_fail:
usb_ep_free_request(gadget->ep0, dev->req);
dev->req = NULL;
ep_fail:
config_fail:
return ret;
}
static int g_loop_bind(struct usb_gadget *gadget,
struct usb_gadget_driver *driver) {
int ret = 0;
struct g_loop_dev *dev;
if (!gadget ||!driver) {
ret = -EINVAL;
goto invalid_param;
}
printk(KERN_INFO "gadget info: speed(%d), max_speed(%d)",
gadget->speed, gadget->max_speed);
printk(KERN_INFO "gadget info: maxpacket(%d), claimed(%d), enabled(%d)",
gadget->ep0->maxpacket, gadget->ep0->claimed?1:0,
gadget->ep0->enabled?1:0);
dev = kzalloc(sizeof(struct g_loop_dev), GFP_KERNEL);
if (!dev) {
printk(KERN_ERR "malloc failed for g_loop_dev\n");
ret = -ENOMEM;
goto malloc_fail;
}
dev->gadget = gadget;
set_gadget_data(gadget, dev);
/* bMaxPacketSize format is 2^bMaxPacketSize0, eg, 2^9 = 512 */
// device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
ret = g_loop_dev_prepare(dev);
if (ret < 0) {
printk(KERN_ERR "g_loop_dev_prepare failed...\n");
goto prepare_fail;
}
printk(KERN_INFO "simple composite ready...\n");
return ret;
prepare_fail:
if (dev) {
kfree(dev);
dev = NULL;
}
malloc_fail:
invalid_param:
return ret;
}
static void g_loop_unbind(struct usb_gadget *gadget) {
struct g_loop_dev *dev = get_gadget_data(gadget);
if (dev->req) {
dev->req->length= USB_BUFSIZE;
free_ep_req(gadget->ep0, dev->req);
}
kfree(dev);
set_gadget_data(gadget, NULL);
printk(KERN_INFO "g_loop_unbind callback complete\n");
return;
}
static int config_buf(struct usb_gadget *gadget,
u8 *buf, u8 type, unsigned index)
{
//int is_source_sink;
int len;
const struct usb_descriptor_header **function;
printk(KERN_INFO "config_buf, type = %d, index = %d\n",
type, index);
function = fs_g_loop_function;
len = usb_gadget_config_buf(&g_loop_config,
buf, USB_BUFSIZE, function);
if (len < 0)
return len;
((struct usb_config_descriptor *) buf)->bDescriptorType = type;
return len;
}
/**
* bos_desc() - prepares the BOS descriptor.
* @cdev: pointer to usb_composite device to generate the bos
* descriptor for
*
* This function generates the BOS (Binary Device Object)
* descriptor and its device capabilities descriptors. The BOS
* descriptor should be supported by a SuperSpeed device.
*/
static int bos_desc(struct usb_gadget *gadget,
const struct usb_request *req) {
struct usb_ext_cap_descriptor *usb_ext;
struct usb_dcd_config_params dcd_config_params;
struct usb_bos_descriptor *bos = req->buf;
bos->bLength = USB_DT_BOS_SIZE;
bos->bDescriptorType = USB_DT_BOS;
bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE);
bos->bNumDeviceCaps = 0;
/*
* A SuperSpeed device shall include the USB2.0 extension descriptor
* and shall support LPM when operating in USB2.0 HS mode.
*/
usb_ext = req->buf + le16_to_cpu(bos->wTotalLength);
bos->bNumDeviceCaps++;
le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE);
usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT | USB_BESL_SUPPORT);
/*
* The Superspeed USB Capability descriptor shall be implemented by all
* SuperSpeed devices.
*/
if (gadget_is_superspeed(gadget)) {
struct usb_ss_cap_descriptor *ss_cap;
ss_cap = req->buf + le16_to_cpu(bos->wTotalLength);
bos->bNumDeviceCaps++;
le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
ss_cap->bmAttributes = 0; /* LTM is not supported yet */
ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
USB_FULL_SPEED_OPERATION |
USB_HIGH_SPEED_OPERATION |
USB_5GBPS_OPERATION);
ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
/* Get Controller configuration */
if (gadget->ops->get_config_params) {
gadget->ops->get_config_params(
&dcd_config_params);
} else {
dcd_config_params.bU1devExitLat =
USB_DEFAULT_U1_DEV_EXIT_LAT;
dcd_config_params.bU2DevExitLat =
cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
}
ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
}
return le16_to_cpu(bos->wTotalLength);
}
/*
* ep0 setup callback, we need to tell what kind of
* device we are...
* according to ch9, we need to response to get_descriptor
* control command...
*/
static int g_loop_setup(struct usb_gadget *gadget,
const struct usb_ctrlrequest *ctl_req) {
struct g_loop_dev *loop_dev = get_gadget_data(gadget);
struct usb_request *req = NULL;
int value = 0;
// u16 w_index = le16_to_cpu(ctl_req->wIndex);
u16 w_value = le16_to_cpu(ctl_req->wValue);
u16 w_length = le16_to_cpu(ctl_req->wLength);
int ret = 0;
int i = 0;
unsigned char *buf;
printk(KERN_INFO "g_loop_setup callback\n");
if (!loop_dev) {
ret = -EFAULT;
goto unknown;
}
req = loop_dev->req;
buf = req->buf;
// dump_stack();
printk(KERN_INFO "setup request: %d, desc_type: 0x%x, "
"w_lenght:%d\n",
ctl_req->bRequest, w_value>>8, w_length);
switch (ctl_req->bRequest) {
/* handle some standard request... */
case USB_REQ_GET_DESCRIPTOR: {
if (ctl_req->bRequestType != USB_DIR_IN ) {
printk(KERN_ERR "error request type(0x%x)\n",
ctl_req->bRequestType);
ret = -EFAULT;
goto unknown;
}
/* high byte means descriptor type,
* descriptor index in low byte...
*/
switch (w_value>>8) {
case USB_DT_DEVICE:
printk(KERN_INFO "get desc for USB_DT_DEVICE\n");
value = min(w_length, (u16) sizeof device_desc);
memcpy(req->buf, &device_desc,
value);
break;
case USB_DT_CONFIG:
printk(KERN_INFO "get desc for USB_DT_CONFIG\n");
/* use some help function fill config descriptor... */
value = config_buf(gadget, req->buf,
w_value >> 8,
w_value & 0xff);
if (value >= 0)
value = min(w_length, (u16) value);
break;
case USB_DT_STRING:
printk(KERN_INFO "get desc for USB_DT_STRING\n");
value = usb_gadget_get_string(&string_table, w_value&0xff,
req->buf);
if (value >= 0)
value = min(w_length, (u16) value);
break;
case USB_DT_OTG:
printk(KERN_INFO "get desc for USB_DT_OTG, TBD...\n");
break;
case USB_DT_BOS:
printk(KERN_INFO "get desc for USB_DT_BOS\n");
if (gadget_is_superspeed(gadget)) {
value = bos_desc(gadget, req);
value = min(w_length, (u16) value);
}
break;
default:
printk(KERN_INFO "descriptor type: %d, do nothing\n",
w_value>>8);
break;
}
}
break;
case USB_REQ_SET_DESCRIPTOR:
printk(KERN_INFO "set descriptor request, do nothing...\n");
break;
case USB_REQ_GET_CONFIGURATION:
printk(KERN_INFO "get configuration request, do nothing...\n");
break;
case USB_REQ_SET_CONFIGURATION:
printk(KERN_INFO "set configuration request, do nothing...\n");
break;
case USB_REQ_GET_INTERFACE:
printk(KERN_INFO "get interfafe request, do nothing...\n");
break;
case USB_REQ_SET_INTERFACE:
printk(KERN_INFO "set interfafe request, do nothing...\n");
break;
default:
printk(KERN_INFO "bRequestType - %d, no handler...\n",
ctl_req->bRequestType);
break;
}
if (value <= 0) {
printk(KERN_ERR "no data needs to be sent\n");
ret = -EFAULT;
goto do_nothing;
}
printk(KERN_INFO "buf:\n");
for (i=0; ilength = value;
req->zero = value < w_length;
printk(KERN_INFO "value: %d, w_length: %d\n",
value, w_length);
printk(KERN_INFO "req->zero: %d\n", req->zero);
ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
if (ret < 0) {
printk(KERN_ERR "usb_ep_queue failed, ret(%d)\n", ret);
req->status = 0;
g_loop_setup_complete(gadget->ep0, req);
}
return ret;
do_nothing:
unknown:
return ret;
}
static void g_loop_reset(struct usb_gadget *gadget) {
printk(KERN_INFO "g_loop_reset callback\n");
usb_ep_autoconfig_reset(gadget);
return;
}
static void g_loop_disconnect(struct usb_gadget *gadget) {
printk(KERN_INFO "g_loop_disconnect callback\n");
return;
}
static struct usb_gadget_driver g_loop_driver = {
.function = "gadget_g_loop",
.max_speed = USB_SPEED_SUPER,
// .max_speed = USB_SPEED_HIGH,
.bind = g_loop_bind,
.unbind = g_loop_unbind,
.setup = g_loop_setup,
.reset = g_loop_reset,
.disconnect = g_loop_disconnect,
};
static int __init g_loop_init(void) {
int ret = 0;
printk(KERN_INFO "g_loop_init in\n");
ret = usb_gadget_probe_driver(&g_loop_driver);
if (ret < 0) {
printk(KERN_ERR "usb gaget driver register failed, "
"ret(%d)\n", ret);
goto probe_failed;
}
printk(KERN_INFO "g_loop_init succeed\n");
return 0;
probe_failed:
return ret;
}
static void __exit g_loop_exit(void) {
printk(KERN_INFO "g_loop_exit in\n");
usb_gadget_unregister_driver(&g_loop_driver);
printk(KERN_INFO "g_loop_exit succeed\n");
return;
}
module_init(g_loop_init);
module_exit(g_loop_exit);
ok, 枚举成功, 说是基本成功了一大半...下面就是传输部分, 希望顺利...