123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Copyright (C) 2015 Karol Kosik <[email protected]>
- * Copyright (C) 2015-2016 Samsung Electronics
- * Igor Kotrasinski <[email protected]>
- *
- * Based on dummy_hcd.c, which is:
- * Copyright (C) 2003 David Brownell
- * Copyright (C) 2003-2005 Alan Stern
- */
- #include <linux/usb.h>
- #include <linux/timer.h>
- #include <linux/usb/ch9.h>
- #include "vudc.h"
- #define DEV_REQUEST (USB_TYPE_STANDARD | USB_RECIP_DEVICE)
- #define DEV_INREQUEST (DEV_REQUEST | USB_DIR_IN)
- #define INTF_REQUEST (USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
- #define INTF_INREQUEST (INTF_REQUEST | USB_DIR_IN)
- #define EP_REQUEST (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
- #define EP_INREQUEST (EP_REQUEST | USB_DIR_IN)
- static int get_frame_limit(enum usb_device_speed speed)
- {
- switch (speed) {
- case USB_SPEED_LOW:
- return 8 /*bytes*/ * 12 /*packets*/;
- case USB_SPEED_FULL:
- return 64 /*bytes*/ * 19 /*packets*/;
- case USB_SPEED_HIGH:
- return 512 /*bytes*/ * 13 /*packets*/ * 8 /*uframes*/;
- case USB_SPEED_SUPER:
- /* Bus speed is 500000 bytes/ms, so use a little less */
- return 490000;
- default:
- /* error */
- return -1;
- }
- }
- /*
- * handle_control_request() - handles all control transfers
- * @udc: pointer to vudc
- * @urb: the urb request to handle
- * @setup: pointer to the setup data for a USB device control
- * request
- * @status: pointer to request handling status
- *
- * Return 0 - if the request was handled
- * 1 - if the request wasn't handles
- * error code on error
- *
- * Adapted from drivers/usb/gadget/udc/dummy_hcd.c
- */
- static int handle_control_request(struct vudc *udc, struct urb *urb,
- struct usb_ctrlrequest *setup,
- int *status)
- {
- struct vep *ep2;
- int ret_val = 1;
- unsigned int w_index;
- unsigned int w_value;
- w_index = le16_to_cpu(setup->wIndex);
- w_value = le16_to_cpu(setup->wValue);
- switch (setup->bRequest) {
- case USB_REQ_SET_ADDRESS:
- if (setup->bRequestType != DEV_REQUEST)
- break;
- udc->address = w_value;
- ret_val = 0;
- *status = 0;
- break;
- case USB_REQ_SET_FEATURE:
- if (setup->bRequestType == DEV_REQUEST) {
- ret_val = 0;
- switch (w_value) {
- case USB_DEVICE_REMOTE_WAKEUP:
- break;
- case USB_DEVICE_B_HNP_ENABLE:
- udc->gadget.b_hnp_enable = 1;
- break;
- case USB_DEVICE_A_HNP_SUPPORT:
- udc->gadget.a_hnp_support = 1;
- break;
- case USB_DEVICE_A_ALT_HNP_SUPPORT:
- udc->gadget.a_alt_hnp_support = 1;
- break;
- default:
- ret_val = -EOPNOTSUPP;
- }
- if (ret_val == 0) {
- udc->devstatus |= (1 << w_value);
- *status = 0;
- }
- } else if (setup->bRequestType == EP_REQUEST) {
- /* endpoint halt */
- ep2 = vudc_find_endpoint(udc, w_index);
- if (!ep2 || ep2->ep.name == udc->ep[0].ep.name) {
- ret_val = -EOPNOTSUPP;
- break;
- }
- ep2->halted = 1;
- ret_val = 0;
- *status = 0;
- }
- break;
- case USB_REQ_CLEAR_FEATURE:
- if (setup->bRequestType == DEV_REQUEST) {
- ret_val = 0;
- switch (w_value) {
- case USB_DEVICE_REMOTE_WAKEUP:
- w_value = USB_DEVICE_REMOTE_WAKEUP;
- break;
- case USB_DEVICE_U1_ENABLE:
- case USB_DEVICE_U2_ENABLE:
- case USB_DEVICE_LTM_ENABLE:
- ret_val = -EOPNOTSUPP;
- break;
- default:
- ret_val = -EOPNOTSUPP;
- break;
- }
- if (ret_val == 0) {
- udc->devstatus &= ~(1 << w_value);
- *status = 0;
- }
- } else if (setup->bRequestType == EP_REQUEST) {
- /* endpoint halt */
- ep2 = vudc_find_endpoint(udc, w_index);
- if (!ep2) {
- ret_val = -EOPNOTSUPP;
- break;
- }
- if (!ep2->wedged)
- ep2->halted = 0;
- ret_val = 0;
- *status = 0;
- }
- break;
- case USB_REQ_GET_STATUS:
- if (setup->bRequestType == DEV_INREQUEST
- || setup->bRequestType == INTF_INREQUEST
- || setup->bRequestType == EP_INREQUEST) {
- char *buf;
- /*
- * device: remote wakeup, selfpowered
- * interface: nothing
- * endpoint: halt
- */
- buf = (char *)urb->transfer_buffer;
- if (urb->transfer_buffer_length > 0) {
- if (setup->bRequestType == EP_INREQUEST) {
- ep2 = vudc_find_endpoint(udc, w_index);
- if (!ep2) {
- ret_val = -EOPNOTSUPP;
- break;
- }
- buf[0] = ep2->halted;
- } else if (setup->bRequestType ==
- DEV_INREQUEST) {
- buf[0] = (u8)udc->devstatus;
- } else
- buf[0] = 0;
- }
- if (urb->transfer_buffer_length > 1)
- buf[1] = 0;
- urb->actual_length = min_t(u32, 2,
- urb->transfer_buffer_length);
- ret_val = 0;
- *status = 0;
- }
- break;
- }
- return ret_val;
- }
- /* Adapted from dummy_hcd.c ; caller must hold lock */
- static int transfer(struct vudc *udc,
- struct urb *urb, struct vep *ep, int limit)
- {
- struct vrequest *req;
- int sent = 0;
- top:
- /* if there's no request queued, the device is NAKing; return */
- list_for_each_entry(req, &ep->req_queue, req_entry) {
- unsigned int host_len, dev_len, len;
- void *ubuf_pos, *rbuf_pos;
- int is_short, to_host;
- int rescan = 0;
- /*
- * 1..N packets of ep->ep.maxpacket each ... the last one
- * may be short (including zero length).
- *
- * writer can send a zlp explicitly (length 0) or implicitly
- * (length mod maxpacket zero, and 'zero' flag); they always
- * terminate reads.
- */
- host_len = urb->transfer_buffer_length - urb->actual_length;
- dev_len = req->req.length - req->req.actual;
- len = min(host_len, dev_len);
- to_host = usb_pipein(urb->pipe);
- if (unlikely(len == 0))
- is_short = 1;
- else {
- /* send multiple of maxpacket first, then remainder */
- if (len >= ep->ep.maxpacket) {
- is_short = 0;
- if (len % ep->ep.maxpacket > 0)
- rescan = 1;
- len -= len % ep->ep.maxpacket;
- } else {
- is_short = 1;
- }
- ubuf_pos = urb->transfer_buffer + urb->actual_length;
- rbuf_pos = req->req.buf + req->req.actual;
- if (urb->pipe & USB_DIR_IN)
- memcpy(ubuf_pos, rbuf_pos, len);
- else
- memcpy(rbuf_pos, ubuf_pos, len);
- urb->actual_length += len;
- req->req.actual += len;
- sent += len;
- }
- /*
- * short packets terminate, maybe with overflow/underflow.
- * it's only really an error to write too much.
- *
- * partially filling a buffer optionally blocks queue advances
- * (so completion handlers can clean up the queue) but we don't
- * need to emulate such data-in-flight.
- */
- if (is_short) {
- if (host_len == dev_len) {
- req->req.status = 0;
- urb->status = 0;
- } else if (to_host) {
- req->req.status = 0;
- if (dev_len > host_len)
- urb->status = -EOVERFLOW;
- else
- urb->status = 0;
- } else {
- urb->status = 0;
- if (host_len > dev_len)
- req->req.status = -EOVERFLOW;
- else
- req->req.status = 0;
- }
- /* many requests terminate without a short packet */
- /* also check if we need to send zlp */
- } else {
- if (req->req.length == req->req.actual) {
- if (req->req.zero && to_host)
- rescan = 1;
- else
- req->req.status = 0;
- }
- if (urb->transfer_buffer_length == urb->actual_length) {
- if (urb->transfer_flags & URB_ZERO_PACKET &&
- !to_host)
- rescan = 1;
- else
- urb->status = 0;
- }
- }
- /* device side completion --> continuable */
- if (req->req.status != -EINPROGRESS) {
- list_del_init(&req->req_entry);
- spin_unlock(&udc->lock);
- usb_gadget_giveback_request(&ep->ep, &req->req);
- spin_lock(&udc->lock);
- /* requests might have been unlinked... */
- rescan = 1;
- }
- /* host side completion --> terminate */
- if (urb->status != -EINPROGRESS)
- break;
- /* rescan to continue with any other queued i/o */
- if (rescan)
- goto top;
- }
- return sent;
- }
- static void v_timer(struct timer_list *t)
- {
- struct vudc *udc = from_timer(udc, t, tr_timer.timer);
- struct transfer_timer *timer = &udc->tr_timer;
- struct urbp *urb_p, *tmp;
- unsigned long flags;
- struct usb_ep *_ep;
- struct vep *ep;
- int ret = 0;
- int total, limit;
- spin_lock_irqsave(&udc->lock, flags);
- total = get_frame_limit(udc->gadget.speed);
- if (total < 0) { /* unknown speed, or not set yet */
- timer->state = VUDC_TR_IDLE;
- spin_unlock_irqrestore(&udc->lock, flags);
- return;
- }
- /* is it next frame now? */
- if (time_after(jiffies, timer->frame_start + msecs_to_jiffies(1))) {
- timer->frame_limit = total;
- /* FIXME: how to make it accurate? */
- timer->frame_start = jiffies;
- } else {
- total = timer->frame_limit;
- }
- /* We have to clear ep0 flags separately as it's not on the list */
- udc->ep[0].already_seen = 0;
- list_for_each_entry(_ep, &udc->gadget.ep_list, ep_list) {
- ep = to_vep(_ep);
- ep->already_seen = 0;
- }
- restart:
- list_for_each_entry_safe(urb_p, tmp, &udc->urb_queue, urb_entry) {
- struct urb *urb = urb_p->urb;
- ep = urb_p->ep;
- if (urb->unlinked)
- goto return_urb;
- if (timer->state != VUDC_TR_RUNNING)
- continue;
- if (!ep) {
- urb->status = -EPROTO;
- goto return_urb;
- }
- /* Used up bandwidth? */
- if (total <= 0 && ep->type == USB_ENDPOINT_XFER_BULK)
- continue;
- if (ep->already_seen)
- continue;
- ep->already_seen = 1;
- if (ep == &udc->ep[0] && urb_p->new) {
- ep->setup_stage = 1;
- urb_p->new = 0;
- }
- if (ep->halted && !ep->setup_stage) {
- urb->status = -EPIPE;
- goto return_urb;
- }
- if (ep == &udc->ep[0] && ep->setup_stage) {
- /* TODO - flush any stale requests */
- ep->setup_stage = 0;
- ep->halted = 0;
- ret = handle_control_request(udc, urb,
- (struct usb_ctrlrequest *) urb->setup_packet,
- (&urb->status));
- if (ret > 0) {
- spin_unlock(&udc->lock);
- ret = udc->driver->setup(&udc->gadget,
- (struct usb_ctrlrequest *)
- urb->setup_packet);
- spin_lock(&udc->lock);
- }
- if (ret >= 0) {
- /* no delays (max 64kb data stage) */
- limit = 64 * 1024;
- goto treat_control_like_bulk;
- } else {
- urb->status = -EPIPE;
- urb->actual_length = 0;
- goto return_urb;
- }
- }
- limit = total;
- switch (ep->type) {
- case USB_ENDPOINT_XFER_ISOC:
- /* TODO: support */
- urb->status = -EXDEV;
- break;
- case USB_ENDPOINT_XFER_INT:
- /*
- * TODO: figure out bandwidth guarantees
- * for now, give unlimited bandwidth
- */
- limit += urb->transfer_buffer_length;
- fallthrough;
- default:
- treat_control_like_bulk:
- total -= transfer(udc, urb, ep, limit);
- }
- if (urb->status == -EINPROGRESS)
- continue;
- return_urb:
- if (ep)
- ep->already_seen = ep->setup_stage = 0;
- spin_lock(&udc->lock_tx);
- list_del(&urb_p->urb_entry);
- if (!urb->unlinked) {
- v_enqueue_ret_submit(udc, urb_p);
- } else {
- v_enqueue_ret_unlink(udc, urb_p->seqnum,
- urb->unlinked);
- free_urbp_and_urb(urb_p);
- }
- wake_up(&udc->tx_waitq);
- spin_unlock(&udc->lock_tx);
- goto restart;
- }
- /* TODO - also wait on empty usb_request queues? */
- if (list_empty(&udc->urb_queue))
- timer->state = VUDC_TR_IDLE;
- else
- mod_timer(&timer->timer,
- timer->frame_start + msecs_to_jiffies(1));
- spin_unlock_irqrestore(&udc->lock, flags);
- }
- /* All timer functions are run with udc->lock held */
- void v_init_timer(struct vudc *udc)
- {
- struct transfer_timer *t = &udc->tr_timer;
- timer_setup(&t->timer, v_timer, 0);
- t->state = VUDC_TR_STOPPED;
- }
- void v_start_timer(struct vudc *udc)
- {
- struct transfer_timer *t = &udc->tr_timer;
- dev_dbg(&udc->pdev->dev, "timer start");
- switch (t->state) {
- case VUDC_TR_RUNNING:
- return;
- case VUDC_TR_IDLE:
- return v_kick_timer(udc, jiffies);
- case VUDC_TR_STOPPED:
- t->state = VUDC_TR_IDLE;
- t->frame_start = jiffies;
- t->frame_limit = get_frame_limit(udc->gadget.speed);
- return v_kick_timer(udc, jiffies);
- }
- }
- void v_kick_timer(struct vudc *udc, unsigned long time)
- {
- struct transfer_timer *t = &udc->tr_timer;
- dev_dbg(&udc->pdev->dev, "timer kick");
- switch (t->state) {
- case VUDC_TR_RUNNING:
- return;
- case VUDC_TR_IDLE:
- t->state = VUDC_TR_RUNNING;
- fallthrough;
- case VUDC_TR_STOPPED:
- /* we may want to kick timer to unqueue urbs */
- mod_timer(&t->timer, time);
- }
- }
- void v_stop_timer(struct vudc *udc)
- {
- struct transfer_timer *t = &udc->tr_timer;
- /* timer itself will take care of stopping */
- dev_dbg(&udc->pdev->dev, "timer stop");
- t->state = VUDC_TR_STOPPED;
- }
|