diff options
author | Daniel Thompson <daniel.thompson@linaro.org> | 2017-07-31 17:23:07 +0100 |
---|---|---|
committer | Daniel Thompson <daniel.thompson@linaro.org> | 2017-07-31 17:23:07 +0100 |
commit | e5b9b8c8b78096e961f4a45b9d1418e4641f24f9 (patch) | |
tree | a88f532f386376fca6a376e2c362173f971dc144 /drivers/usb/gadget | |
parent | 415d386877df49eb051b85ef74fa59a16dc17c7d (diff) |
Orangepi i96 support (mega patch)rda/v2012.04.01-r0
This is https://github.com/orangepi-xunlong/OrangePiRDA_u-boot
5ee06c1afb7c ("add new patch a patch") as a single patch against
a guestimated upstream version.
This is merely a reference tree for later comparisons.
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
NOT-Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/Makefile | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/composite.c | 1082 | ||||
-rw-r--r-- | drivers/usb/gadget/config.c | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/core.c | 50 | ||||
-rw-r--r-- | drivers/usb/gadget/ep0.c | 10 | ||||
-rw-r--r-- | drivers/usb/gadget/epautoconf.c | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/ether.c | 8 | ||||
-rw-r--r-- | drivers/usb/gadget/f_fastboot.c | 473 | ||||
-rw-r--r-- | drivers/usb/gadget/fastboot.c | 986 | ||||
-rw-r--r-- | drivers/usb/gadget/fastboot.h | 8 | ||||
-rw-r--r-- | drivers/usb/gadget/s3c_udc_otg.c | 58 | ||||
-rw-r--r-- | drivers/usb/gadget/s3c_udc_otg_xfer_dma.c | 289 | ||||
-rw-r--r-- | drivers/usb/gadget/usbstring.c | 1 |
13 files changed, 2821 insertions, 150 deletions
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 87d1918cb9..c3eca4b9fe 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -47,6 +47,10 @@ COBJS-$(CONFIG_CPU_PXA27X) += pxa27x_udc.o endif endif +ifndef CONFIG_SPL_BUILD +COBJS-$(CONFIG_USB_FASTBOOT) += f_fastboot.o fastboot.o +endif + COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS)) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c new file mode 100644 index 0000000000..ebb5131a9c --- /dev/null +++ b/drivers/usb/gadget/composite.c @@ -0,0 +1,1082 @@ +/* + * composite.c - infrastructure for Composite USB Gadgets + * + * Copyright (C) 2006-2008 David Brownell + * U-boot porting: Lukasz Majewski <l.majewski@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#undef DEBUG + +#include <linux/bitops.h> +#include <linux/usb/composite.h> + +#define USB_BUFSIZ 4096 + +static struct usb_composite_driver *composite; + +/** + * usb_add_function() - add a function to a configuration + * @config: the configuration + * @function: the function being added + * Context: single threaded during gadget setup + * + * After initialization, each configuration must have one or more + * functions added to it. Adding a function involves calling its @bind() + * method to allocate resources such as interface and string identifiers + * and endpoints. + * + * This function returns the value of the function's bind(), which is + * zero for success else a negative errno value. + */ +int usb_add_function(struct usb_configuration *config, + struct usb_function *function) +{ + int value = -EINVAL; + + debug("adding '%s'/%p to config '%s'/%p\n", + function->name, function, + config->label, config); + + if (!function->set_alt || !function->disable) + goto done; + + function->config = config; + list_add_tail(&function->list, &config->functions); + + if (function->bind) { + value = function->bind(config, function); + if (value < 0) { + list_del(&function->list); + function->config = NULL; + } + } else + value = 0; + + if (!config->fullspeed && function->descriptors) + config->fullspeed = 1; + if (!config->highspeed && function->hs_descriptors) + config->highspeed = 1; + +done: + if (value) + debug("adding '%s'/%p --> %d\n", + function->name, function, value); + return value; +} + +/** + * usb_function_deactivate - prevent function and gadget enumeration + * @function: the function that isn't yet ready to respond + * + * Blocks response of the gadget driver to host enumeration by + * preventing the data line pullup from being activated. This is + * normally called during @bind() processing to change from the + * initial "ready to respond" state, or when a required resource + * becomes available. + * + * For example, drivers that serve as a passthrough to a userspace + * daemon can block enumeration unless that daemon (such as an OBEX, + * MTP, or print server) is ready to handle host requests. + * + * Not all systems support software control of their USB peripheral + * data pullups. + * + * Returns zero on success, else negative errno. + */ +int usb_function_deactivate(struct usb_function *function) +{ + struct usb_composite_dev *cdev = function->config->cdev; + int status = 0; + + if (cdev->deactivations == 0) + status = usb_gadget_disconnect(cdev->gadget); + if (status == 0) + cdev->deactivations++; + + return status; +} + +/** + * usb_function_activate - allow function and gadget enumeration + * @function: function on which usb_function_activate() was called + * + * Reverses effect of usb_function_deactivate(). If no more functions + * are delaying their activation, the gadget driver will respond to + * host enumeration procedures. + * + * Returns zero on success, else negative errno. + */ +int usb_function_activate(struct usb_function *function) +{ + struct usb_composite_dev *cdev = function->config->cdev; + int status = 0; + + if (cdev->deactivations == 0) + status = -EINVAL; + else { + cdev->deactivations--; + if (cdev->deactivations == 0) + status = usb_gadget_connect(cdev->gadget); + } + + return status; +} + +/** + * usb_interface_id() - allocate an unused interface ID + * @config: configuration associated with the interface + * @function: function handling the interface + * Context: single threaded during gadget setup + * + * usb_interface_id() is called from usb_function.bind() callbacks to + * allocate new interface IDs. The function driver will then store that + * ID in interface, association, CDC union, and other descriptors. It + * will also handle any control requests targetted at that interface, + * particularly changing its altsetting via set_alt(). There may + * also be class-specific or vendor-specific requests to handle. + * + * All interface identifier should be allocated using this routine, to + * ensure that for example different functions don't wrongly assign + * different meanings to the same identifier. Note that since interface + * identifers are configuration-specific, functions used in more than + * one configuration (or more than once in a given configuration) need + * multiple versions of the relevant descriptors. + * + * Returns the interface ID which was allocated; or -ENODEV if no + * more interface IDs can be allocated. + */ +int usb_interface_id(struct usb_configuration *config, + struct usb_function *function) +{ + unsigned char id = config->next_interface_id; + + if (id < MAX_CONFIG_INTERFACES) { + config->interface[id] = function; + config->next_interface_id = id + 1; + return id; + } + return -ENODEV; +} + +static int config_buf(struct usb_configuration *config, + enum usb_device_speed speed, void *buf, u8 type) +{ + int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE; + void *next = buf + USB_DT_CONFIG_SIZE; + struct usb_descriptor_header **descriptors; + struct usb_config_descriptor *c = buf; + int status; + struct usb_function *f; + + /* write the config descriptor */ + c = buf; + c->bLength = USB_DT_CONFIG_SIZE; + c->bDescriptorType = type; + + c->bNumInterfaces = config->next_interface_id; + c->bConfigurationValue = config->bConfigurationValue; + c->iConfiguration = config->iConfiguration; + c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes; + c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2); + + /* There may be e.g. OTG descriptors */ + if (config->descriptors) { + status = usb_descriptor_fillbuf(next, len, + config->descriptors); + if (status < 0) + return status; + len -= status; + next += status; + } + + /* add each function's descriptors */ + list_for_each_entry(f, &config->functions, list) { + if (speed == USB_SPEED_HIGH) + descriptors = f->hs_descriptors; + else + descriptors = f->descriptors; + if (!descriptors) + continue; + status = usb_descriptor_fillbuf(next, len, + (const struct usb_descriptor_header **) descriptors); + if (status < 0) + return status; + len -= status; + next += status; + } + + len = next - buf; + c->wTotalLength = cpu_to_le16(len); + return len; +} + +static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) +{ + enum usb_device_speed speed = USB_SPEED_UNKNOWN; + struct usb_gadget *gadget = cdev->gadget; + u8 type = w_value >> 8; + int hs = 0; + struct usb_configuration *c; + + if (gadget_is_dualspeed(gadget)) { + if (gadget->speed == USB_SPEED_HIGH) + hs = 1; + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + if (hs) + speed = USB_SPEED_HIGH; + } + + w_value &= 0xff; + list_for_each_entry(c, &cdev->configs, list) { + if (speed == USB_SPEED_HIGH) { + if (!c->highspeed) + continue; + } else { + if (!c->fullspeed) + continue; + } + if (w_value == 0) + return config_buf(c, speed, cdev->req->buf, type); + w_value--; + } + return -EINVAL; +} + +static int count_configs(struct usb_composite_dev *cdev, unsigned type) +{ + struct usb_gadget *gadget = cdev->gadget; + unsigned count = 0; + int hs = 0; + struct usb_configuration *c; + + if (gadget_is_dualspeed(gadget)) { + if (gadget->speed == USB_SPEED_HIGH) + hs = 1; + if (type == USB_DT_DEVICE_QUALIFIER) + hs = !hs; + } + list_for_each_entry(c, &cdev->configs, list) { + /* ignore configs that won't work at this speed */ + if (hs) { + if (!c->highspeed) + continue; + } else { + if (!c->fullspeed) + continue; + } + count++; + } + return count; +} + +static void device_qual(struct usb_composite_dev *cdev) +{ + struct usb_qualifier_descriptor *qual = cdev->req->buf; + + qual->bLength = sizeof(*qual); + qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER; + /* POLICY: same bcdUSB and device type info at both speeds */ + qual->bcdUSB = cdev->desc.bcdUSB; + qual->bDeviceClass = cdev->desc.bDeviceClass; + qual->bDeviceSubClass = cdev->desc.bDeviceSubClass; + qual->bDeviceProtocol = cdev->desc.bDeviceProtocol; + /* ASSUME same EP0 fifo size at both speeds */ + qual->bMaxPacketSize0 = cdev->desc.bMaxPacketSize0; + qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER); + qual->bRESERVED = 0; +} + +static void reset_config(struct usb_composite_dev *cdev) +{ + struct usb_function *f; + + debug("%s:\n", __func__); + + list_for_each_entry(f, &cdev->config->functions, list) { + if (f->disable) + f->disable(f); + + bitmap_zero(f->endpoints, 32); + } + cdev->config = NULL; +} + +static int set_config(struct usb_composite_dev *cdev, + const struct usb_ctrlrequest *ctrl, unsigned number) +{ + struct usb_gadget *gadget = cdev->gadget; + unsigned power = gadget_is_otg(gadget) ? 8 : 100; + struct usb_descriptor_header **descriptors; + int result = -EINVAL; + struct usb_endpoint_descriptor *ep; + struct usb_configuration *c = NULL; + int addr; + int tmp; + struct usb_function *f; + + if (cdev->config) + reset_config(cdev); + + if (number) { + list_for_each_entry(c, &cdev->configs, list) { + if (c->bConfigurationValue == number) { + result = 0; + break; + } + } + if (result < 0) + goto done; + } else + result = 0; + + debug("%s: %s speed config #%d: %s\n", __func__, + ({ 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; + }; + speed; + }), number, c ? c->label : "unconfigured"); + + if (!c) + goto done; + + cdev->config = c; + + /* Initialize all interfaces by setting them to altsetting zero. */ + for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) { + f = c->interface[tmp]; + if (!f) + break; + + /* + * Record which endpoints are used by the function. This is used + * to dispatch control requests targeted at that endpoint to the + * function's setup callback instead of the current + * configuration's setup callback. + */ + if (gadget->speed == USB_SPEED_HIGH) + descriptors = f->hs_descriptors; + else + descriptors = f->descriptors; + + for (; *descriptors; ++descriptors) { + if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT) + continue; + + ep = (struct usb_endpoint_descriptor *)*descriptors; + addr = ((ep->bEndpointAddress & 0x80) >> 3) + | (ep->bEndpointAddress & 0x0f); + __set_bit(addr, f->endpoints); + } + + result = f->set_alt(f, tmp, 0); + if (result < 0) { + debug("interface %d (%s/%p) alt 0 --> %d\n", + tmp, f->name, f, result); + + reset_config(cdev); + goto done; + } + } + + /* when we return, be sure our power usage is valid */ + power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW; +done: + usb_gadget_vbus_draw(gadget, power); + return result; +} + +/** + * usb_add_config() - add a configuration to a device. + * @cdev: wraps the USB gadget + * @config: the configuration, with bConfigurationValue assigned + * Context: single threaded during gadget setup + * + * One of the main tasks of a composite driver's bind() routine is to + * add each of the configurations it supports, using this routine. + * + * This function returns the value of the configuration's bind(), which + * is zero for success else a negative errno value. Binding configurations + * assigns global resources including string IDs, and per-configuration + * resources such as interface IDs and endpoints. + */ +int usb_add_config(struct usb_composite_dev *cdev, + struct usb_configuration *config) +{ + int status = -EINVAL; + struct usb_configuration *c; + struct usb_function *f; + unsigned int i; + + debug("%s: adding config #%u '%s'/%p\n", __func__, + config->bConfigurationValue, + config->label, config); + + if (!config->bConfigurationValue || !config->bind) + goto done; + + /* Prevent duplicate configuration identifiers */ + list_for_each_entry(c, &cdev->configs, list) { + if (c->bConfigurationValue == config->bConfigurationValue) { + status = -EBUSY; + goto done; + } + } + + config->cdev = cdev; + list_add_tail(&config->list, &cdev->configs); + + INIT_LIST_HEAD(&config->functions); + config->next_interface_id = 0; + + status = config->bind(config); + if (status < 0) { + list_del(&config->list); + config->cdev = NULL; + } else { + debug("cfg %d/%p speeds:%s%s\n", + config->bConfigurationValue, config, + config->highspeed ? " high" : "", + config->fullspeed + ? (gadget_is_dualspeed(cdev->gadget) + ? " full" + : " full/low") + : ""); + + for (i = 0; i < MAX_CONFIG_INTERFACES; i++) { + f = config->interface[i]; + if (!f) + continue; + debug("%s: interface %d = %s/%p\n", + __func__, i, f->name, f); + } + } + + usb_ep_autoconfig_reset(cdev->gadget); + +done: + if (status) + debug("added config '%s'/%u --> %d\n", config->label, + config->bConfigurationValue, status); + return status; +} + +/* + * We support strings in multiple languages ... string descriptor zero + * says which languages are supported. The typical case will be that + * only one language (probably English) is used, with I18N handled on + * the host side. + */ + +static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf) +{ + const struct usb_gadget_strings *s; + u16 language; + __le16 *tmp; + + while (*sp) { + s = *sp; + language = cpu_to_le16(s->language); + for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) { + if (*tmp == language) + goto repeat; + } + *tmp++ = language; +repeat: + sp++; + } +} + +static int lookup_string( + struct usb_gadget_strings **sp, + void *buf, + u16 language, + int id +) +{ + int value; + struct usb_gadget_strings *s; + + while (*sp) { + s = *sp++; + if (s->language != language) + continue; + value = usb_gadget_get_string(s, id, buf); + if (value > 0) + return value; + } + return -EINVAL; +} + +static int get_string(struct usb_composite_dev *cdev, + void *buf, u16 language, int id) +{ + struct usb_string_descriptor *s = buf; + struct usb_gadget_strings **sp; + int len; + struct usb_configuration *c; + struct usb_function *f; + + /* + * Yes, not only is USB's I18N support probably more than most + * folk will ever care about ... also, it's all supported here. + * (Except for UTF8 support for Unicode's "Astral Planes".) + */ + + /* 0 == report all available language codes */ + if (id == 0) { + memset(s, 0, 256); + s->bDescriptorType = USB_DT_STRING; + + sp = composite->strings; + if (sp) + collect_langs(sp, s->wData); + + list_for_each_entry(c, &cdev->configs, list) { + sp = c->strings; + if (sp) + collect_langs(sp, s->wData); + + list_for_each_entry(f, &c->functions, list) { + sp = f->strings; + if (sp) + collect_langs(sp, s->wData); + } + } + + for (len = 0; len <= 126 && s->wData[len]; len++) + continue; + if (!len) + return -EINVAL; + + s->bLength = 2 * (len + 1); + return s->bLength; + } + + /* + * Otherwise, look up and return a specified string. String IDs + * are device-scoped, so we look up each string table we're told + * about. These lookups are infrequent; simpler-is-better here. + */ + if (composite->strings) { + len = lookup_string(composite->strings, buf, language, id); + if (len > 0) + return len; + } + list_for_each_entry(c, &cdev->configs, list) { + if (c->strings) { + len = lookup_string(c->strings, buf, language, id); + if (len > 0) + return len; + } + list_for_each_entry(f, &c->functions, list) { + if (!f->strings) + continue; + len = lookup_string(f->strings, buf, language, id); + if (len > 0) + return len; + } + } + return -EINVAL; +} + +/** + * usb_string_id() - allocate an unused string ID + * @cdev: the device whose string descriptor IDs are being allocated + * Context: single threaded during gadget setup + * + * @usb_string_id() is called from bind() callbacks to allocate + * string IDs. Drivers for functions, configurations, or gadgets will + * then store that ID in the appropriate descriptors and string table. + * + * All string identifier should be allocated using this, + * @usb_string_ids_tab() or @usb_string_ids_n() routine, to ensure + * that for example different functions don't wrongly assign different + * meanings to the same identifier. + */ +int usb_string_id(struct usb_composite_dev *cdev) +{ + if (cdev->next_string_id < 254) { + /* + * string id 0 is reserved by USB spec for list of + * supported languages + * 255 reserved as well? -- mina86 + */ + cdev->next_string_id++; + return cdev->next_string_id; + } + return -ENODEV; +} + +/** + * usb_string_ids() - allocate unused string IDs in batch + * @cdev: the device whose string descriptor IDs are being allocated + * @str: an array of usb_string objects to assign numbers to + * Context: single threaded during gadget setup + * + * @usb_string_ids() is called from bind() callbacks to allocate + * string IDs. Drivers for functions, configurations, or gadgets will + * then copy IDs from the string table to the appropriate descriptors + * and string table for other languages. + * + * All string identifier should be allocated using this, + * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for + * example different functions don't wrongly assign different meanings + * to the same identifier. + */ +int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str) +{ + u8 next = cdev->next_string_id; + + for (; str->s; ++str) { + if (next >= 254) + return -ENODEV; + str->id = ++next; + } + + cdev->next_string_id = next; + + return 0; +} + +/** + * usb_string_ids_n() - allocate unused string IDs in batch + * @c: the device whose string descriptor IDs are being allocated + * @n: number of string IDs to allocate + * Context: single threaded during gadget setup + * + * Returns the first requested ID. This ID and next @n-1 IDs are now + * valid IDs. At least provided that @n is non-zero because if it + * is, returns last requested ID which is now very useful information. + * + * @usb_string_ids_n() is called from bind() callbacks to allocate + * string IDs. Drivers for functions, configurations, or gadgets will + * then store that ID in the appropriate descriptors and string table. + * + * All string identifier should be allocated using this, + * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for + * example different functions don't wrongly assign different meanings + * to the same identifier. + */ +int usb_string_ids_n(struct usb_composite_dev *c, unsigned n) +{ + u8 next = c->next_string_id; + + if (n > 254 || next + n > 254) + return -ENODEV; + + c->next_string_id += n; + return next + 1; +} + +static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req) +{ + if (req->status || req->actual != req->length) + debug("%s: setup complete --> %d, %d/%d\n", __func__, + req->status, req->actual, req->length); +} + +/* + * The setup() callback implements all the ep0 functionality that's + * not handled lower down, in hardware or the hardware driver(like + * device and endpoint feature flags, and their status). It's all + * housekeeping for the gadget function we're implementing. Most of + * the work is in config and function specific setup. + */ +static int +composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) +{ + u16 w_length = le16_to_cpu(ctrl->wLength); + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + struct usb_composite_dev *cdev = get_gadget_data(gadget); + u8 intf = w_index & 0xFF; + int value = -EOPNOTSUPP; + struct usb_request *req = cdev->req; + struct usb_function *f = NULL; + int standard; + u8 endp; + struct usb_configuration *c; + + /* + * partial re-init of the response message; the function or the + * gadget might need to intercept e.g. a control-OUT completion + * when we delegate to it. + */ + req->zero = 0; + req->complete = composite_setup_complete; + req->length = USB_BUFSIZ; + gadget->ep0->driver_data = cdev; + standard = (ctrl->bRequestType & USB_TYPE_MASK) + == USB_TYPE_STANDARD; + if (!standard) + goto unknown; + + switch (ctrl->bRequest) { + + /* we handle all standard USB descriptors */ + case USB_REQ_GET_DESCRIPTOR: + if (ctrl->bRequestType != USB_DIR_IN) + goto unknown; + switch (w_value >> 8) { + + case USB_DT_DEVICE: + cdev->desc.bNumConfigurations = + count_configs(cdev, USB_DT_DEVICE); + value = min(w_length, (u16) sizeof cdev->desc); + memcpy(req->buf, &cdev->desc, value); + break; + case USB_DT_DEVICE_QUALIFIER: + if (!gadget_is_dualspeed(gadget)) + break; + device_qual(cdev); + value = min(w_length, + sizeof(struct usb_qualifier_descriptor)); + break; + case USB_DT_OTHER_SPEED_CONFIG: + if (!gadget_is_dualspeed(gadget)) + break; + + case USB_DT_CONFIG: + value = config_desc(cdev, w_value); + if (value >= 0) + value = min(w_length, (u16) value); + break; + case USB_DT_STRING: + value = get_string(cdev, req->buf, + w_index, w_value & 0xff); + if (value >= 0) + value = min(w_length, (u16) value); + break; + default: + goto unknown; + } + break; + + /* any number of configs can work */ + case USB_REQ_SET_CONFIGURATION: + if (ctrl->bRequestType != 0) + goto unknown; + if (gadget_is_otg(gadget)) { + if (gadget->a_hnp_support) + debug("HNP available\n"); + else if (gadget->a_alt_hnp_support) + debug("HNP on another port\n"); + else + debug("HNP inactive\n"); + } + + value = set_config(cdev, ctrl, w_value); + break; + case USB_REQ_GET_CONFIGURATION: + if (ctrl->bRequestType != USB_DIR_IN) + goto unknown; + if (cdev->config) + *(u8 *)req->buf = cdev->config->bConfigurationValue; + else + *(u8 *)req->buf = 0; + value = min(w_length, (u16) 1); + break; + + /* + * function drivers must handle get/set altsetting; if there's + * no get() method, we know only altsetting zero works. + */ + case USB_REQ_SET_INTERFACE: + if (ctrl->bRequestType != USB_RECIP_INTERFACE) + goto unknown; + if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES) + break; + f = cdev->config->interface[intf]; + if (!f) + break; + if (w_value && !f->set_alt) + break; + value = f->set_alt(f, w_index, w_value); + break; + case USB_REQ_GET_INTERFACE: + if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) + goto unknown; + if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES) + break; + f = cdev->config->interface[intf]; + if (!f) + break; + /* lots of interfaces only need altsetting zero... */ + value = f->get_alt ? f->get_alt(f, w_index) : 0; + if (value < 0) + break; + *((u8 *)req->buf) = value; + value = min(w_length, (u16) 1); + break; + default: +unknown: + debug("non-core control req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + w_value, w_index, w_length); + + /* + * functions always handle their interfaces and endpoints... + * punt other recipients (other, WUSB, ...) to the current + * configuration code. + */ + switch (ctrl->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_INTERFACE: + f = cdev->config->interface[intf]; + break; + + case USB_RECIP_ENDPOINT: + endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f); + list_for_each_entry(f, &cdev->config->functions, list) { + if (test_bit(endp, f->endpoints)) + break; + } + if (&f->list == &cdev->config->functions) + f = NULL; + break; + } + + if (f && f->setup) + value = f->setup(f, ctrl); + else { + c = cdev->config; + if (c && c->setup) + value = c->setup(c, ctrl); + } + + goto done; + } + + /* respond with data transfer before status phase? */ + if (value >= 0) { + req->length = value; + req->zero = value < w_length; + value = usb_ep_queue(gadget->ep0, req, GFP_KERNEL); + if (value < 0) { + debug("ep_queue --> %d\n", value); + req->status = 0; + composite_setup_complete(gadget->ep0, req); + } + } + +done: + /* device either stalls (value < 0) or reports success */ + return value; +} + +static void composite_disconnect(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev = get_gadget_data(gadget); + + if (cdev->config) + reset_config(cdev); + if (composite->disconnect) + composite->disconnect(cdev); +} + +static void composite_unbind(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev = get_gadget_data(gadget); + struct usb_configuration *c; + struct usb_function *f; + + /* + * composite_disconnect() must already have been called + * by the underlying peripheral controller driver! + * so there's no i/o concurrency that could affect the + * state protected by cdev->lock. + */ + BUG_ON(cdev->config); + + while (!list_empty(&cdev->configs)) { + c = list_first_entry(&cdev->configs, + struct usb_configuration, list); + while (!list_empty(&c->functions)) { + f = list_first_entry(&c->functions, + struct usb_function, list); + list_del(&f->list); + if (f->unbind) { + debug("unbind function '%s'/%p\n", + f->name, f); + f->unbind(c, f); + } + } + list_del(&c->list); + if (c->unbind) { + debug("unbind config '%s'/%p\n", c->label, c); + c->unbind(c); + } + } + if (composite->unbind) + composite->unbind(cdev); + + if (cdev->req) { + kfree(cdev->req->buf); + usb_ep_free_request(gadget->ep0, cdev->req); + } + kfree(cdev); + set_gadget_data(gadget, NULL); + + composite = NULL; +} + +static int composite_bind(struct usb_gadget *gadget) +{ + int status = -ENOMEM; + struct usb_composite_dev *cdev; + + cdev = calloc(sizeof *cdev, 1); + if (!cdev) + return status; + + cdev->gadget = gadget; + set_gadget_data(gadget, cdev); + INIT_LIST_HEAD(&cdev->configs); + + /* preallocate control response and buffer */ + cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); + if (!cdev->req) + goto fail; + cdev->req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, USB_BUFSIZ); + if (!cdev->req->buf) + goto fail; + cdev->req->complete = composite_setup_complete; + gadget->ep0->driver_data = cdev; + + cdev->bufsiz = USB_BUFSIZ; + cdev->driver = composite; + + usb_gadget_set_selfpowered(gadget); + usb_ep_autoconfig_reset(cdev->gadget); + + status = composite->bind(cdev); + if (status < 0) + goto fail; + + cdev->desc = *composite->dev; + cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket; + + debug("%s: ready\n", composite->name); + return 0; + +fail: + composite_unbind(gadget); + return status; +} + +static void +composite_suspend(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev = get_gadget_data(gadget); + struct usb_function *f; + + debug("%s: suspend\n", __func__); + if (cdev->config) { + list_for_each_entry(f, &cdev->config->functions, list) { + if (f->suspend) + f->suspend(f); + } + } + if (composite->suspend) + composite->suspend(cdev); + + cdev->suspended = 1; +} + +static void +composite_resume(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev = get_gadget_data(gadget); + struct usb_function *f; + + debug("%s: resume\n", __func__); + if (composite->resume) + composite->resume(cdev); + if (cdev->config) { + list_for_each_entry(f, &cdev->config->functions, list) { + if (f->resume) + f->resume(f); + } + } + + cdev->suspended = 0; +} + +static struct usb_gadget_driver composite_driver = { + .speed = USB_SPEED_HIGH, + + .bind = composite_bind, + .unbind = composite_unbind, + + .setup = composite_setup, + .disconnect = composite_disconnect, + + .suspend = composite_suspend, + .resume = composite_resume, +}; + +/** + * usb_composite_register() - register a composite driver + * @driver: the driver to register + * Context: single threaded during gadget setup + * + * This function is used to register drivers using the composite driver + * framework. The return value is zero, or a negative errno value. + * Those values normally come from the driver's @bind method, which does + * all the work of setting up the driver to match the hardware. + * + * On successful return, the gadget is ready to respond to requests from + * the host, unless one of its components invokes usb_gadget_disconnect() + * while it was binding. That would usually be done in order to wait for + * some userspace participation. + */ +int usb_composite_register(struct usb_composite_driver *driver) +{ + if (!driver || !driver->dev || !driver->bind || composite) + return -EINVAL; + + if (!driver->name) + driver->name = "composite"; + composite = driver; + + return usb_gadget_register_driver(&composite_driver); +} + +/** + * usb_composite_unregister() - unregister a composite driver + * @driver: the driver to unregister + * + * This function is used to unregister drivers using the composite + * driver framework. + */ +void usb_composite_unregister(struct usb_composite_driver *driver) +{ + if (composite != driver) + return; + usb_gadget_unregister_driver(&composite_driver); +} diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index f9163a80ed..f88d0c190c 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -27,6 +27,7 @@ #include <linux/string.h> #include <linux/usb/ch9.h> +#include <usbdescriptors.h> #include <linux/usb/gadget.h> diff --git a/drivers/usb/gadget/core.c b/drivers/usb/gadget/core.c index 46ab3f67f8..1ab14eb3b4 100644 --- a/drivers/usb/gadget/core.c +++ b/drivers/usb/gadget/core.c @@ -364,11 +364,12 @@ void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_ /*rcv_urb->actual_length, rcv_urb->buffer_length); */ /* check the urb is ok, are we adding data less than the packetsize */ - if (!urb_bad && (len <= endpoint->rcv_packetSize)) { + if (!urb_bad) { /*usbdbg("updating actual_length by %d\n",len); */ /* increment the received data size */ rcv_urb->actual_length += len; + rcv_urb->req_length = 0; } else { usberr(" RECV_ERROR actual: %d buffer: %d urb_bad: %d\n", @@ -560,14 +561,55 @@ struct urb *usbd_alloc_urb (struct usb_device_instance *device, memset (urb, 0, sizeof (struct urb)); urb->endpoint = endpoint; urb->device = device; - urb->buffer = (u8 *) urb->buffer_data; - urb->buffer_length = sizeof (urb->buffer_data); + urb->buffer = malloc(URB_BUF_SIZE); + if (!urb->buffer) { + usberr (" F A T A L: mallocFAILED!!!!"); + return NULL; + } + urb->buffer_length = URB_BUF_SIZE; + urb->buffer_data = urb->buffer; urb_link_init (&urb->link); return urb; } +int usbd_init_urb (struct urb *urb, + struct usb_device_instance *device, + struct usb_endpoint_instance *endpoint, + u8 *buf, unsigned int len) +{ + /* Fill in known fields */ + memset (urb, 0, sizeof (struct urb)); + urb->endpoint = endpoint; + urb->device = device; + urb->buffer = buf; + urb->buffer_length = len; + urb->buffer_data = buf; + + urb_link_init (&urb->link); + + return 0; +} + +int usbd_setup_urb(struct urb *urb, u8 *buf, u32 len, int dma) +{ + if (urb) { + urb->req_length = len; + urb->buffer = buf; + urb->use_dma = dma; + } + return 0; +} + +void usbd_free_urb(struct urb *urb) +{ + if (urb) { + urb->req_length = 0; + urb->actual_length = 0; + urb->buffer = NULL; + } +} /** * usbd_dealloc_urb - deallocate an URB and associated buffer * @urb: pointer to an urb structure @@ -577,6 +619,8 @@ struct urb *usbd_alloc_urb (struct usb_device_instance *device, void usbd_dealloc_urb (struct urb *urb) { if (urb) { + if (urb->buffer) + free (urb->buffer); free (urb); } } diff --git a/drivers/usb/gadget/ep0.c b/drivers/usb/gadget/ep0.c index aa8f91600d..40098c5fe9 100644 --- a/drivers/usb/gadget/ep0.c +++ b/drivers/usb/gadget/ep0.c @@ -388,6 +388,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device, * or failure (STALL). * */ +void udc_clear_halt(unsigned int ep, int is_in); int ep0_recv_setup (struct urb *urb) { /*struct usb_device_request *request = urb->buffer; */ @@ -540,14 +541,17 @@ int ep0_recv_setup (struct urb *urb) return -1; case USB_REQ_RECIPIENT_ENDPOINT: - dbg_ep0 (0, "ENDPOINT: %x", le16_to_cpu (request->wValue)); + serial_printf ("ENDPOINT: %x \n", le16_to_cpu (request->wIndex) & 0x0f); if (le16_to_cpu (request->wValue) == USB_ENDPOINT_HALT) { + u8 epnum = request->wIndex & 0xf; + int is_in = request->wIndex & USB_DIR_IN; /*return usbd_device_feature (device, le16_to_cpu (request->wIndex), */ /* request->bRequest == USB_REQ_SET_FEATURE); */ /* NEED TO IMPLEMENT THIS!!! */ - return -1; + udc_clear_halt(epnum, is_in); + return 0; } else { - dbg_ep0 (1, "request %s bad wValue: %04x", + serial_printf ("request %s bad wValue: %04x", USBD_DEVICE_REQUESTS (request->bRequest), le16_to_cpu (request->wValue)); diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 5b8776e0b7..b656c8b9f4 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -23,6 +23,7 @@ #include <common.h> #include <linux/usb/ch9.h> +#include <usbdescriptors.h> #include <asm/errno.h> #include <linux/usb/gadget.h> #include <asm/unaligned.h> diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 9fb0e80ad1..d975fb680e 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -24,6 +24,7 @@ #include <asm/errno.h> #include <linux/netdevice.h> #include <linux/usb/ch9.h> +#include <usbdescriptors.h> #include <linux/usb/cdc.h> #include <linux/usb/gadget.h> #include <net.h> @@ -2396,8 +2397,7 @@ fail: return -1; } -static int usb_eth_send(struct eth_device *netdev, - volatile void *packet, int length) +static int usb_eth_send(struct eth_device *netdev, void *packet, int length) { int retval; void *rndis_pkt = NULL; @@ -2418,11 +2418,11 @@ static int usb_eth_send(struct eth_device *netdev, } rndis_add_hdr(rndis_pkt, length); memcpy(rndis_pkt + sizeof(struct rndis_packet_msg_type), - (void *)packet, length); + packet, length); packet = rndis_pkt; length += sizeof(struct rndis_packet_msg_type); } - req->buf = (void *)packet; + req->buf = packet; req->context = NULL; req->complete = tx_complete; diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c new file mode 100644 index 0000000000..67e5b76911 --- /dev/null +++ b/drivers/usb/gadget/f_fastboot.c @@ -0,0 +1,473 @@ +/* + * ether.c -- Ethernet gadget driver, with CDC and non-CDC options + * + * Copyright (C) 2003-2005,2008 David Brownell + * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define DEBUG + +#include <common.h> +#include <config.h> +#include <asm/unaligned.h> +#include "usbdescriptors.h" +#include <usbdevice.h> + +#if defined(CONFIG_MUSB_UDC) +#include <usb/musb_udc.h> +#else +#error "no usb device controller" +#endif + +#define DEV_CONFIG_CDC 1 + +/* defined and used by gadget/ep0.c */ +extern struct usb_string_descriptor **usb_strings; + +/*-------------------------------------------------------------------------*/ + +/* + * Thanks to NetChip Technologies for donating this product ID. + * It's for devices with only CDC Ethernet configurations. + */ +#define FASTBOOT_VENDOR_NUM 0x18D1 /* Goolge VID */ +#define FASTBOOT_PRODUCT_NUM 0x4EE0 /* Bootloader Product ID */ + +#define FASTBOOT_MANUFACTURER "RDAmicro" +#define FASTBOOT_PRODUCT_NAME "RDA Droid" +#define FASTBOOT_CONFIGURATION_STR "fastboot" +#define FASTBOOT_DATA_INTERFACE_STR "fastboot data intf" + +/*-------------------------------------------------------------------------*/ + +/* + * DESCRIPTORS ... most are static, but strings and (full) configuration + * descriptors are built on demand. For now we do either full CDC, or + * our simple subset. + */ + +#define STRING_MANUFACTURER 1 +#define STRING_PRODUCT 2 +#define STRING_DATA 3 +#define STRING_CFG 4 +#define STRING_SERIALNUMBER 5 + +#define NUM_ENDPOINTS 2 + +static struct usb_device_instance fastboot_dev_instance[1]; +static struct usb_bus_instance fastboot_bus_instance[1]; +static struct usb_configuration_instance fastboot_cfg_instance; +static struct usb_interface_instance fastboot_intf_instance[1]; +static struct usb_alternate_instance fastboot_alternate_instance[1]; +/* one extra for control endpoint */ +static struct usb_endpoint_instance fastboot_ep_instance[NUM_ENDPOINTS + 1]; + +static char serial_number[] = "dragon2012"; + +static struct usb_endpoint_descriptor *ep_desc_ptrs[NUM_ENDPOINTS]; + +static struct usb_device_descriptor + device_desc = { + .bLength = sizeof device_desc, + .bDescriptorType = USB_DT_DEVICE, + + .bcdUSB = __constant_cpu_to_le16(0x0200), + + .bDeviceClass = USB_CLASS_VENDOR_SPEC, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = __constant_cpu_to_le16(FASTBOOT_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16(FASTBOOT_PRODUCT_NUM), + .iManufacturer = STRING_MANUFACTURER, + .iProduct = STRING_PRODUCT, + .iSerialNumber = STRING_SERIALNUMBER, + .bNumConfigurations = 1, +}; + +static struct usb_interface_descriptor + data_intf = { + .bLength = sizeof data_intf, + .bDescriptorType = USB_DT_INTERFACE, + + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 0x42, + .bInterfaceProtocol = 3, + .iInterface = STRING_DATA, +}; + +static struct usb_qualifier_descriptor + dev_qualifier = { + .bLength = sizeof dev_qualifier, + .bDescriptorType = USB_DT_QUAL, + + .bcdUSB = __constant_cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_VENDOR_SPEC, + + .bMaxPacketSize0 = 64, + .bNumConfigurations = 1, +}; + +struct fastboot_config_desc { + struct usb_configuration_descriptor configuration_desc; + struct usb_interface_descriptor interface_desc[1]; + struct usb_endpoint_descriptor data_eps[NUM_ENDPOINTS]; +} __attribute__ ((packed)); + +static struct fastboot_config_desc +fastboot_cfg_desc = { + .configuration_desc = { + .bLength = + sizeof(struct usb_configuration_descriptor), + .bDescriptorType = USB_DT_CONFIG, + .wTotalLength = + cpu_to_le16(sizeof + (struct fastboot_config_desc)), + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = STRING_CFG, + .bmAttributes = + BMATTRIBUTE_SELF_POWERED | BMATTRIBUTE_RESERVED, + .bMaxPower = 0xfa + }, + .interface_desc = { + { + .bLength = sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = NUM_ENDPOINTS, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 0x42, + .bInterfaceProtocol = 3, + .iInterface = STRING_DATA + }, + }, + .data_eps = { + { + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = (1) | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(64), + .bInterval = 0xFF, + }, + { + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = (2) | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(64), + .bInterval = 0xFF, + }, + }, +}; + +/*-------------------------------------------------------------------------*/ + + + +static int fastboot_configured_flag = 0; + +static void fastboot_init_endpoints(void); +static void fastboot_event_handler(struct usb_device_instance *device, + usb_device_event_t event, int data) +{ +#if defined(CONFIG_USBD_HS) + int i; +#endif + switch (event) { + case DEVICE_RESET: + case DEVICE_BUS_INACTIVE: + fastboot_configured_flag = 0; + + break; + case DEVICE_CONFIGURED: + fastboot_configured_flag = 1; + break; + + case DEVICE_ADDRESS_ASSIGNED: +#if defined(CONFIG_USBD_HS) + /* + * is_usbd_high_speed routine needs to be defined by + * specific gadget driver + * It returns TRUE if device enumerates at High speed + * Retuns FALSE otherwise + */ + for (i = 0; i < NUM_ENDPOINTS; i++) { + if (((ep_desc_ptrs[i]->bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK) + && is_usbd_high_speed()) { + + ep_desc_ptrs[i]->wMaxPacketSize = 512; + } + + fastboot_ep_instance[i + 1].tx_packetSize = + ep_desc_ptrs[i]->wMaxPacketSize; + fastboot_ep_instance[i + 1].rcv_packetSize = + ep_desc_ptrs[i]->wMaxPacketSize; + } +#endif + fastboot_init_endpoints(); + + default: + break; + } +} + +/* utility function for converting char* to wide string used by USB */ +static void str2wide (char *str, u16 * wide) +{ + int i; + for (i = 0; i < strlen (str) && str[i]; i++){ + #if defined(__LITTLE_ENDIAN) + wide[i] = (u16) str[i]; + #elif defined(__BIG_ENDIAN) + wide[i] = ((u16)(str[i])<<8); + #else + #error "__LITTLE_ENDIAN or __BIG_ENDIAN undefined" + #endif + } +} + +static struct usb_string_descriptor *fastboot_str_tab[10]; + +static void fastboot_init_strings (void) +{ + struct usb_string_descriptor *string; + + static u8 wstrLang[4] = {4,USB_DT_STRING,0x9,0x4}; + static u8 wstrManufacturer[2 + 2*(sizeof(FASTBOOT_MANUFACTURER)-1)]; + static u8 wstrProduct[2 + 2*(sizeof(FASTBOOT_PRODUCT_NAME)-1)]; + static u8 wstrSerial[2 + 2*(sizeof(serial_number) - 1)]; + static u8 wstrConfiguration[2 + 2*(sizeof(FASTBOOT_CONFIGURATION_STR)-1)]; + static u8 wstrDataInterface[2 + 2*(sizeof(FASTBOOT_DATA_INTERFACE_STR)-1)]; + + + + fastboot_str_tab[0] = + (struct usb_string_descriptor*)wstrLang; + + string = (struct usb_string_descriptor *) wstrManufacturer; + string->bLength = sizeof(wstrManufacturer); + string->bDescriptorType = USB_DT_STRING; + str2wide (FASTBOOT_MANUFACTURER, string->wData); + fastboot_str_tab[STRING_MANUFACTURER]=string; + + + string = (struct usb_string_descriptor *) wstrProduct; + string->bLength = sizeof(wstrProduct); + string->bDescriptorType = USB_DT_STRING; + str2wide (FASTBOOT_PRODUCT_NAME, string->wData); + fastboot_str_tab[STRING_PRODUCT]=string; + + + string = (struct usb_string_descriptor *) wstrSerial; + string->bLength = sizeof(wstrSerial); + string->bDescriptorType = USB_DT_STRING; + str2wide (serial_number, string->wData); + fastboot_str_tab[STRING_SERIALNUMBER]=string; + + string = (struct usb_string_descriptor *) wstrConfiguration; + string->bLength = sizeof(wstrConfiguration); + string->bDescriptorType = USB_DT_STRING; + str2wide (FASTBOOT_CONFIGURATION_STR, string->wData); + fastboot_str_tab[STRING_CFG]=string; + + string = (struct usb_string_descriptor *) wstrDataInterface; + string->bLength = sizeof(wstrDataInterface); + string->bDescriptorType = USB_DT_STRING; + str2wide (FASTBOOT_DATA_INTERFACE_STR, string->wData); + fastboot_str_tab[STRING_DATA]=string; + + /* Now, initialize the string table for ep0 handling */ + usb_strings = fastboot_str_tab; +} +#define init_wMaxPacketSize(x) le16_to_cpu(get_unaligned(\ + &ep_desc_ptrs[(x) - 1]->wMaxPacketSize)); + +static void fastboot_init_instances(void) +{ + int i; + + /* initialize device instance */ + memset(fastboot_dev_instance, 0, sizeof(struct usb_device_instance)); + fastboot_dev_instance->device_state = STATE_INIT; + fastboot_dev_instance->device_descriptor = &device_desc; +#if defined(CONFIG_USBD_HS) + fastboot_dev_instance->qualifier_descriptor = &dev_qualifier; +#endif + fastboot_dev_instance->event = fastboot_event_handler; + fastboot_dev_instance->bus = fastboot_bus_instance; + fastboot_dev_instance->configurations = 1; + fastboot_dev_instance->configuration_instance_array = + &fastboot_cfg_instance; + + /* initialize bus instance */ + memset(fastboot_bus_instance, 0, sizeof(struct usb_bus_instance)); + fastboot_bus_instance->device = fastboot_dev_instance; + fastboot_bus_instance->endpoint_array = fastboot_ep_instance; + fastboot_bus_instance->max_endpoints = 1; + fastboot_bus_instance->maxpacketsize = 64; + fastboot_bus_instance->serial_number_str = serial_number; + + /* configuration instance */ + memset(&fastboot_cfg_instance, 0, + sizeof(struct usb_configuration_instance)); + fastboot_cfg_instance.interfaces = 1; + fastboot_cfg_instance.configuration_descriptor = + (struct usb_configuration_descriptor *) + &fastboot_cfg_desc; + fastboot_cfg_instance.interface_instance_array = + fastboot_intf_instance; + + /* interface instance */ + memset(fastboot_intf_instance, 0, + sizeof(struct usb_interface_instance)); + fastboot_intf_instance->alternates = 1; + fastboot_intf_instance->alternates_instance_array = + fastboot_alternate_instance; + + /* alternates instance */ + memset(fastboot_alternate_instance, 0, + sizeof(struct usb_alternate_instance)); + fastboot_alternate_instance->interface_descriptor = &data_intf; + fastboot_alternate_instance->endpoints = NUM_ENDPOINTS; + fastboot_alternate_instance->endpoints_descriptor_array = ep_desc_ptrs; + + /* endpoint instances */ + memset(&fastboot_ep_instance[0], 0, + sizeof(struct usb_endpoint_instance)); + fastboot_ep_instance[0].endpoint_address = 0; + fastboot_ep_instance[0].rcv_packetSize = 64; + fastboot_ep_instance[0].rcv_attributes = USB_ENDPOINT_XFER_CONTROL; + fastboot_ep_instance[0].tx_packetSize = 64; + fastboot_ep_instance[0].tx_attributes = USB_ENDPOINT_XFER_CONTROL; + udc_setup_ep(fastboot_dev_instance, 0, + &fastboot_ep_instance[0]); + + for (i = 1; i <= NUM_ENDPOINTS; i++) { + memset(&fastboot_ep_instance[i], 0, + sizeof(struct usb_endpoint_instance)); + + fastboot_ep_instance[i].endpoint_address = + ep_desc_ptrs[i - 1]->bEndpointAddress; + + fastboot_ep_instance[i].rcv_attributes = + ep_desc_ptrs[i - 1]->bmAttributes; + + fastboot_ep_instance[i].rcv_packetSize = + init_wMaxPacketSize(i); + + fastboot_ep_instance[i].tx_attributes = + ep_desc_ptrs[i - 1]->bmAttributes; + + fastboot_ep_instance[i].tx_packetSize = + init_wMaxPacketSize(i); + + fastboot_ep_instance[i].tx_attributes = + ep_desc_ptrs[i - 1]->bmAttributes; + + urb_link_init(&fastboot_ep_instance[i].rcv); + urb_link_init(&fastboot_ep_instance[i].rdy); + urb_link_init(&fastboot_ep_instance[i].tx); + urb_link_init(&fastboot_ep_instance[i].done); + + if (fastboot_ep_instance[i].endpoint_address & USB_DIR_IN) + fastboot_ep_instance[i].tx_urb = + usbd_alloc_urb(fastboot_dev_instance, + &fastboot_ep_instance[i]); + else + fastboot_ep_instance[i].rcv_urb = + usbd_alloc_urb(fastboot_dev_instance, + &fastboot_ep_instance[i]); + } +} + +static void fastboot_init_endpoints(void) +{ + int i; + + fastboot_bus_instance->max_endpoints = NUM_ENDPOINTS + 1; + for (i = 1; i <= NUM_ENDPOINTS; i++) { + udc_setup_ep(fastboot_dev_instance, i, + &fastboot_ep_instance[i]); + } +} + +struct usb_endpoint_instance * fastboot_get_out_ep(void) +{ + int i; + int ep_addr; + + for (i = 1; i <= NUM_ENDPOINTS; i++) { + ep_addr = fastboot_ep_instance[i].endpoint_address; + if ((ep_addr != 0) && ((ep_addr & 0x80) == 0)) + return &fastboot_ep_instance[i]; + } + + serial_printf("no out endpoint for fastboot\n"); + return NULL; +} + +struct usb_endpoint_instance * fastboot_get_in_ep(void) +{ + int i; + + for (i = 1; i <= NUM_ENDPOINTS; i++) { + if (fastboot_ep_instance[i].endpoint_address & USB_DIR_IN) + return &fastboot_ep_instance[i]; + } + + serial_printf("no in endpoint for fastboot\n"); + return NULL; + +} + +int fastboot_configured (void) +{ + return fastboot_configured_flag; +} + +/*-------------------------------------------------------------------------*/ + +/* + * Initialize the usb client port. + * + */ +int drv_fastboot_init(void) +{ + ep_desc_ptrs[0] = &fastboot_cfg_desc.data_eps[0]; + ep_desc_ptrs[1] = &fastboot_cfg_desc.data_eps[1]; + + /* Now, set up USB controller and infrastructure */ + + fastboot_init_strings (); + fastboot_init_instances(); + + fastboot_init_endpoints(); + + udc_startup_events(fastboot_dev_instance); /* Enable dev, init udc pointers */ + udc_connect(); /* Enable pullup for host detection */ + + return 0; +} + diff --git a/drivers/usb/gadget/fastboot.c b/drivers/usb/gadget/fastboot.c new file mode 100644 index 0000000000..21aaa0502b --- /dev/null +++ b/drivers/usb/gadget/fastboot.c @@ -0,0 +1,986 @@ +/* + * Copyright (c) 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <common.h> +#include <asm/errno.h> +#include <usbdescriptors.h> +#include <usbdevice.h> +#include <linux/ctype.h> +#include <malloc.h> +#include <command.h> +#include <nand.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <jffs2/jffs2.h> +#include <asm/types.h> +#include <asm/io.h> +#include <android/android_boot.h> +#include <android/android_bootimg.h> +#include <android/boot_mode.h> +#include <asm/arch/rda_sys.h> +#include "fastboot.h" +#include <mmc.h> +#include <mmc/sparse.h> +#include <mmc/mmcpart.h> +#if defined(CONFIG_MUSB_UDC) +#include <usb/musb_udc.h> +#else +#error "no usb device controller" +#endif + +//#define DEBUG +#ifdef DEBUG +#define fb_dbg(fmt, args...) serial_printf(fmt, ##args) +#else +#define fb_dbg(fmt, args...) do {} while(0) +#endif + +#define fb_info(fmt, args...) serial_printf(fmt, ##args) + +#ifdef FLASH_PAGE_SIZE +#undef FLASH_PAGE_SIZE +#endif +#define FLASH_PAGE_SIZE 2048 + +/** implemented in cmd_misc.c */ +extern int load_boot_from_nand(void); +extern int load_boot_from_mmc(void); + +struct fastboot_cmd { + struct fastboot_cmd *next; + const char *prefix; + unsigned prefix_len; + void (*handle) (const char *arg, void *data, loff_t sz); +}; + +struct fastboot_var { + struct fastboot_var *next; + const char *name; + const char *value; +}; + +static struct fastboot_cmd *cmdlist; + +static void fastboot_register(const char *prefix, + void (*handle) (const char *arg, void *data, + loff_t sz)) +{ + struct fastboot_cmd *cmd; + cmd = malloc(sizeof(*cmd)); + if (cmd) { + cmd->prefix = prefix; + cmd->prefix_len = strlen(prefix); + cmd->handle = handle; + cmd->next = cmdlist; + cmdlist = cmd; + } +} + +static struct fastboot_var *varlist; + +static void fastboot_publish(const char *name, const char *value) +{ + struct fastboot_var *var; + var = malloc(sizeof(*var)); + if (var) { + var->name = name; + var->value = value; + var->next = varlist; + varlist = var; + } +} + +static unsigned char buffer[4096]; + +static void *download_base; +static unsigned download_max; +static unsigned download_size; + +enum { + STATE_OFFLINE, + STATE_COMMAND, + STATE_COMPLETE, + STATE_EXIT, + STATE_ERROR +}; + +static unsigned fastboot_state = STATE_OFFLINE; + +static void show_progress(unsigned img_size, unsigned xfer) +{ + static int step = 0; + static unsigned old_size = 0; + + if (img_size != old_size) { + old_size = img_size; + step = 0; + } + + if (step % 64 == 0) + fb_info(">"); + step++; + if (step > 2560) { + printf("%3d%%\n", (u32) (((u64) xfer * 100) / img_size)); + step = 0; + } + if (xfer >= img_size) + fb_info("100%% finised\n"); +} + +static int usb_read(void *_buf, unsigned len) +{ + int count = 0; + struct usb_endpoint_instance *ep_out = fastboot_get_out_ep(); + struct urb *current_urb = NULL; + unsigned char *buf = _buf; + unsigned total = len; + + if (!fastboot_configured()) { + return 0; + } + + if (fastboot_state == STATE_ERROR) + goto oops; + + if (!ep_out) + goto oops; + + fb_dbg("%s, buf 0x%p, len :%d\n", __func__, _buf, len); + current_urb = ep_out->rcv_urb; + while (len > 0) { + int xfer; + int maxPktSize = ep_out->rcv_packetSize; + int dma = 0; + + xfer = (len > maxPktSize) ? maxPktSize : len; + if (xfer == maxPktSize) + dma = 1; + usbd_setup_urb(current_urb, buf, xfer, dma); + udc_irq(); + if (current_urb->actual_length) { + buf += current_urb->actual_length; + len -= current_urb->actual_length; + count += current_urb->actual_length; + if (xfer != current_urb->actual_length) + break; + show_progress(total, count); + current_urb->actual_length = 0; + } + } + current_urb->actual_length = 0; + fb_dbg("%s, read :%d\n", __func__, count); + return count; + +oops: + fb_info("fastboot usb read error\n"); + fastboot_state = STATE_ERROR; + return -1; +} + +static int usb_write(void *_buf, unsigned len) +{ + struct usb_endpoint_instance *ep_in = fastboot_get_in_ep(); + struct urb *current_urb = NULL; + unsigned char *buf = _buf; + int count = 0; + + if (!fastboot_configured()) { + return 0; + } + + if (fastboot_state == STATE_ERROR) + goto oops; + + if (!ep_in) + goto oops; + + fb_dbg("%s, len :%d\n", __func__, len); + current_urb = ep_in->tx_urb; + + while (len > 0) { + int xfer; + int maxPktSize = ep_in->tx_packetSize; + + xfer = (len > maxPktSize) ? maxPktSize : len; + current_urb->buffer = buf; + + current_urb->actual_length = xfer; + fb_dbg("urb actual_len :%d, ep sent, last %d\n", + current_urb->actual_length, ep_in->sent, ep_in->last); + if (udc_endpoint_write(ep_in)) + goto oops; + count += xfer; + len -= xfer; + buf += xfer; + } + fb_dbg("after write urb actual_len :%d, ep sent, last %d, count:%d\n", + current_urb->actual_length, ep_in->sent, ep_in->last, count); + + return count; + +oops: + fb_info("fastboot usb write error\n"); + fastboot_state = STATE_ERROR; + return -1; +} + +void fastboot_ack(const char *code, const char *reason) +{ + char response[64] = { 0 }; + + if (fastboot_state != STATE_COMMAND) + return; + + if (reason == 0) + reason = ""; + + if (strlen(code) + strlen(reason) >= 64) { + fb_info("%s too long string\r\n", __func__); + } + sprintf(response, "%s%s", code, reason); + fastboot_state = STATE_COMPLETE; + + usb_write(response, strlen(response)); + +} + +void fastboot_fail(const char *reason) +{ + fastboot_ack("FAIL", reason); +} + +void fastboot_okay(const char *info) +{ + fastboot_ack("OKAY", info); +} + +void fastboot_info(const char *info) +{ + char response[64] = { 0 }; + const char *code = "INFO"; + + if (info == 0) + info = ""; + + if (strlen(code) + strlen(info) >= 64) { + fb_info("%s too long string\r\n", __func__); + } + snprintf(response, 63, "%s%s", code, info); + + usb_write(response, strlen(response)); +} + +static void cmd_getvar(const char *arg, void *data, loff_t sz) +{ + struct fastboot_var *var; + int value_len; + char str[60]; + + for (var = varlist; var; var = var->next) { + if (!strcmp(var->name, arg)) { + int index = 0; + + value_len = strlen(var->value); + if (value_len < 60) { + fastboot_okay(var->value); + return; + } + /* value length > 60(+INFO > 64) */ + while (value_len) { + int xfer = (value_len > 50) ? 50 : value_len; + + memset(str, 0, sizeof(str)); + strncpy(str, &var->value[index], xfer); + fastboot_info(str); + value_len -= xfer; + index += xfer; + } + fastboot_okay(""); + return; + } + } + fastboot_okay(""); +} + +static void cmd_download(const char *arg, void *data, loff_t sz) +{ + char response[64]; + unsigned len = simple_strtoul(arg, NULL, 16); + int r; + + fb_dbg("%s\n", __func__); + + fb_info("start downloading... length %d is to %p\n", len, data); + download_size = 0; + if (len > download_max) { + fastboot_fail("data too large"); + return; + } + + sprintf(response, "DATA%08x", len); + if (usb_write(response, strlen(response)) < 0) + return; + + r = usb_read(download_base, len); + if ((r < 0) || (r != len)) { + fastboot_state = STATE_ERROR; + return; + } + download_size = len; + fb_info("download ok\n"); + fastboot_okay(""); + //dump_log(download_base, len); +} + +extern int mtdparts_init_default(void); +extern int mtdparts_save_ptbl(int need_erase); + +#ifdef MTDPARTS_UBI_DEF +extern int ubi_part_scan(char *part_name); +extern int ubi_check_default_vols(const char *ubi_default_str); +extern int ubi_erase_vol(char *vol_name); +extern int ubi_update_vol(char *vol_name, void *buf, size_t size); +static int cmd_flash_ubi(const char *arg, void *data, loff_t sz) +{ + int ret = 0; + + ret = ubi_part_scan(MTDPARTS_UBI_PART_NAME); + if(ret) { + fastboot_fail("ubi init failed."); + goto exit; + } + + ret = ubi_check_default_vols(MTDPARTS_UBI_DEF); + if(ret) { + fastboot_fail("ubi volumes check failed."); + goto exit; + } + + fb_info("ready to update ubi volume '%s'\n", arg); + ret = ubi_update_vol((char *)arg, data, sz); +exit: + return ret; +} +#endif /* MTDPARTS_UBI_DEF */ +static void cmd_flash_nand(const char *arg, void *data, loff_t sz) +{ + struct mtd_info *nand; + struct mtd_device *dev; + struct part_info *part; + size_t size = 0; + u8 pnum; + nand_erase_options_t opts; + int ret; + unsigned addr = simple_strtoul(arg, NULL, 16); + loff_t max_limit = 0; + u32 bad_blocks = 0; + sparse_header_t *header = (void *)data; + + fb_info("%s, addr: %s date: %p, sz: 0x%llx\n", __func__, arg, data, sz); + + /* use "flash" command for downloading purpose */ + if (addr && (addr >= PHYS_SDRAM_1) && + (addr < (PHYS_SDRAM_1 + PHYS_SDRAM_1_SIZE))) { + fb_info("in memory, do copy to 0x%x\n", addr); + fastboot_okay(""); + memcpy((void *)addr, download_base, sz); + fastboot_state = STATE_EXIT; + return; + } + + data = download_base; //previous downloaded date to download_base + +#ifdef MTDPARTS_UBI_DEF /* all ubi volumes are in one ubi part */ + if(strstr(MTDPARTS_UBI_DEF, arg)) { + ret = cmd_flash_ubi(arg, data, sz); + goto exit; + } +#endif + + ret = find_dev_and_part(arg, &dev, &pnum, &part); + if (ret) { + fastboot_fail("unknown partition name"); + return; + } else if (dev->id->type != MTD_DEV_TYPE_NAND) { + fastboot_fail("mtd dev type error"); + return; + } + nand = &nand_info[dev->id->num]; + fb_info("found part '%s' offset: 0x%llx length: 0x%llx id: %d\n", + part->name, part->offset, part->size, dev->id->num); + + memset(&opts, 0, sizeof(opts)); + opts.offset = (loff_t) part->offset; + opts.length = (loff_t) part->size; + opts.jffs2 = 0; + opts.quiet = 0; + + fb_dbg("opts off 0x%08x\n", (uint32_t) opts.offset); + fb_dbg("opts size 0x%08x\n", (uint32_t) opts.length); + fb_dbg("nand write size 0x%08x\n", nand->writesize); + fb_info("erase 0x%llx bytes to '%s' offset: 0x%llx\n", + opts.length, part->name, opts.offset); + ret = nand_erase_opts(nand, &opts); + if (ret) { + fastboot_fail("nand erase error"); + return; + } + + if (!strcmp(part->name, "boot") || !strcmp(part->name, "recovery")) { + if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { + fastboot_fail("image is not a boot image"); + return; + } + } + + if (is_power_of_2(nand->writesize)) + sz = ROUND(sz, nand->writesize); + else + sz = roundup(sz, nand->writesize); + size = sz; + max_limit = part->offset + part->size; + + fb_info("writing 0x%x bytes to '%s' offset: 0x%llx\n", size, + part->name, part->offset); + header = (void *)data; + if (header->magic != SPARSE_HEADER_MAGIC) { + ret = + nand_write_skip_bad_new(nand, part->offset, &size, + max_limit, (u_char *) data, + 0, + &bad_blocks); + } else { + ret = nand_write_unsparse(nand, part->offset, &size, max_limit, + (u_char *) data, + 0, + &bad_blocks); + } + + /* the mtd partition table is saved in 'bootloader' partition, + * if 'bootloader' is updated, need to re-write the partition table. */ + if(strcmp(part->name,"bootloader") == 0) { + mtdparts_save_ptbl(1); + } + +#ifdef MTDPARTS_UBI_DEF +exit: +#endif + if (!ret) + fastboot_okay(""); + else + fastboot_fail("flash error"); + fb_info("flash ok\n"); +} + +static block_dev_desc_t *mmc_blkdev; +void cmd_flash_mmc_img(const char *name, void *data, loff_t sz) +{ + disk_partition_t *ptn = 0; + u64 size = 0; + + fb_info("flash to mmc part %s\n", name); + ptn = partition_find_ptn(name); + if (ptn == 0) { + fastboot_fail("partition table doesn't exist"); + return; + } + + if (!strcmp(name, "boot") || !strcmp(name, "recovery")) { + if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { + fastboot_fail("image is not a boot image"); + return; + } + } + + size = (u64) ptn->size * ptn->blksz; + fb_info("partition %s, type %s blocks " LBAFU ", size %llx\n", + ptn->name, ptn->type, ptn->size, size); + if (ROUND(sz, 512) > size) { + fastboot_fail("size too large"); + return; + } else if (partition_write_bytes(mmc_blkdev, ptn, &sz, data)) { + fastboot_fail("flash write failure"); + return; + } + + fastboot_okay(""); + return; +} + +void cmd_flash_mmc_sparse_img(const char *part_name, void *data, loff_t sz) +{ + disk_partition_t *ptn; + unsigned long long size = 0; + int ret; + + fb_info("unsparese and flash part %s\n", part_name); + ptn = partition_find_ptn(part_name); + if (ptn == 0) { + fastboot_fail("partition table doesn't exist"); + return; + } + + size = (u64) ptn->blksz * ptn->size; + if (ROUND(sz, 512) > size) { + fastboot_fail("size too large"); + return; + } + + ret = partition_unsparse(mmc_blkdev, ptn, data, ptn->start, ptn->size); + if (ret) { + fastboot_fail("partition cannot unsparse"); + return; + } + fastboot_okay(""); + return; +} + +void cmd_flash_mmc(const char *arg, void *data, loff_t sz) +{ + sparse_header_t *sparse_header; + + sparse_header = (sparse_header_t *) data; + + /* Using to judge if ext4 file system */ + if (sparse_header->magic != SPARSE_HEADER_MAGIC) + cmd_flash_mmc_img(arg, data, sz); + else + cmd_flash_mmc_sparse_img(arg, data, sz); + + return; +} + +static void cmd_flash(const char *arg, void *data, loff_t sz) +{ + if (rda_media_get() == MEDIA_MMC) + cmd_flash_mmc(arg, data, sz); + else + cmd_flash_nand(arg, data, sz); +} + +static void cmd_erase_nand(const char *arg, void *data, unsigned sz) +{ + struct mtd_info *nand; + struct mtd_device *dev; + struct part_info *part; + u8 pnum; + nand_erase_options_t opts; + int ret; + + fb_info("erase part: %s\n", arg); + +#ifdef MTDPARTS_UBI_DEF /* all ubi volumes are in one ubi part */ + if(strstr(MTDPARTS_UBI_DEF, arg)) { + ubi_part_scan(MTDPARTS_UBI_PART_NAME); + ret = ubi_erase_vol((char *)arg); + if(ret) + fastboot_fail("ubi volume erase error"); + else + fastboot_okay(""); + return; + } +#endif + + ret = find_dev_and_part(arg, &dev, &pnum, &part); + if (ret) { + fastboot_fail("unknown partition name"); + return; + } else if (dev->id->type != MTD_DEV_TYPE_NAND) { + fastboot_fail("mtd dev type error"); + return; + } + nand = &nand_info[dev->id->num]; + fb_info("found part '%s' offset: 0x%llx length: 0x%llx id: %d\n", + part->name, part->offset, part->size, dev->id->num); + + memset(&opts, 0, sizeof(opts)); + opts.offset = (loff_t) part->offset; + opts.length = (loff_t) part->size; + opts.jffs2 = 0; + opts.quiet = 0; + + fb_dbg("opts off 0x%08x\n", (uint32_t) opts.offset); + fb_dbg("opts size 0x%08x\n", (uint32_t) opts.length); + fb_dbg("nand write size 0x%08x\n", nand->writesize); + ret = nand_erase_opts(nand, &opts); + if (ret) + fastboot_fail("nand erase error"); + else + fastboot_okay(""); +} + +static void cmd_erase_mmc(const char *arg, void *data, loff_t sz) +{ + int ret; + disk_partition_t *ptn; + lbaint_t blkcnt; + + fb_info("erase part: %s\n", arg); + ptn = partition_find_ptn(arg); + if (!ptn) { + fastboot_fail("partition table doesn't exist"); + return; + } + + blkcnt = ptn->size; + fb_info("erase mmc from %#x, blocks %#x\n", + (uint32_t)ptn->start, (uint32_t)blkcnt); + ret = partition_erase_blks(mmc_blkdev, ptn, &blkcnt); + if (ret || blkcnt != ptn->size) { + fastboot_fail("partition erase failed"); + return; + } + fastboot_okay(""); +} + +static void cmd_erase(const char *arg, void *data, loff_t sz) +{ + if (rda_media_get() == MEDIA_MMC) + return cmd_erase_mmc(arg, data, sz); + else + return cmd_erase_nand(arg, data, sz); +} + +static unsigned char raw_header[2048]; + +static void cmd_boot(const char *arg, void *data, loff_t sz) +{ + boot_img_hdr *hdr = (boot_img_hdr *) raw_header; + unsigned kernel_actual; + unsigned ramdisk_actual; + char *cmdline; + + fb_info("%s, arg: %s, data: %p, sz: 0x%llx\n", __func__, arg, data, sz); + memcpy(raw_header, data, 2048); + if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { + fb_info("boot image headr: %s\n", hdr->magic); + fastboot_fail("bad boot image header"); + return; + } + kernel_actual = ROUND(hdr->kernel_size, FLASH_PAGE_SIZE); + if (kernel_actual <= 0) { + fastboot_fail("kernel image should not be zero"); + return; + } + ramdisk_actual = ROUND(hdr->ramdisk_size, FLASH_PAGE_SIZE); + if (ramdisk_actual < 0) { + fastboot_fail("ramdisk size error"); + return; + } + + memcpy((void *)hdr->kernel_addr, (void *)data + FLASH_PAGE_SIZE, + kernel_actual); + memcpy((void *)hdr->ramdisk_addr, + (void *)data + FLASH_PAGE_SIZE + kernel_actual, ramdisk_actual); + + fb_info("kernel @0x%08x (0x%08x bytes)\n", hdr->kernel_addr, + kernel_actual); + fb_info("ramdisk @0x%08x (0x%08x bytes)\n", hdr->ramdisk_addr, + ramdisk_actual); + //set boot environment + if (hdr->cmdline[0]) { + cmdline = (char *)hdr->cmdline; + } else { + cmdline = getenv("bootargs"); + } + + fb_info("cmdline %s\n", cmdline); + fastboot_okay(""); + udc_power_off(); + creat_atags(hdr->tags_addr, cmdline, hdr->ramdisk_addr, + hdr->ramdisk_size); + + cleanup_before_linux(); + boot_linux(hdr->kernel_addr, hdr->tags_addr); +} + +extern int do_cboot(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]); + +static void cmd_continue(const char *arg, void *data, loff_t sz) +{ + fb_info("continue....\n"); + fastboot_okay(""); + udc_power_off(); + fastboot_state = STATE_EXIT; + //do_cboot(NULL, 0, 1, NULL); + //normal_mode(); +} + +static void cmd_reboot(const char *arg, void *data, loff_t sz) +{ + fb_info("reboot....\n"); + fastboot_okay(""); + mdelay(10); + udc_power_off(); + fastboot_state = STATE_EXIT; + rda_reboot(REBOOT_TO_NORMAL_MODE); +} + +static void cmd_reboot_bootloader(const char *arg, void *data, loff_t sz) +{ + fb_info("reboot to bootloader....\n"); + fastboot_okay(""); + mdelay(10); + udc_power_off(); + fastboot_state = STATE_EXIT; + rda_reboot(REBOOT_TO_FASTBOOT_MODE); +} + +static void cmd_powerdown(const char *arg, void *data, loff_t sz) +{ + fb_info("power down....\n"); + fastboot_okay(""); + fastboot_state = STATE_EXIT; + //power_down_devices(0); +} + +static void fastboot_command_loop(void) +{ + struct fastboot_cmd *cmd; + int r; + fb_dbg("fastboot: processing commands\n"); + +again: + while ((fastboot_state != STATE_ERROR) + && (fastboot_state != STATE_EXIT)) { + memset(buffer, 0, 64); + r = usb_read(buffer, 64); + if (r < 0) + break; + buffer[r] = 0; + fb_dbg("fastboot: %s, r:%d\n", buffer, r); + + for (cmd = cmdlist; cmd; cmd = cmd->next) { + fb_dbg("cmd list :%s \n", cmd->prefix); + if (memcmp(buffer, cmd->prefix, cmd->prefix_len)) + continue; + fastboot_state = STATE_COMMAND; + cmd->handle((const char *)buffer + cmd->prefix_len, + (void *)download_base, download_size); + if (fastboot_state == STATE_COMMAND) + fastboot_fail("unknown reason"); + if (fastboot_state == STATE_EXIT) + goto fb_done; + goto again; + } + + fastboot_fail("unknown command"); + } + fastboot_state = STATE_OFFLINE; +fb_done: + fb_dbg("fastboot: done\n"); +} + +static int fastboot_handler(void *arg) +{ + while (fastboot_state != STATE_EXIT) { + fastboot_command_loop(); + } + return 0; +} + +static int fastboot_start(void *base, unsigned size) +{ + char *parts; + + fb_info("fastboot start\n"); + + download_base = base; + download_max = size; + + fastboot_register("getvar:", cmd_getvar); + fastboot_register("download:", cmd_download); + fastboot_register("flash:", cmd_flash); + fastboot_register("erase:", cmd_erase); + fastboot_register("boot", cmd_boot); + fastboot_register("reboot", cmd_reboot); + fastboot_register("powerdown", cmd_powerdown); + fastboot_register("continue", cmd_continue); + fastboot_register("reboot-bootloader", cmd_reboot_bootloader); + + fastboot_publish("version", "1.0"); + + parts = getenv("mtdparts"); + fastboot_publish("mtd", parts); + + fastboot_handler(0); + return 0; +} + +/* + * Since interrupt handling has not yet been implemented, we use this function + * to handle polling. . + */ +static void fastboot_wait_for_configed(void) +{ + /* New interrupts? */ + while (!fastboot_configured()) + udc_irq(); +} + +void boot_linux_from_mem(void *data) +{ + boot_img_hdr *hdr = (boot_img_hdr *) data; + unsigned kernel_actual; + unsigned ramdisk_actual; + char *cmdline; + + fb_info("%s, data: %p\n", __func__, data); + if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { + fb_info("boot image headr: %s\n", hdr->magic); + fastboot_fail("bad boot image header"); + return; + } + kernel_actual = ROUND(hdr->kernel_size, FLASH_PAGE_SIZE); + if (kernel_actual <= 0) { + fastboot_fail("kernel image should not be zero"); + return; + } + ramdisk_actual = ROUND(hdr->ramdisk_size, FLASH_PAGE_SIZE); + if (ramdisk_actual < 0) { + fastboot_fail("ramdisk size error"); + return; + } + + memcpy((void *)hdr->kernel_addr, (void *)data + FLASH_PAGE_SIZE, + kernel_actual); + memcpy((void *)hdr->ramdisk_addr, + (void *)data + FLASH_PAGE_SIZE + kernel_actual, ramdisk_actual); + + fb_info("kernel @0x%08x (0x%08x bytes)\n", hdr->kernel_addr, + kernel_actual); + fb_info("ramdisk @0x%08x (0x%08x bytes)\n", hdr->ramdisk_addr, + ramdisk_actual); + //set boot environment + if (hdr->cmdline[0]) { + cmdline = (char *)hdr->cmdline; + } else { + cmdline = getenv("bootargs"); + } + + fb_info("cmdline %s\n", cmdline); + creat_atags(hdr->tags_addr, cmdline, hdr->ramdisk_addr, + hdr->ramdisk_size); + + cleanup_before_linux(); + boot_linux(hdr->kernel_addr, hdr->tags_addr); +} + +void boot_linux_from_nand(void) +{ + if(load_boot_from_nand() == CMD_RET_FAILURE) { + fb_info("fastboot load_boot_from_nand fail\n"); + return; + } + /* boot from mem */ + boot_linux_from_mem((void *)SCRATCH_ADDR); +} + +void boot_linux_from_mmc(void) +{ + if(load_boot_from_mmc() == CMD_RET_FAILURE) { + fb_info("fastboot load_boot_from_mmc fail\n"); + return; + } + /* boot from mem */ + boot_linux_from_mem((void *)SCRATCH_ADDR); +} + +void boot_linux_from_flash(void) +{ + enum media_type media = rda_media_get(); + + if (media == MEDIA_MMC) + boot_linux_from_mmc(); + else if ((media == MEDIA_NAND) || (media == MEDIA_SPINAND)) + boot_linux_from_nand(); + else + fb_info("fastboot can't find media\n"); +} + +#if defined(CONFIG_CMD_FASTBOOT) +extern int drv_fastboot_init(void); + +int do_fastboot(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]) +{ + int ret; + enum media_type media = rda_media_get(); + + udc_init(); + drv_fastboot_init(); + + if ((media == MEDIA_NAND) || (media == MEDIA_SPINAND)) { + ret = mtdparts_init_default(); + if(ret) { + fb_info("nand format partition fail %d\n", ret); + return -1; + } + } + + if (media == MEDIA_MMC) { + ret = mmc_parts_format(); + if (ret) { + fb_info("mmc format partition fail %d\n", ret); + return -1; + } + mmc_blkdev = get_dev_by_name(CONFIG_MMC_DEV_NAME); + } + fastboot_wait_for_configed(); + + fastboot_start((void *)SCRATCH_ADDR, FB_DOWNLOAD_BUF_SIZE); + return 0; +} + +U_BOOT_CMD(fastboot, 1, 1, do_fastboot, + "android fastboot protocol", "flash image to nand"); + +int do_abootf(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]) +{ + boot_linux_from_flash(); + return 1; +} + +U_BOOT_CMD(abootf, 1, 0, do_abootf, + "boot android boot.img from flash", + " - boot android boot.image from flash"); + +int do_abootm(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[]) +{ + ulong offset = 0; + if (argc >= 2) { + offset = simple_strtoul(argv[1], NULL, 16); + } + boot_linux_from_mem((void *)offset); + return 1; +} + +U_BOOT_CMD(abootm, 2, 0, do_abootm, + "boot android boot.img from memory", + "[ off ]\n" + " - boot android boot.image from memory with offset 'off'"); + +#endif diff --git a/drivers/usb/gadget/fastboot.h b/drivers/usb/gadget/fastboot.h new file mode 100644 index 0000000000..123f523b90 --- /dev/null +++ b/drivers/usb/gadget/fastboot.h @@ -0,0 +1,8 @@ +#ifndef __FASTBOOT_H__
+#define __FASTBOOT_H__
+
+extern struct usb_endpoint_instance * fastboot_get_out_ep(void);
+extern struct usb_endpoint_instance * fastboot_get_in_ep(void);
+extern int fastboot_configured (void);
+
+#endif
diff --git a/drivers/usb/gadget/s3c_udc_otg.c b/drivers/usb/gadget/s3c_udc_otg.c index 1050a98b6c..3fdfdf7af0 100644 --- a/drivers/usb/gadget/s3c_udc_otg.c +++ b/drivers/usb/gadget/s3c_udc_otg.c @@ -30,13 +30,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - +#undef DEBUG #include <common.h> #include <asm/errno.h> #include <linux/list.h> #include <malloc.h> #include <linux/usb/ch9.h> +#include <usbdescriptors.h> #include <linux/usb/gadget.h> #include <asm/byteorder.h> @@ -53,19 +54,11 @@ #define OTG_DMA_MODE 1 -#undef DEBUG_S3C_UDC_SETUP -#undef DEBUG_S3C_UDC_EP0 -#undef DEBUG_S3C_UDC_ISR -#undef DEBUG_S3C_UDC_OUT_EP -#undef DEBUG_S3C_UDC_IN_EP -#undef DEBUG_S3C_UDC - -/* #define DEBUG_S3C_UDC_SETUP */ -/* #define DEBUG_S3C_UDC_EP0 */ -/* #define DEBUG_S3C_UDC_ISR */ -/* #define DEBUG_S3C_UDC_OUT_EP */ -/* #define DEBUG_S3C_UDC_IN_EP */ -/* #define DEBUG_S3C_UDC */ +#define DEBUG_SETUP 0 +#define DEBUG_EP0 0 +#define DEBUG_ISR 0 +#define DEBUG_OUT_EP 0 +#define DEBUG_IN_EP 0 #include <usb/s3c_udc.h> @@ -132,6 +125,19 @@ static void nuke(struct s3c_ep *ep, int status); static int s3c_udc_set_halt(struct usb_ep *_ep, int value); static void s3c_udc_set_nak(struct s3c_ep *ep); +void set_udc_gadget_private_data(void *p) +{ + debug_cond(DEBUG_SETUP != 0, + "%s: the_controller: 0x%p, p: 0x%p\n", __func__, + the_controller, p); + the_controller->gadget.dev.device_data = p; +} + +void *get_udc_gadget_private_data(struct usb_gadget *gadget) +{ + return gadget->dev.device_data; +} + static struct usb_ep_ops s3c_ep_ops = { .enable = s3c_ep_enable, .disable = s3c_ep_disable, @@ -216,7 +222,7 @@ void otg_phy_off(struct s3c_udc *dev) */ static void udc_disable(struct s3c_udc *dev) { - DEBUG_SETUP("%s: %p\n", __func__, dev); + debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev); udc_set_address(dev, 0); @@ -234,7 +240,7 @@ static void udc_reinit(struct s3c_udc *dev) { unsigned int i; - DEBUG_SETUP("%s: %p\n", __func__, dev); + debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev); /* device/ep0 records init */ INIT_LIST_HEAD(&dev->gadget.ep_list); @@ -265,12 +271,13 @@ static void udc_reinit(struct s3c_udc *dev) */ static int udc_enable(struct s3c_udc *dev) { - DEBUG_SETUP("%s: %p\n", __func__, dev); + debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev); otg_phy_init(dev); reconfig_usbd(); - DEBUG_SETUP("S3C USB 2.0 OTG Controller Core Initialized : 0x%x\n", + debug_cond(DEBUG_SETUP != 0, + "S3C USB 2.0 OTG Controller Core Initialized : 0x%x\n", readl(®->gintmsk)); dev->gadget.speed = USB_SPEED_UNKNOWN; @@ -287,7 +294,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) int retval = 0; unsigned long flags; - DEBUG_SETUP("%s: %s\n", __func__, "no name"); + debug_cond(DEBUG_SETUP != 0, "%s: %s\n", __func__, "no name"); if (!driver || (driver->speed != USB_SPEED_FULL @@ -311,7 +318,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) retval = driver->bind(&dev->gadget); if (retval) { - DEBUG_SETUP("%s: bind to driver --> error %d\n", + debug_cond(DEBUG_SETUP != 0, + "%s: bind to driver --> error %d\n", dev->gadget.name, retval); dev->driver = 0; return retval; @@ -319,7 +327,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) enable_irq(IRQ_OTG); - DEBUG_SETUP("Registered gadget driver %s\n", dev->gadget.name); + debug_cond(DEBUG_SETUP != 0, + "Registered gadget driver %s\n", dev->gadget.name); udc_enable(dev); return 0; @@ -377,7 +386,7 @@ static void done(struct s3c_ep *ep, struct s3c_request *req, int status) /* don't modify queue heads during completion callback */ ep->stopped = 1; -#ifdef DEBUG_S3C_UDC +#ifdef DEBUG printf("calling complete callback\n"); { int i, len = req->req.length; @@ -671,7 +680,7 @@ static struct usb_request *s3c_alloc_request(struct usb_ep *ep, debug("%s: %s %p\n", __func__, ep->name, ep); - req = kmalloc(sizeof *req, gfp_flags); + req = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*req)); if (!req) return 0; @@ -865,7 +874,8 @@ int s3c_udc_probe(struct s3c_plat_otg_data *pdata) the_controller = dev; for (i = 0; i < S3C_MAX_ENDPOINTS+1; i++) { - dev->dma_buf[i] = kmalloc(DMA_BUFFER_SIZE, GFP_KERNEL); + dev->dma_buf[i] = memalign(CONFIG_SYS_CACHELINE_SIZE, + DMA_BUFFER_SIZE); dev->dma_addr[i] = (dma_addr_t) dev->dma_buf[i]; invalidate_dcache_range((unsigned long) dev->dma_buf[i], (unsigned long) (dev->dma_buf[i] diff --git a/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c b/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c index afd4931fa0..4be603783c 100644 --- a/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c +++ b/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c @@ -53,7 +53,7 @@ static inline void s3c_udc_ep0_zlp(struct s3c_udc *dev) writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, ®->in_endp[EP0_CON].diepctl); - DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n", + debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", __func__, readl(®->in_endp[EP0_CON].diepctl)); dev->ep0state = WAIT_FOR_IN_COMPLETE; } @@ -62,7 +62,8 @@ void s3c_udc_pre_setup(void) { u32 ep_ctrl; - debug_cond(DEBUG_IN_EP, "%s : Prepare Setup packets.\n", __func__); + debug_cond(DEBUG_IN_EP, + "%s : Prepare Setup packets.\n", __func__); invalidate_dcache_range((unsigned long) usb_ctrl_dma_addr, (unsigned long) usb_ctrl_dma_addr @@ -75,9 +76,9 @@ void s3c_udc_pre_setup(void) ep_ctrl = readl(®->out_endp[EP0_CON].doepctl); writel(ep_ctrl|DEPCTL_EPENA, ®->out_endp[EP0_CON].doepctl); - DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n", + debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", __func__, readl(®->in_endp[EP0_CON].diepctl)); - DEBUG_EP0("%s:EP0 ZLP DOEPCTL0 = 0x%x\n", + debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", __func__, readl(®->out_endp[EP0_CON].doepctl)); } @@ -86,9 +87,9 @@ static inline void s3c_ep0_complete_out(void) { u32 ep_ctrl; - DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n", + debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", __func__, readl(®->in_endp[EP0_CON].diepctl)); - DEBUG_EP0("%s:EP0 ZLP DOEPCTL0 = 0x%x\n", + debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", __func__, readl(®->out_endp[EP0_CON].doepctl)); debug_cond(DEBUG_IN_EP, @@ -106,9 +107,9 @@ static inline void s3c_ep0_complete_out(void) writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, ®->out_endp[EP0_CON].doepctl); - DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n", + debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", __func__, readl(®->in_endp[EP0_CON].diepctl)); - DEBUG_EP0("%s:EP0 ZLP DOEPCTL0 = 0x%x\n", + debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", __func__, readl(®->out_endp[EP0_CON].doepctl)); } @@ -145,14 +146,15 @@ static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req) ®->out_endp[ep_num].doeptsiz); writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, ®->out_endp[ep_num].doepctl); - DEBUG_OUT_EP("%s: EP%d RX DMA start : DOEPDMA = 0x%x," - "DOEPTSIZ = 0x%x, DOEPCTL = 0x%x\n" - "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", - __func__, ep_num, - readl(®->out_endp[ep_num].doepdma), - readl(®->out_endp[ep_num].doeptsiz), - readl(®->out_endp[ep_num].doepctl), - buf, pktcnt, length); + debug_cond(DEBUG_OUT_EP != 0, + "%s: EP%d RX DMA start : DOEPDMA = 0x%x," + "DOEPTSIZ = 0x%x, DOEPCTL = 0x%x\n" + "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", + __func__, ep_num, + readl(®->out_endp[ep_num].doepdma), + readl(®->out_endp[ep_num].doeptsiz), + readl(®->out_endp[ep_num].doepctl), + buf, pktcnt, length); return 0; } @@ -168,7 +170,7 @@ int setdma_tx(struct s3c_ep *ep, struct s3c_request *req) length = req->req.length - req->req.actual; if (ep_num == EP0_CON) - length = min_t(length, (u32)ep_maxpacket(ep)); + length = min(length, (u32)ep_maxpacket(ep)); ep->len = length; ep->dma_buf = buf; @@ -225,8 +227,9 @@ static void complete_rx(struct s3c_udc *dev, u8 ep_num) u32 *p = the_controller->dma_buf[ep_index(ep)+1]; if (list_empty(&ep->queue)) { - DEBUG_OUT_EP("%s: RX DMA done : NULL REQ on OUT EP-%d\n", - __func__, ep_num); + debug_cond(DEBUG_OUT_EP != 0, + "%s: RX DMA done : NULL REQ on OUT EP-%d\n", + __func__, ep_num); return; } @@ -249,14 +252,15 @@ static void complete_rx(struct s3c_udc *dev, u8 ep_num) req->req.actual += min(xfer_size, req->req.length - req->req.actual); is_short = (xfer_size < ep->ep.maxpacket); - DEBUG_OUT_EP("%s: RX DMA done : ep = %d, rx bytes = %d/%d, " - "is_short = %d, DOEPTSIZ = 0x%x, remained bytes = %d\n", - __func__, ep_num, req->req.actual, req->req.length, - is_short, ep_tsr, xfer_size); + debug_cond(DEBUG_OUT_EP != 0, + "%s: RX DMA done : ep = %d, rx bytes = %d/%d, " + "is_short = %d, DOEPTSIZ = 0x%x, remained bytes = %d\n", + __func__, ep_num, req->req.actual, req->req.length, + is_short, ep_tsr, xfer_size); if (is_short || req->req.actual == req->req.length) { if (ep_num == EP0_CON && dev->ep0state == DATA_STATE_RECV) { - DEBUG_OUT_EP(" => Send ZLP\n"); + debug_cond(DEBUG_OUT_EP != 0, " => Send ZLP\n"); s3c_udc_ep0_zlp(dev); /* packet will be completed in complete_tx() */ dev->ep0state = WAIT_FOR_IN_COMPLETE; @@ -266,8 +270,9 @@ static void complete_rx(struct s3c_udc *dev, u8 ep_num) if (!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, struct s3c_request, queue); - DEBUG_OUT_EP("%s: Next Rx request start...\n", - __func__); + debug_cond(DEBUG_OUT_EP != 0, + "%s: Next Rx request start...\n", + __func__); setdma_rx(ep, req); } } @@ -392,8 +397,9 @@ static void process_ep_in_intr(struct s3c_udc *dev) while (ep_intr) { if (ep_intr & DAINT_IN_EP_INT(1)) { ep_intr_status = readl(®->in_endp[ep_num].diepint); - debug_cond(DEBUG_IN_EP, "\tEP%d-IN : DIEPINT = 0x%x\n", - ep_num, ep_intr_status); + debug_cond(DEBUG_IN_EP, + "\tEP%d-IN : DIEPINT = 0x%x\n", + ep_num, ep_intr_status); /* Interrupt Clear */ writel(ep_intr_status, ®->in_endp[ep_num].diepint); @@ -430,16 +436,18 @@ static void process_ep_out_intr(struct s3c_udc *dev) u8 ep_num = 0; ep_intr = readl(®->daint); - DEBUG_OUT_EP("*** %s: EP OUT interrupt : DAINT = 0x%x\n", - __func__, ep_intr); + debug_cond(DEBUG_OUT_EP != 0, + "*** %s: EP OUT interrupt : DAINT = 0x%x\n", + __func__, ep_intr); ep_intr = (ep_intr >> DAINT_OUT_BIT) & DAINT_MASK; while (ep_intr) { if (ep_intr & 0x1) { ep_intr_status = readl(®->out_endp[ep_num].doepint); - DEBUG_OUT_EP("\tEP%d-OUT : DOEPINT = 0x%x\n", - ep_num, ep_intr_status); + debug_cond(DEBUG_OUT_EP != 0, + "\tEP%d-OUT : DOEPINT = 0x%x\n", + ep_num, ep_intr_status); /* Interrupt Clear */ writel(ep_intr_status, ®->out_endp[ep_num].doepint); @@ -457,7 +465,8 @@ static void process_ep_out_intr(struct s3c_udc *dev) if (ep_intr_status & CTRL_OUT_EP_SETUP_PHASE_DONE) { - DEBUG_OUT_EP("SETUP packet arrived\n"); + debug_cond(DEBUG_OUT_EP != 0, + "SETUP packet arrived\n"); s3c_handle_ep0(dev); } } else { @@ -503,7 +512,8 @@ static int s3c_udc_irq(int irq, void *_dev) usb_status = (readl(®->dsts) & 0x6); if (usb_status & (USB_FULL_30_60MHZ | USB_FULL_48MHZ)) { - debug_cond(DEBUG_ISR, "\t\tFull Speed Detection\n"); + debug_cond(DEBUG_ISR, + "\t\tFull Speed Detection\n"); set_max_pktsize(dev, USB_SPEED_FULL); } else { @@ -571,7 +581,8 @@ static int s3c_udc_irq(int irq, void *_dev) } else { reset_available = 1; - debug_cond(DEBUG_ISR, "\t\tRESET handling skipped\n"); + debug_cond(DEBUG_ISR, + "\t\tRESET handling skipped\n"); } } @@ -635,7 +646,7 @@ static int s3c_queue(struct usb_ep *_ep, struct usb_request *_req, _req, _req->length, _req->buf, list_empty(&ep->queue), ep->stopped); -#ifdef DEBUG_S3C_UDC +#ifdef DEBUG { int i, len = _req->length; @@ -662,14 +673,15 @@ static int s3c_queue(struct usb_ep *_ep, struct usb_request *_req, } else if (ep_is_in(ep)) { gintsts = readl(®->gintsts); debug_cond(DEBUG_IN_EP, - "%s: ep_is_in, S3C_UDC_OTG_GINTSTS=0x%x\n", - __func__, gintsts); + "%s: ep_is_in, S3C_UDC_OTG_GINTSTS=0x%x\n", + __func__, gintsts); setdma_tx(ep, req); } else { gintsts = readl(®->gintsts); - DEBUG_OUT_EP("%s:ep_is_out, S3C_UDC_OTG_GINTSTS=0x%x\n", - __func__, gintsts); + debug_cond(DEBUG_OUT_EP != 0, + "%s:ep_is_out, S3C_UDC_OTG_GINTSTS=0x%x\n", + __func__, gintsts); setdma_rx(ep, req); } @@ -697,7 +709,7 @@ static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req) max = ep_maxpacket(ep); - DEBUG_EP0("%s: max = %d\n", __func__, max); + debug_cond(DEBUG_EP0 != 0, "%s: max = %d\n", __func__, max); count = setdma_tx(ep, req); @@ -712,10 +724,11 @@ static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req) is_last = 1; } - DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __func__, - ep->ep.name, count, - is_last ? "/L" : "", - req->req.length - req->req.actual - count, req); + debug_cond(DEBUG_EP0 != 0, + "%s: wrote %s %d bytes%s %d left %p\n", __func__, + ep->ep.name, count, + is_last ? "/L" : "", + req->req.length - req->req.actual - count, req); /* requests complete when all IN data is in the FIFO */ if (is_last) { @@ -736,8 +749,9 @@ int s3c_fifo_read(struct s3c_ep *ep, u32 *cp, int max) (unsigned long) ep->dev->dma_buf[ep_index(ep)] + DMA_BUFFER_SIZE); - DEBUG_EP0("%s: bytes=%d, ep_index=%d %p\n", __func__, - bytes, ep_index(ep), ep->dev->dma_buf[ep_index(ep)]); + debug_cond(DEBUG_EP0 != 0, + "%s: bytes=%d, ep_index=%d %p\n", __func__, + bytes, ep_index(ep), ep->dev->dma_buf[ep_index(ep)]); return bytes; } @@ -756,8 +770,9 @@ static void udc_set_address(struct s3c_udc *dev, unsigned char address) s3c_udc_ep0_zlp(dev); - DEBUG_EP0("%s: USB OTG 2.0 Device address=%d, DCFG=0x%x\n", - __func__, address, readl(®->dcfg)); + debug_cond(DEBUG_EP0 != 0, + "%s: USB OTG 2.0 Device address=%d, DCFG=0x%x\n", + __func__, address, readl(®->dcfg)); dev->usb_address = address; } @@ -778,8 +793,9 @@ static inline void s3c_udc_ep0_set_stall(struct s3c_ep *ep) writel(ep_ctrl, ®->in_endp[EP0_CON].diepctl); - DEBUG_EP0("%s: set ep%d stall, DIEPCTL0 = 0x%x\n", - __func__, ep_index(ep), ®->in_endp[EP0_CON].diepctl); + debug_cond(DEBUG_EP0 != 0, + "%s: set ep%d stall, DIEPCTL0 = 0x%p\n", + __func__, ep_index(ep), ®->in_endp[EP0_CON].diepctl); /* * The application can only set this bit, and the core clears it, * when a SETUP token is received for this endpoint @@ -803,8 +819,9 @@ static void s3c_ep0_read(struct s3c_udc *dev) return; } - DEBUG_EP0("%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n", - __func__, req, req->req.length, req->req.actual); + debug_cond(DEBUG_EP0 != 0, + "%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n", + __func__, req, req->req.length, req->req.actual); if (req->req.length == 0) { /* zlp for Set_configuration, Set_interface, @@ -813,8 +830,9 @@ static void s3c_ep0_read(struct s3c_udc *dev) ep->len = 0; s3c_udc_ep0_zlp(dev); - DEBUG_EP0("%s: req.length = 0, bRequest = %d\n", - __func__, usb_ctrl->bRequest); + debug_cond(DEBUG_EP0 != 0, + "%s: req.length = 0, bRequest = %d\n", + __func__, usb_ctrl->bRequest); return; } @@ -836,12 +854,13 @@ static int s3c_ep0_write(struct s3c_udc *dev) req = list_entry(ep->queue.next, struct s3c_request, queue); if (!req) { - DEBUG_EP0("%s: NULL REQ\n", __func__); + debug_cond(DEBUG_EP0 != 0, "%s: NULL REQ\n", __func__); return 0; } - DEBUG_EP0("%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n", - __func__, req, req->req.length, req->req.actual); + debug_cond(DEBUG_EP0 != 0, + "%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n", + __func__, req, req->req.length, req->req.actual); if (req->req.length - req->req.actual == ep0_fifo_size) { /* Next write will end with the packet size, */ @@ -854,11 +873,13 @@ static int s3c_ep0_write(struct s3c_udc *dev) if ((ret == 1) && !need_zlp) { /* Last packet */ dev->ep0state = WAIT_FOR_COMPLETE; - DEBUG_EP0("%s: finished, waiting for status\n", __func__); + debug_cond(DEBUG_EP0 != 0, + "%s: finished, waiting for status\n", __func__); } else { dev->ep0state = DATA_STATE_XMIT; - DEBUG_EP0("%s: not finished\n", __func__); + debug_cond(DEBUG_EP0 != 0, + "%s: not finished\n", __func__); } return 1; @@ -873,30 +894,35 @@ int s3c_udc_get_status(struct s3c_udc *dev, u32 ep_ctrl; u32 *p = the_controller->dma_buf[1]; - DEBUG_SETUP("%s: *** USB_REQ_GET_STATUS\n", __func__); + debug_cond(DEBUG_SETUP != 0, + "%s: *** USB_REQ_GET_STATUS\n", __func__); printf("crq->brequest:0x%x\n", crq->bRequestType & USB_RECIP_MASK); switch (crq->bRequestType & USB_RECIP_MASK) { case USB_RECIP_INTERFACE: g_status = 0; - DEBUG_SETUP("\tGET_STATUS:USB_RECIP_INTERFACE, g_stauts = %d\n", - g_status); + debug_cond(DEBUG_SETUP != 0, + "\tGET_STATUS:USB_RECIP_INTERFACE, g_stauts = %d\n", + g_status); break; case USB_RECIP_DEVICE: g_status = 0x1; /* Self powered */ - DEBUG_SETUP("\tGET_STATUS: USB_RECIP_DEVICE, g_stauts = %d\n", - g_status); + debug_cond(DEBUG_SETUP != 0, + "\tGET_STATUS: USB_RECIP_DEVICE, g_stauts = %d\n", + g_status); break; case USB_RECIP_ENDPOINT: if (crq->wLength > 2) { - DEBUG_SETUP("\tGET_STATUS:Not support EP or wLength\n"); + debug_cond(DEBUG_SETUP != 0, + "\tGET_STATUS:Not support EP or wLength\n"); return 1; } g_status = dev->ep[ep_num].stopped; - DEBUG_SETUP("\tGET_STATUS: USB_RECIP_ENDPOINT, g_stauts = %d\n", - g_status); + debug_cond(DEBUG_SETUP != 0, + "\tGET_STATUS: USB_RECIP_ENDPOINT, g_stauts = %d\n", + g_status); break; @@ -1134,11 +1160,13 @@ static int s3c_udc_clear_feature(struct usb_ep *_ep) ep_num = ep_index(ep); dev = ep->dev; - DEBUG_SETUP("%s: ep_num = %d, is_in = %d, clear_feature_flag = %d\n", - __func__, ep_num, ep_is_in(ep), clear_feature_flag); + debug_cond(DEBUG_SETUP != 0, + "%s: ep_num = %d, is_in = %d, clear_feature_flag = %d\n", + __func__, ep_num, ep_is_in(ep), clear_feature_flag); if (usb_ctrl->wLength != 0) { - DEBUG_SETUP("\tCLEAR_FEATURE: wLength is not zero.....\n"); + debug_cond(DEBUG_SETUP != 0, + "\tCLEAR_FEATURE: wLength is not zero.....\n"); return 1; } @@ -1146,11 +1174,13 @@ static int s3c_udc_clear_feature(struct usb_ep *_ep) case USB_RECIP_DEVICE: switch (usb_ctrl->wValue) { case USB_DEVICE_REMOTE_WAKEUP: - DEBUG_SETUP("\tOFF:USB_DEVICE_REMOTE_WAKEUP\n"); + debug_cond(DEBUG_SETUP != 0, + "\tOFF:USB_DEVICE_REMOTE_WAKEUP\n"); break; case USB_DEVICE_TEST_MODE: - DEBUG_SETUP("\tCLEAR_FEATURE: USB_DEVICE_TEST_MODE\n"); + debug_cond(DEBUG_SETUP != 0, + "\tCLEAR_FEATURE: USB_DEVICE_TEST_MODE\n"); /** @todo Add CLEAR_FEATURE for TEST modes. */ break; } @@ -1159,8 +1189,9 @@ static int s3c_udc_clear_feature(struct usb_ep *_ep) break; case USB_RECIP_ENDPOINT: - DEBUG_SETUP("\tCLEAR_FEATURE:USB_RECIP_ENDPOINT, wValue = %d\n", - usb_ctrl->wValue); + debug_cond(DEBUG_SETUP != 0, + "\tCLEAR_FEATURE:USB_RECIP_ENDPOINT, wValue = %d\n", + usb_ctrl->wValue); if (usb_ctrl->wValue == USB_ENDPOINT_HALT) { if (ep_num == 0) { @@ -1193,11 +1224,13 @@ static int s3c_udc_set_feature(struct usb_ep *_ep) ep_num = ep_index(ep); dev = ep->dev; - DEBUG_SETUP("%s: *** USB_REQ_SET_FEATURE , ep_num = %d\n", + debug_cond(DEBUG_SETUP != 0, + "%s: *** USB_REQ_SET_FEATURE , ep_num = %d\n", __func__, ep_num); if (usb_ctrl->wLength != 0) { - DEBUG_SETUP("\tSET_FEATURE: wLength is not zero.....\n"); + debug_cond(DEBUG_SETUP != 0, + "\tSET_FEATURE: wLength is not zero.....\n"); return 1; } @@ -1205,20 +1238,24 @@ static int s3c_udc_set_feature(struct usb_ep *_ep) case USB_RECIP_DEVICE: switch (usb_ctrl->wValue) { case USB_DEVICE_REMOTE_WAKEUP: - DEBUG_SETUP("\tSET_FEATURE:USB_DEVICE_REMOTE_WAKEUP\n"); + debug_cond(DEBUG_SETUP != 0, + "\tSET_FEATURE:USB_DEVICE_REMOTE_WAKEUP\n"); break; case USB_DEVICE_B_HNP_ENABLE: - DEBUG_SETUP("\tSET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n"); + debug_cond(DEBUG_SETUP != 0, + "\tSET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n"); break; case USB_DEVICE_A_HNP_SUPPORT: /* RH port supports HNP */ - DEBUG_SETUP("\tSET_FEATURE:USB_DEVICE_A_HNP_SUPPORT\n"); + debug_cond(DEBUG_SETUP != 0, + "\tSET_FEATURE:USB_DEVICE_A_HNP_SUPPORT\n"); break; case USB_DEVICE_A_ALT_HNP_SUPPORT: /* other RH port does */ - DEBUG_SETUP("\tSET: USB_DEVICE_A_ALT_HNP_SUPPORT\n"); + debug_cond(DEBUG_SETUP != 0, + "\tSET: USB_DEVICE_A_ALT_HNP_SUPPORT\n"); break; } @@ -1226,11 +1263,13 @@ static int s3c_udc_set_feature(struct usb_ep *_ep) return 0; case USB_RECIP_INTERFACE: - DEBUG_SETUP("\tSET_FEATURE: USB_RECIP_INTERFACE\n"); + debug_cond(DEBUG_SETUP != 0, + "\tSET_FEATURE: USB_RECIP_INTERFACE\n"); break; case USB_RECIP_ENDPOINT: - DEBUG_SETUP("\tSET_FEATURE: USB_RECIP_ENDPOINT\n"); + debug_cond(DEBUG_SETUP != 0, + "\tSET_FEATURE: USB_RECIP_ENDPOINT\n"); if (usb_ctrl->wValue == USB_ENDPOINT_HALT) { if (ep_num == 0) { s3c_udc_ep0_set_stall(ep); @@ -1262,14 +1301,15 @@ void s3c_ep0_setup(struct s3c_udc *dev) /* read control req from fifo (8 bytes) */ s3c_fifo_read(ep, (u32 *)usb_ctrl, 8); - DEBUG_SETUP("%s: bRequestType = 0x%x(%s), bRequest = 0x%x" - "\twLength = 0x%x, wValue = 0x%x, wIndex= 0x%x\n", - __func__, usb_ctrl->bRequestType, - (usb_ctrl->bRequestType & USB_DIR_IN) ? "IN" : "OUT", - usb_ctrl->bRequest, - usb_ctrl->wLength, usb_ctrl->wValue, usb_ctrl->wIndex); + debug_cond(DEBUG_SETUP != 0, + "%s: bRequestType = 0x%x(%s), bRequest = 0x%x" + "\twLength = 0x%x, wValue = 0x%x, wIndex= 0x%x\n", + __func__, usb_ctrl->bRequestType, + (usb_ctrl->bRequestType & USB_DIR_IN) ? "IN" : "OUT", + usb_ctrl->bRequest, + usb_ctrl->wLength, usb_ctrl->wValue, usb_ctrl->wIndex); -#ifdef DEBUG_S3C_UDC +#ifdef DEBUG { int i, len = sizeof(*usb_ctrl); char *p = (char *)usb_ctrl; @@ -1286,10 +1326,12 @@ void s3c_ep0_setup(struct s3c_udc *dev) if (usb_ctrl->bRequest == GET_MAX_LUN_REQUEST && usb_ctrl->wLength != 1) { - DEBUG_SETUP("\t%s:GET_MAX_LUN_REQUEST:invalid", - __func__); - DEBUG_SETUP("wLength = %d, setup returned\n", - usb_ctrl->wLength); + debug_cond(DEBUG_SETUP != 0, + "\t%s:GET_MAX_LUN_REQUEST:invalid", + __func__); + debug_cond(DEBUG_SETUP != 0, + "wLength = %d, setup returned\n", + usb_ctrl->wLength); s3c_udc_ep0_set_stall(ep); dev->ep0state = WAIT_FOR_SETUP; @@ -1298,8 +1340,9 @@ void s3c_ep0_setup(struct s3c_udc *dev) } else if (usb_ctrl->bRequest == BOT_RESET_REQUEST && usb_ctrl->wLength != 0) { /* Bulk-Only *mass storge reset of class-specific request */ - DEBUG_SETUP("%s:BOT Rest:invalid wLength =%d, setup returned\n", - __func__, usb_ctrl->wLength); + debug_cond(DEBUG_SETUP != 0, + "%s:BOT Rest:invalid wLength =%d, setup returned\n", + __func__, usb_ctrl->wLength); s3c_udc_ep0_set_stall(ep); dev->ep0state = WAIT_FOR_SETUP; @@ -1323,8 +1366,9 @@ void s3c_ep0_setup(struct s3c_udc *dev) if (dev->req_std) { switch (usb_ctrl->bRequest) { case USB_REQ_SET_ADDRESS: - DEBUG_SETUP("%s: *** USB_REQ_SET_ADDRESS (%d)\n", - __func__, usb_ctrl->wValue); + debug_cond(DEBUG_SETUP != 0, + "%s: *** USB_REQ_SET_ADDRESS (%d)\n", + __func__, usb_ctrl->wValue); if (usb_ctrl->bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) break; @@ -1333,9 +1377,11 @@ void s3c_ep0_setup(struct s3c_udc *dev) return; case USB_REQ_SET_CONFIGURATION: - DEBUG_SETUP("=====================================\n"); - DEBUG_SETUP("%s: USB_REQ_SET_CONFIGURATION (%d)\n", - __func__, usb_ctrl->wValue); + debug_cond(DEBUG_SETUP != 0, + "=====================================\n"); + debug_cond(DEBUG_SETUP != 0, + "%s: USB_REQ_SET_CONFIGURATION (%d)\n", + __func__, usb_ctrl->wValue); if (usb_ctrl->bRequestType == USB_RECIP_DEVICE) reset_available = 1; @@ -1343,13 +1389,15 @@ void s3c_ep0_setup(struct s3c_udc *dev) break; case USB_REQ_GET_DESCRIPTOR: - DEBUG_SETUP("%s: *** USB_REQ_GET_DESCRIPTOR\n", - __func__); + debug_cond(DEBUG_SETUP != 0, + "%s: *** USB_REQ_GET_DESCRIPTOR\n", + __func__); break; case USB_REQ_SET_INTERFACE: - DEBUG_SETUP("%s: *** USB_REQ_SET_INTERFACE (%d)\n", - __func__, usb_ctrl->wValue); + debug_cond(DEBUG_SETUP != 0, + "%s: *** USB_REQ_SET_INTERFACE (%d)\n", + __func__, usb_ctrl->wValue); if (usb_ctrl->bRequestType == USB_RECIP_INTERFACE) reset_available = 1; @@ -1357,8 +1405,9 @@ void s3c_ep0_setup(struct s3c_udc *dev) break; case USB_REQ_GET_CONFIGURATION: - DEBUG_SETUP("%s: *** USB_REQ_GET_CONFIGURATION\n", - __func__); + debug_cond(DEBUG_SETUP != 0, + "%s: *** USB_REQ_GET_CONFIGURATION\n", + __func__); break; case USB_REQ_GET_STATUS: @@ -1384,8 +1433,9 @@ void s3c_ep0_setup(struct s3c_udc *dev) break; default: - DEBUG_SETUP("%s: *** Default of usb_ctrl->bRequest=0x%x" - "happened.\n", __func__, usb_ctrl->bRequest); + debug_cond(DEBUG_SETUP != 0, + "%s: *** Default of usb_ctrl->bRequest=0x%x" + "happened.\n", __func__, usb_ctrl->bRequest); break; } } @@ -1394,7 +1444,8 @@ void s3c_ep0_setup(struct s3c_udc *dev) if (likely(dev->driver)) { /* device-2-host (IN) or no data setup command, * process immediately */ - DEBUG_SETUP("%s:usb_ctrlreq will be passed to fsg_setup()\n", + debug_cond(DEBUG_SETUP != 0, + "%s:usb_ctrlreq will be passed to fsg_setup()\n", __func__); spin_unlock(&dev->lock); @@ -1406,17 +1457,20 @@ void s3c_ep0_setup(struct s3c_udc *dev) s3c_udc_ep0_set_stall(ep); dev->ep0state = WAIT_FOR_SETUP; - DEBUG_SETUP("\tdev->driver->setup failed (%d)," + debug_cond(DEBUG_SETUP != 0, + "\tdev->driver->setup failed (%d)," " bRequest = %d\n", i, usb_ctrl->bRequest); } else if (dev->req_pending) { dev->req_pending = 0; - DEBUG_SETUP("\tdev->req_pending...\n"); + debug_cond(DEBUG_SETUP != 0, + "\tdev->req_pending...\n"); } - DEBUG_SETUP("\tep0state = %s\n", state_names[dev->ep0state]); + debug_cond(DEBUG_SETUP != 0, + "\tep0state = %s\n", state_names[dev->ep0state]); } } @@ -1427,18 +1481,21 @@ void s3c_ep0_setup(struct s3c_udc *dev) static void s3c_handle_ep0(struct s3c_udc *dev) { if (dev->ep0state == WAIT_FOR_SETUP) { - DEBUG_OUT_EP("%s: WAIT_FOR_SETUP\n", __func__); + debug_cond(DEBUG_OUT_EP != 0, + "%s: WAIT_FOR_SETUP\n", __func__); s3c_ep0_setup(dev); } else { - DEBUG_OUT_EP("%s: strange state!!(state = %s)\n", + debug_cond(DEBUG_OUT_EP != 0, + "%s: strange state!!(state = %s)\n", __func__, state_names[dev->ep0state]); } } static void s3c_ep0_kick(struct s3c_udc *dev, struct s3c_ep *ep) { - DEBUG_EP0("%s: ep_is_in = %d\n", __func__, ep_is_in(ep)); + debug_cond(DEBUG_EP0 != 0, + "%s: ep_is_in = %d\n", __func__, ep_is_in(ep)); if (ep_is_in(ep)) { dev->ep0state = DATA_STATE_XMIT; s3c_ep0_write(dev); diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 95555cf96b..4dbe060d6f 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -13,6 +13,7 @@ #include <common.h> #include <asm/errno.h> #include <linux/usb/ch9.h> +#include <usbdescriptors.h> #include <linux/usb/gadget.h> #include <asm/unaligned.h> |