Loopback Function
Read time: 3 minute(s)
Loopback Function
提供的功能更为简单,它分配了两个 bulk endpoint,所做的就是把
out_ep
接收到的数据 转发到 in_ep
。
主要流程如下:
drivers\usb\gadget\function\f_loopback.c: loopback_bind(): static int loopback_bind(struct usb_configuration *c, struct usb_function *f) { /* (1) 从 gadget 中分配 2 个 bulk endpoint */ /* allocate endpoints */ loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc); loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc); } loopback_set_alt() → enable_loopback() → alloc_requests(): static int alloc_requests(struct usb_composite_dev *cdev, struct f_loopback *loop) { for (i = 0; i < loop->qlen && result == 0; i++) { result = -ENOMEM; in_req = usb_ep_alloc_request(loop->in_ep, GFP_ATOMIC); if (!in_req) goto fail; out_req = lb_alloc_ep_req(loop->out_ep, loop->buflen); if (!out_req) goto fail_in; in_req->complete = loopback_complete; out_req->complete = loopback_complete; in_req->buf = out_req->buf; /* length will be set in complete routine */ in_req->context = out_req; out_req->context = in_req; /* (2) 先启动 OUT endpoint */ result = usb_ep_queue(loop->out_ep, out_req, GFP_ATOMIC); if (result) { ERROR(cdev, "%s queue req --> %d\n", loop->out_ep->name, result); goto fail_out; } } } 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; switch (status) { case 0: /* normal completion? */ if (ep == loop->out_ep) { /* * We received some data from the host so let's * queue it so host can read the from our in ep */ struct usb_request *in_req = req->context; in_req->zero = (req->actual < req->length); in_req->length = req->actual; ep = loop->in_ep; req = in_req; } else { /* * We have just looped back a bunch of data * to host. Now let's wait for some more data. */ req = req->context; ep = loop->out_ep; } /* (3) 环回的关键: OUT endpoint 接收到的数据 转发到 IN endpoint IN endpoint 数据发送完成后 req 重新挂载到 OUT endpoint */ /* queue the buffer back to host or for next bunch of data */ status = usb_ep_queue(ep, req, GFP_ATOMIC); }
也支持一些参数调整:
# ls functions/Loopback.0/
bulk_buflen qlen