?? zero.c
字號:
hs = !hs; if (hs) function = is_source_sink ? hs_source_sink_function : hs_loopback_function; else#endif function = is_source_sink ? fs_source_sink_function : fs_loopback_function; /* for now, don't advertise srp-only devices */ if (!gadget->is_otg) function++; len = usb_gadget_config_buf (is_source_sink ? &source_sink_config : &loopback_config, buf, USB_BUFSIZ, function); if (len < 0) return len; ((struct usb_config_descriptor *) buf)->bDescriptorType = type; return len;}/*-------------------------------------------------------------------------*/static struct usb_request *alloc_ep_req (struct usb_ep *ep, unsigned length){ struct usb_request *req; req = usb_ep_alloc_request (ep, GFP_ATOMIC); if (req) { req->length = length; req->buf = usb_ep_alloc_buffer (ep, length, &req->dma, GFP_ATOMIC); if (!req->buf) { usb_ep_free_request (ep, req); req = NULL; } } return req;}static void free_ep_req (struct usb_ep *ep, struct usb_request *req){ if (req->buf) usb_ep_free_buffer (ep, req->buf, req->dma, req->length); usb_ep_free_request (ep, req);}/*-------------------------------------------------------------------------*//* optionally require specific source/sink data patterns */static intcheck_read_data ( struct zero_dev *dev, struct usb_ep *ep, struct usb_request *req){ unsigned i; u8 *buf = req->buf; for (i = 0; i < req->actual; i++, buf++) { switch (pattern) { /* all-zeroes has no synchronization issues */ case 0: if (*buf == 0) continue; break; /* mod63 stays in sync with short-terminated transfers, * or otherwise when host and gadget agree on how large * each usb transfer request should be. resync is done * with set_interface or set_config. */ case 1: if (*buf == (u8)(i % 63)) continue; break; } ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf); usb_ep_set_halt (ep); return -EINVAL; } return 0;}static voidreinit_write_data ( struct zero_dev *dev, struct usb_ep *ep, struct usb_request *req){ unsigned i; u8 *buf = req->buf; switch (pattern) { case 0: memset (req->buf, 0, req->length); break; case 1: for (i = 0; i < req->length; i++) *buf++ = (u8) (i % 63); break; }}/* if there is only one request in the queue, there'll always be an * irq delay between end of one request and start of the next. * that prevents using hardware dma queues. */static void source_sink_complete (struct usb_ep *ep, struct usb_request *req){ struct zero_dev *dev = ep->driver_data; int status = req->status; switch (status) { case 0: /* normal completion? */ if (ep == dev->out_ep) check_read_data (dev, ep, req); else reinit_write_data (dev, ep, req); break; /* this endpoint is normally active while we're configured */ case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status, req->actual, req->length); if (ep == dev->out_ep) check_read_data (dev, ep, req); free_ep_req (ep, req); return; case -EOVERFLOW: /* buffer overrun on read means that * we didn't provide a big enough * buffer. */ default:#if 1 DBG (dev, "%s complete --> %d, %d/%d\n", ep->name, status, req->actual, req->length);#endif case -EREMOTEIO: /* short read */ break; } status = usb_ep_queue (ep, req, GFP_ATOMIC); if (status) { ERROR (dev, "kill %s: resubmit %d bytes --> %d\n", ep->name, req->length, status); usb_ep_set_halt (ep); /* FIXME recover later ... somehow */ }}static struct usb_request *source_sink_start_ep (struct usb_ep *ep, int gfp_flags){ struct usb_request *req; int status; req = alloc_ep_req (ep, buflen); if (!req) return NULL; memset (req->buf, 0, req->length); req->complete = source_sink_complete; if (strcmp (ep->name, EP_IN_NAME) == 0) reinit_write_data (ep->driver_data, ep, req); status = usb_ep_queue (ep, req, gfp_flags); if (status) { struct zero_dev *dev = ep->driver_data; ERROR (dev, "start %s --> %d\n", ep->name, status); free_ep_req (ep, req); req = NULL; } return req;}static intset_source_sink_config (struct zero_dev *dev, int gfp_flags){ int result = 0; struct usb_ep *ep; struct usb_gadget *gadget = dev->gadget; gadget_for_each_ep (ep, gadget) { const struct usb_endpoint_descriptor *d; /* one endpoint writes (sources) zeroes in (to the host) */ if (strcmp (ep->name, EP_IN_NAME) == 0) { d = ep_desc (gadget, &hs_source_desc, &fs_source_desc); result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; if (source_sink_start_ep (ep, gfp_flags) != 0) { dev->in_ep = ep; continue; } usb_ep_disable (ep); result = -EIO; } /* one endpoint reads (sinks) anything out (from the host) */ } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc); result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; if (source_sink_start_ep (ep, gfp_flags) != 0) { dev->out_ep = ep; continue; } usb_ep_disable (ep); result = -EIO; } /* ignore any other endpoints */ } else continue; /* stop on error */ ERROR (dev, "can't start %s, result %d\n", ep->name, result); break; } if (result == 0) DBG (dev, "buflen %d\n", buflen); /* caller is responsible for cleanup on error */ return result;}/*-------------------------------------------------------------------------*/static void loopback_complete (struct usb_ep *ep, struct usb_request *req){ struct zero_dev *dev = ep->driver_data; int status = req->status; switch (status) { case 0: /* normal completion? */ if (ep == dev->out_ep) { /* loop this OUT packet back IN to the host */ req->zero = (req->actual < req->length); req->length = req->actual; status = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC); if (status == 0) return; /* "should never get here" */ ERROR (dev, "can't loop %s to %s: %d\n", ep->name, dev->in_ep->name, status); } /* queue the buffer for some later OUT packet */ req->length = buflen; status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC); if (status == 0) return; /* "should never get here" */ /* FALLTHROUGH */ default: ERROR (dev, "%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; }}static intset_loopback_config (struct zero_dev *dev, int gfp_flags){ int result = 0; struct usb_ep *ep; struct usb_gadget *gadget = dev->gadget; gadget_for_each_ep (ep, gadget) { const struct usb_endpoint_descriptor *d; /* one endpoint writes data back IN to the host */ if (strcmp (ep->name, EP_IN_NAME) == 0) { d = ep_desc (gadget, &hs_source_desc, &fs_source_desc); result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; dev->in_ep = ep; continue; } /* one endpoint just reads OUT packets */ } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc); result = usb_ep_enable (ep, d); if (result == 0) { ep->driver_data = dev; dev->out_ep = ep; continue; } /* ignore any other endpoints */ } else continue; /* stop on error */ ERROR (dev, "can't enable %s, result %d\n", ep->name, result); break; } /* 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. */ if (result == 0) { struct usb_request *req; unsigned i; ep = dev->out_ep; for (i = 0; i < qlen && result == 0; i++) { req = alloc_ep_req (ep, buflen); if (req) { req->complete = loopback_complete; result = usb_ep_queue (ep, req, GFP_ATOMIC); if (result) DBG (dev, "%s queue req --> %d\n", ep->name, result); } else result = -ENOMEM; } } if (result == 0) DBG (dev, "qlen %d, buflen %d\n", qlen, buflen); /* caller is responsible for cleanup on error */ return result;}/*-------------------------------------------------------------------------*/static void zero_reset_config (struct zero_dev *dev){ if (dev->config == 0) return; DBG (dev, "reset config\n"); /* just disable endpoints, forcing completion of pending i/o. * all our completion handlers free their requests in this case. */ if (dev->in_ep) { usb_ep_disable (dev->in_ep); dev->in_ep = NULL; } if (dev->out_ep) { usb_ep_disable (dev->out_ep); dev->out_ep = NULL; } dev->config = 0; del_timer (&dev->resume);}/* change our operational config. this code must agree with the code * that returns config descriptors, and altsetting code. * * it's also responsible for power management interactions. some * configurations might not work with our current power sources. * * note that some device controller hardware will constrain what this * code can do, perhaps by disallowing more than one configuration or * by limiting configuration choices (like the pxa2xx). */static intzero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags){ int result = 0; struct usb_gadget *gadget = dev->gadget; if (number == dev->config) return 0; if (gadget_is_sa1100 (gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ INFO (dev, "can't change configurations\n"); return -ESPIPE; } zero_reset_config (dev); switch (number) { case CONFIG_SOURCE_SINK: result = set_source_sink_config (dev, gfp_flags); break; case CONFIG_LOOPBACK: result = set_loopback_config (dev, gfp_flags); break; default: result = -EINVAL; /* FALL THROUGH */ case 0: return result; } if (!result && (!dev->in_ep || !dev->out_ep)) result = -ENODEV; if (result) zero_reset_config (dev); else { char *speed; switch (gadget->speed) { case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; default: speed = "?"; break; } dev->config = number; INFO (dev, "%s speed config #%d: %s\n", speed, number, (number == CONFIG_SOURCE_SINK) ? source_sink : loopback); } return result;}/*-------------------------------------------------------------------------*/static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req){
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -