博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
继续写usb gadget驱动(解决枚举失败问题)
阅读量:3559 次
发布时间:2019-05-20

本文共 13771 字,大约阅读时间需要 45 分钟。

上个小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 256struct 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; i
length = 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, 枚举成功, 说是基本成功了一大半...下面就是传输部分,  希望顺利...

 

转载地址:http://gicrj.baihongyu.com/

你可能感兴趣的文章
JVM的4种垃圾回收算法、垃圾回收机制
查看>>
什么是分布式事务
查看>>
常用的分布式事务解决方案
查看>>
设计模式:单例模式 (关于饿汉式和懒汉式)
查看>>
一致性Hash算法
查看>>
更新Navicat Premium 后打开数据库出现1146 - Table 'performance_schema.session_variables' doesn't exist
查看>>
安装rabbitmq时踩的坑
查看>>
2021-06-09数据库添加多条数据
查看>>
简单的JAVA小作品
查看>>
CMake下载
查看>>
未调用fflush产生的图片文件无法打开问题
查看>>
SQL 约束(二)
查看>>
SQL ALTER用法(三)
查看>>
SQL where子句及查询条件语句(六)
查看>>
SQL 连接JOIN(九)
查看>>
linux VM虚拟机可以ping通主机,但主机无法ping通虚拟机
查看>>
linux 错误码
查看>>
C++ 中Struct与typedef struct总结
查看>>
WNetAddConnection2调用失败,错误码1200/1312
查看>>
POI读写Excel的基本使用
查看>>