aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/gadget
diff options
context:
space:
mode:
authorDaniel Thompson <daniel.thompson@linaro.org>2017-07-31 17:23:07 +0100
committerDaniel Thompson <daniel.thompson@linaro.org>2017-07-31 17:23:07 +0100
commite5b9b8c8b78096e961f4a45b9d1418e4641f24f9 (patch)
treea88f532f386376fca6a376e2c362173f971dc144 /drivers/usb/gadget
parent415d386877df49eb051b85ef74fa59a16dc17c7d (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/Makefile4
-rw-r--r--drivers/usb/gadget/composite.c1082
-rw-r--r--drivers/usb/gadget/config.c1
-rw-r--r--drivers/usb/gadget/core.c50
-rw-r--r--drivers/usb/gadget/ep0.c10
-rw-r--r--drivers/usb/gadget/epautoconf.c1
-rw-r--r--drivers/usb/gadget/ether.c8
-rw-r--r--drivers/usb/gadget/f_fastboot.c473
-rw-r--r--drivers/usb/gadget/fastboot.c986
-rw-r--r--drivers/usb/gadget/fastboot.h8
-rw-r--r--drivers/usb/gadget/s3c_udc_otg.c58
-rw-r--r--drivers/usb/gadget/s3c_udc_otg_xfer_dma.c289
-rw-r--r--drivers/usb/gadget/usbstring.c1
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(&reg->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,
&reg->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(&reg->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(&reg->out_endp[EP0_CON].doepctl);
writel(ep_ctrl|DEPCTL_EPENA, &reg->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(&reg->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(&reg->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(&reg->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(&reg->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,
&reg->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(&reg->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(&reg->out_endp[EP0_CON].doepctl));
}
@@ -145,14 +146,15 @@ static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req)
&reg->out_endp[ep_num].doeptsiz);
writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, &reg->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(&reg->out_endp[ep_num].doepdma),
- readl(&reg->out_endp[ep_num].doeptsiz),
- readl(&reg->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(&reg->out_endp[ep_num].doepdma),
+ readl(&reg->out_endp[ep_num].doeptsiz),
+ readl(&reg->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(&reg->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, &reg->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(&reg->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(&reg->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, &reg->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(&reg->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(&reg->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(&reg->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(&reg->dcfg));
+ debug_cond(DEBUG_EP0 != 0,
+ "%s: USB OTG 2.0 Device address=%d, DCFG=0x%x\n",
+ __func__, address, readl(&reg->dcfg));
dev->usb_address = address;
}
@@ -778,8 +793,9 @@ static inline void s3c_udc_ep0_set_stall(struct s3c_ep *ep)
writel(ep_ctrl, &reg->in_endp[EP0_CON].diepctl);
- DEBUG_EP0("%s: set ep%d stall, DIEPCTL0 = 0x%x\n",
- __func__, ep_index(ep), &reg->in_endp[EP0_CON].diepctl);
+ debug_cond(DEBUG_EP0 != 0,
+ "%s: set ep%d stall, DIEPCTL0 = 0x%p\n",
+ __func__, ep_index(ep), &reg->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>