USB Gadget数据收发-批量传输
当执行命令
ln -s functions/Loopback.0 configs/c.1
之后,会调用loopback_alloc函数创建usb_function
struct f_loopback {
struct usb_function function;
struct usb_ep *in_ep;
struct usb_ep *out_ep;
};
usb_function结构体中的回调函数就是启用、禁用卸载设备的回调
loop = kzalloc(sizeof *loop, GFP_KERNEL);
...
loop->function.name = "loopback";
loop->function.bind = loopback_bind;
loop->function.set_alt = loopback_set_alt;
loop->function.disable = loopback_disable;
loop->function.strings = loopback_strings;
loop->function.free_func = lb_free_func;
usb_function的创建,代表着物理固件配置参数的准备好,但对于USB设备来说,存在着高速、全速等因硬件原因而导致的动态配置,故在实际启用UDC设备时:
1.先调用loopback_bind来动态配置这些数据。这些数据包括
2.当物理设备插入主机后,主机根据物理连接情况确定其工作于那种模式下(高速、全速还是起高速),然后主机开始获取设备描述符,分配设备地址,获取配置描述符,字符串描述符后,即开始SET_CONFIG.
SET_CONFIG会SET_INTERFACE对应的回调应是loopback_set_alt
选择了接口SET_INTERFACE,即根据USB定义,其接口描述符下的端点应该可用,这在gadaget中就是初始化端点的收发,对于enable_endpoint。
static int enable_endpoint(struct usb_composite_dev *cdev, struct f_loopback *loop, struct usb_ep *ep)
{
struct usb_request *req;
unsigned i;
int result;
/*
* one endpoint writes data back IN to the host while another endpoint
* just reads OUT packets
*/
result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
if (result)
goto fail0;
result = usb_ep_enable(ep);
if (result < 0)
goto fail0;
ep->driver_data = loop;
printk("now enable_endpoint ep=0x%02x,name=%s\n",ep->address,ep->name);
/*
* allocate a bunch of read buffers and queue them all at once.
* we buffer at most 'qlen' transfers; fewer if any need more
* than 'buflen' bytes each.
*/
for (i = 0; i < qlen && result == 0; i++) {
req = lb_alloc_ep_req(ep, 0);
if (!req)
goto fail1;
req->complete = loopback_complete;
result = usb_ep_queue(ep, req, GFP_ATOMIC);
if (result) {
ERROR(cdev, "%s queue req --> %d\n",ep->name, result);
goto fail1;
}
}
return 0;
fail1:
usb_ep_disable(ep);
fail0:
return result;
}
这其中包括两部分:
- 配置端点及使用
result = config_ep_by_speed(cdev->gadget, &(loop->function), ep); result = usb_ep_enable(ep);
- 初始化收发队列回调,这里配置了32个请求回调
当端点有动作时,执行请求回调。//创建端点请求及初始化完成回调 req = lb_alloc_ep_req(ep, 0); req->complete = loopback_complete; //入队列 result = usb_ep_queue(ep, req, GFP_ATOMIC);
static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_loopback *loop = ep->driver_data;
struct usb_composite_dev *cdev = loop->function.config->cdev;
int status = req->status;
int i;
unsigned char* pData;
printk("loopback_complete status=%d\n",status);
switch (status) {
case 0: /* normal completion? */
if (ep == loop->out_ep) {
req->zero = (req->actual < req->length);
req->length = req->actual;
}
printk("ep=0x%02x\n",ep->address);
printk("length=%d\n",req->length);
pData = req->buf;
//for(i=0;i<10&&i<req->length;i++){
// printk("data[%d]=%02x\n ",i,pData[i]);
//}
/* queue the buffer for some later OUT packet */
req->length = buflen;
status = usb_ep_queue(ep, req, GFP_ATOMIC);
if (status == 0)
return;
/* "should never get here" */
/* FALLTHROUGH */
default:
ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name,
status, req->actual, req->length);
/* FALLTHROUGH */
/* NOTE: since this driver doesn't maintain an explicit record
* of requests it submitted (just maintains qlen count), we
* rely on the hardware driver to clean up on disconnect or
* endpoint disable.
*/
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
free_ep_req(ep, req);
return;
}
}
数据的收发
对于发送数送数据,调用usb_ep_queue挂入队列的请求即表示需要发送的数据包,当发送完成后,会调用loopback_complete表示该请求的执行结果。
对于接收数据,调用usb_ep_queue挂入队列的请求表示收到的数据包,可以直接解析出收到的数据。
如本人将bulk_buflen改为512之后,收到32个包之后,才会在主机端收到指定的数据.前面的32位为初始化OUT端点挂入的32个数据包,数据为随机值。当第一个完成之后,在完成例程中重置自定义数据,再次复用该请求发送数据。故32个之后才是自定义数据。
static struct usb_function_instance *loopback_alloc_instance(void)
{
struct f_lb_opts *lb_opts;
printk("loopback_alloc_instance\n");
lb_opts = kzalloc(sizeof(*lb_opts), GFP_KERNEL);
if (!lb_opts)
return ERR_PTR(-ENOMEM);
mutex_init(&lb_opts->lock);
lb_opts->func_inst.free_func_inst = lb_free_instance;
lb_opts->bulk_buflen = 512;// GZERO_BULK_BUFLEN;//4096
lb_opts->qlen = GZERO_QLEN;//32
config_group_init_type_name(&lb_opts->func_inst.group, "",&lb_func_type);
return &lb_opts->func_inst;
}
BUSHOUND抓包如下
Device Length Phase Data
------ -------- ----- ---------------------------------------------------
54.0 CTL 80 06 00 01 00 00 12 00
54.0 18 IN 12 01 00 02 00 00 00 40 6b 1d 01 2d 01 04 01 02
54.0 CTL 80 06 00 02 00 00 09 00
54.0 9 IN 09 02 20 00 01 01 04 80 3c
54.0 CTL 80 06 00 02 00 00 20 00
54.0 32 IN 09 02 20 00 01 01 04 80 3c 09 04 00 00 02 ff 00
54.0 CTL 80 00 00 00 00 00 02 00
54.0 2 IN 01 00
54.0 CTL 00 09 01 00 00 00 00 00
54.1 512 IN 00 84 8d 94 65 63 20 20 36 20 30 39 3a 33 39 3a
54.1 512 IN 00 86 8d 94 64 65 76 00 fe ed ca fe 28 00 00 00
54.1 512 IN 00 8c 8d 94 ab 00 00 00 00 00 00 00 00 00 00 00
54.1 512 IN 00 00 00 00 24 00 00 00 00 00 00 00 00 00 00 00
54.1 512 IN 00 00 8c 94 65 63 20 20 36 20 30 39 3a 33 39 3a
54.1 512 IN 00 00 00 00 65 63 20 20 36 20 30 39 3a 33 39 3a
54.1 512 IN 00 00 00 00 65 63 20 20 36 20 30 39 3a 33 39 3a
54.1 512 IN 00 60 0b 94 40 00 00 00 a4 72 f3 b0 1f 00 00 00
54.1 512 IN 00 00 00 00 65 63 20 20 36 20 30 39 3a 33 38 3a
54.1 512 IN 00 90 8d 94 65 63 20 20 36 20 30 39 3a 33 38 3a
54.1 512 IN 00 9a 8d 94 65 63 20 20 36 20 30 39 3a 33 38 3a
54.1 512 IN 00 98 8d 94 65 63 20 20 36 20 30 39 3a 33 38 3a
54.1 512 IN 00 00 00 00 65 63 20 20 36 20 30 39 3a 33 38 3a
54.1 512 IN 00 9c 43 94 06 00 00 00 00 00 00 00 00 00 00 00
54.1 512 IN 00 90 43 94 06 00 00 00 00 00 00 00 00 00 00 00
54.1 512 IN 00 9e 43 94 02 00 00 00 00 00 00 00 00 00 00 00
54.1 512 IN 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00
54.1 512 IN 00 4c 75 94 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 4a 75 94 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 48 75 94 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 46 75 94 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 44 75 94 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 42 75 94 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 40 75 94 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 00 00 00 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 2c 75 94 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 2a 75 94 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 28 75 94 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 26 75 94 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 24 75 94 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 22 75 94 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 20 75 94 2f 64 65 76 69 63 65 73 2f 70 6c 61
54.1 512 IN 00 00 00 00 00 00 00 00 00 00 30 39 3a 33 39 3a
54.1 512 IN 01 01 01 01 01 01 01 01 01 01 ca fe 28 00 00 00
54.1 512 IN 02 02 02 02 02 02 02 02 02 02 00 00 00 00 00 00
54.1 512 IN 03 03 03 03 03 03 03 03 03 03 00 00 00 00 00 00
54.1 512 IN 04 04 04 04 04 04 04 04 04 04 30 39 3a 33 39 3a
54.1 512 IN 05 05 05 05 05 05 05 05 05 05 30 39 3a 33 39 3a
54.1 512 IN 06 06 06 06 06 06 06 06 06 06 30 39 3a 33 39 3a
54.1 512 IN 07 07 07 07 07 07 07 07 07 07 f3 b0 1f 00 00 00
54.1 512 IN 08 08 08 08 08 08 08 08 08 08 30 39 3a 33 38 3a
54.1 512 IN 09 09 09 09 09 09 09 09 09 09 30 39 3a 33 38 3a
无论是接收和发送数据,在该请求包完成后,会自动从端点队列中“移除”,然后再执行loopback_complete,如果需要复用,则需要调用usb_ep_queue重新挂入队列。